預設情況下
在預設情況下,不加任何有關接收Date型別資料的配置時,前端傳遞Date型別資料至後端介面,控制檯出現以下異常:
Failed to convert from type [java.lang.String] to type [java.util.Date] for value
'2333333333'; nested exception is java.lang.IllegalArgumentException]]
複製程式碼
也就是說,在SpringBoot
中,必須新增某種配置才能讓前端正確傳遞時間型別資料到後端。下面針對不同的情況來介紹一下解決辦法。
區域性配置——使用@DateTimeFormat
第一種情況,僅需要對某個Bean類的Date型別欄位進行轉換,那麼只需要在Bean類屬性上增加@DateTimeFormat()
註解,括號內 pattern
為前端傳遞的日期格式。比如:
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
Date createTime;
複製程式碼
特點--缺陷:
按照如上配置,只能處理形如:2018-11-2 2:22:2
這樣固定格式的資料,無法處理時間戳和2018-11-2
格式的資料。如果想要處理2018-11-2
這樣的時間,就必須把pattern
改成yyyy-MM-dd
。
可以對不同的屬性賦予不同的pattern
,但是對每個Date型別都要加上註解顯得比較繁瑣,也無法處理單個屬性可能對應不同格式的值的情況。
更通用、有效的方式是定義一個時間轉換類,並將其應用到所有的介面上。
全域性配置——自定義時間轉換器
分為兩個步驟:
- 編寫一個時間轉換類,把可能的格式轉換為Date型別
- 通過某種方式,將時間轉換應用到Spring的所有介面上
時間轉換類
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 日期轉換類
* 將標準日期、標準日期時間、時間戳轉換成Date型別
*/
public class DateConverter implements Converter<String, Date> {
private static final String dateFormat = "yyyy-MM-dd HH:mm:ss";
private static final String shortDateFormat = "yyyy-MM-dd";
private static final String timeStampFormat = "^\\d+$";
@Override
public Date convert(String value) {
if(StringUtils.isEmpty(value)) {
return null;
}
value = value.trim();
try {
if (value.contains("-")) {
SimpleDateFormat formatter;
if (value.contains(":")) {
formatter = new SimpleDateFormat(dateFormat);
} else {
formatter = new SimpleDateFormat(shortDateFormat);
}
return formatter.parse(value);
} else if (value.matches(timeStampFormat)) {
Long lDate = new Long(value);
return new Date(lDate);
}
} catch (Exception e) {
throw new RuntimeException(String.format("parser %s to Date fail", value));
}
throw new RuntimeException(String.format("parser %s to Date fail", value));
}
}
複製程式碼
將時間轉換類應用到介面上
介紹兩種方式:使用@Component
+ @PostConstruct
或@ControllerAdvice
+ @InitBinder
第一種方式:
@Component
+ @PostConstruct
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import javax.annotation.PostConstruct;
/**
* @author zfh
* @version 1.0
* @date 2018/12/30 10:16
*/
@Component
public class WebConfigBeans {
@Autowired
private RequestMappingHandlerAdapter handlerAdapter;
@PostConstruct
public void initEditableAvlidation() {
ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer)handlerAdapter.getWebBindingInitializer();
if(initializer.getConversionService()!=null) {
GenericConversionService genericConversionService = (GenericConversionService)initializer.getConversionService();
genericConversionService.addConverter(new DateConverterConfig());
}
}
}
複製程式碼
第二種方式:
@ControllerAdvice
+ @InitBinder
有關這兩個註解的含義請參考我的部落格:Spring進階之@ControllerAdvice與統一異常處理
import com.aegis.config.converter.DateConverter;
import com.aegis.model.bean.common.JsonResult;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
/**
* @author zfh
* @version 1.0
* @since 2019/1/4 15:23
*/
@ControllerAdvice
public class ControllerHandler {
@InitBinder
public void initBinder(WebDataBinder binder) {
GenericConversionService genericConversionService = (GenericConversionService) binder.getConversionService();
if (genericConversionService != null) {
genericConversionService.addConverter(new DateConverter());
}
}
}
複製程式碼
OK,關於SpringBoot處理前端日期傳值的問題的相關解決辦法就介紹到這裡了。