1.前言
JDK1.8中添加新的时间日期API,LocalDate、LocalDateTime、LocalTime,但是我们在开发中使用时间戳作为参数值来传递是比较常用的,然而在SpringBoot中并没有为我们提供合适的JsonSerializer和JsonDeserializer。
我们先看看使用默认的Json序列化和反序列化器的情况,时间戳来自如下:
1.1 LocalDateTime返回值格式问题
@RestController
public class TestController {
@GetMapping("/test")
public DateDTO test() {
DateDTO dateDTO = new DateDTO();
dateDTO.setDateTime(LocalDateTime.now());
return dateDTO;
}
@Data
static class DateDTO {
private LocalDateTime dateTime;
}
}
请求参数:
curl --request GET \
--url http://127.0.0.1:9999/test
响应参数:
{
"code": 200,
"msg": "success",
"data": {
"dateTime": "2023-02-12T17:57:03.7918033"
}
}
这里LocalDateTime类型的属性的返回值格式,不是我们通用的时间戳格式,不利于前端同学格式化。
1.2 LocalDateTime请求参数问题
@RestController
public class TestController {
@GetMapping("/test")
public void test(@RequestBody DateDTO date) {
System.out.println(date);
}
@Data
static class DateDTO {
private LocalDateTime dateTime;
}
}
请求参数:
curl --request GET \
--url http://127.0.0.1:9999/test \
--header 'content-type: application/json' \
--data '{
"dateTime": 1676193312235
}'
当请求发送之后,系统直接报错了。看报错信息,意思是我们的参数值的格式不对,需要使用LocalDateTime的默认格式,例如:"2023-02-12T17:57:03.7918033"
,这样的话,前端同学在传值的时候就会比较麻烦
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: raw timestamp (1676193312235) not allowed for `java.time.LocalDateTime`: need additional information such as an offset or time-zone (see class Javadocs);
1.3 LocalDate请求参数问题
@RestController
public class TestController {
@GetMapping("/test")
public void test(@RequestBody DateDTO date) {
System.out.println(date);
}
@Data
static class DateDTO {
private LocalDate date;
}
}
请求参数:
curl --request GET \
--url http://127.0.0.1:9999/test \
--header 'content-type: application/json' \
--data '{
"date": 1676131200000
}'
当请求发送之后,系统直接报错了。看报错信息,提示我们传入的值超出了范围,其实我们传的就是毫秒级别的时间戳。
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Invalid value for EpochDay (valid values -365243219162 - 365241780471): 1676131200000;
1.4 统一格式为时间戳
在SpringBoot中提供了
@JsonComponent
注解,可以直接帮我们注入JsonSerializer
、JsonDeserializer
到Spring容器中,我们可以自定义将传参和返回值统一为时间戳。
接下来,我们来编写自定义的JsonSerializer
以及JsonDeserializer
。
@JsonComponent
public class JsonConfig {
public static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
@SneakyThrows
@Override
public void serialize(LocalDateTime value, JsonGenerator generator, SerializerProvider serializers) {
generator.writeNumber(LocalDateTimeUtil.toEpochMilli(value));
}
}
public static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
String value = jsonParser.getText();
// 约定传时间戳
if (NumberUtil.isNumber(value)) {
return LocalDateTimeUtil.of(Long.parseLong(value));
} else {
return DateUtil.parse(value).toLocalDateTime();
}
}
}
public static class LocalDateSerializer extends JsonSerializer<LocalDate> {
@SneakyThrows
@Override
public void serialize(LocalDate value, JsonGenerator generator, SerializerProvider serializers) {
generator.writeNumber(LocalDateTimeUtil.toEpochMilli(value));
}
}
public static class LocalDateDeserializer extends JsonDeserializer<LocalDate> {
@Override
public LocalDate deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
String value = jsonParser.getText();
// 约定传时间戳
if (NumberUtil.isNumber(value)) {
return LocalDateTimeUtil.of(Long.parseLong(value)).toLocalDate();
} else {
return DateUtil.parse(value).toLocalDateTime().toLocalDate();
}
}
}
}
现在我们来测试一下传参的格式:
@RestController
public class TestController {
@GetMapping("/test")
public DateDTO test(@RequestBody DateDTO date) {
System.out.println(date);
date.setDate(LocalDate.now());
date.setDateTime(LocalDateTime.now());
return date;
}
@Data
static class DateDTO {
private LocalDate date;
private LocalDateTime dateTime;
}
}
1.4.1 时间戳
请求参数:
curl --request GET \
--url http://127.0.0.1:9999/test \
--header 'content-type: application/json' \
--data '{
"date": 1676131200000,
"dateTime": 1676198645075
}'
正常接收并返回:
{
"code": 200,
"msg": "success",
"data": {
"date": 1676131200000,
"dateTime": 1676198792976
}
}
1.4.2 正常时间格式
请求参数
curl --request GET \
--url http://127.0.0.1:9999/test \
--header 'content-type: application/json' \
--data '{
"date": "2023-02-12",
"dateTime": "2023-02-12 09:00:00"
}'
正常接收并返回:
{
"code": 200,
"msg": "success",
"data": {
"date": 1676131200000,
"dateTime": 1676199084811
}
}
通过上面的处理,我们就实现了传参和返回值的统一。