在日常开发中,日期是很常见的一种数据类型,特别是在与数据库打交道的场景。
为了提升日期的可读性,通常会将日期进行格式化之后再输出,用于前端展示和日志打印等场景。
Jackson在对日期进行序列化时,也支持按指定的格式进行序列化。
本篇内容基于Jackson 2.11.2版本,马上开始学习吧。
默认日期格式
创建一个代表产品的类Product,其中发布时间publishDate为Date类型。
public class Product {
private String name;
private Date publishDate;
// 省略getter、setter方法
@Override
public String toString() {
return "Product [name=" + name + ", publishDate=" + publishDate + "]";
}
}
使用默认的配置进行序列化。
/**
* 默认日期格式化.
*
* @throws JsonProcessingException
*/
@Test
public void dateToLong() throws JsonProcessingException {
Product product = new Product();
product.setName("TV");
product.setPublishDate(new Date());
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(product));
}
执行结果:
{"name":"TV","publishDate":1601862136345}
结果中的publishDate字段值为1601862136345,是一个数字类型。
在默认情况下,Jackson序列化Date、Calendar日期类型时,会转化为Long数字类型。反序列化时,也是使用Long类型来转化为对应的日期类型。
全局日期格式化
Jackson支持设置序列化日期的格式,日期格式参数使用Java的java.text.DateFormat。
在进行序列化之前,通过调用ObjectMapper的setDateFormat方法,设置指定的日期格式。
/**
* 全局日期格式化.
*
* @throws JsonProcessingException
*/
@Test
public void dateToString() throws JsonProcessingException {
Product product = new Product();
product.setName("TV");
product.setPublishDate(new Date());
ObjectMapper mapper = new ObjectMapper();
// 设置日期格式
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// mapper.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(mapper.writeValueAsString(product));
String jsonString = "{\"name\":\"TV\",\"publishDate\":\"2020-10-04 22:21:07\"}"; // 格式化
Product newProduct = mapper.readValue(jsonString, Product.class);
System.out.println(newProduct.toString());
jsonString = "{\"name\":\"TV\",\"publishDate\":1601821267709}"; // Long类型
newProduct = mapper.readValue(jsonString, Product.class);
System.out.println(newProduct.toString());
}
执行结果:
{"name":"TV","publishDate":"2020-10-05 09:57:25"}
Product [name=TV, publishDate=Sun Oct 04 22:21:07 CST 2020]
Product [name=TV, publishDate=Sun Oct 04 22:21:07 CST 2020]
序列化后的publishDate字段,值为字符串类型,格式与设置的yyyy-MM-dd HH:mm:ss相同。
在设置了日期格式之后,反序列化支持2种日期类型,一种是默认的数字类型,另一种是设置的日期格式。
另外,如果默认的时区不满足要求,可以在设置日期格式的同时,设置对应的时区。
mapper.setTimeZone(TimeZone.getTimeZone("UTC"));
其中,getTimeZone的参数为时区ID。例如中国上海为Asia/Shanghai,美国洛杉矶为America/Los_Angeles。
JsonFormat注解格式化字段
如果只需要格式化特定的字段,或者不同字段使用不同的格式时,可以使用JsonFormat注解来实现。
格式化为字符串
为日期字段添加JsonFormat注解,并指定序列化类型为字符串。
public class ProductWithJsonFormat {
private String name;
@JsonFormat(shape=Shape.STRING)
private Date publishDate;
// 省略getter、setter方法
}
/**
* 在日期字段添加JsonFormat注解设置日期格式
*
* @throws JsonProcessingException
*/
@Test
public void jsonFormat() throws JsonProcessingException {
ProductWithJsonFormat product = new ProductWithJsonFormat();
product.setName("TV");
product.setPublishDate(new Date());
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(product));
}
执行结果:
{"name":"TV","publishDate":"2020-10-05T04:42:04.842+00:00"}
指定日期格式
通过pattern属性指定日期格式为yyyy-MM-dd HH:mm:ss。
@JsonFormat(shape=Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")
private Date publishDate;
执行结果:
{"name":"TV","publishDate":"2020-10-05 04:45:55"}
指定时区
格式没问题了,但是时间不对,晚了8个小时。
JsonFormat注解提供了另外一个属性timezone,用来设置时区,这里设置为中国上海Asia/Shanghai。
@JsonFormat(shape=Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss", timezone="Asia/Shanghai")
private Date publishDate;
执行结果:
{"name":"TV","publishDate":"2020-10-05 12:47:20"}
这个才是我们想要的结果。
小结
日期格式化在日常开发中比较常见,常用于前端展示和日志打印等场景,格式化后的可读性比较强。
对于日期类型,Jackson默认会序列化为数值类型,可读性比较差。
如果每个日期字段都需要格式化,并且格式都相同,那么可以使用ObjectMapper进行全局的设置。
如果需要对每个字段单独设置格式,则可以通过JsonFormat注解进行不同的配置。
同时,需要注意默认的时区是否能够满足需求,时区也可以根据实际需要进行设置。
参考
https://github.com/FasterXML/jackson (opens in a new tab)
https://www.logicbig.com/tutorials/misc/jackson/json-format.html (opens in a new tab)