Spring 框架在处理 HTTP 请求和响应时,会使用配置的 HttpMessageConverter(消息转换器)来完成数据格式的转换。这是 Spring MVC 实现 RESTful API、处理 JSON/XML 数据以及 @RequestBody 和 @ResponseBody 注解功能的核心机制。

以下是关于 Spring 如何使用 HttpMessageConverter 的详细解析:

1. 核心工作原理

HttpMessageConverter 是一个策略接口,负责在 ‌HTTP 请求/响应字节流‌ 与 ‌Java 对象‌ 之间进行双向转换。

读取请求(反序列化)‌:当控制器方法参数带有 @RequestBody 时,Spring 会根据请求头中的 Content-Type媒体类型(如 application/json`)和参数类型,选择合适的 Converter 将请求体字节流转换为 Java 对象。
写入响应(序列化)‌:当控制器方法带有 @ResponseBody 或返回值为对象且被 ResponseEntity 包裹时,Spring 会根据请求头中的 Accept 属性(客户端希望接收的类型)和返回值类型,选择合适的 Converter 将 Java 对象转换为字节流写入响应体。
2. 匹配与选择机制

Spring 并不是随机选择一个转换器,而是遵循严格的匹配逻辑:

遍历转换器列表‌:Spring 容器中维护了一个 List<HttpMessageConverter<?>>。
判断可读/可写性‌:
对于请求:调用 canRead(Class<?> clazz, MediaType mediaType)。检查该转换器是否支持目标 Java 类型以及请求的 Content-Type。
对于响应:调用 canWrite(Class<?> clazz, MediaType mediaType)。检查该转换器是否支持返回的 Java 类型以及客户端接受的 MediaType(通过 Accept 头协商)。
执行转换‌:一旦找到第一个满足条件的 Converter,就会调用其 read() 或 write() 方法执行实际转换。如果找不到合适的 Converter,通常会抛出 HttpMediaTypeNotSupportedException (415) 或 HttpMessageNotWritableException (500/406)。
3. 常用的内置 HttpMessageConverter

Spring Boot 默认会自动配置一组常用的转换器,主要包括:

转换器类名支持的 MediaType功能描述依赖库
‌MappingJackson2HttpMessageConverter‌application/json, application/*+json将 Java 对象与 JSON 字符串互转。这是处理 JSON 最常用的转换器。Jackson (jackson-databind)
‌StringHttpMessageConverter‌text/plain, */*将请求/响应体作为纯字符串处理。常用于接收原始文本或简单字符串返回。无 (Spring Core)
‌FormHttpMessageConverter‌application/x-www-form-urlencoded将表单数据转换为 MultiValueMap<String, String>。无 (Spring Web)
‌ByteArrayHttpMessageConverter‌application/octet-stream, */*处理二进制字节数组。无 (Spring Core)
‌ResourceHttpMessageConverter‌*/*处理 org.springframework.core.io.Resource 对象,常用于文件下载。无 (Spring Core)
‌Jaxb2RootElementHttpMessageConverter‌application/xml, text/xml将 Java 对象与 XML 互转。JAXB

注意‌:StringHttpMessageConverter 默认使用的字符集通常是 ISO-8859-1,但在 Spring Boot 中通常会被配置为 UTF-8 以避免中文乱码。

4. 自定义与配置

在实际开发中,默认的转换器可能无法满足所有需求(例如特定的日期格式、Null 值处理、自定义协议等),可以通过以下方式配置:

A. 修改默认行为(推荐)

通过实现 WebMvcConfigurer 接口来定制现有的转换器,特别是针对 Jackson 的配置。
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 1. 移除默认的 StringConverter 以解决潜在的编码问题或替换它
        converters.removeIf(c -> c instanceof StringHttpMessageConverter);
        
        // 2. 添加自定义编码的 StringConverter
        StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
        stringConverter.setWriteAcceptCharset(false); // 避免在响应头中强制添加 charset
        converters.add(stringConverter);

        // 3. 自定义 Jackson 转换器(例如统一日期格式)
        MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        jacksonConverter.setObjectMapper(objectMapper);
        
        // 添加到列表前端,提高优先级
        converters.add(0, jacksonConverter);
    }
}

B. 完全自定义 Converter

如果需处理非标准格式(如特定硬件设备的私有协议),可以实现 HttpMessageConverter 接口并注册到 Spring 容器中。

5. 常见陷阱与最佳实践
JSON 依赖缺失‌:如果使用 @ResponseBody 返回对象但项目中没有引入 Jackson 依赖(jackson-databind),Spring 无法找到 MappingJackson2HttpMessageConverter,会导致报错。确保 pom.xml 中包含相关依赖。
日期格式不一致‌:前端传来的日期字符串格式必须与后端 ObjectMapper 或字段上 @JsonFormat 定义的格式一致,否则会抛出 TypeMismatchException 或 JsonParseException。
Content-Type 匹配‌:
发送 JSON 时,请求头必须包含 Content-Type: application/json。
如果发送的是表单数据(application/x-www-form-urlencoded),则不能使用 @RequestBody 接收复杂对象,而应使用 @RequestParam 或 POJO 直接接收(由 FormHttpMessageConverter 或数据绑定机制处理)。
优先级问题‌:转换器的顺序很重要。Spring 按列表顺序遍历,第一个匹配的会被使用。如果需要自定义转换器优先生效,应将其添加到列表的前面(如 converters.add(0, myConverter))。
总结

Spring 通过 HttpMessageConverter 机制实现了 HTTP 协议数据与 Java 对象的解耦。开发者只需关注 Java 对象模型,而无需手动处理字节流的解析与生成。理解这一机制有助于解决常见的 415、406、400 错误以及中文乱码、日期格式化等问题。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