SpringCloud中时间戳和LocalDateTime相关的接收和转换
前言
- 一般情况下, 前端和后端在时间格式的传递上都走的是
时间戳(方便前端自由定制) - 时间格式由于
java8的新增时间处理类比较好用,而且更加线程安全, 所以将项目中的时间相关改为LocalDateTime,而不是传统的Date
前置要求
mybatis需要3.4.6以上, 否则会不支持xml和javaType的转换druid需要比较新的版本, 这里使用的是1.1.21, 否则查询会报错,结果集result set中找不到元素
正文
请求方式的分类
- 通过
@RequestBody中修饰LocalDate - 其他, 比如
@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();