阅读 57

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

此文章已同步更新至我的个人博客simonting.gitee.io

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

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

代码示例

/**
 * @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生效的包路径,不指定默认全局生效。

测试类

/**
* @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方法生效。