1. 博客编写背景

本文章的编写背景:由于在 JDK 8 中,Date、Timestamp 对象已经不推荐使用,所以在公司的新项目上,我计划将 LocalDateTime 使用在新项目中。

由于本人所在项目组,统一的前后端时间的交互方式为时间戳,而时间戳并不能直接被fastJsonjackson 直接转换,所以踩了不少的坑,个人建议有耐心的看完。

实现的效果如下:

  1. 前端传递时间戳
{
"localDateTime": 1584700466000
}
  1. 后端返回时间戳
{
"code": "0",
"desc": "请求成功",
"data": {
"localDateTime": 1584700466000
}
}

========================================================

若是感觉废话比较多,那么直接看标注了【★★★】的即可

个人写这个博客,并不想直接写结论,更多的是想给读者分享踩坑的过程

========================================================


2. LocalDateTime 前端交互

2.1 LocalDateTime 向前端写入时间戳

2.1.1 fastJson 默认的写入格式

本项目使用的是 fastJson 会写前端,我们先看下以下代码

  1. 回写前端的 VO 对象
@Data
public class LocalDateTimeVO {
private LocalDateTime localDateTime;
}
  1. 测试方法
public static void main(String[] args) {
LocalDateTimeVO localDateTimeVO = new LocalDateTimeVO();
localDateTimeVO.setLocalDateTime(LocalDateTime.now());
String json = JSON.toJSONString(localDateTimeVO);
System.out.println(json);
}
  1. 控制台输出
{"localDateTime":"2020-03-12T23:00:28.747"}

从上图中可以看出,服务端并不能正常的返回时间戳给前端。并不符合需求。

2.1.2 更改 fastJson 写入格式,让其回写时间戳 (★★★)

  1. fastJson提供了自定义 json 转换的方法 @JSONFiled,我们添加 serializeUsing,将其指定到我们自定义的序列化控制器即可。
  2. 自定义 fastJson 序列化转换器,重写 ObjectSerializer
/**
* 由于 LocalDateTime 类型在转换 JSON 的时候,并不能被转换为字符串,使用 @JsonFormat 只能转换为指定的 pattern 类型,因此我们需要自定义一个序列化执行器
* LocalDateTime 序列化(将 LocalDateTime类型 转换为 时间戳 返回给前端 )
*
* @author Chimm Huang
* @date 2020/3/7
*/
public class LocalDateTimeSerializer implements ObjectSerializer {
@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
if (object != null) {
LocalDateTime localDateTime = (LocalDateTime) object;
//将localDateTime转换为中国区(+8)时间戳。
serializer.write(localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli());
} else {
serializer.write(null);
}
}
}
  1. 使用我们自己写的 fastJson 序列化转换器
@Data
public class LocalDateTimeVO {
@JSONField(serializeUsing = LocalDateTimeSerializer.class)
private LocalDateTime localDateTime;
}
  1. 再次执行测试方法,控制台输出
{"localDateTime":1584026032912}

可以看出,LocalDateTime 已经成功被转换为了时间戳,并且可以返回给前端。

2.2 接收前端传递的时间戳为 LocalDateTimme

2.2.1 Post 请求参数封装

1. LocalDateTime 默认接收的格式

不管我们传递时间戳(1584026032912),还是传递自定义格式("2020-03-13"),在服务端接受的时候,都会报错400。也就是说,传入的格式是错误的,无法被 spring 转换为 LocalDateTime

经过我的粗略测试,我发现,默认的接受格式为 LocalDateTime 特有的格式,即:2020-03-12T23:00:28.747,除此之外都会报400。这种格式与 Date 格式的唯一区别就在于,Date之间是用空格区分的,而 LocalDateTime 是用 T 来区分的。

2. 更改 fastJson 反序列化方法,让其能够转换时间戳为 LocalDateTime(★★★)

  1. fastJson 提供的 @JSONField 注解包括了反序列化转换器的指定,因此,我们重写其方法 ObjectDeserializer
