开发者

springboot的切面应用方式(注解Aspect)

开发者 https://www.devze.com 2025-04-12 11:13 出处:网络 作者: 你是猪,
目录spring boot 拦截的方式1.过滤器filter2.拦截器interceptor3.切面拦截ASPect执行顺序切片的使用相关注解示例总结spring boot 拦截的方式
目录
  • spring boot 拦截的方式
    • 1.过滤器filter
    • 2.拦截器interceptor
    • 3.切面拦截ASPect
  • 执行顺序
    • 切片的使用
      • 相关注解
    • 示例
      • 总结

        spring boot 拦截的方式

        1.过滤器filter

        可以获取http、http请求和响应,但无法获取与spring框架相关的信息,如哪个control处理,哪个方法处理,有哪些参数,这些都是无法获取的。

        主要用于内容上的过滤,敏感字替换成*等,也可用于非登入状态的非法请求过滤。

        2.拦截器interceptor

        除了获取http、http请求和响应对象,还可以获取请求的类名、方法名,但拦截器无法获取请求参数的值,从DispatcherServlet类源码分析。

        主要用于对公共的一些拦截获取,例如请求的IP 地址,IP黑白名单里的过过滤,非登入状态的接口请求拦截。

        3.切面拦截Aspect

        能获取到方法请求的参数,方法名,以及方法返回的json数据,更多的是用于数据的处理,比如对操作进行记录,修改,新建,查询,审批等操作记录进行处理统计。

        对返回的json中的一些特殊数据,比如字典值替换成对应的数据,避免前端转化,等等。

        执行顺序

        • 正常情况:过滤器、拦截器、切片,
        • 异常报错:切片、ControllerAdvice注解类、拦截器、过滤器

        切片的使用

        相关注解

        (1)@Pointcut 注解:

        指定一个切点,定义需要拦截的东西,这里介绍两个常   用的表达式:一个是使用 execution(),另一个是使用 annotation()。

        • execution表达式:

        以 execution(* com.mutest.controller..*.*(..))) 表达式为例:

        • 第一个 * 号的位置:表示返回值类型,* 表示所有类型。包名:表示需要拦截的包名,后面的两个句*斜体样式*点表示当前包和当前包的所有子包,在本例中指 com.mutest.controller包、子包下所有类的方法。
        • 第二个 * *号的位置:表示类名,** 表示所有类。
        • (..):*这个星号表示方法名*,* 表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。

        annotation() 表达式:

        annotation() 方式是针对某个注解来定义切点,其中注解包括GetMapping等

        (2)@Around注解:

         用于修饰Around增强处理,Around增强处理非常强大,表现在:

         @Around可以自由选择增强动作与目标方法的执行顺序,也就是说可以在增强动作前后,甚至过程中执行目标方法。这个特性的实现在于,调用 ProceedingJoinPoint参数的procedd()方法才会执行目标方法。

         @Around可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回值。

        (3)@Before 注解:

        指定的方法在切面切入目标方法之前执行,可以做一些 Log 处理,也可以做一些信息的统计,可以通过参数JointPoint 来获取一些有用的信息,可以用它来获取一个签名,利用签python名可以获取请求的包名、方法名,包括参数(通过joinPoint. getArgs() 获取)等。

        (4)@After注解:

        和before注解相对应的注解,同样可以进行一些日志处理等

        (5)@AfterReturning 注解:

        和@After 有些类似,区别在于 @AfterReturning 注解可以用来捕获切入方法执行完之后的返回值,对返回值进行业务逻辑上的增强处理。

        对返回的json字符串进行处理。

        (6)@@AfterThrowing注解:

        当被切方法执行过程中抛出异常时,会进入 @AfterThrowing 注解的方法中执行,在该方法中可以做一些异常的处理逻辑。

        示例

        import com.alibaba.fastjson.JSONObject;
        import com.cmhit.crm.constants.FunctionEnum;
        import com.cmhit.crm.service.OperateLogService;
        import com.cmhit.crm.utils.JsonUtil;
        import com.cmhit.crm.vo.operlog.OperateLogCreateReqVO;
        import lombok.extern.slf4j.Slf4j;
        import org.aspectj.lang.JoinPoint;
        import org.aspectj.lang.ProceedingJoinPoint;
        import org.aspectj.lang.annotation.*;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.stereotype.Component;
        
        import Java.util.Objects;
        
        @Slf4j
        @Aspect
        @Component
        public class OperateLogAspect {
           
           //操作日志service
           @Autowired 
           private OperateLogService operateLogService;
          //操作日志实体
           private OperateLogCreateReqVO operateLog = new OperateLogCreateReqVO();
        
           // 定义一个切入点
           @Pointcut("execution(* com.cmhit.crm.controller.*.*(..))")
           public void operlog(){
              //这编程客栈里面不要写代码,不会执行的
           }
        
           // 前置通知
           @Before(value = "operlog()")
           public void before(JoinPoint jp) {
               //方法名获取
               String name = jp.getSignature().getName();
               //方法参数获取
               Object[] args = jp.getArgs();
               //设置操作日志
               setOperateLogType(name,args);
               log.debug("{}方法开始执行...开始设置设置操作日python志的操作类型",name);
           }
        
          编程 // 后置通知
           @After(value = "operlog()")
           public void after(JoinPoint jp) {
               String name = jp.getSignature().getName();
               log.debug("{}方法执行结束...",name);
           }
        
           // 返回通知
           @AfterReturning(value = "operlog()")
           public void afterReturning(JoinPoint jp) {
               String name = jpeBYNun.getSignature().getName();
               if (Objects.nonNull(operateLog.getSourceId())) {
                   operateLog.setOperationResult("操作成功!");
                   operateLogService.insertOperateLog(operateLog);
               }
               log.debug("{}方法执行成功",name);
           }
        
           // 异常通知
           @AfterThrowing(value = "operlog()", throwing = "e")
           public void afterThrowing(JoinPoint jp, Exception e) {
               String name = jp.getSignature().getName();
               if (Objects.nonNull(operateLog.getSourceId())){
                   operateLog.setOperationResult(e.getMessage());
                   operateLogService.insertOperateLog(operateLog);
               }
               log.debug("{}方法抛异常,异常是{}",name , e.getMessage());
           }
        
           // 环绕通知
           @Around("operlog()")
           public Object around(ProceedingJoinPoint pjp) throws Throwable {
               String name = pjp.getSignature().getName();
               // 统计方法执行时间
              long start = System.currentTimeMillis();
              Object result = pjp.proceed();
              long end = System.currentTimeMillis();
              System.out.println(name + "方法执行时间为:" + (end - start) + " ms");
               return result;
           }
           private void setOperateLogType(String name,Object[] args){
             //公司的业务逻辑,这里建立使用自己的
            }
        
           }
           //参数处理方法
           private void dealGetinfoArgs(Object[] args){
            //自己写逻辑吧
           }
          
        
        }

        总结

        以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

        0

        精彩评论

        暂无评论...
        验证码 换一张
        取 消

        关注公众号