詳解SpringBoot中時(shí)間類型的序列化與反序列化
背景
前后端進(jìn)行時(shí)間類型的傳遞時(shí),往往是
- 前端傳遞時(shí)間格式的字符串,后端反序列化成對(duì)應(yīng)的時(shí)間類型
- 后端返回?cái)?shù)據(jù)時(shí),一般是將時(shí)間類型的對(duì)象,序列化成時(shí)間格式的字符串
Spring 的生態(tài)中已經(jīng)為我們提供了對(duì)應(yīng)的解決方案
約定
如下是對(duì)本文的討論背景做出的約定
- 框架 : Spring boot (Spring web)
- json 序列化、反序列化工具 : Jackson
- 傳輸協(xié)議 : http
- 接口返回值格式 : JSON
反序列化
時(shí)間格式字符串->時(shí)間類型
常見于前端傳參,一般分為4種情況
- Post +
Content-Type : application/json - Post +
Content-Type : application/x-www-form-urlencoded - Post +
Content-Type : multipart/form-data - Get
以上四種最常見情況,每種數(shù)據(jù)編碼格式都不一樣,因此對(duì)應(yīng)的反序列化方法也不同
在 Spring web 生態(tài)中,對(duì)于 Post + Content-Type : application/json 的方式 一般是用 json 工具進(jìn)行反序列化,例如 Spring 自帶的 jackson,抑或是阿里巴巴的 fastjson
而其它非 json 提交的情況, json 工具就派不上用場了,Spring 提供了額外的反序列化方式,來處理這些情況
局部處理反序列化
局部處理反序列化的好處在于,粒度更細(xì),使用更靈活,在 Spring web 生態(tài)中有兩種局部處理方式,來處理上述4種常見情況
@JsonFormat 或 @JSONField
@JsonFormat 或 @JSONField 注解都可以用在時(shí)間類型的字段上,用來對(duì)該字段提供反序列化支持,例如
@JSONField(format="yyyy-MM-dd HH:mm:ss") private Date date; @JSONField(format="yyyy-MM-dd HH:mm:ss") private LocalDateTime localDateTime4; @JSONField(format="yyyy-MM-dd") private LocalDate localDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date date; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime localDateTime4; @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate localDate;
注意 @JsonFormat 或 @JSONField 注解,只能用于json(Post + Content-Type : application/json)提交的反序列化,表單提交或者Get提交是不支持的
// 這種帶 @RequestBody 的 Pojo ,內(nèi)部的 時(shí)間類型字段就可以使用 @JsonFormat 或 @JSONField
@PostMapping("/json")
public Pojo json(@RequestBody Pojo pojo) {
return pojo;
}
@JsonFormat 、 @JSONField 的區(qū)別與使用@JsonFormat 注解來源于 Spring web 自帶 jackson,無需配置直接可以使用@JSONField 注解來源于阿里巴巴的 fastjson,需要進(jìn)行配置,用 fastjson 替換掉Spring web 默認(rèn)使用的 jackson 之后,才能使用。
@DateTimeFormat
@DateTimeFormat 是 Spring web 提供的針對(duì)非 json 提交,如
- Post +
Content-Type : application/x-www-form-urlencoded - Post +
Content-Type : multipart/form-data - Get
等方式時(shí),時(shí)間類型的反序列化解決方案
// Get 傳參的 Pojo ,內(nèi)部的 時(shí)間類型字段可以使用 @DateTimeFormat 進(jìn)行反序列化
@GetMapping
public Pojo get(Pojo pojo) {
return pojo;
}
// 表單傳參的 Pojo ,內(nèi)部的 時(shí)間類型字段可以使用 @DateTimeFormat 進(jìn)行反序列化
@PostMapping
public Pojo post(Pojo pojo) {
return pojo;
}@DateTimeFormat 的用法
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date date; @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime localDateTime; @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate localDate;
全局處理
Spring web 對(duì)于 json 傳參 使用的是 HttpMessageConverter<T> 轉(zhuǎn)換類,而時(shí)間字符串作為普通請(qǐng)求參數(shù)傳入時(shí),轉(zhuǎn)換用的是 Converter<S, T>, Converter 的不同,意味著處理方式也不同。
非 json 傳參的反序列化全局處理
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.TimeZone;
/**
* 自定義參數(shù)轉(zhuǎn)換器,全局反序列化 GET請(qǐng)求、POST表單 提交的時(shí)間字符串
*/
@Configuration
public class DateConverterConfig {
/**
* yyyy-MM-dd 時(shí)間格式的正則表達(dá)式
*/
private static final String DATE_REGEX = "[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])";
/**
* HH:mm:ss 時(shí)間格式的正則表達(dá)式
*/
private static final String TIME_REGEX = "(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d";
/**
* yyyy-MM-dd HH:mm:ss 時(shí)間格式的正則表達(dá)式
*/
private static final String DATE_TIME_REGEX = DATE_REGEX + "\s" + TIME_REGEX;
/**
* yyyy-MM-ddTHH:mm:ss 時(shí)間格式的正則表達(dá)式
*/
private static final String DATE_T_TIME_REGEX = DATE_REGEX + "T" + TIME_REGEX;
/**
* yyyy-MM-ddTHH:mm:ss.SSS 時(shí)間格式的正則表達(dá)式
*/
private static final String DATE_T_TIME_MS_REGEX = DATE_REGEX + "T" + TIME_REGEX + ".\d{3}";
/**
* 13位時(shí)間戳正則表達(dá)式
*/
private static final String TIME_STAMP_REGEX = "1\d{12}";
/**
* yyyy-MM 時(shí)間格式的正則表達(dá)式
*/
private static final String YEAR_MONTH_REGEX = "[1-9]\d{3}-(0[1-9]|1[0-2])";
/**
* yyyy-MM 格式
*/
private static final String YEAR_MONTH_PATTERN = "yyyy-MM";
/**
* DateTime格式化字符串
*/
private static final String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
/**
* DateTime格式化字符串 ISO 格式
*/
private static final String DEFAULT_DATETIME_ISO_PATTERN = "yyyy-MM-ddTHH:mm:ss";
/**
* DateTime格式化字符串 帶毫秒值的 ISO 格式
*/
private static final String DEFAULT_DATETIME_MS_ISO_PATTERN = "yyyy-MM-ddTHH:mm:ss.SSS";
/**
* Date格式化字符串
*/
private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
/**
* Time格式化字符串
*/
private static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
/**
* 根據(jù) pattern 構(gòu)建 SimpleDateFormat
* @param pattern
* @return
*/
private SimpleDateFormat getSimpleDateFormat(String pattern){
SimpleDateFormat df = new SimpleDateFormat(pattern);
System.out.println(TimeZone.getDefault());
df.setTimeZone(TimeZone.getTimeZone ("GMT"));
return df;
}
/**
* String -> Date 轉(zhuǎn)換器
* 用于轉(zhuǎn)換 @RequestParam參數(shù)、@PathVariable參數(shù)、表單參數(shù)
*/
@Bean
public Converter<String, Date> dateConverter() {
return new Converter<String, Date>() {
@SuppressWarnings("NullableProblems")
@Override
public Date convert(String source) {
if (StringUtils.isEmpty(source)) {
return null;
}
// 13位毫秒值 -> Date
if (source.matches(TIME_STAMP_REGEX)) {
return new Date(Long.parseLong(source));
}
try {
// yyyy-MM-dd HH:mm:ss -> Date
if (source.matches(DATE_TIME_REGEX)) {
return getSimpleDateFormat(DEFAULT_DATETIME_PATTERN).parse(source);
}
// yyyy-MM-dd -> Date
if (source.matches(DATE_REGEX)) {
return getSimpleDateFormat(DEFAULT_DATE_FORMAT).parse(source);
}
// yyyy-MM -> Date
if (source.matches(YEAR_MONTH_REGEX)) {
return getSimpleDateFormat(YEAR_MONTH_PATTERN).parse(source);
}
} catch (ParseException e) {
throw new RuntimeException(e);
}
return null;
}
};
}
/**
* String -> LocalDateTime 轉(zhuǎn)換器
* 用于轉(zhuǎn)換 @RequestParam參數(shù)、@PathVariable參數(shù)、表單參數(shù)
*/
@Bean
public Converter<String, LocalDateTime> localDateTimeConverter() {
return new Converter<String, LocalDateTime>() {
@SuppressWarnings("NullableProblems")
@Override
public LocalDateTime convert(String source) {
if (StringUtils.isEmpty(source)) {
return null;
}
// 13位毫秒值 -> LocalDateTime
if (source.matches(TIME_STAMP_REGEX)) {
Instant instant = Instant.ofEpochMilli(Long.parseLong(source));
ZoneId zone = ZoneId.systemDefault();
return LocalDateTime.ofInstant(instant, zone);
}
// yyyy-MM-dd HH:mm:ss -> LocalDateTime
if (source.matches(DATE_TIME_REGEX)) {
return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN));
}
// yyyy-MM-ddTHH:mm:ss -> LocalDateTime
if (source.matches(DATE_T_TIME_REGEX)) {
return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATETIME_ISO_PATTERN));
}
// yyyy-MM-ddTHH:mm:ss.SSS -> LocalDateTime
if (source.matches(DATE_T_TIME_MS_REGEX)) {
return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATETIME_MS_ISO_PATTERN));
}
return null;
}
};
}
/**
* String -> LocalDate 轉(zhuǎn)換器
* 用于轉(zhuǎn)換 @RequestParam參數(shù)、@PathVariable參數(shù)、表單參數(shù)
*/
@Bean
public Converter<String, LocalDate> localDateConverter() {
return new Converter<String, LocalDate>() {
@SuppressWarnings("NullableProblems")
@Override
public LocalDate convert(String source) {
if (StringUtils.isEmpty(source)) {
return null;
}
// 13位毫秒值 -> LocalDate
if (source.matches(TIME_STAMP_REGEX)) {
Instant instant = Instant.ofEpochMilli(Long.parseLong(source));
ZoneId zone = ZoneId.systemDefault();
return LocalDateTime.ofInstant(instant, zone).toLocalDate();
}
// yyyy-MM-dd -> LocalDate
if (source.matches(DATE_REGEX)) {
return LocalDate.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT));
}
return null;
}
};
}
/**
* String -> LocalTime 轉(zhuǎn)換器
* 用于轉(zhuǎn)換 @RequestParam參數(shù)、@PathVariable參數(shù)、表單參數(shù)
*/
@Bean
public Converter<String, LocalTime> localTimeConverter() {
return new Converter<String, LocalTime>() {
@SuppressWarnings("NullableProblems")
@Override
public LocalTime convert(String source) {
if (StringUtils.isEmpty(source)) {
return null;
}
// HH:mm:ss -> LocalTime
return LocalTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT));
}
};
}
}注意:使用了自定義參數(shù)轉(zhuǎn)化器(Converter),Spring 會(huì)優(yōu)先使用該方式進(jìn)行處理,@DateTimeFormat 注解將不生效!!! 這兩種方案是不兼容!!!
json 傳參的反序列化全局處理
如果是 json 傳參,反序列化時(shí),可以通過配置 json 工具進(jìn)行全局處理。
以 Spring web 自帶的 jackson 為例,它配置全局時(shí)間格式化時(shí), java.util 包中的時(shí)間類型與 java 8 之后引入了 java.time 包中的時(shí)間類型,要分開配置
全局配置 java.util 包中的時(shí)間類型的反序列化格式
常用的時(shí)間類型包括
- java.util.Date
- java.util.Calendar
通過配置文件配置,以 yaml 為例
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
這是最簡單的配置方式,也可以采取其他方式,這里就不例舉了
全局配置 java.time 包中的時(shí)間類型的反序列化格式
常用的時(shí)間類型包括
- java.time.LocalDateTime
- java.time.LocalDate
@Configuration
public class JacksonConfig {
private static final String DATE_FORMAT = "yyyy-MM-dd";
private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> {
builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
builder.deserializerByType(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DATE_FORMAT)));
};
}
}序列化
時(shí)間類型->時(shí)間格式字符串
常見于后端返回,現(xiàn)在后端接口,返回格式一般都采用 json ,因此處理起來比反序列化要簡單
局部處理
在要返回類的時(shí)間類型字段上使用 @JsonFormat 或 @JSONField 注解,來對(duì)該字段提供序列化支持。例如
@JSONField(format="yyyy-MM-dd HH:mm:ss") private Date date; @JSONField(format="yyyy-MM-dd HH:mm:ss") private LocalDateTime localDateTime4; @JSONField(format="yyyy-MM-dd") private LocalDate localDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date date; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime localDateTime4; @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate localDate;
是的 @JsonFormat 或 @JSONField 注解,既能用于json提交的反序列化,也能用于返回 json 的序列化
同樣,使用 @JSONField 注解之前,需要先進(jìn)行配置。用 fastjson 替換掉Spring web 默認(rèn)使用的 jackson 之后,才能使用。
全局處理
以 Spring web 自帶的 jackson 為例,它配置全局時(shí)間格式化時(shí), java.util 包中的時(shí)間類型與 java 8 之后引入了 java.time 包中的時(shí)間類型,要分開配置
全局配置 java.util 包中的時(shí)間類型的序列化格式
常用的時(shí)間類型包括
- java.util.Date
- java.util.Calendar
通過配置文件配置
以 yaml 為例
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
這是最簡單的配置方式,也可以采取其他方式,這里就不例舉了
全局配置 java.time 包中的時(shí)間類型的序列化格式
常用的時(shí)間類型包括
- java.time.LocalDateTime
- java.time.LocalDate
@Configuration
public class JacksonConfig {
private static final String DATE_FORMAT = "yyyy-MM-dd";
private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return jacksonObjectMapperBuilder -> {
// 配置 Jackson 序列化 LocalDate、LocalDateTime 時(shí)使用的格式
jacksonObjectMapperBuilder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_FORMAT)));
jacksonObjectMapperBuilder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
};
}
}推薦配置
對(duì)時(shí)間類型進(jìn)行 序列化 時(shí), 由于統(tǒng)一返回的都是 json 格式,推薦進(jìn)行全局配置,實(shí)際開發(fā)過程中,如果遇到特殊情況,再選擇用 @JsonFormat 進(jìn)行局部覆蓋
對(duì)時(shí)間類型進(jìn)行 反序列化 時(shí)
- 如果是 json 傳參同樣推薦全局配置,實(shí)際開發(fā)過程中,如果遇到特殊情況,再選擇用
@JsonFormat進(jìn)行局部覆蓋。 - 如果是 Get 請(qǐng)求或是 Post表單,全局配置
Converter<S, T>后,@DateTimeForma注解將失效??辞闆r自行選擇。
配置一覽
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
@Configuration
public class JacksonConfig {
private static final String DATE_FORMAT = "yyyy-MM-dd";
private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return jacksonObjectMapperBuilder -> {
// 配置 Jackson 序列化 LocalDate、LocalDateTime 時(shí)使用的格式
jacksonObjectMapperBuilder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_FORMAT)));
jacksonObjectMapperBuilder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
// 配置 Jackson 反序列化 LocalDate、LocalDateTime 時(shí)使用的格式
jacksonObjectMapperBuilder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
jacksonObjectMapperBuilder.deserializerByType(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DATE_FORMAT)));
};
}
}import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.TimeZone;
/**
* 自定義參數(shù)轉(zhuǎn)換器,全局反序列化 GET請(qǐng)求、POST表單 提交的時(shí)間字符串
*/
@Configuration
public class DateConverterConfig {
/**
* yyyy-MM-dd 時(shí)間格式的正則表達(dá)式
*/
private static final String DATE_REGEX = "[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])";
/**
* HH:mm:ss 時(shí)間格式的正則表達(dá)式
*/
private static final String TIME_REGEX = "(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d";
/**
* yyyy-MM-dd HH:mm:ss 時(shí)間格式的正則表達(dá)式
*/
private static final String DATE_TIME_REGEX = DATE_REGEX + "\s" + TIME_REGEX;
/**
* yyyy-MM-ddTHH:mm:ss 時(shí)間格式的正則表達(dá)式
*/
private static final String DATE_T_TIME_REGEX = DATE_REGEX + "T" + TIME_REGEX;
/**
* yyyy-MM-ddTHH:mm:ss.SSS 時(shí)間格式的正則表達(dá)式
*/
private static final String DATE_T_TIME_MS_REGEX = DATE_REGEX + "T" + TIME_REGEX + ".\d{3}";
/**
* 13位時(shí)間戳正則表達(dá)式
*/
private static final String TIME_STAMP_REGEX = "1\d{12}";
/**
* yyyy-MM 時(shí)間格式的正則表達(dá)式
*/
private static final String YEAR_MONTH_REGEX = "[1-9]\d{3}-(0[1-9]|1[0-2])";
/**
* yyyy-MM 格式
*/
private static final String YEAR_MONTH_PATTERN = "yyyy-MM";
/**
* DateTime格式化字符串
*/
private static final String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
/**
* DateTime格式化字符串 ISO 格式
*/
private static final String DEFAULT_DATETIME_ISO_PATTERN = "yyyy-MM-ddTHH:mm:ss";
/**
* DateTime格式化字符串 帶毫秒值的 ISO 格式
*/
private static final String DEFAULT_DATETIME_MS_ISO_PATTERN = "yyyy-MM-ddTHH:mm:ss.SSS";
/**
* Date格式化字符串
*/
private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
/**
* Time格式化字符串
*/
private static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
/**
* 根據(jù) pattern 構(gòu)建 SimpleDateFormat
* @param pattern
* @return
*/
private SimpleDateFormat getSimpleDateFormat(String pattern){
SimpleDateFormat df = new SimpleDateFormat(pattern);
System.out.println(TimeZone.getDefault());
df.setTimeZone(TimeZone.getTimeZone ("GMT"));
return df;
}
/**
* String -> Date 轉(zhuǎn)換器
* 用于轉(zhuǎn)換 @RequestParam參數(shù)、@PathVariable參數(shù)、表單參數(shù)
*/
@Bean
public Converter<String, Date> dateConverter() {
return new Converter<String, Date>() {
@SuppressWarnings("NullableProblems")
@Override
public Date convert(String source) {
if (StringUtils.isEmpty(source)) {
return null;
}
// 13位毫秒值 -> Date
if (source.matches(TIME_STAMP_REGEX)) {
return new Date(Long.parseLong(source));
}
try {
// yyyy-MM-dd HH:mm:ss -> Date
if (source.matches(DATE_TIME_REGEX)) {
return getSimpleDateFormat(DEFAULT_DATETIME_PATTERN).parse(source);
}
// yyyy-MM-dd -> Date
if (source.matches(DATE_REGEX)) {
return getSimpleDateFormat(DEFAULT_DATE_FORMAT).parse(source);
}
// yyyy-MM -> Date
if (source.matches(YEAR_MONTH_REGEX)) {
return getSimpleDateFormat(YEAR_MONTH_PATTERN).parse(source);
}
} catch (ParseException e) {
throw new RuntimeException(e);
}
return null;
}
};
}
/**
* String -> LocalDateTime 轉(zhuǎn)換器
* 用于轉(zhuǎn)換 @RequestParam參數(shù)、@PathVariable參數(shù)、表單參數(shù)
*/
@Bean
public Converter<String, LocalDateTime> localDateTimeConverter() {
return new Converter<String, LocalDateTime>() {
@SuppressWarnings("NullableProblems")
@Override
public LocalDateTime convert(String source) {
if (StringUtils.isEmpty(source)) {
return null;
}
// 13位毫秒值 -> LocalDateTime
if (source.matches(TIME_STAMP_REGEX)) {
Instant instant = Instant.ofEpochMilli(Long.parseLong(source));
ZoneId zone = ZoneId.systemDefault();
return LocalDateTime.ofInstant(instant, zone);
}
// yyyy-MM-dd HH:mm:ss -> LocalDateTime
if (source.matches(DATE_TIME_REGEX)) {
return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN));
}
// yyyy-MM-ddTHH:mm:ss -> LocalDateTime
if (source.matches(DATE_T_TIME_REGEX)) {
return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATETIME_ISO_PATTERN));
}
// yyyy-MM-ddTHH:mm:ss.SSS -> LocalDateTime
if (source.matches(DATE_T_TIME_MS_REGEX)) {
return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATETIME_MS_ISO_PATTERN));
}
return null;
}
};
}
/**
* String -> LocalDate 轉(zhuǎn)換器
* 用于轉(zhuǎn)換 @RequestParam參數(shù)、@PathVariable參數(shù)、表單參數(shù)
*/
@Bean
public Converter<String, LocalDate> localDateConverter() {
return new Converter<String, LocalDate>() {
@SuppressWarnings("NullableProblems")
@Override
public LocalDate convert(String source) {
if (StringUtils.isEmpty(source)) {
return null;
}
// 13位毫秒值 -> LocalDate
if (source.matches(TIME_STAMP_REGEX)) {
Instant instant = Instant.ofEpochMilli(Long.parseLong(source));
ZoneId zone = ZoneId.systemDefault();
return LocalDateTime.ofInstant(instant, zone).toLocalDate();
}
// yyyy-MM-dd -> LocalDate
if (source.matches(DATE_REGEX)) {
return LocalDate.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT));
}
return null;
}
};
}
/**
* String -> LocalTime 轉(zhuǎn)換器
* 用于轉(zhuǎn)換 @RequestParam參數(shù)、@PathVariable參數(shù)、表單參數(shù)
*/
@Bean
public Converter<String, LocalTime> localTimeConverter() {
return new Converter<String, LocalTime>() {
@SuppressWarnings("NullableProblems")
@Override
public LocalTime convert(String source) {
if (StringUtils.isEmpty(source)) {
return null;
}
// HH:mm:ss -> LocalTime
return LocalTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT));
}
};
}
}以上就是詳解SpringBoot中時(shí)間類型的序列化與反序列化的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot序列化 反序列化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java定時(shí)/延時(shí)任務(wù)之Timer用法詳解
在?Java?Development?Kit?(JDK)?中,java.util.Timer?是一個(gè)用于調(diào)度任務(wù)的工具類,本文主要來和大家聊聊Timer的用法,有需要的小伙伴可以了解下2024-12-12
Java如何通過反射機(jī)制獲取數(shù)據(jù)類對(duì)象的屬性及方法
文章介紹了如何使用Java反射機(jī)制獲取類對(duì)象的所有屬性及其對(duì)應(yīng)的get、set方法,以及如何通過反射機(jī)制實(shí)現(xiàn)類對(duì)象的實(shí)例化,感興趣的朋友跟隨小編一起看看吧2025-01-01
bool當(dāng)成函數(shù)參數(shù)錯(cuò)誤理解
經(jīng)常會(huì)在函數(shù)的參數(shù)里使用bool參數(shù),這會(huì)大大地降低代碼的可讀性2012-11-11
Request對(duì)象如何獲取請(qǐng)求頭數(shù)據(jù)
這篇文章主要介紹了Request對(duì)象如何獲取請(qǐng)求頭數(shù)據(jù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
java IO流 之 輸入流 InputString()的使用
這篇文章主要介紹了java IO流 之 輸入流 InputString()的使用,以及讀取數(shù)據(jù)的三種方式詳解,非常不錯(cuò),需要的朋友可以參考下2016-12-12
Java中數(shù)組array和列表list相互轉(zhuǎn)換
這篇文章主要介紹了Java中數(shù)組array和列表list相互轉(zhuǎn)換,在Java中,可以將數(shù)組(array)和列表(list)相互轉(zhuǎn)換,但需要注意一些細(xì)節(jié)和限制,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09

