您的位置:

如何正确使用RequestBodyAdvice处理HTTP请求 - 一个全能开发工程师的技巧

一、什么是RequestBodyAdvice

RequestBodyAdvice是Spring框架中的一个接口,我们可以在实现它的过程中对请求的body进行处理。实现这个接口可以让我们在处理掉登录信息之外的请求时候,为请求做一些统一的处理,比如日志、加解密、甚至是自定义的转换等操作。


public interface RequestBodyAdvice {
    boolean supports(MethodParameter var1, Type var2, Class<? extends HttpMessageConverter<?>> var3);

    Object handleEmptyBody(Object var1, HttpInputMessage var2, MethodParameter var3, Type var4, Class<? extends HttpMessageConverter<?>> var5);

    HttpInputMessage beforeBodyRead(HttpInputMessage var1, MethodParameter var2, Type var3, Class<? extends HttpMessageConverter<?>> var4) throws IOException;

    Object afterBodyRead(Object var1, HttpInputMessage var2, MethodParameter var3, Type var4, Class<? extends HttpMessageConverter<?>> var5);
}

二、如何使用RequestBodyAdvice

1. 创建一个实现RequestBodyAdvice接口的类

我们创建一个名为MyRequestBodyAdvice的类,并实现RequestBodyAdvice接口的所有方法。


@ControllerAdvice
public class MyRequestBodyAdvice implements RequestBodyAdvice {

    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    @Override
    public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return o;
    }

    @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) {
        return o;
    }
}

2. 配置RequestBodyAdvice实例

在Spring Boot工程的application.properties文件中添加以下代码,将MyRequestBodyAdvice类注入到Spring容器中。


spring.mvc.async.request-timeout=-1
spring.mvc.ignore-default-model-on-redirect=true
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

spring.mvc.argument-resolvers.order=1
spring.mvc.argument-resolvers.enabled=true
spring.mvc.argument-resolvers.cache.seconds=0

spring.mvc.converters.preferred-json-mapper=jackson

spring.mvc.requestbody.enabled=true
spring.mvc.requestbody.wrap-exceptions=true

spring.mvc.date-format=yyyy-MM-dd HH:mm:ss
spring.mvc.locale=zh_CN
spring.mvc.dispatch-trace-request=false

spring.mvc.throw-exception-if-no-handler-found=true

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

spring.mvc.add-application-context-header=true

spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/

spring.http.encoding.charset=UTF-8
spring.http.encoding.force=true
spring.http.encoding.enabled=true

spring.http.multipart.enabled=true
spring.http.multipart.max-file-size=5MB
spring.http.multipart.max-request-size=10MB

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
spring.jackson.default-property-inclusion=NON_NULL
spring.jackson.deserialization.fail-on-unknown-properties=false

logging.level.root=warn

3. 添加自定义的转换逻辑

我们可以在beforeBodyRead方法中,对请求体进行自定义转换操作。


@Bean
public MappingJackson2HttpMessageConverter jsonConverter() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
    jsonConverter.setObjectMapper(objectMapper);
    return jsonConverter;
}

@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
    String body = IOUtils.toString(httpInputMessage.getBody(), StandardCharsets.UTF_8);
    Map<String, Object> map = new HashMap<>();
    map.put("data", JSONObject.parse(body));
    return new ServletServerHttpRequest(new MockHttpServletRequest(), new ServletInputStreamWrapper(JSONObject.toJSONBytes(map)), httpInputMessage.getHeaders());
}

三、使用RequestBodyAdvice的注意事项

1. 统一处理请求body可以有助于提高代码复用率

通过实现RequestBodyAdvice接口,在处理请求body时,我们可以做一些统一的操作,例如加解密、自定义转换、日志、参数校验等。这样可以帮助我们提高代码复用率,降低代码量。

2. 一定要实现supports方法

在实现RequestBodyAdvice接口时,一定要实现supports方法,它用于判断哪些请求需要处理,哪些不需要处理。如果不实现supports方法,会让整个RequestBodyAdvice失效。

3. 小心处理异常

在处理请求body时,我们要小心处理异常,比如说请求body为空时,要处理掉这个异常。


@Override
public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
    return o;
}

本文对如何正确使用RequestBodyAdvice处理HTTP请求作了详细阐述,主要包括RequestBodyAdvice的定义、如何使用RequestBodyAdvice和使用RequestBodyAdvice的注意事项。通过实现RequestBodyAdvice,我们可以统一处理请求body,提高代码复用率,降低代码量。