/**
* 由于 时间戳 并不能直接被 fastJSON 转换为 LocalDateTime 类型,因此我们需要自定义一个序列化执行器
* LocalDateTime 反序列化(将前端传递的 时间戳 转换为 LocalDateTime 类型)
*
* @author Chimm Huang
* @date 2020/3/7
*/
public class LocalDateTimeDeserializer implements ObjectDeserializer { @Override
@SuppressWarnings("unchecked")
public LocalDateTime deserialze(DefaultJSONParser parser, Type type, Object fieldName) { String timestampStr = parser.getLexer().numberString(); if (timestampStr == null || "".equals(timestampStr)) {
return null;
} timestampStr = timestampStr.replaceAll("\"", ""); long timestamp = Long.parseLong(timestampStr);
if(timestamp == 0) {
return null;
}
return Instant.ofEpochMilli(timestamp).atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
} @Override
public int getFastMatchToken() {
return 0;
}
}
  1. 使用我们自己写的 fastJson 反序列化转换器
@Data
pubcli class LocalDateTimeVO {
@JSONField(serializeUsing = LocalDateTimeSerializer.class, deserializeUsing = LocalDateTimeDeserializer.class)
private LocalDateTime localDateTime;
}
  1. 测试方法
public static void main(String[] args) {
String json = "{\"localDateTime\":1584026032912}";
LocalDateTimeVO localDateTimeVO = JSON.parseObject(json, LocalDateTimeVO.class);
System.out.println(localDateTimeVO);
}
  1. 控制台执行结果展示
LocalDateTimeVO(localDateTime=2020-03-12T23:13:52.912)

可以看出,时间戳成功被 fastJson 接受,并转换为了 LocalDateTime

3. 【坑】更改 SpringBoot 的 @RequestBody 为 fastJson 接收(★★★)

当你看到这个小标题时,肯定会很疑惑,我们项目目前不就是使用的 fastJson

吗?

实际情况经过我测试,得出的结论是,我们在回写前端的时候,是使用 fastJson 进行转换的,但是在接受 Json 的时候,是使用 Spring 默认的 jackson 来接受的,所以这会导致,我们重写了 fastJson 的反序列化方法并未执行。前端传递时间戳给后端,后端报错400。


因此,我们需要更改 spring 默认提供的 jacksonfastJson

/**
* springboot 默认使用的是 jackson 进行 requestBody 请求的封装,该项目切换为使用 fastJson 进行请求封装和响应
* 配置 springboot 使用 fastJson 进行数据的请求接受和响应
*
* @author Chimm Huang
* @date 2020/3/7
*/
@Configuration
public class WebConfig implements WebMvcConfigurer { public HttpMessageConverter<String> stringConverter() {
return new StringHttpMessageConverter(StandardCharsets.UTF_8);
} public FastJsonHttpMessageConverter fastConverter() {
//1、定义一个convert转换消息的对象
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
//2、添加fastJson的配置信息
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullNumberAsZero,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullBooleanAsFalse); fastJsonConfig.setCharset(StandardCharsets.UTF_8);
//2-1 处理中文乱码问题
List<MediaType> fastMediaTypes = new ArrayList<>();
fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
fastConverter.setSupportedMediaTypes(fastMediaTypes);
//3、在convert中添加配置信息
fastConverter.setFastJsonConfig(fastJsonConfig);
return fastConverter;
} @Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.clear();
converters.add(stringConverter());
converters.add(fastConverter());
}
}

配置完成之后,后端与前端使用时间戳进行交互已完成。

2.2.2 GET 请求参数封装

只需自定义一个转换类即可

/**
* LocalDateTime 作为 作为 RequestParam 或者 PathVariable 时,将前端传递的时间戳转换
*
* @author Chimm Huang
* @date 2020/04/16
*/
@Configuration
public class LocalDateTimeGetConverter {
@Bean
public Converter<String, LocalDateTime> localDateTimeConverter() {
return new Converter<String, LocalDateTime>() {
@Override
public LocalDateTime convert(String source) {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(source)), ZoneId.systemDefault());
}
};
}
}

