Spring Aop 权限开发(Java后台管理权限)

第一次使用aop开发后台权限,之前使用过aop开发过日志功能。

看了网上很多案例。感觉跟自己想要的还是有一定的区别,然后参照网上的案例,自己摸索写一个。

供大家参考。

1:首先,后台所有的功能菜单都放入数据库中。(用户列表,等这种功能菜单。)

2:后台所有的功能权限也放入到数据库中。(user:拥有用户列表权限,拥有用户列表查看,修改权限,没有删除,新增权限)

数据库要提前建立好。

开发代码:

创建操作枚举(增删改查)

/**
 * 操作枚举
 * 增(INSERT)
 * 删(DELETE)
 * 改(UPDATE)
 * 查(SELECT)
 * @author think
 */
public enum OperationEnum {

 //0:默认可以使用该权限
 //99:没有权限
 INSERT("INSERT","0"),
 DELETE("DELETE","0"),
 UPDATE("UPDATE","0"),
 SELECT("SELECT","0");
 
 private String key;
 private String value;
 
 private OperationEnum(String key,String value) {
  // TODO Auto-generated constructor stub
  this.key = key;
  this.value = value;
 }
 public String getKey() {
  return key;
 }
 public void setKey(String key) {
  this.key = key;
 }
 public String getValue() {
  return value;
 }
 public void setValue(String value) {
  this.value = value;
 }
}

 

创建权限注解,默认只有查询功能。

/**
 * 权限注解
 * @author think
 */
@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.METHOD)
@Documented
public @interface Authority {

    OperationEnum value() default OperationEnum.SELECT;
}

 

创建aop工具类

/**
 * 解析权限注解
 * @author think
 */
@Aspect
@Component
public class AnnotationParse {
    @Autowired(required = false)
 private HttpServletRequest request;
 @Autowired
 private ManagerPermissionsService managerPermissionsService;

//对应你的权限注解类,上面一个方法
    @Pointcut("@annotation(com.mag.pro.pojo.aop.Authority)")
    public void operationAuthority() {
    }
    

//执行你的切面方法。

//这里面的权限逻辑没有,

//查询出用户有哪些权限,然后根据获得注解上的 操作权限来判断,该用户是否拥有权限操作。

//这里面有几个坑,

//1:ProceedingJoinPoint  请使用该类 2:一定要有返回值,不然报错搞死你。返回值object类型,不然搞死你。

//3:myExcpetion 是自定义异常,toBeanMap是自己写的方法,用于页面返回json格式,没有写?搞死你。。。

//4:PathKeyEnum 这个是自己定义的 枚举方法,主要存放 code msg entity。就是json格式
    @Around("operationAuthority()")
 public Object selectAuth(ProceedingJoinPoint joinPoint)throws Throwable{
  MyException myException = null;
  //获取controller参数集合,
  Enumeration parameter = request.getParameterNames();
  String users_only_md5 = getUsersId(parameter);
  Object result = "";//aop环绕返回值专用
  
  //当url传递的参数(users_only_id)为空时,则判断出系统异常
  //本来该判断是在controller里面处理的。但是环绕通知会优先执行,导致这里需要进行判断约束
  if(StringUtils.isNullString(users_only_md5)){
   myException = new MyException(PathKeyEnum.ERROR.getKey(),PathKeyEnum.ERROR.getValue(),PathCommonEnum.ERROR.getValue());
   return myException.toArgsUsersId();
  }
  
  //查询出用户所拥有的权限列表
  List<ManagerPermissions> listManagerPermissions = managerPermissionsService.selectManagerPermissionsUsers(users_only_md5);
  
  //当用户权限查询出来为null时,则定义为该用户没有权限
  if(StringUtils.isListNull(listManagerPermissions)){
   myException = new MyException(PathKeyEnum.AUTHORITY.getKey(),PathKeyEnum.AUTHORITY.getValue(),PathCommonEnum.ERROR.getValue());
   return myException.toBeanMap();
  }
  
  OperationEnum operationEnum = getControllerMethodDescription(joinPoint);
  String controllerUrl = getUrl();

if(StringUtils.isNullString(controllerUrl)){
   myException = new MyException(PathKeyEnum.AUTHORITY.getKey(),PathKeyEnum.AUTHORITY.getValue(),PathCommonEnum.ERROR.getValue());
   return myException.toBeanMap();
  }


  try{
   //listManagerPermissions 当这个集合不为空时,循环判断str跟集合里的权限是否有存在。
   for (int i = 0; i < listManagerPermissions.size(); i++) {
    if(listManagerPermissions.get(i).getFunction_permissions_controller().equals(controllerUrl)){
     if("SELECT".equals(operationEnum.getKey())){
      if(listManagerPermissions.get(i).getFunction_select() == Integer.parseInt(operationEnum.getValue())){
       result = joinPoint.proceed();
       break;
      }else{
       myException = new MyException(PathKeyEnum.AUTHORITY.getKey(),PathKeyEnum.AUTHORITY.getValue(),PathCommonEnum.ERROR.getValue());
       return myException.toBeanMap();
      }
     }else if("UPDATE".equals(operationEnum.getKey())){
      if(listManagerPermissions.get(i).getFunction_update() == Integer.parseInt(operationEnum.getValue())){
       result = joinPoint.proceed();
       break;
      }else{
       myException = new MyException(PathKeyEnum.AUTHORITY.getKey(),PathKeyEnum.AUTHORITY.getValue(),PathCommonEnum.ERROR.getValue());
       return myException.toBeanMap();
      }
     }else if("DELETE".equals(operationEnum.getKey())){
      if(listManagerPermissions.get(i).getFunction_delete() == Integer.parseInt(operationEnum.getValue())){
       result = joinPoint.proceed();
       break;
      }else{
       myException = new MyException(PathKeyEnum.AUTHORITY.getKey(),PathKeyEnum.AUTHORITY.getValue(),PathCommonEnum.ERROR.getValue());
       return myException.toBeanMap();
      }
     }else if("INSERT".equals(operationEnum.getKey())){
      if(listManagerPermissions.get(i).getFunction_add() == Integer.parseInt(operationEnum.getValue())){
       result = joinPoint.proceed();
       break;
      }else{
       myException = new MyException(PathKeyEnum.AUTHORITY.getKey(),PathKeyEnum.AUTHORITY.getValue(),PathCommonEnum.ERROR.getValue());
       return myException.toBeanMap();
      }
     }
    }
   }
  } catch (Exception e) {
   // TODO: handle exception
  }
  if("" == result){
   myException = new MyException(PathKeyEnum.AUTHORITY.getKey(),PathKeyEnum.AUTHORITY.getValue(),PathCommonEnum.ERROR.getValue());
   return myException.toBeanMap();
  }
  return result;
 }
    
