SpringCloud中时间戳和LocalDateTime相关的接收和转换

1,468 阅读3分钟

SpringCloud中时间戳和LocalDateTime相关的接收和转换

前言

  1. 一般情况下, 前端和后端在时间格式的传递上都走的是时间戳(方便前端自由定制)
  2. 时间格式由于java8的新增时间处理类比较好用,而且更加线程安全, 所以将项目中的时间相关改为LocalDateTime,而不是传统的Date

前置要求

  1. mybatis需要3.4.6以上, 否则会不支持xmljavaType的转换
  2. druid需要比较新的版本, 这里使用的是1.1.21, 否则查询会报错,结果集result set中找不到元素

正文

请求方式的分类

  1. 通过@RequestBody中修饰LocalDate
  2. 其他, 比如@RequestParam@PathVariable以及不加注解的单参数和对象参数

1. 通过@RequestBody中修饰LocalDate

通过@RequestBody很明显的就是要通过JSON序列化进行处理,Spring默认的是Jackson进行处理,所以我们需要对默认的JSON处理器进行日期类型的添加(假如默认不带对应序列化器的情况下)

此时需要用的是JsonDeserializer这个类,对应的实现如下所示:

 /**
 * 入参 时间戳 -> LocalDateTime
 */
public class CustomDateDeserializer {


    public static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

        @Override
        public LocalDateTime deserialize(JsonParser p, DeserializationContext context) throws IOException {
            Long timestamp = Long.valueOf(p.getText());
            Instant instant = Instant.ofEpochMilli(timestamp);
            return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        }
    }

}
/**
 * @author kun.han on 2020/3/4 15:45
 * 返回参数 LocalDateTime -> 时间戳
 */
public class CustomDateSerializer {

    public static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {

        @Override
        public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            jsonGenerator.writeNumber(localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli());
        }
    }
}

有了这个了类,还需要添加到Spring中,Spring利用的是ObjectMapper,我们自定义一个ObjectMapper替换原本的就可以了。

@Configuration
public class CustomDateConfig implements WebMvcConfigurer {
    
    /**
     * Json序列化和反序列化转换器,用于转换Post请求体中的json以及将我们的对象序列化为返回响应的json
     */
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        //不显示为null的字段
        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        // 忽略不能转移的字符
        objectMapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
        // 过滤对象的null属性.
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        //忽略transient
        objectMapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);

        objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);

        //LocalDateTime系列序列化和反序列化模块,继承自jsr310,我们在这里修改了日期格式
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        // LocalDateTime 这里只需要LocalDateTime 如果需要转其他的,相应放开注释, 并在上面两个类中适当修改
        javaTimeModule.addSerializer(LocalDateTime.class, new CustomDateSerializer.LocalDateTimeSerializer());
        javaTimeModule.addDeserializer(LocalDateTime.class,new CustomDateDeserializer.LocalDateTimeDeserializer());
        // // LocalDate
        // javaTimeModule.addSerializer(LocalDate.class, new CustomDateSerializer.LocalDateSerializer());
        // javaTimeModule.addDeserializer(LocalDate.class, new CustomDateDeserializer.LocalDateDeserializer());
        // //Date序列化和反序列化
        // javaTimeModule.addSerializer(Date.class,new CustomDateSerializer.DateSerializer());
        // javaTimeModule.addDeserializer(Date.class,new CustomDateDeserializer.DateDeserializer());

        objectMapper.registerModule(javaTimeModule);
        return objectMapper;
    }
}

2. 其他 比如@RequestParam@PathVariable以及不加注解的单参数和对象参数

可以根据自身需求进行定制,这里我通过Convert转换LocalDateTime为例,进行转换:

public class CustomDateConverter {

    public static class LocalDateConvert implements Converter<String, LocalDateTime> {
        @Override
        public LocalDateTime convert(String timestamp) {
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(timestamp)), ZoneId.systemDefault());
        }
    }
}

同样的需要在配置类中引用

@Configuration
public class CustomDateConfig implements WebMvcConfigurer {
    @Bean
    public Converter<String, LocalDateTime> localDateConverter() {
        //此处不能替换为lambda表达式
        return new CustomDateConverter.LocalDateConvert();
    }
}

相关知识点

时间差

  • 精确时间差:

    		long start = 1584328558000L;
            long now = 1584400558000L;
    
            Instant startTime = Instant.ofEpochMilli(start);
            LocalDateTime startTimeT = LocalDateTime.ofInstant(startTime, ZoneId.systemDefault());
            Instant endTime = Instant.ofEpochMilli(now);
            LocalDateTime entTimeT = LocalDateTime.ofInstant(startTime, ZoneId.systemDefault());
            Duration duration = Duration.between(startTimeT, entTimeT);
            // Duration duration = Duration.between(startTime, entTime);
            long day = duration.toDays();
            long hours = duration.toHours();
            long min = duration.toMinutes();
            long millis= duration.toMillis();
            long nanos = duration.toNanos();
    
  • 粗略时间差, 比如今天明天算一天

    		long start = 1584328558000L;
            long now = 1584400558000L;
    
    		Instant startTime = Instant.ofEpochMilli(start);
            LocalDate startTimeT = LocalDateTime.ofInstant(startTime, ZoneId.systemDefault()).toLocalDate();
            Instant endTime = Instant.ofEpochMilli(now);
            LocalDate entTimeT = LocalDateTime.ofInstant(startTime, ZoneId.systemDefault()).toLocalDate();
            Period period = Period.between(startTimeT, entTimeT);
            int years = period.getYears();
            int months = period.getMonths();
            int days = period.getDays();