当我们使用java8的LocalDateTime,LocalDate等接收来自前端请求json的时间字段时,会由于格式问题会导致反序列化失败,这里提供一种全局的解决方案。
1. 示例
1.1 代码
build.gradle
plugins {
id 'org.springframework.boot' version '2.1.11.RELEASE'
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven { url "http://maven.aliyun.com/nexus/content/groups/public" }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation "org.apache.commons:commons-lang3:3.9}"
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
java代码
@Date
public class ComputeParam {
LocalDateTime createTime;
}
@PostMapping("/compute")
public Stirng compute(@RequestBody ComputeParam param) {
return ok;
}
1.2 请求
curl --request POST \
--url http://localhost:8080/compute \
--header 'content-type: application/json' \
--data '{"createTime": "2020-01-04 12:12:12"}'
1.3 响应
异常信息
2020-01-05 00:41:33.506 WARN [,fa2f61967e660396,fa2f61967e660396,false] 84616 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.time.LocalDateTime` from String "2020-01-04 12:12:12": Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException) Text '2020-01-04 12:12:12' could not be parsed at index 10; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.time.LocalDateTime` from String "2020-01-04 12:12:12": Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException) Text '2020-01-04 12:12:12' could not be parsed at index 10
at [Source: (PushbackInputStream); line: 2, column: 16] (through reference chain: cn.justme.justmerule.bean.param.ComputeParam["createTime"])]
解决方案
注册自定义LocalDateTimeDeserializer
代码
// 全局生效
@JsonComponent
public class JsonConfig {
public static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
if (StringUtils.isNumeric(jsonParser.getValueAsString())) { // 如果是时间戳形式
return new Date(jsonParser.getValueAsLong()).toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime()
} else { // 默认是yyyy-MM-dd HH:mm:ss 形式,如果有多种格式,可以自行拓展
return LocalDateTime.parse(jsonParser.getValueAsString(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
}
}
}
}
关于@JsonComponent
参照官网
如果不想全局生效:
我们可以去掉@JsonComponent注解,然后在ComputeParam实体类上添加@JsonDeserialize,如下:
@Date public class ComputeParam { @JsonDeserialize(using = JsonConfig.LocalDateTimeDeserializer.class) LocalDateTime createTime; }
这样可以指定特定的
Deserializer
,而不影响全局其他同类型的字段。更简单的直接在createTime字段上增加
@JsonFormat
注解即可@Date public class ComputeParam { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") LocalDateTime createTime; }