[转载]springboot aop拦截、修改请求参数

前言
最近有这么个功能,由于使用了thymeleaf,多个页面遇到要使用同一个数据的问题,但是如果在每个Controller下都要向Model放数据,那么就有很多重复代码,不太优雅,所以想到了AOP,在进入方法前取到Model实例,向他增加数据即可。

引入依赖
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-aop</artifactId>
 </dependency>

doBefore中的代码也可以放入到@After下执行。

@Aspect
@Component
public class ResultAop {

    @Pointcut("execution(public * com.he.edu.edu.controller.IndexController.*(..)))")
    public void BrokerAspect(){

    }

    @Before("BrokerAspect()")
    public void doBefore(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            if (arg instanceof Model){
                Model model = (Model) arg;
                model.addAttribute("test","存放公共参数");
            }
        }
    }


    @After("BrokerAspect()")
    public void doAfter(JoinPoint joinPoint){

    }

}
@Controller
public class IndexController {
    Logger logger = LoggerFactory.getLogger(IndexController.class);
    
     @GetMapping("test")
     public String test(Model model){
         logger.info("{}",model.getAttribute("test"));
         return "test";
     }
 }
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div th:text="${test}"></div>
</body>
</html>

这样,每个方法下的Model中都有了这份数据,取出渲染即可。


image.png

获取请求参数
我们可以通过RequestContextHolder获取url中的参数,RequestContextHolder就是一个典型的ThreadLocal应用,用于在当前线程中获取当前请求及其属性,如果要在service层中使用request,或者其他任何地方,都可以直接调用RequestContextHolder来获取request对象和response对象。

@Aspect
@Component
public class TestAop {
    private Logger logger = LoggerFactory.getLogger(TestAop.class);
    @Pointcut("execution(public * com.he.edu.edu.controller.IndexController.*(..)))")
    public void BrokerAspect(){

    }

    @Before("BrokerAspect()")
    public void doBefore(JoinPoint joinPoint){
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        logger.info("URL参数={}",requestAttributes.getRequest().getQueryString());

    }

}
  @GetMapping("test")
  public String test(Model model,@RequestParam("id") Integer id){
      logger.info("id={}",id);
      model.addAttribute("test",id);
      return "test";
  }
image.png

修改请求参数
可以利用@Around来修改请求参数,@Around功能非常强大,作用如下:

可以在目标方法之前增加逻辑,也可以在执行目标方法之后增加逻辑.
可以决定目标方法在什么时候执行,如何执行,也可以阻止目标目标方法执行.
可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回值.
使用ProceedingJoinPoint时如果要改变参数,必须调用 proceed(Object[] var1)方法,传入新的参数数组,数组元素类型必须和目标方法相互对应,否则会报ClassCastException异常。

下面是将传入的id扩大十倍。

@Aspect
@Component
public class TestAop {
    private Logger logger = LoggerFactory.getLogger(TestAop.class);
    @Pointcut("execution(public * com.he.edu.edu.controller.IndexController.*(..)))")
    public void BrokerAspect(){

    }

    @Around("BrokerAspect()")
    public void doAround(ProceedingJoinPoint proceedingJoinPoint){
        Object[] sourceObject =proceedingJoinPoint.getArgs();
        sourceObject[1] =new Integer(((Integer) sourceObject[1])*10);
        try {
            proceedingJoinPoint.proceed(sourceObject);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

}
 @GetMapping("test")
 public String test(Model model,@RequestParam("id") Integer id){
     logger.info("id={}",id);
     model.addAttribute("test",id);
     return "test";
 }
image.png

修改返回值
proceed方法的返回值就是目标方法的返回值,我们可以拿到他做一些修改,或者返回新的数据。

下面加了ResponseBody注解,会将对象转换成json,将返回user1,user2,user3。

 @GetMapping("listUser")
 @ResponseBody
 public List<String> listUser(){
     return Stream.of("user1","user2","user3").collect(Collectors.toList());
 }

在切入点进行修改,返回user4,user5,user6。

 @Around("BrokerAspect()")
 public Object doAround(ProceedingJoinPoint proceedingJoinPoint){
     try {
         Object proceed = proceedingJoinPoint.proceed();
         return Stream.of("user4","user5","user6").collect(Collectors.toList());
     } catch (Throwable throwable) {
         throwable.printStackTrace();
     }
     return  null;
 }
image.png

打印带有指定注解方法的参数
首先自定义一个注解,最终将做到打印标有这个注解的请求参数。

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodLog {
}
@MethodLog
@GetMapping("log")
public String log(Model model,@RequestParam("id") Integer id){

    model.addAttribute("test",id);
    return "test";
}
@GetMapping("noLog")
public String noLog(Model model,@RequestParam("id") Integer id){

    model.addAttribute("test",id);
    return "test";
}

接下来取到目标方法,从方法中判断是否存有MethodLog注解,有的话就通过RequestContextHolder来获取请求参数。

@Before("BrokerAspect()")
public void doBefore(JoinPoint joinPoint) throws NoSuchMethodException {
    Signature signature = joinPoint.getSignature();
    MethodSignature methodSignature = (MethodSignature)signature;
    Method targetMethod = methodSignature.getMethod();
    if (((MethodSignature) joinPoint.getSignature()).getMethod().getDeclaredAnnotation(MethodLog.class)!=null){
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        logger.info("URL参数={}",requestAttributes.getRequest().getQueryString());
    }
}

访问不带注解方法时:

11.gif

访问带有注解方法时:

22.gif

版权声明:本文为HouXinLin_CSDN原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/HouXinLin_CSDN/article/details/108430756

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容