避坑:自定义 Spring MVC 的 HttpMessageConverter 时,应显式设置各Converter的先后顺序,避免被Spring框架的“自动调整”打乱优先级。
@Configuration public class MyConfig impliments WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(0, converter1); converters.add(1, converter2); converters.add(2, converter3); ... } }
HttpMessageConverter 是用于 读写 HTTP Message Body 的数据转换器。
用 序列化和反序列化 类比:
- 读 Request Body 时, 其职能类似 反序列化;
- 写 Response Body 时,其职能类似 序列化。
踩坑经历
最近某个项目升级 Spring Boot,其依赖的 spring-boot-starter-web 原版本为 1.5.12.RELEASE,现使用版本为 “2.1.3.RELESE”。
结果升级出了点问题,请我去帮忙排查。
升级后发现 HTTP REST API 的返回值“格式”变了:返回类型为 复杂对象的 API,其返回值中的字段名都不符合序列化设置。
如,原来返回的字段名为 task_id,现在是 taskId 。
这显然是针对HTTP Response的“序列化”出了问题。
于是找到相关配置代码:
@Configuration public class MyHttpMsgConverter extends WebMvcConfigurerAdapter { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { StringHttpMessageConverter strConverter = ... converters.add(strConverter); FastJsonHttpMessageConverter objConverter = ... converters.add(objConverter); } }
原作者是想用 FastJson 序列化复杂对象。他在相关返回类中用 @JSONField 注解设置了各字段序列化后的名称。
因为 FastJson 序列化字符串时会在其前后加引号,所以先添加一个 StringHttpMessageConverter,优先级高于 FastJsonHttpMessageConverter。
注:
FastJson 中的StringCodec类负责序列化字符串;
StringCodec 会调用 SerializeWriter 的 writeString(String text)方法;
writeString 方法会在原字符串前后加了一对引号(双引号或单引号):
package com.alibaba.fastjson.serializer; public final class SerializeWriter extends Writer { public void writeString(String text) { if (useSingleQuotes) { writeStringWithSingleQuote(text); } else { writeStringWithDoubleQuote(text, (char) 0); } } }
经过调试发现是新版 spring-webmvc(5.1.5.RELEASE) 中 原来两个自定义的Converter 被spring框架默认的Converter取代了。
自定义的Converter排在末尾,优先级低于其它默认Converter。
MappingJackson2HttpMessageConverter 接管了“序列化”复杂对象的职责,而不是 FastJsonHttpMessageConverter。
这两类Converter都实现了 HttpMessageConverter<Object> 接口,所以 FastJsonHttpMessageConverter 可以被替代。
AbstractMessageConverterMethodProcessor 中的 writeWithMessageConverters 方法负责选取合适的 Converter。
它们在下图右侧中的序号分别为 7 和 12。
因为默认 StringHttpMessageConverter 的字符编码(Charset) 与 原自定义Converter 相同,所以返回类型为String的API一切正常。
它们在下图右侧中的序号分别为 1 和 11。
原 spring-webmvc(4.3.16.RELEASE)中这两个自定义Converter排在最前面,优先级高于默认的Converter。
新版本的 spring-webmvc 中,因为 WebMvcConfigurer 实例列表中各项顺序不同,所以最终得到的Converter列表里各项顺序也不同。
Spring框架提供的默认Converter来自 WebMvcAutoConfiguration。
在新版spring-webmvc中,它先于自定义的MyHttpMsgConverterConfig被处理,所以自定义Converter优先级最低。
相关代码:
class WebMvcConfigurerComposite implements WebMvcConfigurer { public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.delegates.addAll(configurers); } } }
改造配置类
最直接的解决思路就是将自定义的Converter放到列表头部,使其优先级高于Spring默认的Converter。
@Configuration public class MyHttpMsgConverterConfig impliments WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { StringHttpMessageConverter strConverter = ... converters.add(0, strConverter); FastJsonHttpMessageConverter objConverter = ... converters.add(1, objConverter); } }
相关推荐
在开发 RESTful Web 服务时,Spring MVC 的 HttpMessageConverter 是一个至关重要的组件。这个功能允许我们将 Java 对象转换为 HTTP 响应消息,并将 HTTP 请求消息解析为 Java 对象。本文将深入探讨如何利用 Spring ...
本文将深入探讨如何结合Spring MVC和Spring Security来实现自定义登录功能。 首先,Spring MVC是Spring框架的一部分,它为构建基于HTTP的Web应用程序提供了模型-视图-控制器架构。通过使用Spring MVC,开发者可以...
Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。Spring MVC4是当前zuixin的版本,在众多特性上有了进一步的提升。, 在精通Spring...
网上很多人想使用注解拦截spring mvc action中的一个方法,实现方法很多,一般是通过在拦截器中分析url路径来实现, 使用自定义注解的方式来标注要拦截的 action 中的某个方法, 没有很好的解决方法, 如果通过借助spring...
Spring MVC 是一个基于Java的轻量级Web应用框架,它是Spring框架的重要组成部分,主要用于构建Web应用程序的后端控制器。这个教程“Spring MVC - A Tutorial”旨在帮助开发者深入理解和掌握Spring MVC的核心概念和...
Spring MVC 是一款强大的Java Web开发框架,用于构建高效、可维护和模块化的Web应用程序。它作为Spring框架的一部分,提供了一种优雅的方式来处理HTTP请求和响应,使得开发者可以专注于业务逻辑而不是底层实现。在这...
拦截器(Interceptor)是Spring MVC中的一种机制,可以在请求处理前、后执行自定义逻辑。通过实现HandlerInterceptor接口或使用@Interceptor注解,开发者可以添加全局的行为,如日志记录、权限检查等。 此外,...
十二、Spring MVC如何把全局异常记录到日志中:讲述了如何将异常信息记录到日志文件中,以便于问题的追踪和调试。 十三、如何给Spring3 MVC中的Action做JUnit单元测试:说明了如何对Spring MVC中的控制器进行单元...
通过自定义异常处理器,Spring MVC允许优雅地处理运行时异常,提供了统一的错误页面和异常信息。 **7. RESTful支持** Spring MVC支持构建RESTful服务,通过HTTP方法如GET、POST、PUT、DELETE等,实现资源的增删改查...
第12章spring-mvc自定义类型转换器
Spring MVC源码的深入理解有助于开发者更好地掌握框架的工作原理,优化代码性能,甚至为自定义扩展提供基础。 压缩包内的文件"www.pudn.com.txt"可能是一个链接或说明文档,指向更多关于该主题的资源,例如在pudn....
下面将详细介绍Spring MVC与Freemarker自定义标签的使用。 首先,我们需要了解Freemarker的基础。Freemarker是一个基于模板的语言,它的主要任务是根据数据模型生成输出。在Spring MVC中,Freemarker模板通常用于...
Spring MVC 配置详解 ...Spring MVC 是一个功能强大且灵活的 Web 框架,它提供了许多可配置的组件,以便我们根据需要进行自定义配置。掌握 Spring MVC 的配置和原理是我们开发高质量 Web 应用程序的关键。
9. **拦截器(Interceptor)**: Spring MVC允许自定义拦截器,可以在请求处理前或后执行一些通用逻辑,如权限检查、日志记录等。 10. **异常处理**: 可以全局或局部地配置异常处理器,将异常转换为特定的视图或HTTP...
在本项目中,我们主要探讨的是如何利用Spring MVC和Spring Security框架构建一个基本的无数据库登录系统。Spring MVC是Spring框架的一部分,用于处理Web应用程序的请求-响应模型,而Spring Security则是一个强大的...
- 在Spring MVC配置文件中声明处理器映射器、视图解析器、以及自定义的控制器等。 4. **创建简单示例** 在这个"Spring MVC 简单Demo"中,我们可能有一个名为`SummerWeb`的目录,其中包含以下文件: - `web.xml`...
Spring MVC是Spring框架的一个核心模块,专用于构建Web应用程序。这个"Spring MVC使用Demo"提供了实践操作,帮助开发者深入理解Spring MVC的开发环境配置、注解的使用以及工作原理。 首先,Spring MVC的设计模式...