0%

SpringBoot项目实战之@ControllerAdvice+RequestBodyAdvice实现请求体全局统一处理

在实际项目开发中,经常需要对前台发来的请求body进行处理,例如参数过滤,参数校验,不合法参数拦截,参数解密等等。Spring中提供了 @ControllerAdvice+RequestBodyAdvice 的解决方案 对请求进行全局统一处理,可以避免在controller层对业务代码入侵。

注意:该方法只对使用了@RequestBody注解的参数生效,本质上是AOP,获取的是在请求头中的属性,如果通过GET请求方式,例如http://localhost:8080/xx?id=1 此种方法,是无法获得id参数的,此处下面将用代码证明。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
* @Author zhangting
* @Desc 请求body全局统一处理
* @Date 2020/07/29
**/
@Slf4j
@ControllerAdvice(basePackages = "com.example.demo.controller2")
public class GlobalRequestBodyAdvice implements RequestBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
// 此处true代表执行当前advice的业务,false代表不执行
return true;
}

/**
* 读取参数前执行
*
* @param httpInputMessage
* @param methodParameter
* @param type
* @param aClass
* @return
* @throws IOException
*/
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
log.info("-----beforeBodyRead-----");
return httpInputMessage;
}

/**
* 读取参数后执行
*
* @param o
* @param httpInputMessage
* @param methodParameter
* @param type
* @param aClass
* @return
*/
@Override
public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
log.info("-----afterBodyRead-----");
log.info("class name is {}",methodParameter.getDeclaringClass().getSimpleName());
log.info("method name is {}",methodParameter.getMethod().getName());
log.info("request parameter is {}",o.toString());
return o;
}

/**
* 无请求时的处理
*
* @param o
* @param httpInputMessage
* @param methodParameter
* @param type
* @param aClass
* @return
*/
@Override
public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
log.info("-----handleEmptyBody-----");
return o;
}
}

@ControllerAdvice可以指定当前Advice生效的包路径,不指定默认全局生效。

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* @Author zhangting
* @Desc 测试
* @Date 2020/07/29
**/
@RestController
@RequestMapping("/v2")
@Slf4j
public class TestController2 {

@RequestMapping(method = RequestMethod.GET, value = "/get")
public ResponseEntity<?> get(@RequestParam String id) {
log.info("id is {}", id);
Map<String,String> rsp = new HashMap<>();
rsp.put("code","200");
rsp.put("msg","success");
return new ResponseEntity<>(rsp, HttpStatus.OK);
}

@RequestMapping(method = RequestMethod.POST, value = "/post")
public ResponseEntity<?> post(@RequestBody Map<String, String> map) {
log.info("begin /v2/post");
Map<String,String> rsp = new HashMap<>();
rsp.put("code","200");
rsp.put("msg","success");
log.info("end /v2/post");
return new ResponseEntity<>(rsp, HttpStatus.OK);
}
}

测试类中共包含两个api:
1、/v2/get , 请求方式为GET
2、/v2/post ,请求方式为POST
通过postman测试:

测试POST方式:

在这里插入图片描述
在这里插入图片描述
结论:RequestBodyAdvice对POST方式+@RequestBody注解生效,成功获取请求的类名、方法名及参数,我们就可以对参数进行具体的业务处理。

测试GET方式:

在这里插入图片描述
在这里插入图片描述
结论:RequestAdvice未对GET方法生效。