当使用 RedisTemplate 将包含 LocalDateTime 类型字段的对象存储到 Redis 中时,可能会遇到如下问题和解决方案:

Bug复现

问题描述:
在使用 RedisTemplate 向 Redis 中存储包含 LocalDateTime 类型字段的对象时,可能会遇到以下错误:

org.springframework.data.redis.serializer.SerializationException: Could not write JSON: Java 8 date/time type `java.time.LocalDateTime` not supported by default

错误分析:
默认情况下,Jackson 库不支持 Java 8 的 LocalDateTime 类型的序列化和反序列化,因此在将对象序列化为 JSON 字符串时会抛出 SerializationException 异常。

错误堆栈示例:

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 (through reference chain: java.util.ArrayList[0]->com.example.model.Comments["createdTime"])
    at org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer.serialize(Jackson2JsonRedisSerializer.java:151)
    at org.springframework.data.redis.core.AbstractOperations.rawValue(AbstractOperations.java:128)
    at org.springframework.data.redis.core.DefaultValueOperations.set(DefaultValueOperations.java:251)
    at com.example.service.CommentService.saveComments(CommentService.java:45)
    ...

解决过程

解决方案:

  1. 添加依赖: 首先确保在项目中添加 com.fasterxml.jackson.datatype:jackson-datatype-jsr310 依赖,这是 Jackson 库的一个扩展模块,用于支持 Java 8 的日期和时间类型。

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>2.13.0</version>
    </dependency>
    
  2. 自定义序列化器和反序列化器: 在 Redis 配置中,需要自定义 Jackson 的 ObjectMapper,以处理 LocalDateTime 类型的字段。这包括注册 JavaTimeModule,并配置 LocalDateTime 的序列化和反序列化规则。

    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.Jackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    import java.util.List;
    
    @Configuration
    public class RedisConfig {
    
        @Bean(name = "commentListRedisTemplate")
        public RedisTemplate<String, List<Comments>> commentListRedisTemplate(
                RedisConnectionFactory redisConnectionFactory) {
    
            RedisTemplate<String, List<Comments>> template = new RedisTemplate<>();
            template.setConnectionFactory(redisConnectionFactory);
            template.setKeySerializer(new StringRedisSerializer());
    
            ObjectMapper objectMapper = new ObjectMapper()
                    .registerModule(new JavaTimeModule())
                    .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    
            Jackson2JsonRedisSerializer<List<Comments>> serializer =
                    new Jackson2JsonRedisSerializer<>(List.class);
            serializer.setObjectMapper(objectMapper);
    
            template.setValueSerializer(serializer);
            template.setHashKeySerializer(new StringRedisSerializer());
            template.setHashValueSerializer(serializer);
    
            return template;
        }
    }
    
  3. 在实体类中配置: 确保在包含 LocalDateTime 类型字段的实体类中,使用 Jackson 注解对该字段进行配置,包括序列化器、反序列化器和日期时间格式。

    import com.fasterxml.jackson.annotation.JsonFormat;
    import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
    import com.fasterxml.jackson.databind.annotation.JsonSerialize;
    import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
    import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
    import java.time.LocalDateTime;
    
    public class Comments {
    
        @JsonSerialize(using = LocalDateTimeSerializer.class)
        @JsonDeserialize(using = LocalDateTimeDeserializer.class)
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
        private LocalDateTime createdTime;
    
        // 其他字段和方法...
    }
    

总结

通过上述步骤,解决了在使用 RedisTemplate 存储包含 LocalDateTime 类型字段的对象时遇到的序列化问题。通过添加适当的 Jackson 扩展依赖,并在 Redis 配置中自定义序列化器和反序列化器,以及在实体类中配置 Jackson 注解,确保了 LocalDateTime 类型字段能够正确地序列化为 JSON 字符串,并在需要时正确地反序列化回对象。这样就能够顺利地将对象存储到 Redis 中,并从中检索出来,同时保持了日期时间的格式和时区的一致性。

GitHub 加速计划 / js / json
41.72 K
6.61 K
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:1 个月前 )
960b763e 4 个月前
8c391e04 7 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