接收参数错误
web端请求时,会附带各种类型的参数。对应地服务端在接收这些参数时,会以指定的类型接收。
然而,有些web端参数虽然实际可以转换为对应的服务端参数,但Spring Boot本身并没有提供这样的转换,就会导致报错。
最典型的例子就是时间戳和日期类型参数。
例如,web端请求时附带参数为:
{
time: 1609466400000
}
服务端使用JavaBean接收,class定义为:
class TestT {
private Timestamp time;
...
}
当服务端收到请求时,会首先用String
接收1609466400000,然后尝试转换为Timestamp
类型。
但String
并不能直接转为Timestamp
,于是此时就会报错:
Failed to convert property value of type ‘java.lang.String’ to required type ‘java.sql.Timestamp’ for property ‘testTime’; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.sql.Timestamp] for value ‘1609466400000’; nested exception is java.lang.IllegalArgumentException: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]
但实际上,只要将该String
转为Long
,就可以创建Timestamp
。但Spring本身并不知道要这样转换。
解决方案
创建自定义的Converter
类,在其中添加String
到Timestamp
的转换。
自定义Timestamp
转换
定义ObjectToTimestampConverter
import com.alibaba.fastjson.util.TypeUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import java.sql.Timestamp;
/**
* 自定义Converter - Object 转 Timestamp
* Object可为任意类型及格式的时间数据。
* 载入该Converter后,系统可将任意的合法Object转换为 Timestamp 。
* @date 2021/01/27
*/
@Component
public class ObjectToTimestampConverter implements Converter<Object, Timestamp> {
@Override
public Timestamp convert(Object value) {
return TypeUtils.castToTimestamp(value);
}
}
其中的转换使用了fastjson
的TypeUtils
。
定义了Converter
后,理论来说需要将其手动注册给Spring框架的转换服务ConversionService
,这样在转换时才会获取到自定义的Converter
。而实际上,Spring Boot在启动时会自动检查ApplicationContext中的Bean
,若继承了org.springframework.core.convert.converter.Converter
,则会自动将其注册给框架的转换服务。
因此,只要使用@Component
将自定义的Converter
注册为组件即可生效。
自定义Date
转换
Date
转换同理。
import com.alibaba.fastjson.util.TypeUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 自定义Converter - Object 转 Date
* Object可为任意类型及格式的时间数据。
* 载入该Converter后,系统可将任意的合法Object转换为 Date 。
* @date 2021/01/27
*/
@Component
public class ObjectToDateConverter implements Converter<Object, Date> {
@Override
public Date convert(Object value) {
return TypeUtils.castToDate(value);
}
}