java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > springboot切面应用(注解Aspect)

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

作者:你是猪,

文章总结:Spring Boot提供了三种拦截器:Filter、Interceptor和Aspect,Filter主要用于内容过滤和非登录状态的非法请求过滤,无法获取Spring框架相关的信息,Interceptor可以在获取请求类名、方法名的同时,获取请求参数,但无法获取参数值

spring boot 拦截的方式

1.过滤器filter

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

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

2.拦截器interceptor

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

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

3.切面拦截Aspect

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

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

执行顺序

切片的使用

相关注解

(1)@Pointcut 注解:

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

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

annotation() 表达式:

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

(2)@Around注解:

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

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

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

(3)@Before 注解:

指定的方法在切面切入目标方法之前执行,可以做一些 Log 处理,也可以做一些信息的统计,可以通过参数JointPoint 来获取一些有用的信息,可以用它来获取一个签名,利用签名可以获取请求的包名、方法名,包括参数(通过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("{}方法开始执行...开始设置设置操作日志的操作类型",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 = jp.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){
    //自己写逻辑吧
   }
  

}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文