使用AOP获取RequestBody

2016-11-20 高悦翔 更多博文 » 博客 » GitHub »

原文链接 http://blog.gaoyuexiang.cn/get_RequestBody_by_aop/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


  • doc {:toc}

一开始使用spring拦截器拦截请求记录日志,对于请求路径、header这些都很好获取,唯独POST请求无法获取其中的RequestBody.

原因很明显,RequestBody是只能读取一次的,如果在拦截器中读取了,就无法通过@RequestBody注解去获取,因为这个数据是内存中的流数据.

那要如何做呢?明显就需要用到aop

利用AOP读取RequestBody

aop就是用来做切面的,具体概念这里不说了,自行谷歌.这里就讲具体问题的思路.

这里用aop去切入Controller里面所有public的方法,利用JoinPoint获取参数,从而得到RequestBody. 得到RequestBody后使用Spring Boot的日志打印

创建一个切面

@Aspect
@Component
public class RequestMapAspect {}
  • @Aspect注解表明这是一个切面
  • @Componet注册为组件,否则无法使用Spring Boot的日志

声明一个logger

private final Log log = LogFactory(this.getClass());
  • 这里的LogLogFactory均在org.apache.commons.logging包下,不是slf4j,不是logback也不是log4j!

声明切点

@Pointcut(value = "excution(public * cn.gaoyuexiang.controller.*.*(..))")
public void controllerLog() {}

编写Before获取参数

@Before("controllerLog()")
public void before(JoinPoint point) {
  logger.info("controller aspect begging");
  Object[] args = point.getArgs();
  for (Object arg : args) {
    logger.info("arg: " + arg); 
  }
  String method = point.getSignature().getDeclaringTypeName() + '.' + point.getSignature().getName();
  logger.info("aspect finishing");
  logger.info("calling " + method);
}
  • JoinPoint.getArgs()可以得到目标方法的参数,返回类型为Object[]
  • RequestBody作为参数时,因为是在调用方法前已经被Spring读取并解析了,所以不存在重复读取的问题.调用目标方法时,Beforeaop被执行,拿到传递给目标的参数