ResponseBodyAdvice
It is a powerful interface provided by Spring MVC, allowing you to be written in the response bodyBefore HTTP responseProcess it globally.
Below I will give a comprehensive introduction to its working principles, usage scenarios and best practices.
Basic concepts
Interface definition
public interface ResponseBodyAdvice<T> { boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType); @Nullable T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response); }
Core Methods
supports()
- Decide whether to apply advice to the return value of the method
- parameter:
-
returnType
: Return type information of controller method -
converterType
: The message converter type to be used to serialize the response body
-
beforeBodyWrite()
- Process the message converter before it is written to the response body
- parameter:
-
body
: The original response body returned by the controller - Other parameters and
supports()
same -
request
/response
: Current request and response objects
-
Typical application scenarios
1. Unified response encapsulation
The most common purpose is to wrap the return values of all controllers into a unified format:
@RestControllerAdvice public class UnifiedResponseAdvice implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { if (body instanceof ApiResponse) { return body; } return (body); } }
2. Desensitization in response to data
Automatically process sensitive data:
@Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { if (body instanceof UserInfo) { UserInfo user = (UserInfo) body; (desensitize(())); } return body; }
3. Response data cache
Cache specific responses:
@Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { if (().getPath().contains("/api/cacheable")) { (generateCacheKey(request), body); } return body; }
Advanced Usage and Best Practices
1. Accurately control the application scope
passsupports()
Methods accurately control which methods need to be processed:
@Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { // Only process methods that annotate @ResponseWrap return (); // Or exclude controllers under specific packages // return !().getPackage().getName().startsWith(""); }
2. Handle special cases Handle String type return value
@Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { if (body instanceof String) { ().setContentType(MediaType.APPLICATION_JSON); return ((body)); } // Other processing...}
Process non-JSON responses such as file downloads
@Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { //Exclude file download and other scenarios return !(converterType); }
3. Performance optimization
@RestControllerAdvice public class CustomResponseAdvice implements ResponseBodyAdvice<Object> { // Reuse the ObjectMapper instance private static final ObjectMapper objectMapper = new ObjectMapper(); // Predefined successful response private static final ApiResponse<?> EMPTY_SUCCESS = (null); @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { if (body == null) { return EMPTY_SUCCESS; } // Other processing... } }
Frequently Asked Questions
1. Compatibility issues with Swagger
@Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { //Exclude Swagger-related controllers return !().getPackage().getName().startsWith(""); }
2. Circular reference problem
When the wrapped object has a circular reference, it needs to be configured in the ObjectMapper:
(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); (SerializationFeature.FAIL_ON_SELF_REFERENCES, false);
3. Exception handling
AlthoughResponseBodyAdvice
No exception handling, but can be used with@ExceptionHandler
Use with:
@ExceptionHandler() public ApiResponse<?> handleException(Exception e) { return (()); }
Complete example
@RestControllerAdvice public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> { private final ObjectMapper objectMapper; public GlobalResponseAdvice(ObjectMapper objectMapper) { = objectMapper; } @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { // Exclude Swagger and Actuator endpoints return !(().getName().contains("springfox") || ().getName().contains("")); } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { // Non-JSON responses are not processed if (!(MediaType.APPLICATION_JSON)) { return body; } // It is already a packaging type and will not be processed if (body instanceof ApiResponse) { return body; } // Process String type return value if (body instanceof String) { try { ().setContentType(MediaType.APPLICATION_JSON); return ((body)); } catch (JsonProcessingException e) { throw new RuntimeException("JSON serialization failed", e); } } // Null value processing if (body == null) { return (); } // Default packaging return (body); } @Data @NoArgsConstructor @AllArgsConstructor public static class ApiResponse<T> { private int code; private String message; private T data; private long timestamp = (); public static <T> ApiResponse<T> success() { return new ApiResponse<>(200, "success", null); } public static <T> ApiResponse<T> success(T data) { return new ApiResponse<>(200, "success", data); } } }
By reasonable useResponseBodyAdvice
, you can implement centralized management of response processing to make the code more neat and consistent.
This is the article about the best practice records of Spring MVC interface ResponseBodyAdvice and its application. For more relevant Spring MVC ResponseBodyAdvice content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!