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