Springboot 接收&返回 LocalDateTime 全自动时间戳互转 支持Swagger3 home 编辑时间 2023/04/18 ![](/api/file/getImage?fileId=6448d693da74050013024329) ## 前言 `LocalDateTime` 就是一个更高效率的 `Date` , 从 `Java 8` 开始支持 `Springboot` 中前端传入和返回 `LocalDateTime` 默认的格式比较蛋疼 希望是传入和返回都是毫秒级的时间戳 例如 `2023-04-25 12:25:47.442` 对应 `1682396747442` 期望前端传入和返回时间都用Number类型的时间戳 后端自动序列化或反序列化为LocalDateTime **补充** 这样做还有一个隐藏问题就是取值范围 `JavaScript` 中的 `Number` 整数取值范围是 `±2的53次方-1` 对应到 `Java` 的 `Integer` 取值范围是 `±2的31次方-1` , `Java` 的 `Long` 是64次方 所以 `Java` 端必须用 `Long` 或 `String` 来接收和返回数据 <br> ## 折腾 经过一番学习和折腾,基本了解了大概的逻辑 Springboot默认用Jackson处理JSON转换 理论上只要改Jackson处理LocalDateTime的方式 最简单的代码如下 ```java @Configuration public class LocalDateTimeConfig { @Bean public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() { return builder -> { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); builder.deserializers(new LocalDateTimeDeserializer(dateTimeFormatter)); builder.serializers(new LocalDateTimeSerializer(dateTimeFormatter)); }; } } ``` 传入和返回的格式都为 `yyyy-MM-dd HH:mm:ss` ```json { "startTime": "2023-04-25 12:25:47" } ``` <br> 然鹅,他自带的序列化都是改时间格式 YYMMDD,我这里需要的是long类型时间戳 那么延续这个思路,我重写了序列化和反序列化的方法 (错误示范) ```java @Configuration public class LocalDateTimeConfig { @Bean public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() { return builder -> { builder.serializers(new LocalDateTimeSerializer() { @Override public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { if (localDateTime != null) { jsonGenerator.writeNumber(localDateTime.atZone(ZoneId.of("UTC+8")).toInstant().toEpochMilli()); } } }); builder.deserializers(new LocalDateTimeDeserializer() { @Override public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException { return LocalDateTime.ofInstant(Instant.ofEpochMilli(parser.getValueAsLong()), ZoneId.of("UTC+8")); } }); }; } } ``` 然后就不出意外的出意外了 😭 传入 `1682481600000` 正常接收 返回 `2023-04-26T12:00:00` 炸了... 成默认格式了 根据一番打断点调试读源码百度看文档等折腾后... 发现序列化方法 `public void serialize` 根本没执行 执行了重写之前的那个默认的序列化方法 就很蛋疼 最后折腾了2天,发现csdn这位老哥写的就是正确答案 [SpringBoot--LocalDateTime格式转换(响应给前端) - CSDN](https://blog.csdn.net/feiying0canglang/article/details/120335612) ```java @Configuration public class LocalDateTimeConfig { @Bean public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() { return builder -> { builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer()); builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer()); }; } public static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> { @Override public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException { if (value != null) { gen.writeNumber(value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); } } } public static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> { @Override public LocalDateTime deserialize(JsonParser parser, DeserializationContext deserializationContext) throws IOException { long timestamp = parser.getValueAsLong(); return timestamp < 0 ? null : LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault()); } } } ``` 至此传入和返回都是 `1682493795958` 大功告成 <br> 最后兼容一下Swagger3 传入参数默认自动填Long类型数字 ```java @Bean public Docket createRestApi() { return new Docket(DocumentationType.OAS_30) ... .build() // 重点是这句 .directModelSubstitute(LocalDateTime.class, Long.class); } ``` <br> ## END 参考 [SpringBoot--LocalDateTime格式转换(响应给前端) - CSDN](https://blog.csdn.net/feiying0canglang/article/details/120335612) [Formatting json Date/LocalDateTime/LocalDate in Spring Boot - Spring Cloud](https://www.springcloud.io/post/2022-09/springboot-date-format/) [spring boot 时间戳和LocalDateTime相互转换 - CSDN](https://blog.csdn.net/wzl1369248650/article/details/105439725) 送人玫瑰,手留余香 赞赏 Wechat Pay Alipay Smart-doc 仅需要注释即可全自动生成开发文档 Springboot 开发必备 代替Swagger 微信小程序 Java服务端 登录相关代码 工具类 2023最新版