Jackson教程
全局配置和JsonFormat注解设置日期格式

在日常开发中,日期是很常见的一种数据类型,特别是在与数据库打交道的场景。

为了提升日期的可读性,通常会将日期进行格式化之后再输出,用于前端展示和日志打印等场景。

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)