项目中突然遇到redis缓存中的实体类日期字段使用LocalDateTime,在Redis序列化时报错,会往Redis中写入如下数据:,导致实体中的时间类型映射不上

"createTime": {
  "date": {
    "year": 2019,
    "month": "MAY",
    "day": 15,
    "prolepticMonth": 24232,
    "era": [
      "java.time.chrono.IsoEra",
      "CE"
    ],
    "dayOfYear": 135,
    "dayOfWeek": "WEDNESDAY",
    "leapYear": false,
    "dayOfMonth": 15,
    "monthValue": 5,
    "chronology": {
      "id": "ISO",
      "calendarType": "iso8601"
    }
  },
  "time": {
    "hour": 11,
    "minute": 3,
    "second": 43,
    "nano": 758000000
  },
  "dayOfYear": 135,
  "dayOfWeek": "WEDNESDAY",
  "month": "MAY",
  "dayOfMonth": 15,
  "year": 2019,
  "monthValue": 5,
  "hour": 11,
  "minute": 3,
  "second": 43,
  "nano": 758000000,
  "chronology": [
    "java.time.chrono.IsoChronology",
    {
      "id": "ISO",
      "calendarType": "iso8601"
    }
  ]
}

首先来分析下问题出现的原因:
1、项目的RedisConfig中使用的是 ObjectMapper() 来实现对象的序列化和反序列化的,类似与如下代码

@Test
public void test() throws Exception{
	EntityDto entityDto = new EntityDto();
	entityDto.setCreateTime(LocalDateTime.now());
	String s = JSON.toJSONString(entityDto);
	ObjectMapper om = new ObjectMapper();
	System.out.println("JSON实体类" + s);
	System.out.println("JSON实体类" + om.writeValueString(entityDto));
}

输出结果:
在这里插入图片描述
可以看到日期类型的值样式被改写了,那修改成原来JSON字符串的格式就需要我们自定义序列化方式

对日期类型数据的序列化:

(这里序列化类型为DateTime,之后时间类型为LocalDate、LocalTime、LocalDateTime、Date都可以用 )

public class JodaDateTimeJsonSerializer extends JsonSerializer<DateTime> {
    @Override
    public void serialize(DateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(value.toString("yyyy-MM-dd HH:mm:ss"));
    }
}

对 DateTime 类型日期的反序列化:

public class JodaDateTimeJsonDeSerializer extends JsonDeserializer<DateTime> {
    @Override
    public DateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        String s = p.readValueAs(String.class);
        DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
        return DateTime.parse(s,dateTimeFormatter);
    }
}

添加配置:

 // 日期序列化处理
        om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        om.registerModule(new Jdk8Module())
                .registerModule(new JavaTimeModule())
                .registerModule(new ParameterNamesModule());

方案一:设置Redis配置文件对日期序列化处理 (推荐)

RedisConfig 完整配置:

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 配置连接工厂
        template.setConnectionFactory(factory);
        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        // 日期序列化处理
        om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        om.registerModule(new Jdk8Module())
                .registerModule(new JavaTimeModule())
                .registerModule(new ParameterNamesModule());
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // key采用String的序列化方式
        template.setKeySerializer(new StringRedisSerializer());
        // 值采用Jackson序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // 设置hash的key采用String序列化模式
        template.setHashKeySerializer(new StringRedisSerializer());
        // 设置hash的value采用Jackson序列化模式
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

方案二:每个时间类型字段都需要添加,(不推荐,因为太麻烦)

@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime birthday;

配置好后问题就解决了;

关于ObjectMapper( ) 的用法详情看这里:
Jackson之ObjectMapper对象的使用

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