实例代码:

@GetMapping("/soutTime")
public void soutTimeByGet(LocalDateTime localDateTime) {
System.out.println(localDateTime);
}

前端请求:

localhost:8001/api/demo/soutTime?localDateTime=1587026916000

控制台输出:

2020-04-16T16:48:36

3. LocalDateTime 与数据库交互(★★★)

与数据库交互比较简单,我们使用的 mybatis 的版本为 3.4.5。且数据库时间类型为:datetime

我们只需要在 pom 文件中引入 jsr310 坐标即可

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-typehandlers-jsr310</artifactId>
<version>1.0.2</version>
</dependency>

3.1 【坑】数据库交互LocalDateTime被四舍五入(★★★)

LocalDateTime 是可以精确到纳秒的,但是数据库datetime类型如果不指定长度的话,默认是精确到秒的。这就会造成,在LocalDateTime为最大值的时候,如:2020-04-01T23:59:59.999999999,存入数据库的时候被四舍五入为了2020-04-02 00:00:00

解决方案一:

重置一下LocalDateTime的最大时间,将最大精度设置为秒。

解决方案二:

将数据库的datetime类型长度设置为6(datetime(6)即微秒),然后将LocalDateTime的最大精度重置为对应的微妙即可。

以上两种方案调用LocalDateTimewithNano()方法即可

public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime todayMax = LocalDateTime.of(now.toLocalDate(), LocalTime.MAX);
// 输出当天的时间
System.out.println(now);
// 输出当天的最大时间(默认最大)
System.out.println(todayMax);
// 输出当天的最大时间(datetime精度为秒的时候)
System.out.println(todayMax.withNano(0));
// 输出当天的最大时间(datetime精度为毫秒的时候) datetime(3)
System.out.println(todayMax.withNano(999000000));
// 输出当天的最大时间(datetime精度为微秒的时候) datetime(6)
System.out.println(todayMax.withNano(999999000));
}

控制台输出

2020-04-01T09:50:46.830845400
2020-04-01T23:59:59.999999999
2020-04-01T23:59:59
2020-04-01T23:59:59.999
2020-04-01T23:59:59.999999

LocalDateTime在项目中的使用(LocalDateTime对接前端通过时间戳互转、LocalDateTime对接数据库)的更多相关文章

  1. Java算法之递归打破及在真实项目中的使用实例

    开心一笑 刚才领导问开发:"你觉得这个项目的最大风险是什么",开发说:"加班猝死" , 气氛尴尬了一分钟!!! 提出问题 1.递归算法简单复习 2.如何实现递归 ...

  2. 在 ASP.NET Core 项目中使用 npm 管理你的前端组件包

    一.前言 在项目的前端开发中,对于绝大多数的小伙伴来说,当然,也包括我,不可避免的需要在项目中使用到一些第三方的组件包.这时,团队中的小伙伴是选择直接去组件的官网上下载,还是图省事直接在网上搜索,然后 ...

  3. Spring Data JPA系列3:JPA项目中核心场景与进阶用法介绍

    大家好,又见面了. 到这里呢,已经是本SpringData JPA系列文档的第三篇了,先来回顾下前面两篇: 在第1篇<Spring Data JPA系列1:JDBC.ORM.JPA.Spring ...

  4. C# 动态创建SQL数据库(二) 在.net core web项目中生成二维码 后台Post/Get 请求接口 方式 WebForm 页面ajax 请求后台页面 方法 实现输入框小数多 自动进位展示,编辑时实际值不变 快速掌握Gif动态图实现代码 C#处理和对接HTTP接口请求

    C# 动态创建SQL数据库(二) 使用Entity Framework  创建数据库与表 前面文章有说到使用SQL语句动态创建数据库与数据表,这次直接使用Entriy Framwork 的ORM对象关 ...

  5. 项目中 SimpleDateFormat 的正确使用

    项目中 SimpleDateFormat 的正确使用 日常开发中,我们经常需要使用时间相关类,说到时间相关类,想必大家对 SimpleDateFormat 并不陌生.主要是用它进行时间的格式化输出和解 ...

  6. [技巧]实际项目中background-image应写在页面上

    摘自:http://www.zhangxinxu.com 因为实际项目中(数据对接时),这肯定是个动态的URL地址,css文件似乎不支持动态URL 地址. <img src="../i ...

  7. vue项目中遇到的那些事。

    前言 有好几天没更新文章了.这段实际忙着做了一个vue的项目,从 19 天前开始,到今天刚好 20 天,独立完成. 做vue项目做这个项目一方面能为工作做一些准备,一方面也精进一下技术. 技术栈:vu ...

  8. 记录ThreadPoolTaskExecutor线程池的在项目中的实际应用,讲解一下线程池的配置和参数理解。

    前言:最近项目中与融360项目中接口对接,有反馈接口(也就是我们接收到请求,需要立即响应,并且还要有一个接口推送给他们其他计算结果),推送过程耗时.或者说两个接口不能是同时返回,有先后顺序. 这时我想 ...

  9. vue-cli项目中使用mockjs(基础使用和全局配置使用)

    参考:vue+mockjs 模拟数据,实现前后端分离开发 (Github-Demo可查看全部代码),Mockjs ,Axios 很多时候前后端分离的项目在开发过程中前端所需数据和后端接口并不会同步开发 ...

