问题描述
这两天遇到一个问题,新的微服务调用现有的微服务的Feign Client时出现了一个错误,把错误日志打了出来,发现是日期格式转换错误的问题:
具体错误信息如下:
Could not read document: Can not deserialize value of type java.util.Date from String "2014-04-09 15:48:29": not a valid representation (error: Failed to parse Date value '2014-04-09 15:48:29': Can not parse date "2014-04-09 15:48:29Z": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSS'Z'', parsing fails (leniency? null))
at [Source: java.io.PushbackInputStream@3aef1a63; line: 1, column: 106] (through reference chain: com.***.mdm.main.client.response.CommonResponse["data"]->com.***.mdm.main.client.bean.pojo.Tenement["createdOn"]); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type java.util.Date from String "2014-04-09 15:48:29": not a valid representation (error: Failed to parse Date value '2014-04-09 15:48:29': Can not parse date "2014-04-09 15:48:29Z": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSS'Z'', parsing fails (leniency? null))
at [Source: java.io.PushbackInputStream@3aef1a63; line: 1, column: 106] (through reference chain: com.***.mdm.main.client.response.CommonResponse["data"]->com.***.mdm.main.client.bean.pojo.Tenement["createdOn"])
然后调用相同Client的其他服务,同样是取回日期,发现没有转换问题,我就很纳闷,为什么呢?仔细看了一遍之后发现不能正常调用的服务中都包含了 @ResponseBody 的注解,到网上查找了一下,发现了问题:A服务在调用B服务时,无论A还是B,请求和返回的日期格式都是’yyyy-MM-dd HH:mm:ss’,@ResponseBody则会在返回时会使用jackson将数据转换为DTO对象,而jackson的默认日期数据格式为:'yyyy-MM-dd’T’HH:mm:ss.SSS。这也刚好印证了我上面的截图中jackson报的错误。
注:@ResponseBody 返回json字符串的核心类是org.springframework.http.converter.json.MappingJacksonHttpMessageConverter,它使用了Jackson 这个开源的第三方类库。
故需要解决的问题是:如何将返回的数据格式进行统一,而不使用@ResponseBody默认的数据格式。
解决方案
方案一
使用注解:
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
使用这个注解,问题可以解决。
刚开始我考虑的解决方案是:在Model对象中加上这两个注解问题就能迎刃而解了,但是! 当我开始想要给Model加上的时候,我忽然想到一个问题:之前也有其他微服务调用这些接口,为什么它们就可以用?所以一定还有其他的解决方案。百思不得其解的我继续开始摸索,回头去看了一看其他的微服务调用的方式也是一模一样的,我就开始考虑一个问题,是不是yml配置或者拦截器已经进行了处理?机智的我就去翻了翻yml文件,发现,哦豁,还真是。
方案二
yml或properties文件中配置上如下配置:
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
Spring boot就会根据配置将jackson的数据格式统一了。
注意!!! 今天运维中出现了一个比较严重的问题,微服务中因为使用了方案二的全局配置,导致大部分调用该微服务的接口都因为时间转换格式变动的原因而导致无法使用(主要是会影响已有调用系统,如果你自己是新的服务,这个问题影响就不大),差点造成严重问题,幸亏是晚上,只是苦了我的黑眼圈了。。
所以,如果需要使用方案二,请确认该服务是否有对外接口是有时间格式的转换,如果有,需要确认是否会对调用方产生影响,如果涉及系统较多,就不太建议使用方案二了,切记!