zoukankan      html  css  js  c++  java
  • SpringAOP的自定义注解实践

          springaop属于spring的重要属性,在java中有相当广泛的用途,大家一般都接触过aop实现事务的管理,在xml里配好声明式事务,然后直接在service上直接加上相应注解即可,

         今天我们来实现下SpringAOP的自定义注解,用来在前置通知中做下权限校验,有利于我们代码的解藕,提高复用性,增加代码B格;

        话不多说,上代码,首先定义一个自定义注解

        

       这里的参数我们并没有在使用,先随意定义个type,以后想使用时可以再赋值

       再来看切面

      

    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletRequest;

    import org.apache.commons.lang.StringUtils;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;

    import com.jiubao.common.core.cache.redis.JedisUtil;
    import com.jiubao.common.core.exception.MyException;
    import com.jiubao.livenet.cache.JiuBaoCache;
    import com.jiubao.livenet.constant.ServiceConstants;
    import com.jiubao.livenet.enums.Limitsenum;
    import com.jiubao.livenet.service.CustomerService;

    /**
    * 注解切面
    * @author Administrator
    *
    */
    @Aspect
    @Component
    public class AuthorityAspect {

    private static final Logger logger = LoggerFactory.getLogger(AuthorityAspect.class);

    @Resource
    private CustomerService customerService;

    //Controller层切点
    @Pointcut("execution (* com.jiubao.livenet.controller.*.*(..))")
    public void controllerAspect() {}



    /**
    * 前置通知
    * 只拦截带有Authority注解的controller方法
    * @param joinPoint 切点
    * @return
    */

    //@org.springframework.stereotype.Controller *) 表示拦截controller方法   @annotation(Authority) 表示只拦截带此注解的方法 


    @Before("within(@org.springframework.stereotype.Controller *) && @annotation(Authority)")
    public void doBefore(JoinPoint joinPoint) throws MyException {
      logger.info("==========执行商户权限controller前置通知===============");
        Object[] args = joinPoint.getArgs();
      HttpServletRequest request=null;
      for (int i = 0; i < args.length; i++) {
        Object object = args[i];
        if(object instanceof HttpServletRequest) {
        request=(HttpServletRequest) args[i];
        break;
       }
    }
      Map<String, Object> paramMap = new HashMap<String, Object>();
      if(request ==null) {
        return;
      }

      String url = request.getRequestURI().toString(); //请求的url,注意,只有方法参数里有HttpServletRequest request才能获取到request

      /**
      * 权限控制
        */
       JedisUtil jedis = JiuBaoCache.getJedisUtil();
       String userId = jedis.getUserId(request);
       paramMap.put("uid", userId); //登录人UID
       boolean isAccess=false;
       List<Map<String, String>> userAuthlist= customerService.getUserAuth(paramMap); //查询登录人的商户角色列表
      for (int i = 0; i < userAuthlist.size(); i++) {
        if(userAuthlist.get(i).get("role")!=null) {
         String[] limitsArray = Limitsenum.limitsArray(Integer.valueOf(userAuthlist.get(i).get("role")));  //使用枚举得到此角色对应的URL数组
          for (int a = 0; a < limitsArray.length; a++) {
          if(url.contains(limitsArray[a])) {  //判断是否有,如果有则跳出
             isAccess=true;
            break;
         }
    }
      if(isAccess) {
         break;
       }
      }
    }

      if (!isAccess){
          throw new MyException(-1,ServiceConstants.NO_ACCESS); //无权限访问,如果没有权限直接扔出个自定义异常,在那里会用response返回给前端提示
           }
    }

      //全部拦截,这样的before就是全局拦截,会拦截所有方法
      @Before("controllerAspect()")
      public void doBefore2(JoinPoint joinPoint) {
        System.out.println("==========执行全部拦截controller前置通知===============");
      }

      

      @AfterReturning(returning="rvt",pointcut="controllerAspect()") //打印所有方法的返回值
      public Object AfterExec(JoinPoint joinPoint,Object rvt){ //pointcut是对应的注解类 rvt就是方法运行完之后要返回的值
        logger.info("返回值为:" + rvt);
        return rvt;
      }

    }

    再看看调用过程 

    直接加在controller里想要限制的方法上即可

    上面就是全部逻辑了,还有after和Around注解在此省略,这里要开始测试了,我几次都测不通,发现根本无效,而且 

    我配置文件里也有  <aop:aspectj-autoproxy proxy-target-class="true" />,不知道怎么回事,后来才发现

    如果你的配置文件是这样的:

    你除了在spring-mybaits.xml里要有这个外,还需要在spring-mvc.xml里有,好吧,都要加上才有效,而且别忘了头部的声明哦

    顺便鄙视一下springmvc,配置文件就是麻烦

    在此就完成了所有代码了,亲测是有效的

     需提醒是的,当一个切面里有多个同样的注解时,会按链式分先后执行,比如上面第1个before,所有配了@Authority的方法会执行,接着执行第2个before,

     而没有配@Authority的方法会直接执行第2个before,第1个由于不满足条件不会执行,这样方便我们在一个切面里写多种灵活的逻辑.

     springaop由于配置灵活,复用性强,无性能损耗,在封装代码上很好用,比拦截器更方法,推荐使用

     再推荐几个这方面比较好的文章:

    1.https://www.cnblogs.com/jianjianyang/p/4910851.html

    2.https://www.cnblogs.com/sjlian/p/7325602.html

    3.https://www.cnblogs.com/mouseIT/p/5033746.html

  • 相关阅读:
    嵌入式linux问题杂锦
    QT creator 调试问题
    torcs代码
    ubuntu12.04安装KDevelop
    ubuntu12.04LTS安装以及卸载 QT4.8.6和QT creator2.5.2
    用vs2010编译vs2013建的工程
    mysql+matlab配置
    流形学习笔记
    可用的rtmp互联网地址
    信用卡术语
  • 原文地址:https://www.cnblogs.com/lpcyj/p/9733027.html
Copyright © 2011-2022 走看看