为bookStore添加权限【动态代理和注解】
来源:互联网 发布:c语言的编程环境 编辑:程序博客网 时间:2024/05/15 12:40
前言
目前为止,我们已经学习了动态代理技术和注解技术了。于是我们想要为之前的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层方法中需要权限的地方添加注解CategoryServiceImpl
@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是类似的】
CategoryService
@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添加权限【动态代理和注解】
- 注解+动态代理实现bookstore的权限控制
- bookstore权限管理采用改写struts源代码,和注解方式
- 注解+动态代理实现权限拦截
- Java注解 和动态代理
- 通过JDK动态代理和自定义注解来控制方法级别的权限访问
- 每日一结,注解和动态代理
- JAVAWEB开发之Servlet3.0新特性的使用以及注解的详细使用和自定义注解的方法、动态代理的使用、利用动态代理实现细粒度的权限控制以及类加载和泛型反射
- 通用动态代理链-为你的应用程序添加AOP
- 【Android】Android动态代理为SurfaceHolder添加Hook
- Java中有关注解和动态代理的知识
- java动态代理详解,并用动态代理和注解实现日志记录功能
- JDK动态代理和CGLIB动态代理,实现Spring注解管理事务区别。
- 为NPM添加代理
- 为wget添加代理
- java 注解与动态代理
- spring 注解方式动态代理
- Java注解及动态代理
- bzoj4843
- VR系列——Oculus Rift 介绍指南:四、Oculus Rift的硬件设置
- 找出数组中出现次数最多的数字&找出数组中只出现一次的数字
- DOM4J XML解析
- POJ 2411 Mondriaan's Dream 状态压缩
- 为bookStore添加权限【动态代理和注解】
- fl2440 内核移植
- tkinter的variable属性
- 数组拷贝操作 从数组默认下标 到拷到我指定的长度
- 数据库中常用的锁及其应用场景
- (转载/侵删)mvc与三层结构终极区别
- ElasticMaterial.cs
- Sort operation used more than the maximum 33554432 bytes of RAM
- 降维方法