    /**
     * 解析注解上的权限
     * @param joinPoint
     * @return
     */
    public static OperationEnum getControllerMethodDescription(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Authority controllerAuthority = method.getAnnotation(Authority.class);
        OperationEnum discription = controllerAuthority.value();
        return discription;
    }

//因为我们这边只需要用户的ID 所以取的id后退出循环
 private String getUsersId(Enumeration parameter){
  while(parameter.hasMoreElements()) {
   String args = (String) parameter.nextElement();
   if("users_only_md5".equals(args)){
    return request.getParameter(args);
   }
  }
  return PathCommonEnum.NULL.getValue();
 }

/**
  * 截取url的controller
  * @return
  */
 private String getUrl(){
  String url = request.getRequestURI();

//url: /xxxx/xx/xxx.htmls

//我这边取的是第二个xx 即controller的mapping值,

//第一个xxxx应该是项目名称 所以下面的 截取需要根据自己的连接来调整值。
  if(!StringUtils.isNullString(url)){
   return url.substring(13,url.lastIndexOf("/"));
  }
  return null;
 }

}

创建自定义异常类:

/**
 * 自定义异常
 * @author think
 */
public class MyException extends RuntimeException{

    private String code;
    private String msg;
    private Object entity;
    
    public MyException(String code, String msg,Object entity) {
        // TODO Auto-generated constructor stub
        this.code = code;
        this.msg = msg;
        this.entity = entity;
    }
    
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public Object getEntity() {
        return entity;
    }
    public void setEntity(Object entity) {
        this.entity = entity;
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return JsonMethod.setJsonMethod(code, msg, entity).toString();
    }
    
    /**
     * 返回map格式
     * @return
     */
    public Map<String, Object> toBeanMap(){
        return JsonMethod.setJsonMethod(code, msg, entity);
    }

/**
     * 返回map格式
     * @return
     */
    public Map<String, Object> toArgsUsersId(){
        return JsonMethod.setJsonMethod(code, msg, entity);
    }

创建常量枚举类:

/**
 * 常量key枚举
 * 枚举具有安全性,不可修改性,默认final
 * @author boss 3
 */
public enum PathKeyEnum {
    
    SUCCESS("20000","执行成功"),
    ERROR("90000","系统繁忙,请稍后再试"),
    LOGINE("90001","该环境无法登录后台管理系统"),
    AUTHORITY("90003","权限不足");
    
    private String key;
    private String value;
    
