SpringMVC 返回Java8 時間JSON資料的格式化問題處理
有時在Spring MVC中返回JSON格式的response的時候會使用@ResponseBody
註解,不過在處理java8中時間的時候會很麻煩,一般我們使用的HTTPMessageConverter是MappingJackson2HttpMessageConverter
,它預設返回的時間格式是這種:
1 "startDate" : { 2 "year" : 2010, 3 "month" : "JANUARY", 4 "dayOfMonth" : 1, 5 "dayOfWeek" : "FRIDAY", 6 "dayOfYear" : 1,7 "monthValue" : 1, 8 "hour" : 2, 9 "minute" : 2, 10 "second" : 0, 11 "nano" : 0, 12 "chronology" : { 13 "id" : "ISO", 14 "calendarType" : "iso8601" 15 } 16 }
但是我們不會返回這種給前端使用,針對LocalDate想要返回的格式是2016-11-26,而LocalDateTime想要返回的格式是
2016-11-26
21:04:34
這樣的資料。通過專案研究並查閱相關資料,這裡介紹下個人研究中實現的兩種方式。
解決方法一:
若是maven專案,在pom中引入下面的jar包:
1 <dependency> 2 <groupId>com.fasterxml.jackson.datatype</groupId> 3 <artifactId>jackson-datatype-jsr310</artifactId> 4 <version>2.8.5</version> 5 </dependency>
然後在你想要JSON化的POJO欄位的get函式上加上一個@JsonSerializer
註解,如下
1 import com.fasterxml.jackson.annotation.JsonFormat; 2 3 @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") 4 public LocalDateTime getBirthday() { 5 return this.loginTime; 6 } 7 8 @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 9 public LocalDateTime getLastLoginTime() { 10 return this.loginTime; 11 }
這種方式的優點是可以針對具體域型別設定不同顯示方式,然而優點也是缺點,因為每個日期屬性都要手動新增,實際中日期屬性又是普遍必備,並且需要額外引入jsr310的jar包。
解決方法二:
繼承ObjectMapper來實現返回json字串。MappingJackson2HttpMessageConverter主要通過ObjectMapper來實現返回json字串。這裡我們編寫一個JsonUtil類,獲取ObjectMapper以針對java8中新的日期時間API,註冊相應的JsonSerializer<T>。
1 /** 2 * json處理工具類 3 * 4 * 5 */ 6 @Component 7 public class JsonUtil { 8 9 private static final ObjectMapper mapper; 10 11 public ObjectMapper getMapper() { 12 return mapper; 13 } 14 15 static { 16 17 mapper = new ObjectMapper(); 18 19 SimpleModule module = new SimpleModule(); 20 module.addSerializer(LocalDate.class, new LocalDateSerializer()); 21 module.addSerializer(LocalTime.class, new LocalTimeSerializer()); 22 module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer()); 23 mapper.registerModule(module); 24 } 25 26 public static String toJson(Object obj) { 27 try { 28 return mapper.writeValueAsString(obj); 29 } catch (Exception e) { 30 throw new RuntimeException("轉換json字元失敗!"); 31 } 32 } 33 34 public <T> T toObject(String json, Class<T> clazz) { 35 try { 36 return mapper.readValue(json, clazz); 37 } catch (IOException e) { 38 throw new RuntimeException("將json字元轉換為物件時失敗!"); 39 } 40 } 41 } 42 43 class LocalDateSerializer extends JsonSerializer<LocalDate> { 44 45 private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); 46 47 @Override 48 public void serialize(LocalDate value, JsonGenerator jgen, SerializerProvider provider) 49 throws IOException, JsonProcessingException { 50 jgen.writeString(dateFormatter.format(value)); 51 } 52 } 53 54 class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> { 55 56 private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); 57 58 @Override 59 public void serialize(LocalDateTime value, JsonGenerator jgen, SerializerProvider provider) 60 throws IOException, JsonProcessingException { 61 jgen.writeString(dateTimeFormatter.format(value)); 62 } 63 64 } 65 66 class LocalTimeSerializer extends JsonSerializer<LocalTime> { 67 68 private static final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); 69 70 @Override 71 public void serialize(LocalTime value, JsonGenerator jgen, SerializerProvider provider) 72 throws IOException, JsonProcessingException { 73 jgen.writeString(timeFormatter.format(value)); 74 75 } 76 77 }View Code
然後在springmvc的配置檔案中,再將<mvc:annotation-driven/>改為以下配置,配置一個新的json轉換器,將它的ObjectMapper物件設定為JsonUtil中的objectMapper物件,此轉換器比spring內建的json轉換器優先順序更高,所以與json有關的轉換,spring會優先使用它。
1 <mvc:annotation-driven> 2 <mvc:message-converters> 3 <bean 4 class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 5 <property name="objectMapper" value="#{jsonUtil.mapper}" /> 6 <property name="supportedMediaTypes"> 7 <list> 8 <value>application/json;charset=UTF-8</value> 9 </list> 10 </property> 11 </bean> 12 </mvc:message-converters> 13 </mvc:annotation-driven>View Code
然後java8中的幾種日期和時間型別就可以正常友好的顯示了。優點是全域性統一管理日期和時間等型別,缺點對pojo中的某個域做特殊處理。