为bookStore添加权限【动态代理和注解】
前言
目前为止,我们已经学习了动态代理技术和注解技术了。于是我们想要为之前的bookStore项目添加权限控制…..
只有用户有权限的时候,后台管理才可以进行相对应的操作…..
实现思路
之前我们做权限管理系统的时候,是根据用户请求的URI来判断该链接是否需要权限的。这次我们使用动态代理的技术和注解来判断:用户调用该方法时,检查该方法是否需要权限…
根据MVC模式,我们在web层都是调用service层来实现功能的。那么我们具体的思路是这样的:
- web层调用service层的时候,得到的并不是ServiceDao对象,而是我们的代理对象
- 在service层中的方法添加注解,如果方法上有注解,那么说明调用该方法需要权限…
- 当web层调用代理对象方法的时候,代理对象会判断该方法是否需要权限,再给出相对应的提示….
设计实体、数据库表
上次我们做的权限管理系统是引入了角色这个概念的,这次主要为了练习动态代理和注解技术,就以简单为主,不引入角色这个实体。直接是用户和权限之间的关系了。
Privilege实体
public class Privilege {
private String id ;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
数据库表
- privilege表
CREATE TABLE privilege (
id VARCHAR(40) PRIMARY KEY,
name VARCHAR(40)
);
privilege和user是多对多的关系,于是使用第三方表来维护他们的关系
- user_privilege表
CREATE TABLE user_privilege (
privilege_id VARCHAR(40),
user_id VARCHAR(40),
PRIMARY KEY (privilege_id, user_id),
CONSTRAINT privilege_id_FK FOREIGN KEY (privilege_id) REFERENCES privilege(id),
CONSTRAINT user_id_FK1 FOREIGN KEY (user_id) REFERENCES user(id)
);
添加测试数据
为了方便,直接添加数据了。就不写详细的DAO了。
- 在数据库中添加了两个权限
- 为id为1的user添加了两个权限
编写DAO
后面在动态代理中,我们需要检查该用户是否有权限…那么就必须查找出该用户拥有的哪些权限。再看看用户有没有相对应的权限
//查找用户的所有权限
public List<Privilege> findUserPrivilege(String user_id) {
QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
String sql = "SELECT p.* FROM privilege p, user_privilege up WHERE p.id = up.privilege_id AND up.user_id = ?";
try {
return (List<Privilege>) queryRunner.query(sql, new Object[]{user_id}, new BeanListHandler(Privilege.class));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
抽取到接口上
List<Privilege> findUserPrivilege(String user_id);
注解模块
- 编写注解
@Retention(RetentionPolicy.RUNTIME)
public @interface permission {
String value();
}
- 在Service层方法中需要权限的地方添加注解
@permission("添加分类")
/*添加分类*/
public void addCategory(Category category) {
categoryDao.addCategory(category);
}
/*查找分类*/
public void findCategory(String id) {
categoryDao.findCategory(id);
}
@permission("查找分类")
/*查看分类*/
public List<Category> getAllCategory() {
return categoryDao.getAllCategory();
}
抽取Service
把Service的方法抽取成ServiceDao。在Servlet中,也是通过ServiceFactory来得到Service的对象【和DaoFactory是类似的】
ServiceDao
@permission("添加分类")
/*添加分类*/ void addCategory(Category category);
/*查找分类*/
void findCategory(String id);
@permission("查找分类")
/*查看分类*/ List<Category> getAllCategory();
ServiceFactory
public class ServiceDaoFactory {
private static final ServiceDaoFactory factory = new ServiceDaoFactory();
private ServiceDaoFactory() {
}
public static ServiceDaoFactory getInstance() {
return factory;
}
//需要判断该用户是否有权限
public <T> T createDao(String className, Class<T> clazz, final User user) {
System.out.println("添加分类进来了!");
try {
//得到该类的类型
final T t = (T) Class.forName(className).newInstance();
//返回一个动态代理对象出去
return (T) Proxy.newProxyInstance(ServiceDaoFactory.class.getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, PrivilegeException {
//判断用户调用的是什么方法
String methodName = method.getName();
System.out.println(methodName);
//得到用户调用的真实方法,注意参数!!!
Method method1 = t.getClass().getMethod(methodName,method.getParameterTypes());
//查看方法上有没有注解
permission permis = method1.getAnnotation(permission.class);
//如果注解为空,那么表示该方法并不需要权限,直接调用方法即可
if (permis == null) {
return method.invoke(t, args);
}
//如果注解不为空,得到注解上的权限
String privilege = permis.value();
//设置权限【后面通过它来判断用户的权限有没有自己】
Privilege p = new Privilege();
p.setName(privilege);
//到这里的时候,已经是需要权限了,那么判断用户是否登陆了
if (user == null) {
//这里抛出的异常是代理对象抛出的,sun公司会自动转换成运行期异常抛出,于是在Servlet上我们根据getCause()来判断是不是该异常,从而做出相对应的提示。
throw new PrivilegeException("对不起请先登陆");
}
//执行到这里用户已经登陆了,判断用户有没有权限
Method m = t.getClass().getMethod("findUserPrivilege", String.class);
List<Privilege> list = (List<Privilege>) m.invoke(t, user.getId());
//看下权限集合中有没有包含方法需要的权限。使用contains方法,在Privilege对象中需要重写hashCode和equals()
if (!list.contains(p)) {
//这里抛出的异常是代理对象抛出的,sun公司会自动转换成运行期异常抛出,于是在Servlet上我们根据getCause()来判断是不是该异常,从而做出相对应的提示。
throw new PrivilegeException("您没有权限,请联系管理员!");
}
//执行到这里的时候,已经有权限了,所以可以放行了
return method.invoke(t, args);
}
});
} catch (Exception e) {
new RuntimeException(e);
}
return null;
}
}
PrivilegeExcetption
当用户没有登陆或者没有权限的时候,我们应该给用户一些友好的提示….于是我们自定义了PrivilegeException
public class PrivilegeException extends Exception {
public PrivilegeException() {
super();
}
public PrivilegeException(String message) {
super(message);
}
public PrivilegeException(String message, Throwable cause) {
super(message, cause);
}
public PrivilegeException(Throwable cause) {
super(cause);
}
}
我们继承的是Exception,通过方法名抛出去。但是我们是通过代理对象调用方法的,于是sun公司的策略就是把它们转换成运行期异常抛出去。
因此,我们就在Servlet上得到异常,再给出友好的提示。。
效果:
- 没有登陆的时候:
- 登陆了,但是没有相对应的权限的时候
- 登陆了,并且有权限
总结
该权限控制是十分优雅的,只要我在Service层中添加一个注解…那么当web层调用该方法的时候就需要判断用户有没有该权限….
要点总结
- 外界调用Service层的方法是代理调用invoke()方法,我们在invoke()方法可以对其进行增强!
- 在反射具体方法的时候,必须记得要给出相对应的参数!
- 在invoke()方法抛出的编译时期异常,java会自动转换成运行期异常进行抛出…
- 使用contains()方法时,就要重写该对象的hashCode()和equals()
为bookStore添加权限【动态代理和注解】的更多相关文章
- cglib动态代理导致注解丢失问题及如何修改注解允许被继承
现象 SOAService这个bean先后经过两个BeanPostProcessor,会发现代理之后注解就丢失了. 开启了cglib代理 @SpringBootApplication @EnableA ...
- Java动态代理原理及其简单应用
概念 代理对象和被代理对象一般实现相同的接口,调用者与代理对象进行交互.代理的存在对于调用者来说是透明的,调用者看到的只是接口.代理对象则可以封装一些内部的处理逻辑,如访问控制.远程通信.日志.缓存等 ...
- java开发必学知识:动态代理
目录 1. 引言 2. 代理模式及静态代理 2.1 代理模式说明 2.2 静态代理 2.3 静态代理局限性 3. 动态代理 3.1 JAVA反射机制 3.2 JDK动态代理 3.2.1 JDK动态代理 ...
- 理解Java动态代理(1)—找我还钱?我出钱要你的命
代理模式是最常用的一个设计模式之一,理解起来也是很简单,一张图足以说明了,LZ就不废话了. 至于代理模式能干嘛也不是LZ今天想说的,今天主要想简单介绍下JAVA里面的动态代理.“动”当然是相对“静”来 ...
- MyBatis_Study_004(动态代理)
源码:https://github.com/carryLess/mbtsstd-004 0.readme 基于前几篇:dao的实现类基本煤气到什么作用 仅仅是通过SQLSession的相应API定位到 ...
- Java——动态代理
在静态代理中,我们在调用target类的时候,都是先拿到proxy类.由于proxy类中将target类作为了成员变量,而且跟target类继承了一样的接口,具有同样的方法,所以,在proxy类中.通 ...
- Java-基础-JDK动态代理
1. 简介 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 比如:我们在调用 ...
- Java基础加强-(注解,动态代理,类加载器,servlet3.0新特性)
1. Annotation注解 1.1. Annotation概述 Annotation是JDK 5.0以后提供对元数据的支持,可以在编译.加载和运行时被读取,并执行相应的处理.所谓Annota ...
- spring-AOP动态代理,以及aspectJ的xml配置或注解配置方法,各个拦截器的使用顺序
package com.itheima.aspect; public class MyAspect { public void check_Permissions(){ System.out.prin ...
随机推荐
- statement和preparedstatement的区别
在执行SQL命令时,我们有二种选择:可以使用PreparedStatement对象,也可以使用Statement对象.无论多少次地使用同一个SQL命令,PreparedStatement都只对它解析和 ...
- Android上传图片到服务器,服务端利用.NET WCFRest服务读取文件的解决方案
在项目中遇到要将Android设备拍摄的照片上传的服务器,将文件保存在服务器本地的文件夹中,数据库中保存的是图片文件名.整个上传是将图片生成二进制流通过HTTP请求上传到服务端,服务端是基于.NET环 ...
- 采用SmartQQ 协议可制作聊天机器人
采用.NET CORE可运行在 Linux . Windows 和 Mac OSX 平台下. SmartQQ可以: 收发文字消息 获取好友.群.讨论组.好友分组和最近会话的列表 SmartQQ不可以: ...
- 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——实现篇:(二)用户接口层之RtspClient类及其构造函数
RtspClient类是myRTSPClient函数库所有特性集中实现的地方. 主要为用户提供: 1. RTSP协议通信接口函数,如DoOPTIONS(): 2. RTSP账号.密码设置函数,如Set ...
- 原创:Docker在云家政的应用 谢绝复制粘贴内容
我们公司目前大规模使用了Docker,目前除了数据库应用,其他所有应用都在Docker容器内运行,下面我就Docker在公司的应用做一些分享.. 首先我介绍一下公司的背景,公司属于中小型创业公司,服务 ...
- 【SpringMVC】XML配置说明
springmvc流程:前端控制器(DispatcherServlet)-->映射器HandlerMapping-->适配器HandlerAdapter-->视图解析器ViewRes ...
- Struts2简介以及初步搭建配置
一.基本介绍 Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互. ...
- Tornado框架简介
-------------------简介------------------- 1.概念: Tornado全称Tornado Web Server,是一个用Python语言写成的Web服务器 ...
- 前端开发【第一篇:HTML】
HTML初识 1.什么是HTML HTML是英文Hyper Text Mark-up Language(超文本标记语言)的缩写,他是一种制作万维网页面标准语言(标记).相当于定义统一的一套规则,大家都 ...
- Java Integer封装类的IntegerCache内部类
个人理解,不喜勿喷,欢迎指正. 首先看下面这段代码,猜一下输出结果是什么 Integer a = 10; Integer b = 10; System.out.println(a == b); a = ...