💻 痛点导入:消失的精度与奇怪的日期

深夜 11 点,你还在调试“苍穹外卖”的订单模块。 “明明后端传过去的 ID 是 17283940582736451,怎么前端一接收就变成了 17283940582736450?还有这日期,为什么返回的是一串数字时间戳,而不是 yyyy-MM-dd HH:mm:ss?”

你揉了揉发涩的眼睛,翻遍了 Controller 也没找到问题。其实,这一切的背后,都是 Spring MVC 消息转换器在“搞鬼”。

如果你也正被 JSON 序列化、日期格式、字段空值转换等问题折磨,这篇文章就是你的救命稻草。

🛠️ 一、 什么是 HttpMessageConverter?(快速入门)

在 Spring MVC 中,当我们在 Controller 方法上使用 @RequestBody 或 @ResponseBody 时,Spring 就会自动调用 HttpMessageConverter。

核心结论: 它是 Spring MVC 提供的用于处理 HTTP 请求和响应消息的转换接口。它负责将请求体中的 JSON/XML 转换为 Java 对象,或将 Java 对象序列化为响应体。

1.1 常见实现类

Spring 默认内置了多个转换器,最常用的莫过于:

  • StringHttpMessageConverter:处理字符串。
  • MappingJackson2HttpMessageConverter:利用 Jackson 处理 JSON(这是我们最常打交道的一个)。

🚀 二、 实战演练:在“苍穹外卖”中统一配置转换器

在项目中,我们通常需要自定义一个 JacksonObjectMapper 来解决日期格式化Long 类型精度丢失(JS 不支持 64 位整数)的问题。

2.1 第一步:定义对象映射器

public class JacksonObjectMapper extends ObjectMapper {
    public JacksonObjectMapper() {
        super();
        // 收到未知属性时不报错
        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 定义日期、长整型的序列化规则
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance); // 重点:解决 Long 精度丢失
        this.registerModule(simpleModule);
    }
}

2.2 第二步:在配置类中扩展转换器

我们需要在继承了 WebMvcConfigurationSupport 的配置类中重写 extendMessageConverters 方法。

@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
    /**
     * 扩展 Spring MVC 框架的消息转换器
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 1. 创建一个新的消息转换器对象
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        // 2. 为消息转换器设置一个对象转换器(即上面的 JacksonObjectMapper)
        converter.setObjectMapper(new JacksonObjectMapper());
        // 3. 将自己的转换器添加到容器中,并设置为第一优先级
        converters.add(0, converter);
    }
}

🧠 三、 深度剖析:转换器的工作原理

3.1 核心流程图

在这里插入图片描述

3.2 为什么用 extendMessageConverters 而不是 configureMessageConverters?

  • configureMessageConverters:会覆盖掉 Spring 默认的所有转换器。如果你只想加一个,剩下的就得手动全部重配,非常麻烦。
  • extendMessageConverters:是在默认转换器列表的末尾追加。通过 converters.add(0, converter),我们可以把自定义的转换器放在首位,确保它优先被匹配。

📊 四、 常见避坑场景对比

在这里插入图片描述

💡 五、 面试加分项:内容协商机制

面试官:Spring MVC 是如何决定使用哪个 MessageConverter 的?

回答要点:

  1. Content-Type:根据请求头中的 Content-Type(如 application/json)匹配 canRead。
  2. Accept:根据请求头中的 Accept(如 application/xml)匹配 canWrite。
  3. 返回值类型:根据 Controller 方法的返回类型,判断转换器是否支持处理该类。
  4. 优先级:遍历 converters 列表,第一个匹配成功的转换器将承担重任。

✅ 总结与互动

Spring MVC 消息转换器是解决前后端“沟通障碍”的翻译官。通过自定义转换器,我们不仅能统一接口规范,还能避开 JS 处理大数的陷阱。

每日一思: 如果你的项目既要支持 JSON 也要支持 XML,你应该如何配置转换器?欢迎在评论区分享你的配置方案!👇

看完有收获?别忘了点赞、关注、收藏“三连”哦!你的支持是我更新的最大动力!🌟

Logo

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

更多推荐