这里其实有多种解决方案
如果你不需要获取request对象 可以采用aop(环绕通知)的方式来统一修改
如果你需要获取request对象,那么就需要采用下面的方式
0自己定义一个注解,内容如下
@Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyResponseBody { }
1继承org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
覆盖
supportsReturnType()方法
handleReturnValue() 方法
以上两个方法的意思就是如果返回值对应的方法或其所在的类打上了@ResponseBody注解, 则返回true, 即使用这个MethodProcessor进行处理. 具体处理过程在handleReturnValue()中
具体代码如下
import java.io.IOException; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor; import com.zhaoyao.zybb2b.annotation.MyResponseBody; import com.zhaoyao.zybb2b.utils.ZybResult; public class MuliLanguageResponseBodyMethodProcessor extends RequestResponseBodyMethodProcessor { private final Logger log = LoggerFactory.getLogger(getClass()); public MuliLanguageResponseBodyMethodProcessor(List<HttpMessageConverter<?>> messageConverters) { super(messageConverters); } // 打@MyResponseBody注解且返回类型为ZybResult的方法 @Override public boolean supportsReturnType(MethodParameter returnType) { return (AnnotationUtils.findAnnotation(returnType.getContainingClass(), MyResponseBody.class) != null || returnType.getMethodAnnotation(MyResponseBody.class) != null) && ZybResult.class.equals(returnType.getParameterType()); } // 具体的处理过程 @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) { // 设置为true以后, 其他的MethodProcessor就不会再进行处理了 mavContainer.setRequestHandled(true); ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); try { writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); } catch (HttpMediaTypeNotAcceptableException | IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
2在SpringMvc中配置该bean(关于消息处理器,根据自己的需要灵活配置)
<mvc:annotation-driven> <mvc:message-converters> <ref bean="httpConverter" /> </mvc:message-converters> <mvc:return-value-handlers> <bean class="com.zhaoyao.zybb2b.interceptor.MuliLanguageResponseBodyMethodProcessor"> <constructor-arg> <list> <ref bean="httpConverter" /> </list> </constructor-arg> </bean> </mvc:return-value-handlers> </mvc:annotation-driven> <bean id="httpConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="com.fasterxml.jackson.databind.ObjectMapper"> <!-- 处理responseBody 里面日期类型 --> <property name="dateFormat"> <bean class="java.text.SimpleDateFormat"> <constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" /> </bean> </property> <!-- 为null字段时不显示 --> <property name="serializationInclusion"> <value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value> </property> </bean> </property> </bean>
3在方法上 打上MyResponseBody 注解,并且返回值是ZybResult 就会执行我们的处理器
原理解读:
通过阅读RequestMappingHandlerAdapter相关代码发现,HandlerMethodReturnValueHandler是对方法返回值进行处理的策略接口。
而RequestResponseBodyMethodProcessor(用于处理@RequestBody和@ResponseBody注解)继承了AbstractMessageConverterMethodProcessor。
AbstractMessageConverterMethodProcessor实现了HandlerMethodReturnValueHandler接口。
因为我当前的项目是响应json数据给客户端,所以直接继承了RequestResponseBodyMethodProcessor,并重写相关方法
为什么要自定义注解?
因为SpringMvc会优先执行系统的,再执行用户自定义的处理器。
在这里,顺便提一下SpringMvc的核心处理过程,后面遇到问题就可以找到特定的流程去处理
Spring工作流程描述
1. 用户向服务器发送请求,请求被SpringMvc 前端控制器DispatcherServlet(org.springframework.web.servlet.DispatcherServlet)捕获;
2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)
4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(这里可以简单的理解为Controller)。 在填充Handler的入参过程中,根据你的配置,SprinMvc将帮你做一些额外的工作:
adapter具体怎么处理的,请查看这篇文章(http://donald-draper.iteye.com/blog/2326185)
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
6. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
7. ViewResolver 结合Model和View,来渲染视图
8. 将渲染结果返回给客户端。