RequestBodyAdvice和ResponseBodyAdvice在SpringMVC项目中的使用

在实际项目中,我们常常需要在请求前后进行一些操作,比如:参数解密/返回结果加密,打印请求参数和返回结果的日志等。这些与业务无关的东西,我们不希望写在controller方法中,造成代码重复可读性变差。这里,我们讲讲使用 @ControllerAdvice 和 RequestBodyAdvice、 RequestBodyAdvice 来对请求前后进行处理(本质上就是AOP),来实现日志记录每一个请求的参数和返回结果。

1、请求前处理

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Slf4j
@ControllerAdvice
public class LogRequestBodyAdvice implements RequestBodyAdvice {
 
    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }
  
    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
        return httpInputMessage;
    }
  
    @Override
    public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        Method method=methodParameter.getMethod();
        log.info("{}.{}:{}",method.getDeclaringClass().getSimpleName(),method.getName(),JSON.toJSONString(o));
        return o;
    }
  
    @Override
    public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        Method method=methodParameter.getMethod();
        log.info("{}.{}",method.getDeclaringClass().getSimpleName(),method.getName());
        return o;
    }
}

RequestBodyAdvice 针对所有以 @RequestBody 的参数,在读取请求body之前或者在body转换成对象之前可以做相应的增强。我们处理了有参数和没有参数的情况,打印出请求类、方法、请求参数。注意:这里要加上 @ControllerAdvice或 @RestControllerAdvice请求才能增强。

2、请求后处理

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
@Slf4j
@ControllerAdvice
public class LogResponseBodyAdvice implements ResponseBodyAdvice {
 
    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }
  
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        Method method=methodParameter.getMethod();
        String url=serverHttpRequest.getURI().toASCIIString();
        log.info("{}.{},url={},result={}",method.getDeclaringClass().getSimpleName(),method.getName(),url,JSON.toJSONString(o));
  
        return o;
    }
}

ResponseBodyAdvice 用于响应体写出之前做一些处理。这里我们记录了请求类、方法、链接、请求结果。同 RequestBodyAdvice 一样,也需要加上@ControllerAdvice 或@RestControllerAdvice 进行请求增强。

3、编写请求代码

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
@RestController
@Slf4j
@RequestMapping("/lm")
public class HelloController {
  
    @RequestMapping("/hello1")
    public String hello(@RequestBody JSONObject jsonObject){
        return "hello 1:"+jsonObject.getString("name");
    }
  
    @RequestMapping("/hello2")
    public String hello(@RequestParam("name") String name){
        return "hello 2:"+name;
    }
}

可见,我们记录请求参数和返回结果的代码都不用写在controller中了。

4、发起请求

访问hello1接口,日志如下:

1
2
2018-11-26 20:36:11.599 &nbsp;INFO 75364 HelloController.hello:{"name":"ggg"}
2018-11-26 20:36:11.611 &nbsp;INFO 75364 HelloController.hello,url=http://localhost:8501/lm/hello1,result="hello 1:ggg"&nbsp;

访问hello2接口,日志如下:

1
2018-11-26 20:37:55.643  INFO 75364 HelloController.hello,url=http://localhost:8501/lm/hello2?name=vvv,result="hello 2:vvv"

可以看到,hello2接口因为参数没有用 @RequestBody 绑定,只打印了ResponseBodyAdvice里的日志,没有进入RequestBodyAdvice。

总结

使用@ControllerAdvice注解+ResponseBodyAdvice+ResponseBodyAdvice,可以对请求的输入输出进行处理,避免了在controller中对业务代码侵入。

1人评论了“RequestBodyAdvice和ResponseBodyAdvice在SpringMVC项目中的使用”

  1. Pingback: SpringBoot接口参数加密解密 – 梓潼

发表评论

欢迎阅读『RequestBodyAdvice和ResponseBodyAdvice在SpringMVC项目中的使用|Java、开发语言、框架算法|Nick Tan-梓潼Blog』