MVC入门(5)-- HttpMessageConverter 消息转换器

发布于:2025-05-21 ⋅ 阅读:(17) ⋅ 点赞:(0)

概念

HttpMessageConverter 是 Spring 框架中用于处理 HTTP 请求和响应数据的核心接口,负责在 Java 对象与 HTTP 消息体(请求体或响应体)之间进行双向转换。简单来说,它是 Spring 用来将 HTTP 请求中的原始数据(如 JSON、XML、表单数据等)转换为 Java 对象,或者将 Java 对象转换为 HTTP 响应数据的“翻译器”

就是返回的是 UserVO 对象,但是最后传输到前端时,变成了 Json 字符串

核心作用

  • 序列化和反序列化
    • 请求:将客户端发送的 HTTP 请求体(如 JSON 字符串)反序列化为 Java 对象(如 User 类)
    • 响应:将 Java 对象(如 User 对象)序列化为客户端需要的格式(如 JSON、XML)
  • 内容协商:根据客户端请求的 Content-Type(请求数据类型)和 Accept(期望的响应数据类型),自动选择匹配的 HttpMessageConverter 处理数据格式

接口源码

package org.springframework.http.converter;

import java.io.IOException;
import java.util.List;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;

public interface HttpMessageConverter<T> {
    boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);

    boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);

    List<MediaType> getSupportedMediaTypes();

    default List<MediaType> getSupportedMediaTypes(Class<?> clazz) {
        return !this.canRead(clazz, (MediaType)null) && !this.canWrite(clazz, (MediaType)null) ? Collections.emptyList() : this.getSupportedMediaTypes();
    }

    T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException;

    void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;
}

根据源码解释作用:

  • 在请求时,通过请求头 Content-Type 上,表示请求内容(Request Body)的内容类型。这样,Spring MVC 会从 HttpMessageConverter 数组中,通过 canRead(clazz, mediaType) 方法,判断是否够读取指定的 mediaType 内容类型,转换成对应的 clazz 对象。如果可以的话,则调用 read(Class<? extends T> clazz, HttpInputMessage inputMessage) 方法,读取请求内容,转换成 clazz 对象。
  • 在响应时,通过请求头 Accept 上,表示请求内容(Response Body)的内容类型。Spring MVC 会从 HttpMessageConverter 数组中,通过 canWrite(clazz, mediaType) 方法,判断是否能够将 clazz 对象,序列化成 mediaType 内容类型。如果可以的话,则调用 write(contentType, outputMessage) 方法,将 clazz 对象,序列化成 contentType 内容类型,写入到响应。

常见实现方法

内置了多种 HttpMessageConverter 实现,支持不同数据格式

实现类 作用
MappingJackson2HttpMessageConverter 处理 JSON 格式(基于 Jackson 库)
GsonHttpMessageConverter 处理 JSON 格式(基于 Gson 库)
Jaxb2RootElementHttpMessageConverter 处理 XML 格式(基于 JAXB)
StringHttpMessageConverter 处理纯文本(如 text/plain
FormHttpMessageConverter 处理表单数据(application/x-www-form-urlencoded

案例

同时支持 JSON/XML 格式提交数据,也同时支持 JSON/XML 格式响应数据的案例

XmlMapper 是 Jackson 提供的用于处理 XML 的类,位于 jackson-dataformat-xml 模块中。默认情况下,SpringBoot 并不会自动包含该模块,需要手动添加相关依赖。

配置

重写 MappingJackson2XmlHttpMessageConverter 配置类,新增 XML 格式

@Configuration
@RequiredArgsConstructor
public class SpringMVCConfiguration implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder xmlBuilder = Jackson2ObjectMapperBuilder.xml();
        xmlBuilder.indentOutput(true);
        converters.add(new MappingJackson2XmlHttpMessageConverter(xmlBuilder.build()));
    }
}

接口

新增接口

@RestController
@RequestMapping("/users")
public class UserController {

    @PostMapping(
            value = "/addXml",
            // ↓ 增加 "application/xml"、"application/json" ,针对 Content-Type 请求头
            consumes = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE},
            // ↓ 增加 "application/xml"、"application/json" ,针对 Accept 请求头
            produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}
    )
    public UserVO addXml(@RequestBody UserAddDTO addDTO) {
        return new UserVO().setUsername("username: " + addDTO.getUsername());
    }

}
  • consumes 属性:限制可接受的请求内容类型,不匹配时返回 415 Unsupported Media Type 状态码
  • produces 属性:限制可返回的响应内容类型,不匹配时返回 406 Not Acceptable 状态码

请求接口

POST http://localhost:8080/users/addXml  
Content-Type: application/xml  
Accept: application/xml  
  
<user>  
    <id>1</id>  
    <username>张三</username>  
    <password>123456</password>  
</user>

返回

<Result>
    <code>200</code>
    <msg>成功</msg>
    <data>
        <id/>
        <username>username: 张三</username>
    </data>