    /**
     * 枚举必须使用私有化
     * @param key
     * @param value
     */
    private PathKeyEnum(String key,String value) {
        this.key = key;
        this.value = value;
    }
    
    /** 获取key值 */
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    /** 获取对应的key的描述 */
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }

下面就是controller类:

/**
     * 查询所有功能菜单
     * @param req
     * @param res
     * @return
     */
    @Authority(OperationEnum.DELETE)//这个就是功能子权限,增删改查,这边我自己写的是测试
    @OperLog(logDescription="查询所有功能菜单")//这个是系统日志aop 目前没有贴处来,可以删除掉
    @RequestMapping(value="selectFunctionPermissions",method=RequestMethod.GET)
    @ResponseBody
    public Map<String, Object> selectFunctionPermissions(HttpServletRequest req,
            HttpServletResponse res){
        res.setCharacterEncoding("UTF-8");
        System.out.println("进入controller");
        List<FunctionPermissions> listFunctionPermissions = functionPermissionsService.selectFunctionPermissions();
        
        if(StringUtils.isListNull(listFunctionPermissions))
            return JsonMethod.setJsonMethod(PathKeyEnum.ERROR.getKey(), PathKeyEnum.ERROR.getValue(), PathCommonEnum.ERROR.getValue());
        return JsonMethod.setJsonMethod(PathKeyEnum.SUCCESS.getKey(), PathKeyEnum.SUCCESS.getValue(), listFunctionPermissions);
    }

spring-mvc.xml配置环绕通知:

 <bean id="aprseAspect" class="com.commons.utils.aop.AnnotationParse"></bean>
    <!-- 环绕通知 -->
    <aop:config>
        <aop:aspect ref="aprseAspect">
            <aop:pointcut id="doPointCut" expression="execution(* com.mag.pro.service..*impl.*(..))"/>  
            <aop:around method="selectAuth" pointcut-ref="doPointCut"/>
        </aop:aspect>
    </aop:config>

最后是测试的效果:

1:@Authority(OperationEnum.DELETE)  当我们将方法定义为delete时请求的效果:

因为数据库里没有值,所以返回无数据。

走了service方法,说明执行了数据库查询。

2:我们将delte改成其他权限,

@Authority(OperationEnum.SELECT)

因为aop判断的是delete,所以select是走异常,是没有权限的。

运行结果是:

以上就是我写的一个后台权限判断。需要在权限aop方法里,加入自己查询到的用户m来遍历判断。

目前aop代码没有优化,if else 三层嵌套,不太好,需要优化下。

(更新:请看底部优化方式)

附上数据库图

1:功能菜单表

2:用户权限表(0:启用 99:禁用)

controller请求的接口

参考该代码时,需要自己创建数据库,直接是运行不了的。

JsonMethod.setJsonMethod 这个方法是我自己封装的一个json格式,各位可以用自己的json格式就行。

还有自己的ssm框架没问题就行。需要框架,可以看我博客里面的融云即时聊天二有csdn下载链接。需要1积分。头疼。

以上已完结,本人运行没有任何问题。如有问题,可以留言。大家互相探讨,有好的建议,优化方法,也可以提出来,大家一起学习,本人小白在此献丑了!!!!

 

更新:权限if 嵌套循环优化

这里使用了状态设计模式来优化代码:

1:创建状态抽象类

/**
 * 权限状态抽象类
 * 使用状态设计模式
 * @author think
 */
public abstract class ConcreteState {

    /**
     * 如果是查询,则返回查询对应的状态信息
     */
    public abstract Object selectOperationEnum(List<ManagerPermissions> listManagerPermissions, 
            OperationEnum operationEnum, ProceedingJoinPoint joinPoint, int i) throws Throwable;
    
    /**
     * 如果是修改,则返回修改对应的状态信息
     */
    public abstract Object updateOperationEnum(List<ManagerPermissions> listManagerPermissions, 
            OperationEnum operationEnum, ProceedingJoinPoint joinPoint, int i) throws Throwable;
    
    /**
     * 如果是新增,则返回新增对应的状态信息
     */
    public abstract Object insertOperationEnum(List<ManagerPermissions> listManagerPermissions, 
            OperationEnum operationEnum, ProceedingJoinPoint joinPoint, int i) throws Throwable;
    
    /**
     * 如果是删除,则返回删除对应的状态信息
     */
    public abstract Object deleteOperationEnum(List<ManagerPermissions> listManagerPermissions, 
            OperationEnum operationEnum, ProceedingJoinPoint joinPoint, int i) throws Throwable;
    
