查看原文
其他

Spring Boot 解决 json 日期格式化疑难问题,基于注解实现全局日期格式化

Java精选 2022-08-09

>>号外:关注“Java精选”公众号,菜单栏->聚合->干货分享,回复关键词领取视频资料、开源项目。

java开发中对于json数据中时间格式化一直都是程序员头疼的问题,这里看作者使用 @JsonComponent是怎么处理日期。另外还可以根据时区动态展示不同时间,你会了吗?

学习目标

快速学会通过注解 @JsonComponent自定义日期格式化的序列化器。

快速查阅

专题阅读:《SpringBoot 布道系列》:https://www.jianshu.com/p/964370d9374e

源码下载:SpringBoot Date Format Anno:https://github.com/yizhiwazi/springboot-socks

--- Hey Man,Don't forget to Star or Fork . ---

使用教程

根据官方文档 Custom JSON Serializers and Deserializers ,想要接管Jackson的JSON的序列化和反序列化,只需通过注解 @JsonComponent来声明其静态内部类即可。

首先根据项目要求提供自定义的日期序列化器和反序列化器,其中包括:

  • DateJsonSerializerextendsJsonSerializer<Date> 表示将Date格式化为日期字符串。

  • DateJsonDeserializerextendsJsonDeserializer<Date> 表示将日期字符串解析为Date日期。

/**
* 全局日期格式化
*/
@JsonComponent
public class DateFormatConfig {

private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

/**
* 日期格式化
*/
public static class DateJsonSerializer extends JsonSerializer<Date> {
@Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(dateFormat.format(date));
}
}

/**
* 解析日期字符串
*/
public static class DateJsonDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
try {
return dateFormat.parse(jsonParser.getText());
} catch (ParseException e) {
throw new RuntimeException(e);
}

}
}
}

然后提供相应的测试信息,这里以查询用户为例:

/**
* 查询用户信息
*/
@RestController
public class UserController {
@GetMapping("/")
public User get() {
return new User("1", "socks", "123456", new Date(), "GMT");
}
}

/**
* 用户信息
*/
public class User {

private String userId;
private String username;
private String password;
private Date createTime;
private String timezone;

public User(String userId, String username, String password, Date createTime, String timezone) {
this.userId = userId;
this.username = username;
this.password = password;
this.createTime = createTime;
this.timezone = timezone;
}

//省略getters&setters
}

大功告成,接下来启动应用并访问 http://127.0.0.1:8080 ,可以拿到正确结果:

{
"userId": "1",
"username": "socks",
"password": "123456",
"createTime": "2018-12-26 01:03:25"
}

除了日期格式化解析之外,我们还可以在 DateFormatConfig 注入业务变量,例如根据当前登录人的所属时区(虽然 SimpleDateFormat默认读取了当地时区,但在实际的国际化系统中,用户的所属时区是指其在系统录入的所属时区,而不是指当地时区。例如Tony这个用户账号挂在GMT+0时区,但此时他出差在香港使用,系统仍需要按照GMT+0时区来显示时间),为了解决这个问题,此时我们可以在 DateFormatConfig 注入当前登录人然后改变日期工具类的 TimeZone来动态修改时区。

根据当前登录人动态展示时区:

/**
* 全局日期格式化
*/
@JsonComponent
public class DateFormatConfig {

private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z") {
@Override
public Date parse(String source) throws ParseException {
try {
if (StringUtils.isEmpty(source)) {
return null;
}
return super.parse(source);
} catch (Exception e) {
return new StdDateFormat().parse(source);
}
}
};

private static UserController userController;//这里是指获取当前登录人的工具类

@Autowired
public void setUserController(UserController userController) {
DateFormatConfig.userController = userController;
}

/**
* 日期格式化
*/
public static class DateJsonSerializer extends JsonSerializer<Date> {
@Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
//获取当前登录人的所属时区
dateFormat.setTimeZone(TimeZone.getTimeZone(userController.get().getTimezone()));
//格式化日期
jsonGenerator.writeString(dateFormat.format(date));
}
}

/**
* 解析日期字符串
*/
public static class DateJsonDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
try {
//获取当前登录人的所属时区
dateFormat.setTimeZone(TimeZone.getTimeZone(userController.get().getTimezone()));
//解析日期
return dateFormat.parse(jsonParser.getText());
} catch (ParseException e) {
throw new RuntimeException(e);
}

}
}
}

修改完后重新启动应用并访问 http://127.0.0.1:8080 ,可以拿到正确结果:

{
"userId": "1",
"username": "socks",
"password": "123456",
"createTime": "2018-12-25 17:35:50 +0000",
"timezone": "GMT"
}

小结

1、使用注解 @JsonComponent 可以快速自定义日期格式化的序列化器,免除传统通过模块注册的烦恼。

2、使用注解 @JsonComponent 实现与当地无关的动态时区的精髓就在于将获取当前等人的方法写在解析日期和格式化日期的代码里。

3、使用注解 @JsonComponent 是直接处理String和Date的相互转换的,所以要注意空串问题。例如dateFormat.parse()要预防空串。

作者:yizhiwazi

jianshu.com/p/f4654d251104

往期精选  点击标题可跳转

资深程序员建议放弃 JSP 吧,否则你可能“无路可走”!

后端接口访问数据查询如何提高性能?从MySQL、ES、HBASE等技术出发解决慢查询!

那些总是写“烂代码”的程序员,强烈推荐使用这款 IntelliJ IDEA 插件!

使用 Intellij IDEA 实时模版完美解决 Java8 的数据流问题

关于 Session 会话深入探讨

从零开始,徒手撸一个简单的 RPC 框架,轻松搞定!

Spring Boot 2.x 推荐缓存框架 Caffeine 高性能设计剖析

在 Java 项目中,如何使用 Error 日志更加方便排查问题,这才是正确姿势,非常实用!

19 张思维导图带你梳理 Spring Cloud 体系中的重要知识点!

程序员经常浏览的 60 个技术网站汇总,还不赶快收藏!

还在手动部署 Spring Boot 项目?使用 Docker 真香!

点个赞,就知道你“在看”!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存