SoFunction
Updated on 2025-04-15

Spring MVC Interface ResponseBodyAdvice and its application best practice records

ResponseBodyAdviceIt 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 andsupports()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&lt;? extends HttpMessageConverter&lt;?&gt;&gt; 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&lt;? extends HttpMessageConverter&lt;?&gt;&gt; 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&lt;? extends HttpMessageConverter&lt;?&gt;&gt; converterType) {
    //Exclude file download and other scenarios    return !(converterType);
}

3. Performance optimization

@RestControllerAdvice
public class CustomResponseAdvice implements ResponseBodyAdvice&lt;Object&gt; {
    // Reuse the ObjectMapper instance    private static final ObjectMapper objectMapper = new ObjectMapper();
    // Predefined successful response    private static final ApiResponse&lt;?&gt; EMPTY_SUCCESS = (null);
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, 
                                MediaType selectedContentType,
                                Class&lt;? extends HttpMessageConverter&lt;?&gt;&gt; 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&lt;? extends HttpMessageConverter&lt;?&gt;&gt; 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

AlthoughResponseBodyAdviceNo exception handling, but can be used with@ExceptionHandlerUse with:

@ExceptionHandler()
public ApiResponse<?> handleException(Exception e) {
    return (());
}

Complete example

@RestControllerAdvice
public class GlobalResponseAdvice implements ResponseBodyAdvice&lt;Object&gt; {
    private final ObjectMapper objectMapper;
    public GlobalResponseAdvice(ObjectMapper objectMapper) {
         = objectMapper;
    }
    @Override
    public boolean supports(MethodParameter returnType, Class&lt;? extends HttpMessageConverter&lt;?&gt;&gt; converterType) {
        // Exclude Swagger and Actuator endpoints        return !(().getName().contains("springfox") || 
                ().getName().contains(""));
    }
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, 
                                MediaType selectedContentType,
                                Class&lt;? extends HttpMessageConverter&lt;?&gt;&gt; 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&lt;T&gt; {
        private int code;
        private String message;
        private T data;
        private long timestamp = ();
        public static &lt;T&gt; ApiResponse&lt;T&gt; success() {
            return new ApiResponse&lt;&gt;(200, "success", null);
        }
        public static &lt;T&gt; ApiResponse&lt;T&gt; success(T data) {
            return new ApiResponse&lt;&gt;(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!