問題場景:java
使用Springboot框架搭建服務,傳日期參數json參數爲2016-08-15 17:00:00這種格式,springboot中不能識別,將其轉化爲對象對應的日期屬性。而是拋出異常信息,提示轉換失敗。ajax
代碼:spring
傳參對應實體類json
public class Demo { private String id; private Date date; public String getId() { return id; } public void setId(String id) { this.id = id; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }
controller安全
@RequestMapping("/demo") public String demo(@RequestBody Demo demo) { System.out.println(demo.getId()); return "this is client1"; }
ajax調用使用的postmanspringboot
請求報錯:app
{ "timestamp": "2018-09-17T14:01:00.278+0000", "status": 400, "error": "Bad Request", "message": "JSON parse error: Cannot deserialize value of type `java.util.Date` from String \"2018-09-17 21:46:08\": not a valid representation (error: Failed to parse Date value '2018-09-17 21:46:08': Cannot parse date \"2018-09-17 21:46:08\": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSZ', parsing fails (leniency? null)); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String \"2018-09-17 21:46:08\": not a valid representation (error: Failed to parse Date value '2018-09-17 21:46:08': Cannot parse date \"2018-09-17 21:46:08\": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSZ', parsing fails (leniency? null))\n at [Source: (PushbackInputStream); line: 3, column: 9] (through reference chain: com.hanggle.eurekaclient.Demo[\"date\"])", "path": "/demo" }
錯誤緣由是日期轉換失敗,因爲springboot默認採用jackson,而jackson只能識別如下幾種日期格式:框架
"yyyy-MM-dd'T'HH:mm:ss.SSSZ"; "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; "yyyy-MM-dd"; "EEE, dd MMM yyyy HH:mm:ss zzz"; long類型的時間戳(毫秒時間戳)
不能識別yyyy-MM-dd HH:mm:ss相似格式的數據,因此轉換失敗。 ide
解決辦法有如下幾種:post
1. 採用long時間戳(毫秒時間戳!!!!)如:1537191968000
2.在傳參的對象上加上@JsonFormat註解而且指定時區(此方法治標不治本)
@JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
若是項目中使用json解析框架爲fastjson框架,則可以使用以下解決方法:
在實體字段上使用@JsonFormat註解格式化日期
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")
三、採用全局處理方式統一處理,推薦這個作法
重寫springboot默認轉換
參考:http://www.javashuo.com/article/p-foopgbua-gx.html
public class MyDateFormat extends DateFormat { private DateFormat dateFormat; private SimpleDateFormat format1 = new SimpleDateFormat("yyy-MM-dd HH:mm:ss"); public MyDateFormat(DateFormat dateFormat) { this.dateFormat = dateFormat; } @Override public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { return dateFormat.format(date, toAppendTo, fieldPosition); } @Override public Date parse(String source, ParsePosition pos) { Date date = null; try { date = format1.parse(source, pos); } catch (Exception e) { date = dateFormat.parse(source, pos); } return date; } // 主要仍是裝飾這個方法 @Override public Date parse(String source) throws ParseException { Date date = null; try { // 先按個人規則來 date = format1.parse(source); } catch (Exception e) { // 不行,那就按原先的規則吧 date = dateFormat.parse(source); } return date; } // 這裏裝飾clone方法的緣由是由於clone方法在jackson中也有用到 @Override public Object clone() { Object format = dateFormat.clone(); return new MyDateFormat((DateFormat) format); } }
@Configuration public class WebConfig { @Autowired private Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder; @Bean public MappingJackson2HttpMessageConverter MappingJsonpHttpMessageConverter() { ObjectMapper mapper = jackson2ObjectMapperBuilder.build(); // ObjectMapper爲了保障線程安全性,裏面的配置類都是一個不可變的對象 // 因此這裏的setDateFormat的內部原理實際上是建立了一個新的配置類 DateFormat dateFormat = mapper.getDateFormat(); mapper.setDateFormat(new MyDateFormat(dateFormat)); MappingJackson2HttpMessageConverter mappingJsonpHttpMessageConverter = new MappingJackson2HttpMessageConverter( mapper); return mappingJsonpHttpMessageConverter; } }
參考資料: