Redis 在Springboot 中反序列化 LocalDateTime 時報錯


最近使用了 JDK8 中新的時間 API LocalDateTime,中間使用了Redis作為緩存,發現 Springboot 默認使用的 Jackson 無法正確序列化 LocalDateTime,究其原因是 Jackson 在序列化 LocalDateTime 時輸出的不是普通的字符串時間格式,而是如下所示的格式

"createTime":{
    "date":			{"year":2020,"month":"FEBRUARY","day":4,"dayOfWeek":"TUESDAY","era":"CE","dayOfYear":35,"leapYear":true,"monthValue":2,"dayOfMonth":4,
                     "chronology":{"id":"ISO","calendarType":"iso8601"},"prolepticMonth":24241
           }

而普通時間格式是:2019-02-27 12:10:17。

以下是拋出的異常:

2020-11-02 22:08:15.606 ERROR 2992 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with 
path [] threw exception [Request processing failed; nested exception is org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot
 construct instance of `java.time.LocalDateTime` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based
 Creator)
 at [Source: (byte[])"["java.util.ArrayList",[["cn.duniqb.mall.tiny.modules.ums.model.UmsResource",{"id":1,"createTime":{"date":
{"year":2020,"month":"FEBRUARY","day":4,"dayOfWeek":"TUESDAY","era":"CE","dayOfYear":35,"leapYear":true,"monthValue":2,"dayOfMonth":4,"chronology":
{"id":"ISO","calendarType":"iso8601"},"prolepticMonth":24241},"time":
{"hour":17,"minute":4,"second":55,"nano":0},"month":"FEBRUARY","dayOfWeek":"TUESDAY","dayOfYear":35,"nano":0,"year":2020,"monthValue":2,"dayOfMonth":4,"hour":17,"minu
te":4,"secon"[truncated 17976 bytes]; line: 1, column: 100] (through reference chain: java.util.ArrayList[0]-
>cn.duniqb.mall.tiny.modules.ums.model.UmsResource["createTime"]); nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct
 instance of `java.time.LocalDateTime` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

所以是原因是 Jackson 序列化 LocalDateTime 跟我們所預想的不一致,將注冊給 Redis 的序列化模板修改成以下就行。

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisSerializer<Object> serializer = redisSerializer();
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(serializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(serializer);
        redisTemplate.afterPropertiesSet();

        // 下面代碼解決LocalDateTime序列化與反序列化不一致問題
        Jackson2JsonRedisSerializer<Object> j2jrs = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 解決jackson2無法反序列化LocalDateTime的問題
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
        j2jrs.setObjectMapper(objectMapper);
        // 序列化 value 時使用此序列化方法
        redisTemplate.setValueSerializer(j2jrs);
        redisTemplate.setHashValueSerializer(j2jrs);

        return redisTemplate;
    }

這樣使用就不會出錯了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM