`

【避坑】Spring MVC 自定义 HttpMessageConverter 优先级问题

    博客分类:
  • Java
阅读更多

避坑:自定义 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);
  }
}

 

 

  • 大小: 121.2 KB
  • 大小: 55.5 KB
分享到:
评论

相关推荐

    使用 Spring 3 MVC HttpMessageConverter 功能构建 RESTful web 服务

    在开发 RESTful Web 服务时,Spring MVC 的 HttpMessageConverter 是一个至关重要的组件。这个功能允许我们将 Java 对象转换为 HTTP 响应消息,并将 HTTP 请求消息解析为 Java 对象。本文将深入探讨如何利用 Spring ...

    spring mvc 和spring security自定义登录

    本文将深入探讨如何结合Spring MVC和Spring Security来实现自定义登录功能。 首先,Spring MVC是Spring框架的一部分,它为构建基于HTTP的Web应用程序提供了模型-视图-控制器架构。通过使用Spring MVC,开发者可以...

    精通Spring MVC 4

    Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。Spring MVC4是当前zuixin的版本,在众多特性上有了进一步的提升。, 在精通Spring...

    spring mvc 中 实现自定义注解 拦截需要的方法

    网上很多人想使用注解拦截spring mvc action中的一个方法,实现方法很多,一般是通过在拦截器中分析url路径来实现, 使用自定义注解的方式来标注要拦截的 action 中的某个方法, 没有很好的解决方法, 如果通过借助spring...

    Spring.MVC-A.Tutorial-Spring.MVC学习指南 高清可复制版PDF

    Spring MVC 是一个基于Java的轻量级Web应用框架,它是Spring框架的重要组成部分,主要用于构建Web应用程序的后端控制器。这个教程“Spring MVC - A Tutorial”旨在帮助开发者深入理解和掌握Spring MVC的核心概念和...

    最全最经典spring-mvc教程

    Spring MVC 是一款强大的Java Web开发框架,用于构建高效、可维护和模块化的Web应用程序。它作为Spring框架的一部分,提供了一种优雅的方式来处理HTTP请求和响应,使得开发者可以专注于业务逻辑而不是底层实现。在这...

    Mastering Spring MVC 4(2015.09)源码

    拦截器(Interceptor)是Spring MVC中的一种机制,可以在请求处理前、后执行自定义逻辑。通过实现HandlerInterceptor接口或使用@Interceptor注解,开发者可以添加全局的行为,如日志记录、权限检查等。 此外,...

    Spring MVC 教程快速入门 深入分析

    十二、Spring MVC如何把全局异常记录到日志中:讲述了如何将异常信息记录到日志文件中,以便于问题的追踪和调试。 十三、如何给Spring3 MVC中的Action做JUnit单元测试:说明了如何对Spring MVC中的控制器进行单元...

    Spring MVC 4.2.4.RELEASE 中文文档

    通过自定义异常处理器,Spring MVC允许优雅地处理运行时异常,提供了统一的错误页面和异常信息。 **7. RESTful支持** Spring MVC支持构建RESTful服务,通过HTTP方法如GET、POST、PUT、DELETE等,实现资源的增删改查...

    第12章spring-mvc自定义类型转换器

    第12章spring-mvc自定义类型转换器

    开发Spring MVC应用程序补充—程序源码下载.rar_spring_spring mvc_spring mvc 源码_sp

    Spring MVC源码的深入理解有助于开发者更好地掌握框架的工作原理,优化代码性能,甚至为自定义扩展提供基础。 压缩包内的文件"www.pudn.com.txt"可能是一个链接或说明文档,指向更多关于该主题的资源,例如在pudn....

    spring mvc freemarker 自定义标签

    下面将详细介绍Spring MVC与Freemarker自定义标签的使用。 首先,我们需要了解Freemarker的基础。Freemarker是一个基于模板的语言,它的主要任务是根据数据模型生成输出。在Spring MVC中,Freemarker模板通常用于...

    spring MVC配置详解

    Spring MVC 配置详解 ...Spring MVC 是一个功能强大且灵活的 Web 框架,它提供了许多可配置的组件,以便我们根据需要进行自定义配置。掌握 Spring MVC 的配置和原理是我们开发高质量 Web 应用程序的关键。

    Spring mvc5.0.3 所有jar包

    9. **拦截器(Interceptor)**: Spring MVC允许自定义拦截器,可以在请求处理前或后执行一些通用逻辑,如权限检查、日志记录等。 10. **异常处理**: 可以全局或局部地配置异常处理器,将异常转换为特定的视图或HTTP...

    基本的spring mvc + spring security实现的登录(无数据库)

    在本项目中,我们主要探讨的是如何利用Spring MVC和Spring Security框架构建一个基本的无数据库登录系统。Spring MVC是Spring框架的一部分,用于处理Web应用程序的请求-响应模型,而Spring Security则是一个强大的...

    Spring MVC 简单Demo

    - 在Spring MVC配置文件中声明处理器映射器、视图解析器、以及自定义的控制器等。 4. **创建简单示例** 在这个"Spring MVC 简单Demo"中,我们可能有一个名为`SummerWeb`的目录,其中包含以下文件: - `web.xml`...

    Spring MVC使用Demo

    Spring MVC是Spring框架的一个核心模块,专用于构建Web应用程序。这个"Spring MVC使用Demo"提供了实践操作,帮助开发者深入理解Spring MVC的开发环境配置、注解的使用以及工作原理。 首先,Spring MVC的设计模式...

Global site tag (gtag.js) - Google Analytics