背景
在我們的數據庫使用datatime等類型時,實體類需要使用Date
或者LocalDateTime
等相對應(當然也可以使用String
,不過格式不受控制,而且有時候我們其他功能需要使用Date
等類型,所以不推薦使用String
),我們希望給調用者以我們希望的時間格式傳遞json,而不是默認的格式。
通常我們可能會使用for循環,遍歷每一個元素進行轉換,如下
List<User> users = xxx;
SimpleDateFormat fomatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (User user : users) {
user.setLastLoginTimeStr(formatter.format(user.getLastLoginTime));
}
這種寫法的確可以實現我們的功能,但是比較繁瑣,不優雅,並且還需要新增其他輔助字段,所以我們並不希望使用這種寫法
使用@JsonFormat
使用一個組件或是jar時,就需要引入相應的依賴
如果是使用SpringBoot,在引用web
的starter
時,會自動引入com.fasterxml.jackson.core
相關包,其中有一個@JsonFormat
註解,我們可以使用它來幫助我們實現我們的功能
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonFormat {
...
String pattern() default "";
String timezone() default "##default";
...
}
我們主要關係以上兩個屬性
- pattern:格式化表達式
- timezone:時區
數據庫
我們創建一張表,名字以及字段無所謂,但需要包含兩個datetime類型的字段來進行測試
編寫實體類
我們使用一個Date
以及一個LocalDateTime
分別對應數據庫相應的列,然後標註@JsonFormat
註解,兩個註解分別用不同的pattern
來起到測試的目的
public User {
...
// 表示查詢時不查詢此字段
@JsonFormat(pattern = "yyyyMMdd'T'HHmmss'Z'")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
...
}
進行測試
接下來我們需要查詢實體,直接把實體返回查看json
@RestController
@AllArgsConstructor
public class TestController {
private IUserService userService;
@GetMapping("test/user")
public List<User> test() {
return userService.list();
}
}
啓動項目,訪問路徑,看下結果
我們看到,兩個日期確實按照我們的指定的格式進行了轉換,證明@JsonFormat
以及pattern
有效,可以達到我們的目的。
但是事情還沒有結束,我們對比一下數據庫
可以看出LocalDateTime
類型的updateTime
字段和數據庫的值一致,但是Date
類型的createTime
卻比數據庫少了8個小時。一想差8小時,我們就應該明白這就是時區問題。Date
類型把時間變爲了世界時GMT,而北京時間爲GMT+8
增加JsonFormat
的timezone
屬性,如下
@JsonFormat(pattern = "yyyyMMdd'T'HHmmss'Z'", timezone="GMT+8")
private Date createDate;
再次運行,查看結果
可以看到時間已經正確了
小結
JsonFormat
註解可以幫助我們實現日期轉化爲指定格式的時間字符串pattern
屬性指定時間格式,timezone
屬性指定時區LocalDateTime
不會產生時區問題;Date
會產生時區問題,需要使用timezone
進行指定