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中都有了这份数据,取出渲染即可。
在这里插入图片描述

获取请求参数

我们可以通过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";
  }

在这里插入图片描述

修改请求参数

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

  1. 可以在目标方法之前增加逻辑,也可以在执行目标方法之后增加逻辑.
  2. 可以决定目标方法在什么时候执行,如何执行,也可以阻止目标目标方法执行.
  3. 可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回值.

使用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";
 }

在这里插入图片描述

修改返回值

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;
 }

在这里插入图片描述

打印带有指定注解方法的参数

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

@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());
    }
}

访问不带注解方法时:

在这里插入图片描述
访问带有注解方法时:

在这里插入图片描述

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值