Springboot下jackson配置不起作用
这几天的开发过程中,需要修改原有同事写的项目,原项目采用的是springboot写的后端服务,json序列化使用原始jackson进行,并在配置文件的properties文件中声明了jackson的一些基本配置
1
2
3
4
5
|
# Json spring.jackson.time-zone=GMT+ 8 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.property-naming-strategy=SNAKE_CASE spring.jackson.deserialization.READ_UNKNOWN_ENUM_VALUES_AS_NULL= true |
起初在没有加入项目的拦截器LoginInterceptor的时候,按照项目配置文件的配置,postman请求时采用属性为下划线的形式并不会报错,而且在序列化时间类型的属性时也不会出现时间格式化出问题的情况。开始对项目进行改造之后增加了登陆验证。并在springboot项目启动的时候增加了Webconfig来向程序注册拦截器
1
2
3
4
5
6
7
8
9
10
11
12
|
@Configuration public class WebConfig extends WebMvcConfigurationSupport { // 关键,将拦截器作为bean写入配置中 @Autowired private LoginInterceptor loginInterceptor; @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor).addPathPatterns( "/**" ); // 上传图片的路径除外 super .addInterceptors(registry); } } |
做完这些之后,准备调试程序时发现,用原有的报文请求程序的接口的时候总是报错。首先是时间类型转换失败,报错信息如下:
1
2
|
Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Can not deserialize value of type java.util.Date from String "2018-06-12 12:00:00" : not a valid representation (error: Failed to parse Date value '2018-06-12 12:00:00' : Can not parse date "2018-06-12 12:00:00" : while it seems to fit format 'yyyy-MM-dd' T 'HH:mm:ss.SSS' , parsing fails (leniency? null )); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type java.util.Date from String "2018-06-12 12:00:00" : not a valid representation (error: Failed to parse Date value '2018-06-12 12:00:00' : Can not parse date "2018-06-12 12:00:00" : while it seems to fit format 'yyyy-MM-dd' T 'HH:mm:ss.SSS' , parsing fails (leniency? null )) at [Source: java.io.PushbackInputStream @7688ebdb ; line: 1 , column: 281 ] (through reference chain: com.hlt.cloudoak.base.ForeignApplication[ "order" ]->com.hlt.cloudoak.base.ForeignApplication$Order[ "notification" ]->com.hlt.cloudoak.base.ForeignApplication$Order$Notification[ "date" ]->com.hlt.cloudoak.base.ForeignApplication$Order$Notification$HappenDate[ "notify" ]) |
然后通过一通查资料,最终在Model的属性上增加了@JsonFormat注解得以解决了这个时间格式化错误的问题。
但是事情并没有完,虽然解决了时间格式化报错的问题。但是使用下划线形式的Json请求接口依旧行不通,转化失败。程序拿不到对应属性的值。于是又是一顿某度和某歌的翻找。
最后在WebConfig类的实现中增加了代码,才使得原有的项目依旧得以采用下划线形式的Json,并且时间格式化时也并不会出错,最终代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
@Configuration public class WebConfig extends WebMvcConfigurationSupport { // 关键,将拦截器作为bean写入配置中 @Autowired private LoginInterceptor loginInterceptor; @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor).addPathPatterns( "/**" ); // 上传图片的路径除外 super .addInterceptors(registry); } @Bean public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() { MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false ); objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true ); objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); objectMapper.setTimeZone(TimeZone.getTimeZone( "GMT+8" )); objectMapper.setDateFormat( new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" )); jsonConverter.setObjectMapper(objectMapper); return jsonConverter; } @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(customJackson2HttpMessageConverter()); super .addDefaultHttpMessageConverters(converters); } } |
资料上讲,自定义WebMvcConfigur之后,原有properties中的jackson配置会失效。所以必须在自定义实现类中再次对jackson的配置进行补充。查询资料的过程中,看到有的文章提到需要将注解@EnableWebMvc
去掉。但是我们的项目中并不显式的包含这个注解,相信可能有部分人跟我一样在看到这个解决方案时并不知道如何对项目进行更改。下面贴一下官方的一段话来解释一下WebMvcConfigurationSupport类:
public class WebMvcConfigurationSupport
extends Object
implements ApplicationContextAware, ServletContextAware
@EnableWebMvc
to an application@Configuration
class. An alternative more advanced option is to extend directly from this class and override methods as necessary remembering to add@Configuration
to the subclass and @Bean
to overridden @Bean
methods. For more details see the Javadoc of @EnableWebMvc
.This class registers the following HandlerMapping
s:
RequestMappingHandlerMapping
ordered at 0 for mapping requests to annotated controller methods.HandlerMapping
ordered at 1 to map URL paths directly to view names.BeanNameUrlHandlerMapping
ordered at 2 to map URL paths to controller bean names.HandlerMapping
ordered atInteger.MAX_VALUE-1
to serve static resource requests.HandlerMapping
ordered atInteger.MAX_VALUE
to forward requests to the default servlet.
Registers these HandlerAdapter
s:
RequestMappingHandlerAdapter
for processing requests with annotated controller methods.HttpRequestHandlerAdapter
for processing requests withHttpRequestHandler
s.SimpleControllerHandlerAdapter
for processing requests with interface-basedController
s.
Registers a HandlerExceptionResolverComposite
with this chain of exception resolvers:
ExceptionHandlerExceptionResolver
for handling exceptions through @ExceptionHandler
methods.ResponseStatusExceptionResolver
for exceptions annotated with @ResponseStatus
.DefaultHandlerExceptionResolver
for resolving known Spring exception types
Registers an AntPathMatcher
and a UrlPathHelper
to be used by:
- the
RequestMappingHandlerMapping
, - the
HandlerMapping
for ViewControllers - and the
HandlerMapping
for serving resources
Note that those beans can be configured with a PathMatchConfigurer
.
Both the RequestMappingHandlerAdapter
and the ExceptionHandlerExceptionResolver
are configured with default instances of the following by default:
- a
ContentNegotiationManager
- a
DefaultFormattingConversionService
- a
OptionalValidatorFactoryBean
if a JSR-303 implementation is available on the classpath - a range of
HttpMessageConverter
s depending on the third-party libraries available on the classpath.
_________________________________________________________________________________________
pringBoot 接口返回的 JSON 数据的时间误差8小时
最近做的一个springboot2.0项目。
前提是我的服务器时区没有问题:
[root@wangbo ~]# date -R Mon, 22 Apr 2019 19:24:33 +0800
可以参考:查看和修改Linux服务器的时区和时间
使用MySQL57,(程序中打印的时间字段)查询出的时间字段总是和数据库存储的相差两个小时。
最后是通过修改数据库连接解决了这个问题。添加了下面这个属性。
&serverTimezone=Asia/Shanghai
接着又出现问题了。
默认情况下使用 @ResponseBody ,项目返回的JSON数据,返回对象会自动转为JSON格式,但是对象中的日期格式Date字段转换的时候相差了八小时,程序内打印时间没有问题,如果将 Date 改为 String 类型的话,也不会出现这种情况了。
所以问题应该出在返回结果格式化为JSON的这个过程中。
原因是spring转json的默认实现jackson中会根据时区去转换时间,而jackson的默认时区跟国内应该是相差8小时,所以在时间换算上自动减去了8小时。
可以通过jackson 的注解 @JsonFormat 解决问题
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss" ,timezone = "GMT+8") private Date createTime; @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss" ,timezone = "GMT+8") private Date updateTime;
也可以在 SpringBoot 配置文件中统一配置,推荐使用这种方式:
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.time-zone=GTM+8