利用Spring boot开发对于Java开发者来说是必备的开发框架,该框架自2014年发布1.0以来,经过6年多的发展,其体系变得越来越大,越来越复杂,对开发者来说Java开发变得越来越容易,因此,Java新手基于Spring boot开发基本都是CRUD,因此,当出现问题后,大量的时间被耗费在百度、StackOverflow查找答案,找到答案后就变成了拷贝粘贴,对于深层次原理和设计的研究越来越肤浅……
1、问题描述
如果没有任何配置的话,请求应该是失败的,如下图所示:
错误就是无法从String转成Date:
Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'
2、通过源码分析问题所在
Spring boot中对于输入参数的转换,是通过一个叫GenericConversionService的类负责的,如下图:
其中有一个关键的属性是Converters,这里就记录了所有注册的类型转换器:
其中就有String到Date的转换器。那为什么还会出错呢?通过调试我们得知默认情况下String到Date调用的转换器是ObjectToObjectConverter:
这个转换器实际是到了万不得已的情况才会调用的,它的实现实际上就是通过反射将输入的String作为Target(这里就是Date)的构造函数的输入参数,然后创建新对象的过程,具体代码如下:
1、通过sourceClass和targetClass标明了是从String到Date的转换
2、通过反射得到构造函数引用,然后调用:
ctor.newInstance(source);
这其中source就是我们输入的按字符串编码的日期,调用了Date(String)这个构造函数。所以我们就知道为什么会出错了?原因很简单,就是我们输入的格式Date不认,最终就爆出了开篇所说的异常信息。
3、问题解决
通过源码分析我们清晰的定位了问题所在,所以解决起来就得心应手了,方案可以有两个:
一是懒办法
就是什么也不改,针对问题,我们知道Date(String)这个构造函数对于日期的格式是有要求的,我们只要按要求改输入的格式就可以了,我们来看看Date的源码:
可以得知,Date(String s)这个构造函数被标注了Deprecated,就是不建议使用了,不过没关系,只要没有真正移除就还能用[吐彩虹]。构造函数里调用了parse(s)方法,我们接着看:
通过了解parse方法的注释,我们清晰的知道,该方法可以解析的时间格式有好几种:IETF标准日期格式、美国大陆时区的缩写等,具体来说以下格式都是认的:
December 17, 1995 03:24:00Sat, 12 Aug 1995 13:30:00 GMTSun Oct 25 11:54:38 CST 20202020/10/20 10:12:2310/20/2020 10:12:23
各位可以根据实际情况选用,特别需要注意的是如果用Sun Oct 25 11:54:38 CST 2020或Sat, 12 Aug 1995 13:30:00 GMT时,需要注意时区的问题!
二是主动出击
如果默认的格式我们不想用,或者无法满足要求,则可以自定义转换器,例如:
1、创建一个实现Convert的转换器
2、定义我们自定义的日期格式:"yyyy-MM-dd HH:mm:ss.SSS",本例中,可以定义任意种格式;
3、实现convert接口方法,完成转换动作
4、注入RequestMappingHandlerAdapter
5、将我们自定义的转换器注册到Spring boot中
至此,问题得到完美解决!