在项目中遇到接口参数@RequestBody的参数需要在后面的全局异常处理器中打印出来,发现@RequestBody注解的参数是流的形式,内部的流限制为只能读取一次(inputStream的数据只能读取一次,从inputStream中读取过数据之后,后续再从inputStream中就不能再读取到数据了),解决方案采用aop面在进入方法前通过JoinPoint获取方法参数并把参数set进request,顺便总结写一个aop的demo
注:
aop切面主要有三部分组成
- Aspect切面类
- Pointcut切点
- @Before、@After等通知
切点配置说明
pom.xml添加依赖
<!-- springboot aop依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
新建一个切面类(主要有切点和通知组成)
@Aspect
@Component
public class ControllerAspect {
private Logger logger = LoggerFactory.getLogger(getClass());
/*@PointCut注解表示表示横切点,哪些方法需要被横切*/
@Pointcut("execution(* com.xinhuo.demo.web.StudentController.*(..))")
public void pointCut() {
}
/**
* 前置通知:方法调用前被调用
* 通过JoinPoint 获取通知的签名信息,如目标方法名,目标方法参数信息等
* 把接口中的requestMsg参数重新设置进request
* @param joinPoint
*/
// @Before("execution(* com.xinhuo.demo.web..*.*(..))")
@Before("execution(* com.xinhuo.demo.web.StudentController.*(..))")
public void beforeController(JoinPoint joinPoint){
logger.info("aop before");
//获取接口的参数,设置回request
Object[] o = joinPoint.getArgs();
// RequestMsg requestMsg = (RequestMsg) o[0];
//获取RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
//从获取RequestAttributes中获取HttpServletRequest的信息
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
request.setAttribute("body",o[0]);
}
/**
* 后置返回通知
* @AfterReturning注解用于获取方法的返回值
* @param object
*/
@AfterReturning(pointcut = "pointCut()", returning = "object")
public void getAfterReturn(Object object) {
logger.info("aop afterReturning");
logger.info("aop afterReturning返回值:{}", JSONObject.toJSONString(object));
}
/**
* 后置最终通知(目标方法只要执行完了就会执行后置通知方法)
* @After注解表示在方法执行之后执行
*/
@After("pointCut()")
public void after(JoinPoint joinPoint) {
logger.info("aop after");
}
/**
* 后置异常通知
* 当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法;
*/
@AfterThrowing(value="pointCut()",throwing = "exception")
public void afterThrowing(JoinPoint joinPoint,Throwable exception) {
logger.info("aop afterThrowing");
}
}
web层
@RestController
@RequestMapping("/student")
public class StudentController {
Logger log = LoggerFactory.getLogger(getClass());
@Autowired
private StudentService studentService;
/**
* 查询学生信息
* @param requestMsg
* @return
*/
@GetMapping("/find")
public ResultMsg findStudent(@RequestBody RequestMsg requestMsg) {
log.info("进入findStudent start");
int sid = requestMsg.getData().getIntValue("sid");
if(sid == 0){
// return ResultMsg.error(-1,"参数sid为空");
throw new RuntimeException("参数sid为空");
}
Student stu = studentService.getById(sid);
ResultMsg resultMsg = new ResultMsg();
resultMsg.setData(stu);
log.info("进入findStudent end");
return resultMsg;
}
}
测试aop的方法的通知顺序
异常时的顺序