</Result>

Fastjson 依赖

在 SpringBoot 中默认是用 Jackson 作为对 JSON 的序列化和反序列化,即默认使用 MappingJackson2HttpMessageConverter(基于 Jackson 库)处理 JSON 数据,有时候可以使用第三方依赖来替换 Jackson 实现对 JSON 的序列化和反序列化,比如 Fastjson 依赖。

Fastjson 是阿里巴巴开源的一款高性能 Java JSON 库,用于实现 Java 对象与 JSON 数据之间的序列化(对象 → JSON)和反序列化(JSON → 对象)。它的核心目标是提供极致的 JSON 处理性能(号称“最快的 JSON 库”),同时支持复杂的 Java 类型(如泛型、枚举、Lambda 表达式)和灵活的配置。

使用原因

  • 性能优势
    • 更快的处理速度:在序列化和反序列化时通常比 Jackson 更快(尤其是处理大对象或复杂结构时),适合高并发场景
    • 低内存占用:Fastjson 的设计优化了内存使用,减少 GC 压力
  • 功能丰富性
    • 支持复杂类型:如泛型、LocalDateTime、枚举等,无需额外配置
    • 灵活的注解:通过 @JSONField 注解可自定义字段名称、格式、忽略字段等
    • 定制化配置
  • 易用性
    • 简洁的API:Fastjson 提供类似 JSON.toJSONString(obj) 和 JSON.parseObject(json, User.class) 的直接方法
    • 中文支持友好

配置过程

添加 Fastjson 依赖

<dependency>  
    <groupId>com.alibaba</groupId>  
    <artifactId>fastjson</artifactId>  
    <version>2.0.50</version>  
</dependency>

添加 Fastjson 依赖后,需要排除掉默认 Jackson 依赖(如果你不需要它的话)

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<exclusions>
		<exclusion>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-json</artifactId>
	 	</exclusion>
	</exclusions>
</dependency>	

配置 Fastjson

@Configuration
@RequiredArgsConstructor
public class SpringMVCConfiguration implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {

        // 定义一个convert转换消息的对象
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();

        // 添加fastjson的配置信息
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(
                // 格式化输出
                SerializerFeature.PrettyFormat,
                // 输出空字段
                SerializerFeature.WriteMapNullValue,
                // 日期格式化
                SerializerFeature.WriteDateUseDateFormat
        );
        fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);

        // 处理中文乱码问题
        List<MediaType> fastMediaTypes = new ArrayList<>();
        // fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
        fastMediaTypes.add(MediaType.APPLICATION_JSON);
        fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);

        // 在converters中添加fastjson的配置信息
        converters.add(0, fastJsonHttpMessageConverter);
    }

}

fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8) 会有 'APPLICATION_JSON_UTF8' is deprecated提示,因为 Framework 自 5.2 起,推荐使用 MediaType.APPLICATION_JSON,因为主要浏览器(如 Chrome)现在遵循规范,能够正确解析 UTF-8 特殊字符,而无需在 Content-Type 中指定 charset=UTF-8 参数。

setSerializerFeatures 方法

config.setSerializerFeatures 是 Fastjson 中用于配置 JSON 序列化行为的核心方法,它通过启用或禁用不同的 SerializerFeature 枚举值,控制 Java 对象转换为 JSON 字符串时的具体规则

Fastjson 默认的序列化行为较为简洁(例如不输出空字段、日期使用时间戳格式),但在实际开发中,我们通常需要更灵活的配置。

场景示例 默认行为 配置特性后的行为
空字段处理 忽略 null 字段 输出 {"name": null}
日期格式 日期转为时间戳(如 1672531200000 转为 "2023-01-01 00:00:00"
JSON 可读性 压缩输出(无缩进换行) 格式化输出(带缩进和换行)
枚举类型处理 输出枚举的 name() 值 输出枚举的 ordinal() 值
  • PrettyFormat:格式化 JSON 输出,添加换行和缩进,使 JSON 更易阅读
// 未启用 PrettyFormat
{"name":"Alice","age":25}

// 启用 PrettyFormat
{
  "name": "Alice",
  "age": 25
}
  • WriteMapNullValue:序列化时保留值为 null 的字段
// 未启用 WriteMapNullValue
{"name":"Alice"}

// 启用 WriteMapNullValue
{"name":"Alice", "age":null}
  • WriteDateUseDateFormat:将 Date 类型字段按指定格式(如 yyyy-MM-dd HH:mm:ss)序列化
config.setDateFormat("yyyy-MM-dd");
// 输出
{"birthday": "2023-01-01"}
  • WriteEnumUsingToString:将枚举类型按 toString() 方法的值输出,而非默认的 name()
enum Status { OPEN("开启"), CLOSE("关闭"); }
// 默认输出 "OPEN"
// 启用后输出 "开启"

参考


网站公告

今日签到

点亮在社区的每一天
去签到