随机推荐

  1. Node.js中间件的使用

    1.中间件 为主要的业务逻辑服务:接收到请求,以及做出响应 应用级中间件.路由级中间件.内置中间件.第三方中间件.错误处理中间件 (1)路由级中间件 路由器的使用 (2)应用级中间件 也称为自定义中间 ...

  2. python操作excel----openpyxl模块

    openpyxl模块支持.xls和.xlsx格式的excel创建,但是只支持.xlsx格式的读取操作,不支持.xls的读取(可以使用xlrd模块来读取,写入操作也可使用xlwt模块),也可使用pand ...

  3. 爬虫之requests的请求与响应

    requests是基于urllib3的一个用于发起http请求的库(中文文档)数据采集流程: 指定url>> 基于 requests模块发起请求>> 获取响应中的数据>& ...

  4. 06 返回静态文件的映射(函数/多线程)web框架

    06 返回静态文件的映射(函数/多线程)web框架 服务器server端python程序(函数版): import socket server = socket.socket() server.bin ...

  5. 201771010128王玉兰《面向对象程序设计(Java)》第十二周学习总结

    第一部分:理论知识 1.AWT与Swing简介 (1)Swing用户界面库是非基于对等体的GUI工具箱. Swing具有更丰富并且更方便的用户界面元素集合. Swing对底层平台的依赖很少,因此与 ...

  6. Poj 2109 k^n = p.

    Poj2109(1)和Poj2109(2)这两种解答都是有漏洞的,就是解不一定存在. 当然这种漏洞的存在取决于出题人是否假设输入的n,p必须默认有kn = p这样的关系存在. 这道题可以详细看http ...

  7. 【数据分析入门】之Spyder中如何让图表单独显示出来

    一般图表只显示在ipython console中,且是静态,无法进行放大,移动等操作解决方案:[win]tools——preferences——ipython console——graphics中ba ...

  8. php实用正则

    1 Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$ 2 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z ...

  9. Android_四大组件之Service

    一.概述 Service是四大组件之一.它主要用于在后台执行耗时的逻辑,即使用户切换到其他应用甚至退出应用,它也能继续在后台运行. 下面主要介绍了service的两种形式启动和绑定 ,并通过简单例子说 ...

  10. 2019-ICLR-DARTS: Differentiable Architecture Search-论文阅读

    DARTS 2019-ICLR-DARTS Differentiable Architecture Search Hanxiao Liu.Karen Simonyan.Yiming Yang GitH ...