关键词:SpringBoot,jackson,@JsonFormat,@DateTimeFormat,LocalDateTime,LocalDate,LocalTime,Date
前言
前后端处理时间的过程转中,可能会遇到因前后端传递与解析时间格式不一致导致的各种问题,比如:
1. 前端往后端的方向:
-
前端传字符串格式时间,后端用某一种时间类接收时报转换类型错误,无法从String转到某一种时间类
-
前端传字符串时间戳,后端用某一种时间类接收时报转换类型错误,无法从String转到某一种时间类
前端往后端传json字符串,时间以时间戳方式传递,后端无法反序列化时间到某一种时间类
2. 后端往前端方向:
-
后端往前端传字符串格式时间,前端可能需要自定义时间格式,接收时间格式字符串显然有一定的局限性
前端的日期类是Date,通过new Date(),可以接收时间戳和字符串时间(包含日期的时间概念),可以同过自定义工具输出自定义的时间格式。
前端自定义转换工具:
//来源基本值的拼接
var date = new Date(时间戳); //获取一个时间对象
/**
1. 下面是获取时间日期的方法,需要什么样的格式自己拼接起来就好了
2. 更多好用的方法可以在这查到 -> http://www.w3school.com.cn/jsref/jsref_obj_date.asp
*/
date.getFullYear(); // 获取完整的年份(4位,1970)
date.getMonth(); // 获取月份(0-11,0代表1月,用的时候记得加上1)
date.getDate(); // 获取日(1-31)
date.getTime(); // 获取时间(从1970.1.1开始的毫秒数)
date.getHours(); // 获取小时数(0-23)
date.getMinutes(); // 获取分钟数(0-59)
date.getSeconds(); // 获取秒数(0-59)
// 再自定义方法进行拼接,如输出成 2022-03-23 13:45:56
1. 将时间戳转换成日期格式yyyy-MM-dd HH:mm:ss
// 时间戳转yy-MM-dd HH:mm:ss
TimeToStrDate(time_number) {
var dd = new Date(time); // 13位时间戳
var y = dd.getFullYear();
var m = (dd.getMonth() + 1) < 10 ? '0' + (dd.getMonth() + 1) : (dd.getMonth() + 1);//获取当前月份的日期,不足10补0
var d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate(); //获取当前几号,不足10补0
var h = dd.getHours() < 10 ? '0' + dd.getHours() : dd.getHours();
var n = dd.getMinutes() <10 ? '0' + dd.getMinutes() : dd.getMinutes();
var s = dd.getSeconds() <10 ? '0' + dd.getSeconds() : dd.getSeconds();
return y + '-' + m + '-' + d + ' ' + h + ':' + n + ':' + s;
}
例子
// 使用自定义的方法TimeToStrDate转换时间戳成字符串日期格式 yyyy-MM-dd HH:mm:ss
TimeToStrDate(1648055956520);
//'2022-03-24 01:19:16'
2. date格式转yy-MM-dd HH:mm:ss格式
// date格式转成yy-MM-dd HH:mm:ss
DateToStr(dd) {
var y = dd.getFullYear();
var m = (dd.getMonth() + 1) < 10 ? '0' + (dd.getMonth() + 1) : (dd.getMonth() + 1);//获取当前月份的日期,不足10补0
var d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate(); //获取当前几号,不足10补0
var h = dd.getHours() < 10 ? '0' + dd.getHours() : dd.getHours();
var n = dd.getMinutes() <10 ? '0' + dd.getMinutes() : dd.getMinutes();
var s = dd.getSeconds() <10 ? '0' + dd.getSeconds() : dd.getSeconds();
return y + '-' + m + '-' + d + ' ' + h + ':' + n + ':' + s;
}
//如: Mon Nov 11 2019 20:15:12 GMT+0800 (中国标准时间) -> 2019-11-11 20:15:12
后端日期类情况
后端的日期类以数据库和后端语言的时间类来说,分别是:
数据库的时间类情形:
以MySQL数据库为例:
YEAR、TIME、DATE、DTAETIME、TIMESTAMP
类型名称 | 日期格式 | 日期范围 | 存储需求 |
---|---|---|---|
YEAR | YYYY | 1901 ~ 2155 | 1 个字节 |
TIME | HH:MM:SS | -838:59:59 ~ 838:59:59 | 3 个字节 |
DATE | YYYY-MM-DD | 1000-01-01 ~ 9999-12-3 | 3 个字节 |
DATETIME | YYYY-MM-DD HH:MM:SS | 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 | 8 个字节 |
TIMESTAMP | YYYY-MM-DD HH:MM:SS | 1980-01-01 00:00:01 UTC ~ 2040-01-19 03:14:07 UTC | 4 个字节 |
参考链接:
MySQL DTAETIME、TIMESTAMP、DATE、TIME、YEAR(日期和时间类型)
Java语言的时间类型有:
常用的有:
java.util包中的Date类,转换是需要注意时区设置
java8之后java.time包中的新时间类:LocalDateTime,LocalDate,LocalTime
也就是说:Java有两套日期和时间的API:
-
旧的Date、Calendar和TimeZone;
-
新的LocalDateTime、ZonedDateTime、ZoneId等。推荐使用新的API
参考链接:
廖雪峰官网java教程部分内容链接:日期与时间
综合各种考虑,具体问题具体分析,需求不同,选用的格式不同。
选用:
一般数据库选timestamp和datetime和date
java选择LocalDateTime,LocalDate,LocalTime,适当考虑Date
前后端为了统一起见,一般统一传时间戳,或统一传字符串格式时间
SpringBoot中时间转换和序列化及反序列化
在SpringBoot中:
-
加注在类字段上的@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss"),只能作用与当前类的加注字段上,用于转换前端传来的字符串格式的字符串时间格式到某种时间类上。该注解也只能转换前端传来的非时间戳时间参数信息。
-
加注在类字段上的@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8", shape = JsonFormat.Shape.STRING)注解,只能序列化和反序列化前端传来的非时间戳时间信息,在返回给前端json序列化和j解析前端传来的json数据反序列化成对象时起作用。
显然,遇到其他情形,局限性就显现出来了,怎么办呢?
嗯,办法还是有的,查看源码后,通过SpringBoot添加全局转换时间和序列化与反序列化的自定义配置,解决此问题。
我们来分情况,从序列化反序列化、时间转换两方面来解决。
序列化和反序列化问题
情形一 前后端统一以字符串格式时间打交道时,序列化方面的全局处理
配置全局序列化和反序列化组件:
/**
* @Description 配置全局的时间序列化和反序列化转换
* @Author moyongjun
* @Date 2022-03-25 23:32:51
* @Version 1.0
**/
@Configuration
public class AnyTimeToStringJacksonConfig {
/**
* @return
* @Author moyongjun
* @Description 全局date序列化成字符串格式,输出字符串格式日期yyyy-MM-dd HH:mm:ss\yyyy-MM-dd\HH:mm:ss三中类型字符串
* @Date 2022-03-25 23:34:12
**/
@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
return builder -> {
/**
* 针对java.util.Date的序列化输出字符串,结合上面的时区,java.uitl.Date才可格式化出正确的时间
*
*/
// 针对java.util.Date的转换
builder.locale(Locale.CHINA);
builder.timeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* 对LocalDateTime,LocalDate,LocalTime的序列化输出字符串
*/
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
builder.modules(javaTimeModule);
};
}
}
情形二 前后统一用时间戳打交道时,序列法和反序列化方面的全局配置
配置全局序列化和反序列化组件
下面组件的定义考虑到了可以根据配置选择序列化输出为字符串日期还是字符串时间戳,反序列化则根据前端传来的json信息中是时间戳还是字符串格式时间来自动反序列化到对象上,接收json信息的javaBean对象需要加@requestBody,也就是说在post请求情况下使用。相当于全局有了 @JsonFormat注解的效果,还解决了 @JsonFormat不能序列化和反序列化前端传来的时间戳的痛点。
/**
* @Description 全局配置时间类序列化和反序列化,除LocalTime返回HH:mm:ss格式字符串外其余的Date,LocalDateTime,LocalDate返回时间戳
* @Author moyongjun
* @Date 2022-03-25 22:51:03
* @Version 1.0
**/
@Configuration
public class AnyTimeToTimestampJacksonConfig {
// 用枚举的方式结合switch控制转换配置,推荐此方式
// ConvertTypeEnum convertTypeEnum = ConvertTypeEnum.STRING_FORMAT;
// 从配置文件中读取配置
// 枚举配置的字段值,对应属性文件中serializerConvertForJackson的值STRING_FORMAT
@Value("${serializerConvertForJackson}")
ConvertTypeEnum convertTypeEnum;
/**
* @return
* @Author moyongjun
* @Description 定义序列化和反序列化策略
* @Date 2022-03-25 22:54:50
* @Param
**/
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> {
// LocalDateTime-->timpstamp
builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer());
// LocalDate-->timpstamp
builder.serializerByType(LocalDate.class, new LocalDateSerializer());
/**
* LocalTime--> HH:mm:ss
* LocalTime 全局序列化成字符串时间,格式为 HH:mm:ss,LocalTime是不能序列化时间戳处理的,因为无日期
*
*/
//方式一和方式二任选一种,
// 方式一:自定义LocalTimeSerializer,自由配置
builder.serializerByType(LocalTime.class, new LocalTimeSerializer());
// 方式二,不灵活,只能序列化成字符串格式
// JavaTimeModule javaTimeModule = new JavaTimeModule();
// javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
// builder.modules(javaTimeModule);
// Date-->timestamp
builder.serializerByType(Date.class, new DateSerializer());
// 各自的反序列化自定义类
builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer());
builder.deserializerByType(LocalDate.class, new LocalDateDeserializer());
builder.deserializerByType(LocalTime.class, new LocalTimeDeserializer());
builder.deserializerByType(Date.class, new DateDeserializer());
};
}
/**
* @Description Date类反序列化
* @Author moyongjun
* @Date 2022-03-26 10:38:27
* @Version 1.0
**/
class DateDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
long valueAsLong = jsonParser.getValueAsLong();
String valueAsString = jsonParser.getValueAsString();
Date date=null;
if (valueAsLong > 0) {
// System.out.println("从json中读取读取到了long类型值");
date = new Date(valueAsLong);
return date;
}
if (valueAsString != null) {
// System.out.println("从json中读取到了String类型值");
if (valueAsString.contains("-") || valueAsString.contains(" ") || valueAsString.contains(":")) {
System.out.println("转换字符串格式到日期类:");
Instant instant = LocalDateTime.parse(valueAsString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).atZone(ZoneId.of("+8")).toInstant();
date = Date.from(instant);
return date;
} else {
// System.out.println("转换字符串时间戳到日期类:");
date = new Date(Long.parseLong(valueAsString));
return date;
}
} else {
return null;
}
}
}
/**
* @Description Date序列化内部类
* @Author moyongjun
* @Date 2022-03-26 10:37:15
* @Version 1.0
**/
class DateSerializer extends JsonSerializer<Date> {
@Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
if (date != null) {
// 枚举方式
switch (convertTypeEnum) {
case TIMESTAMP:
long timestmp = date.toInstant().toEpochMilli();
jsonGenerator.writeNumber(timestmp);
break;
case STRING_FORMAT:
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateformat = simpleDateFormat.format(date);
jsonGenerator.writeString(dateformat);
break;
}
} else {
return;
}
}
}
/**
* @Description LocalTime序列化输出为字符串时间
* @Author moyongjun
* @Date 2022-03-26 01:14:23
* @Version 1.0
**/
//方式一关联的自定义内部类
class LocalTimeSerializer extends JsonSerializer<LocalTime> {
@Override
public void serialize(LocalTime localTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
if (localTime != null) {
// 枚举方式
switch (convertTypeEnum) {
// case穿透,Time需要特殊独立序列化为字符串格式
case TIMESTAMP:
case STRING_FORMAT:
String stringformat = localTime.format(DateTimeFormatter.ofPattern("HH:mm:ss"));
jsonGenerator.writeString(stringformat);
break;
}
} else {
return;
}
}
}
/**
* @Description 自定义LocalDateTime反序列化内部类
* @Author moyongjun
* @Date 2022-03-26 12:20:04
* @Version 1.0
**/
class LocalTimeDeserializer extends JsonDeserializer<LocalTime> {
@Override
public LocalTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
long timestamp = jsonParser.getValueAsLong();
String valueAsString = jsonParser.getValueAsString();
LocalTime localTime = null;
if (timestamp > 0) {
localTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.of("+8")).toLocalTime();
return localTime;
}
if (valueAsString != null) {
if (valueAsString.contains("-") || valueAsString.contains(":") || valueAsString.contains(" ")) {
localTime = LocalTime.parse(valueAsString, DateTimeFormatter.ofPattern("HH:mm:ss"));
return localTime;
} else {
localTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(valueAsString)), ZoneId.of("+8")).toLocalTime();
return localTime;
}
} else {
return null;
}
}
}
/**
* @Description 自定义内部类LocalDate序列化,将LocalDate序列化为毫秒级时间戳,返回给前端
* @Author moyongjun
* @Date 2022-03-25 23:56:19
* @Version 1.0
**/
class LocalDateSerializer extends JsonSerializer<LocalDate> {
@Override
public void serialize(LocalDate localDate, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
if (localDate != null) {
// 枚举方式
switch (convertTypeEnum) {
case TIMESTAMP:
long timestamp = localDate.atStartOfDay().toInstant(ZoneOffset.of("+8")).toEpochMilli();
// 将转换后的时间戳写出去
jsonGenerator.writeNumber(timestamp);
break;
case STRING_FORMAT:
String stringformat = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
jsonGenerator.writeString(stringformat);
break;
}
} else {
return;
}
}
}
/**
* @Description 自定义内部类LocalDate反序列化
* @Author moyongjun
* @Date 2022-03-26 00:33:31
* @Version 1.0
**/
class LocalDateDeserializer extends JsonDeserializer<LocalDate> {
@Override
public LocalDate deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
long timestamp = jsonParser.getValueAsLong();
String valueAsString = jsonParser.getValueAsString();
LocalDate localDate = null;
if (timestamp > 0) {
localDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.of("+8")).toLocalDate();
return localDate;
}
if (valueAsString != null) {
if (valueAsString.contains("-") || valueAsString.contains(":") || valueAsString.contains(" ")) {
localDate = LocalDate.parse(valueAsString, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
return localDate;
} else {
localDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(valueAsString)), ZoneId.of("+8")).toLocalDate();
return localDate;
}
} else {
return null;
}
}
}
/**
* @Description 自定义内部类LocalDateTime序列化,将LocalDateTime序列化为毫秒级时间戳,返回给前端
* @Author moyongjun
* @Date 2022-03-25 22:57:58
* @Version 1.0
**/
class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
@Override
public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
// 将LocalDateTime转化为时间戳
if (localDateTime != null) {
switch (convertTypeEnum) {
case TIMESTAMP:
long timestamp = localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
// 将转换后的时间戳写出去
jsonGenerator.writeNumber(timestamp);
break;
case STRING_FORMAT:
String stringformat = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
jsonGenerator.writeString(stringformat);
}
} else {
return;
}
}
}
/**
* @Description 自定义内部类LocalDateTime反序列化,将毫秒级时间戳序列化为LocalDateTime
* @Author moyongjun
* @Date 2022-03-25 23:00:24
* @Version 1.0
**/
class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
//获取json中得到对应转换目标的long类型值
long timestamp = jsonParser.getValueAsLong();
String valueAsString = jsonParser.getValueAsString();
// System.out.println(timestamp);
LocalDateTime localDateTime = null;
if (timestamp > 0) {
localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.of("+8"));
return localDateTime;
}
if (valueAsString != null) {
if (valueAsString.contains("-") || valueAsString.contains(":") || valueAsString.contains(" ")) {
localDateTime = LocalDateTime.parse(valueAsString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
return localDateTime;
}else {
localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(valueAsString)), ZoneId.of("+8"));
return localDateTime;
}
} else {
return null;
}
}
}
}
上面组件用到的枚举类:
/**
*
* @Description jackson时间序列化类型枚举
* @Author moyongjun
* @Date 2022-03-26 16:06:52
* @Version 1.0
*
**/
public enum ConvertTypeEnum {
TIMESTAMP,STRING_FORMAT;
}
上面组件从属性文件application.yml中读取的配置值:
# 自定义jackson中日期类序列化配置,控制日期和时间的序列化方式,两种方式:STRING_FORMAT和TIMESTAMP,详情查看枚举类ConvertTypeEnum。
# serializerConvertForJackson为TIMESTAMP时,对Date,LocalDate,LocalDateTime全局序列化为时间戳,LocalTime在任何情况下都序列化为字符串时间格式HH:mm:ss
# serializerConvertForJackson为STRING_FORMAT时,对Date,LocalDate,LocalDateTime全局序列化为各自的字符串格式,LocalTime在任何情况下都序列化为字符串时间格式HH:mm:ss
serializerConvertForJackson: TIMESTAMP
解决前端时间全局信息转换的问题
配置全局转换组件
对于上述两种前后端传参情形都适用,在定义中,考虑到了根据前端传递的是字符串时间戳还是字符串格式时间信息,都可以总动适配转换成LocalDateTime,LocalDate,LocalTime,Date中的对应类上。相当于全局有了 @DateTimeFormat注解的效果,还多了 @DateTimeFormat不能转换前端传来的时间戳的痛点。
/**
* @ClassName AnyTimeConvertersConfig
* @Description 全局时间转换器,配置前端传来的字符串时间戳或字符串类型时间转换成时间类(Date、LocalDateTime、LocalDate、LocalTime)
* @Author moyongjun
* @Date 2022/3/25 23:13
* @Version 1.0
**/
@Configuration
public class AnyTimeConvertersConfig {
/**
* 全局转换前端的字符串格式时间或者字符串时间戳到LocalDateTime,前端字符串的格式为:yyyy-MM-dd HH:mm:ss
*
* @return
*/
@Bean
public Converter<String, LocalDateTime> localDateTimeConvert() {
return new Converter<String, LocalDateTime>() {
@Override
public LocalDateTime convert(String source) {
LocalDateTime localDateTime = null;
// 根据字符串类型是时间戳还是日期格式自动转换
if (source.contains("-") || source.contains(" ") || source.contains(":")) {
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
try {
//2020-01-01 00:00:00
switch (source.length()) {
case 10:
// logger.debug("传过来的是日期格式:{}",source);
source = source + " 00:00:00";
break;
case 13:
// logger.debug("传过来的是日期 小时格式:{}",source);
source = source + ":00:00";
break;
case 16:
// logger.debug("传过来的是日期 小时:分钟格式:{}",source);
source = source + ":00";
break;
}
localDateTime = LocalDateTime.parse(source, df);
} catch (Exception e) {
// logger.error(e.getMessage(),e);
}
return localDateTime;
} else {
// 将前端传来的字符串类型的毫秒级时间戳转换成LocalDateTime
// 异常处理
try {
localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(source)), ZoneId.of("+8"));
} catch (Exception e) {
// logger.error(e.getMessage(),e);
}
// 转换到秒级,传入的时间戳除1000操作
// LocalDateTime localDateTime1 = LocalDateTime.ofEpochSecond(currentTimeTimestamp/1000, 0, ZoneOffset.of("+8"));
return localDateTime;
}
}
};
}
/**
* java.util.Date转换器,字符串时间戳或字符串日期转Date
* 接收毫秒级时间戳字符串——>Date
*
* @return
*/
@Bean
public Converter<String, Date> dateConverter() {
return new Converter<String, Date>() {
@Override
public Date convert(String source) {
Date date = null;
if (source.contains("-") || source.contains(":") || source.contains(" ")) {
try {
// SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// date = simpleDateFormat.parse(source);
//或者
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
Instant instant = LocalDateTime.parse(source, dateTimeFormatter).atZone(ZoneId.of("+8")).toInstant();
date = Date.from(instant);
} catch (Exception e) {
// todo 记录异常、处理异常
}
} else {
try {
date = new Date(Long.parseLong(source));
// 或者
//date= Date.from(Instant.ofEpochMilli(Long.parseLong(source)));
} catch (Exception e) {
// 记录异常日志
//todo
}
}
return date;
}
};
}
/**
* 全局配置LocalDate转换器,字符串时间戳或字符串日期转LocalDate
*
* @return
*/
@Bean
// 配置LocalDate转换器
public Converter<String, LocalDate> localDateConverter() {
return new Converter<String, LocalDate>() {
@Override
public LocalDate convert(String source) {
DateTimeFormatter dateTimeFormatter = null;
// 根据前端传递饿不同格式匹配转换规则
switch (source.length()) {
case 10:
//LocalTime只匹配时间部分,日期部分规则做冗余处理
dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
break;
case 16:
//LocalTime只匹配时间部分,日期部分规则做冗余处理
dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
break;
case 19:
//LocalTime只匹配时间部分,日期部分规则做冗余处理
dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
break;
case 8:
dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
break;
}
LocalDate localDate = null;
// 转换字符串格式日期到LocalDate ,前端格式为 yyyy-MM-dd
try {
if (source.contains("-") || source.contains(" ") || source.contains(":")) {
localDate = LocalDate.parse(source, dateTimeFormatter);
} else {
// 转换字符串时间戳到LocalDate
localDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(source)), ZoneId.of("+8")).toLocalDate();
}
} catch (Exception e) {
//记录日志
// todo
}
return localDate;
}
};
}
/**
* 全局配置LocalTime转换器,字符串时间戳或字符串日期转LocalTime
*
* @return
*/
@Bean
// 配置LocalTime转换器
public Converter<String, LocalTime> localTimeConverter() {
return new Converter<String, LocalTime>() {
@Override
public LocalTime convert(String source) {
DateTimeFormatter dateTimeFormatter = null;
// 根据前端传递饿不同格式匹配转换规则
switch (source.length()) {
case 19:
//LocalTime只匹配时间部分,日期部分规则做冗余处理
dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
break;
case 8:
dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
break;
}
LocalTime localTime = null;
try {
if (source.contains("-") || source.contains(":") || source.contains(" ")) {
localTime = LocalTime.parse(source, dateTimeFormatter);
} else {
localTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(source)), ZoneId.of("+8")).toLocalTime();
}
} catch (Exception e) {
// 日志处理
}
return localTime;
}
};
}
}
经过序列化相关和转换相关的全局化配置后,实现了统一性,针对性对于LocalTime序列化采取了统一Wie时间格式HH:mm:ss。
说明:
全局配置后,对于两种注解,使用注解无效。因为SpringBoot的原则是配置大于默认提供的。也就是配置覆盖了原有的注解的效果。