LocalDateTime在项目中的使用(LocalDateTime对…
2020-04-14 16:04:17来源:博客园 阅读 ()
LocalDateTime在项目中的使用(LocalDateTime对接前端通过时间戳互转、LocalDateTime对接数据库)
目录
- 1. 博客编写背景
- 2. LocalDateTime 前端交互
- 2.1 LocalDateTime 向前端写入时间戳
- 2.1.1 fastJson 默认的写入格式
- 2.1.2 更改 fastJson 写入格式,让其回写时间戳 (★★★)
- 2.2 接收前端传递的时间戳为 LocalDateTimme
- 2.2.1 LocalDateTime 默认接收的格式
- 2.2.2 更改 fastJson 反序列化方法,让其能够转换时间戳为 LocalDateTime(★★★)
- 2.2.3 【坑】更改 SpringBoot 的 @RequestBody 为 fastJson 接收(★★★)
- 2.1 LocalDateTime 向前端写入时间戳
- 3. LocalDateTime 与数据库交互(★★★)
- 3.1 【坑】数据库交互LocalDateTime被四舍五入(★★★)
1. 博客编写背景
本文章的编写背景:由于在 JDK 8 中,Date、Timestamp 对象已经不推荐使用,所以在公司的新项目上,我计划将 LocalDateTime 使用在新项目中。
由于本人所在项目组,统一的前后端时间的交互方式为时间戳,而时间戳并不能直接被fastJson
或 jackson
直接转换,所以踩了不少的坑,个人建议有耐心的看完。
实现的效果如下:
- 前端传递时间戳
{
"localDateTime": 1584700466000
}
- 后端返回时间戳
{
"code": "0",
"desc": "请求成功",
"data": {
"localDateTime": 1584700466000
}
}
========================================================
若是感觉废话比较多,那么直接看标注了【★★★】的即可
个人写这个博客,并不想直接写结论,更多的是想给读者分享踩坑的过程
========================================================
2. LocalDateTime 前端交互
2.1 LocalDateTime 向前端写入时间戳
2.1.1 fastJson 默认的写入格式
本项目使用的是 fastJson
会写前端,我们先看下以下代码
- 回写前端的
VO
对象
@Data
public class LocalDateTimeVO {
private LocalDateTime localDateTime;
}
- 测试方法
public static void main(String[] args) {
LocalDateTimeVO localDateTimeVO = new LocalDateTimeVO();
localDateTimeVO.setLocalDateTime(LocalDateTime.now());
String json = JSON.toJSONString(localDateTimeVO);
System.out.println(json);
}
- 控制台输出
{"localDateTime":"2020-03-12T23:00:28.747"}
从上图中可以看出,服务端并不能正常的返回时间戳给前端。并不符合需求。
2.1.2 更改 fastJson 写入格式,让其回写时间戳 (★★★)
fastJson
提供了自定义json
转换的方法@JSONFiled
,我们添加serializeUsing
,将其指定到我们自定义的序列化控制器即可。- 自定义
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);
}
}
}
- 使用我们自己写的
fastJson
序列化转换器
@Data
public class LocalDateTimeVO {
@JSONField(serializeUsing = LocalDateTimeSerializer.class)
private LocalDateTime localDateTime;
}
- 再次执行测试方法,控制台输出
{"localDateTime":1584026032912}
可以看出,LocalDateTime
已经成功被转换为了时间戳,并且可以返回给前端。
2.2 接收前端传递的时间戳为 LocalDateTimme
2.2.1 LocalDateTime 默认接收的格式
不管我们传递时间戳(1584026032912),还是传递自定义格式("2020-03-13"),在服务端接受的时候,都会报错400。也就是说,传入的格式是错误的,无法被 spring 转换为 LocalDateTime
经过我的粗略测试,我发现,默认的接受格式为 LocalDateTime
特有的格式,即:2020-03-12T23:00:28.747
,除此之外都会报400。这种格式与 Date
格式的唯一区别就在于,Date
在日
与时
之间是用空格区分的,而 LocalDateTime
是用 T
来区分的。
2.2.2 更改 fastJson 反序列化方法,让其能够转换时间戳为 LocalDateTime(★★★)
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;
}
}
- 使用我们自己写的
fastJson
反序列化转换器
@Data
pubcli class LocalDateTimeVO {
@JSONField(serializeUsing = LocalDateTimeSerializer.class, deserializeUsing = LocalDateTimeDeserializer.class)
private LocalDateTime localDateTime;
}
- 测试方法
public static void main(String[] args) {
String json = "{\"localDateTime\":1584026032912}";
LocalDateTimeVO localDateTimeVO = JSON.parseObject(json, LocalDateTimeVO.class);
System.out.println(localDateTimeVO);
}
- 控制台执行结果展示
LocalDateTimeVO(localDateTime=2020-03-12T23:13:52.912)
可以看出,时间戳成功被 fastJson
接受,并转换为了 LocalDateTime
。
2.2.3 【坑】更改 SpringBoot 的 @RequestBody 为 fastJson 接收(★★★)
当你看到这个小标题时,肯定会很疑惑,我们项目目前不就是使用的 fastJson
吗?
实际情况经过我测试,得出的结论是,我们在回写前端的时候,是使用 fastJson
进行转换的,但是在接受 Json 的时候,是使用 Spring 默认的 jackson
来接受的,所以这会导致,我们重写了 fastJson
的反序列化方法并未执行。前端传递时间戳给后端,后端报错400。
因此,我们需要更改 spring 默认提供的 jackson
为 fastJson
/**
* 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());
}
}
配置完成之后,后端与前端使用时间戳进行交互已完成。
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
的最大精度重置为对应的微妙即可。
以上两种方案调用LocalDateTime
的withNano()
方法即可
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
原文链接:https://www.cnblogs.com/chimmhuang/p/12695823.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- MyBatis中的$和#,用不好,准备走人! 2020-06-11
- 项目经理说这种代码必须重构,我同意了,这代码是写的是有多 2020-06-11
- 构造函数中的this()和super() 2020-06-10
- eclipse下创建Maven项目(包含webapp目录结构) 2020-06-09
- 怎么用Java 高效提取、替换、删除PDF文档中的图片 2020-06-09
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash