分析
有时候需要将前台传来一些特定格式的数据对象转化成特定的Java对象,这个时候类型转换器就派上用场了。这里简单介绍使用比较简单的Converter接口。Converter是Spring 3.0后的一个函数式接口,只有一个方法,将source转化成target:
在WebMvcConfigurationSupport中有这样一个方法:
根据注释,可以在WebMvcConfigurer实现中重写这个方法(跟上面的套路一样有木有):
启动项目后输出的是WebConversionService:
可以发现WebConversionService是ConversionService的一个实现,而ConversionService是用来处理具体Converter的逻辑的一个接口:
在WebConversionService的父类GenericConversionService中有这样一个方法,这个方法将会多次被调用,直到注册所有的Converter:
添加Converter会先将其转化成ResolvableType[],里面包含了source和target的相关信息。然后会将当前Converter和数组的第一、二个元素封装成一个ConverterAdapter。即分别为具体转换实现,可以进行转换的ResolvableType和能够被转换的ResolvableType。里面有可以返回当前ConverterAdapter能够转换对象的信息和convert方法具体实现转换的方法。
ConverterAdapter是GenericConverter的具体实现:
在具体执行转换前GenericConversionService会先判断能够实现转换:
如果能够实现转换,则会调用convert()方法进行转换:
具体转换方法如下:
首先会进行一系列的null判断,然后获取GenericConverter,也就是之前封装好的ConverterAdapter,会发现在之前调用canConvert()方法的时候也执行过这个getConverter()方法,相当于是先判断能否转换类型,将相应的转换器存入缓存,然后接下来执行转换的时候会直接从缓存中取。getConverter()方法如下:
这个方法首先会将source和target封装成ConverterCacheKey,然后根据这个key从缓存中获取,这个缓存就是一个Map:
如果未找到可以匹配的Converter,value会被存储为NO_MATCH:
最终都会存储到缓存Map中。
自定义类型转换
首先需要定义自己的转换器,需要实现Converter<S,T>接口,convert就是具体的转换方法,ConverterAdapter在具体转换时会调用这个方法。这里将日期“yyyy-MM-dd”类型转换为Date类型:
然后需要将自定义的转换器进行注册:
这里的注册本质上还是WebConversionService调用父类GenericConversionService的addConverter()进行注册。
进行测试:
控制台输出结果,测试成功: