如何实现类级@ResponseBody风格注解:使其作用于类中所有方法
Great question! If you want to create a class-level annotation that automatically applies the @ResponseBody behavior to all methods in the annotated class, you can leverage Spring MVC's extension points to build this functionality. Here's a step-by-step guide:
Step 1: Define Your Custom Class-Level Annotation
First, create an annotation that targets classes and retains at runtime:
import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface GlobalResponseBody { }
Step 2: Customize the Return Value Handler
Spring uses RequestResponseBodyMethodProcessor to handle methods annotated with @ResponseBody. We'll extend this processor to check if the method's containing class has our @GlobalResponseBody annotation:
import org.springframework.core.MethodParameter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor; import java.util.List; public class GlobalResponseBodyReturnValueHandler extends RequestResponseBodyMethodProcessor { public GlobalResponseBodyReturnValueHandler(List<HttpMessageConverter<?>> converters) { super(converters); } public GlobalResponseBodyReturnValueHandler(List<HttpMessageConverter<?>> converters, List<Object> requestResponseBodyAdvice) { super(converters, null, requestResponseBodyAdvice); } @Override public boolean supportsReturnType(MethodParameter returnType) { // Check if the class has our custom annotation first Class<?> containingClass = returnType.getContainingClass(); if (containingClass.isAnnotationPresent(GlobalResponseBody.class)) { return true; } // Fall back to the original logic (check for @ResponseBody on methods) return super.supportsReturnType(returnType); } }
Step 3: Register the Custom Handler with Spring MVC
We need to add our custom handler to Spring's return value handler chain, ensuring it takes priority over the default processor. Use WebMvcConfigurer to configure this:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; @Configuration public class CustomWebMvcConfig implements WebMvcConfigurer { @Autowired private List<HttpMessageConverter<?>> messageConverters; @Autowired(required = false) private List<Object> requestResponseBodyAdvice; @Override public void configureReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) { // Create our custom handler GlobalResponseBodyReturnValueHandler customHandler = new GlobalResponseBodyReturnValueHandler(messageConverters, requestResponseBodyAdvice); // Add it to the front of the list to ensure it's checked first handlers.add(0, customHandler); } }
Step 4: Use the Annotation
Now you can annotate any controller class with @GlobalResponseBody, and all its methods will automatically return serialized response bodies (just like using @ResponseBody on every method):
@Controller @GlobalResponseBody public class DemoController { // This method will return JSON (or configured format) without @ResponseBody @GetMapping("/demo") public DemoDto getDemo() { return new DemoDto("Hello", "World"); } }
How It Works
- Our custom
GlobalResponseBodyReturnValueHandleroverridessupportsReturnTypeto check if the method's class has our annotation. If yes, it tells Spring to process the return value as a response body. - By adding our handler to the start of the handler list, we ensure our logic takes precedence over the default
RequestResponseBodyMethodProcessor. - This approach aligns with Spring's native handling of
@ResponseBody, so you get all the same features (like content negotiation, message converters, andResponseBodyAdvicesupport).
内容的提问来源于stack exchange,提问作者sibo.wang

