Ethan,这份笔记将从底层原理到通用代码实现,带你彻底打通 Spring Boot 的“数据流通脉络”。我们将这三者看作一个翻译系统:ObjectMapper 是字典,MessageConverter 是翻译官,而 RedisTemplate 是负责记录翻译结果的档案员。
一、 ObjectMapper:全能字典 (The Core Engine)
深入浅出:
ObjectMapper 是 Jackson 库的心脏。它的唯一工作就是:把 Java 对象揉碎成 JSON 字符串(序列化),或者把 JSON 字符串拼回成 Java 对象(反序列化)。
默认情况下,这本“字典”很笨,它不知道怎么处理 Java 8 的 LocalDateTime(于是把它转成数组或时间戳),遇到 Java 对象里没有的字段还会报错。
🛠️ 通用配置代码
@Configuration
public class JacksonConfig {
@Bean
@Primary // 设置为首选 Bean,方便其他组件自动注入
public ObjectMapper objectMapper() {
ObjectMapper om = new ObjectMapper();
// 1. 核心:日期时间处理模块
JavaTimeModule javaTimeModule = new JavaTimeModule();
// 设置序列化格式(Java -> JSON)
javaTimeModule.addSerializer(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
// 设置反序列化格式(JSON -> Java)
javaTimeModule.addDeserializer(LocalDateTime.class,
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
// 注册模块到字典中
om.registerModule(javaTimeModule);
// 2. 增强通用性与健壮性
// 【反序列化】时:如果 JSON 里多出了字段,而 Java 类里没有,不要报错(防止接口升级导致旧代码崩溃)
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 【序列化】时:如果对象属性全是 null,不要报错(允许空对象的传输)
om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
// 3. 字段命名策略(可选):比如把 Java 的驼峰命名转为 JSON 的下划线命名
// om.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
return om;
}
}二、 HttpMessageConverter:Web 翻译官 (The Messenger)
深入浅出:
当你在 Controller 里写 return shop; 时,Spring MVC 并不知道怎么把这个对象发给浏览器。它会派出一个 消息转换器 (MessageConverter)。
这个转换器就像一个快递员,他手里拿着你配置好的 ObjectMapper(字典),把对象翻译成 JSON 字符串,塞进 HTTP 响应体里发出去。
🛠️ 关联配置
Java
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private ObjectMapper objectMapper;
/**
* 扩展消息转换器:确保全项目 Web 接口输出的 JSON 格式高度统一
*/
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
// 创建一个专用的 JSON 转换器,并塞入我们的“自定义字典”
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(objectMapper);
// 关键点:将它放在列表的最前面(索引 0),确保 Spring 优先用它,而不是系统默认的
converters.add(0, converter);
}
}三、 RedisTemplate:仓库管理员 (The Archivist)
深入浅出:
Redis 只能存字节。RedisTemplate 的作用就是决定以什么样的姿势把对象压成字节存进去。
为了通用性,我们必须解决**“类型丢失”**的问题。如果你用普通的序列化,取出来时它可能只是一堆 LinkedHashMap,而不是你原本的 Shop 对象。
🛠️ 通用化 Redis 配置
Java
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory, ObjectMapper objectMapper) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 1. 使用通用 JSON 序列化器
// 重点:使用 GenericJackson2JsonRedisSerializer,它会在 JSON 中存入对象的 @class 类型信息
// 这样取出来时,Jackson 才知道要把它转回哪个类,实现了真正的“通用”
GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer(objectMapper);
// 2. 配置 Key 和 Value 的序列化规则
// Key 通常是字符串,使用 StringRedisSerializer
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
// Value 使用上面配置好的 JSON 序列化器
template.setValueSerializer(jsonSerializer);
template.setHashValueSerializer(jsonSerializer);
template.afterPropertiesSet();
return template;
}
}🎯 总结:三者的深度绑定关系
| 组件 | 核心职能 | 为什么配置它? |
|---|---|---|
| ObjectMapper | 核心逻辑层 | 定义“怎么转”。不配它,LocalDateTime 就会乱码。 |
| MessageConverter | HTTP 展现层 | 负责“发出去”。不配它,前端拿到的数据格式不符合 UI 要求。 |
| RedisTemplate | 数据持久层 | 负责“存起来”。不配它,Redis 里的数据是一堆看不懂的乱码。 |
💡 Ethan,你应该如何查阅和使用这套笔记?
- 全局一致性:这三者通过
ObjectMapper实现联动。你在JacksonConfig里改了日期格式,Web 接口和 Redis 缓存会同步改变,这叫“单一事实来源”。 - 通用性体现:在
RedisTemplate中使用GenericJackson2JsonRedisSerializer后,你可以存入任何对象(Shop, User, Order),取出来时不需要手动强转,框架会自动根据 JSON 里的@class字段帮你转好。 - Hutool 的位置:在有了这套自动化配置后,尽量避免在 Redis 操作中手动调用
JSONUtil.toJsonStr()。直接让RedisTemplate帮你转,这样才能享受到我们在JacksonConfig里配置的各种福利。
这套体系架构是目前主流 Java 互联网项目的标准模版。配置好后,你可以把更多的精力放在业务逻辑(比如你的 RAG 学习助手)上,而不需要每天在日期格式和序列化报错上浪费时间。
在使用这套配置的过程中,关于反序列化时的 NoClassDefFound 或者 @class 注入问题,你还有什么疑虑吗?