在默认情况下,不加任何有关接收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类型都要加上注解显得比较繁琐,也无法处理单个属性可能对应不同格式的值的情况。
更通用、有效的方式是定义一个时间转换类,并将其应用到所有的接口上。
分为两个步骤:
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处理前端日期传值的问题的相关解决办法就介绍到这里了。