org.springframework.validation.BindException異常解決
一. 異常現象
我在進行開發平臺後臺管理項目開發的時候,需要對token進行管理,其中需要對token進行編輯,效果如下:
結果在編輯token的時候,產生了如下現象:
token無法被編輯,阻塞了編輯操作的正常進行!
查看瀏覽器控制檯,發現出現了400狀態碼:
並且開發工具控制檯出現如下異常信息:
[http-nio-8080-exec-22] org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.logException Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'userToken' on field 'expireTime': rejected value [1588986551000]; codes [typeMismatch.userToken.expireTime,typeMismatch.expireTime,typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userToken.expireTime,expireTime]; arguments []; default message [expireTime]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'expireTime'; nested exception is java.lang.IllegalArgumentException: Could not parse date: Unparseable date: "1588986551000"]
Field error in object 'userToken' on field 'startTime': rejected value [1588468151000]; codes [typeMismatch.userToken.startTime,typeMismatch.startTime,typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userToken.startTime,startTime]; arguments []; default message [startTime]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'startTime'; nested exception is java.lang.IllegalArgumentException: Could not parse date: Unparseable date: "1588468151000"]]
二. 異常原因
從上面的異常信息中,我提取出核心的異常信息如下:
...Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'expireTime'...nested exception is java.lang.IllegalArgumentException: Could not parse date: Unparseable date: "1588986551000"
rejected value [1588986551000]; codes [typeMismatch.userToken.expireTime,typeMismatch.expireTime,typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userToken.expireTime,expireTime]; arguments []; default message [expireTime]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'expireTime'; nested exception is java.lang.IllegalArgumentException: Could not parse date: Unparseable date: "1588986551000"]
從異常信息可以看出,是因爲前端頁面以字符串形式傳遞日期時間字符串到後臺接口,默認的SpringMVC處理器無法將java.lang.String類型的字符串轉換成java.util.Date類型,進而導致IllegalArgumentException: Could not parse date,歸根結底就是前端頁面中的日期時間字符串與後端JavaBean類中的Date類型不匹配,typeMismatch.userToken.expireTime,typeMismatch.java.util.Date,typeMismatch!
三. 解決辦法
解決辦法其實有多種,其實只要保證前後端參數可以實現轉換就行了,所以基於這種思路,我提供如下幾種解決辦法。
解決方法一:
在後端的日期類型的字段上,添加如下註解:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date expireTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
因爲我的前端頁面,是普通的html頁面,且參數是以表單形勢傳遞的,如下:
所以利用@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")註解格式化前端傳遞進來的日期時間參數形式;
利用@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")格式化後端對外輸出的日期時間格式。
解決方法二:
第一種解決方法,需要在每個有日期時間類型字段的類中,都添加那樣的2個註解,當代碼較多時,就有些麻煩,可以編寫一個全局的轉換器,代碼如下:
package com.yyg.openapi.convert;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @Author 一一哥
* @Blame yiyige
* @Since Created in 2020/6/29
*/
public class CustomDateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return simpleDateFormat.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
然後把該類在spring.xml文件中進行註冊配置。
<!--全局的日期時間轉換器,解決前後端時間類型不匹配而導致的400異常!-->
<bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.yyg.openapi.convert.CustomDateConverter"/>
</list>
</property>
</bean>
此時JavaBean類中的屬性,只需要格式化對外輸出的類型,如下即可:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date expireTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date startTime;