    /**
     * 如果是启用/禁用,则返回启用/禁用对应的状态信息
     */
    public abstract Object disableOperationEnum(List<ManagerPermissions> listManagerPermissions, 
            OperationEnum operationEnum, ProceedingJoinPoint joinPoint, int i) throws Throwable;
}

 

2:创建状态实现类

/**
 * 权限状态实现类
 * 使用状态设计模式
 * @author think
 */
public class ConcreteStateImpl extends ConcreteState{
    
    //默认返回map,无需修改
    private final MyException myException = new MyException(PathKeyEnum.AUTHORITY.getKey(),PathKeyEnum.AUTHORITY.getValue(),PathCommonEnum.ERROR.getValue());
    
    /**
     * 如果是查询,则返回查询对应的状态信息
     */
    @Override
    public Object selectOperationEnum(List<ManagerPermissions> listManagerPermissions, 
            OperationEnum operationEnum, ProceedingJoinPoint joinPoint, int i) throws Throwable{
        // TODO Auto-generated method stub
        if(listManagerPermissions.get(i).getFunction_select() == Integer.parseInt(operationEnum.getValue())){
            return joinPoint.proceed();
        } else {
            return myException.toBeanMap();
        }
    }
    
    /**
     * 如果是修改,则返回修改对应的状态信息
     */
    @Override
    public Object updateOperationEnum(List<ManagerPermissions> listManagerPermissions, 
            OperationEnum operationEnum, ProceedingJoinPoint joinPoint, int i) throws Throwable{
        // TODO Auto-generated method stub
        if(listManagerPermissions.get(i).getFunction_update() == Integer.parseInt(operationEnum.getValue())){
            return joinPoint.proceed();
        } else {
            return myException.toBeanMap();
        }
    }
    
    /**
     * 如果是新增,则返回新增对应的状态信息
     */
    @Override
    public Object insertOperationEnum(List<ManagerPermissions> listManagerPermissions, 
            OperationEnum operationEnum, ProceedingJoinPoint joinPoint, int i) throws Throwable{
        // TODO Auto-generated method stub
        if(listManagerPermissions.get(i).getFunction_delete() == Integer.parseInt(operationEnum.getValue())){
            return joinPoint.proceed();
        } else {
            return myException.toBeanMap();
        }
    }
    
    /**
     * 如果是删除,则返回删除对应的状态信息
     */
    @Override
    public Object deleteOperationEnum(List<ManagerPermissions> listManagerPermissions, 
            OperationEnum operationEnum, ProceedingJoinPoint joinPoint, int i) throws Throwable{
        // TODO Auto-generated method stub
        if(listManagerPermissions.get(i).getFunction_add() == Integer.parseInt(operationEnum.getValue())){
            return joinPoint.proceed();
        } else {
            return myException.toBeanMap();
        }
    }
    
    /**
     * 如果是启用/禁用,则返回启用/禁用对应的状态信息
     */
    @Override
    public Object disableOperationEnum(List<ManagerPermissions> listManagerPermissions, OperationEnum operationEnum,
            ProceedingJoinPoint joinPoint, int i) throws Throwable {
        // TODO Auto-generated method stub
        if(listManagerPermissions.get(i).getFunction_disable() == Integer.parseInt(operationEnum.getValue())){
            return joinPoint.proceed();
        }else{
            return myException.toBeanMap();
        }
    }
}

该方法在AnnotationParse 类里面写即可

3:创建调用实现类方法

/**
     * 状态设计模式
     * @param stateStr
     * @param listManagerPermissions
     * @param operationEnum
     * @param joinPoint
     * @param i
     * @return
     * @throws Throwable
     */
    private Object stateUtils(String stateStr,List<ManagerPermissions> listManagerPermissions, 
            OperationEnum operationEnum, ProceedingJoinPoint joinPoint, int i) throws Throwable{
        
        ConcreteStateImpl concreteStateImpl = new ConcreteStateImpl();
        
        switch (stateStr) {
            case "SELECT":
                return concreteStateImpl.selectOperationEnum(listManagerPermissions, operationEnum, joinPoint, i);
            case "UPDATE":
                return concreteStateImpl.updateOperationEnum(listManagerPermissions, operationEnum, joinPoint, i);
            case "INSERT":
                return concreteStateImpl.insertOperationEnum(listManagerPermissions, operationEnum, joinPoint, i);
            case "DELETE":
                return concreteStateImpl.deleteOperationEnum(listManagerPermissions, operationEnum, joinPoint, i);
            case "DISABLE":
                return concreteStateImpl.disableOperationEnum(listManagerPermissions, operationEnum, joinPoint, i);
            default:
                return null;
        }
    }

4:修改for循环里面的if代码

只需要这段代码。参数正常传递即可。

这样。if else if 代码优化已完成。并且已测试过。该代码优化运行正常。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值