问题场景:
使用Springboot框架搭建服务,传日期参数json参数为2016-08-15 17:00:00这种格式,springboot中不能识别,将其转化为对象对应的日期属性。而是抛出异常信息,提示转换失败。
代码:
传参对应实体类
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调用使用的postman
请求报错:
{ "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)) 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类似格式的数据,所以转换失败。
解决办法有以下几种:
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")
3、采用全局处理方式统一处理,推荐这个做法
重写springboot默认转换
参考:https://blog.csdn.net/qq906627950/article/details/79503801
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; } }
参考资料: