记一次 Spring Boot 3 + Redis 序列化 LocalDateTime 的踩坑与填坑
最近在开发一个基于 Spring Boot 3 的商城项目时,需要将查询到的商品列表存入 Redis 缓存。商品实体类Product中包含一个java.time.LocalDateTime类型的createdAt字段,用于记录创建时间。
本以为这是一个非常常规的操作,没想到却遇到了一个经典的序列化异常。
当代码执行到redisTemplate.opsForValue().set(...)时,程序直接抛出了异常,控制台打印了长长的堆栈信息。核心错误如下:
org.springframework.data.redis.serializer.SerializationException: Could not write JSON: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling ... Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default错误信息非常明确:Jackson 在默认情况下不支持java.time.LocalDateTime类型的序列化,并提示我们需要添加jackson-datatype-jsr310模块。
检查依赖
<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> </dependency>首先,我检查了pom.xml文件。发现spring-boot-starter-json依赖中已经包含了jackson-datatype-jsr310。这说明依赖是存在的,问题不在于缺少 jar 包。
2.检查 Redis 配置
既然依赖没问题,那问题很可能出在 Redis 的序列化配置上。我检查了项目中的RedisConfig配置类,发现确实手动配置了RedisTemplate。
这是最初有问题的代码:
@Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { // 配置 Key 的序列化器 StringRedisSerializer keySerializer = new StringRedisSerializer(); // 配置 Value 的序列化器 // ❌ 错误点:这里直接 new 了一个新的 ObjectMapper,它没有注册 JavaTimeModule GenericJackson2JsonRedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer(); RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(connectionFactory); redisTemplate.setKeySerializer(keySerializer); redisTemplate.setValueSerializer(valueSerializer); return redisTemplate; }解决方案
解决思路很简单:我们需要手动创建一个ObjectMapper,并显式地向其中注册JavaTimeModule,然后将这个配置好的ObjectMapper传递给GenericJackson2JsonRedisSerializer。
package com.haina.mall.config; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { // 1. 配置 Key 的序列化器 StringRedisSerializer keySerializer = new StringRedisSerializer(); // 2. 配置 Value 的序列化器 (核心修改在这里) ObjectMapper mapper = new ObjectMapper(); // ✅ 关键一步:注册 Java 8 时间模块 mapper.registerModule(new JavaTimeModule()); // 使用我们配置好的 ObjectMapper 来创建序列化器 GenericJackson2JsonRedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer(mapper); // 3. 创建并配置 RedisTemplate RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(connectionFactory); redisTemplate.setKeySerializer(keySerializer); redisTemplate.setValueSerializer(valueSerializer); // 建议:也设置一下 Hash 的 Key 和 Value 序列化器,避免存取 Hash 类型数据时出现问题 redisTemplate.setHashKeySerializer(keySerializer); redisTemplate.setHashValueSerializer(valueSerializer); return redisTemplate; } }ok啦老铁