7.盘点springmvc的常用接口之Converter(下篇)###
前两章介绍了Converter
、ConverterFactory
以及衍生出来的GenericConverter
、ConditionalGenericConverter
,最后附录罗列了Spring自带的各种转换器。这么多的转换器,我们开发者可不想在要使用转换器时还自己来查找转换器使用。所以为了统一调用Converter
进行类型转换,Spring友好地为我们提供了一个org.springframework.core.convert.ConversionService
接口。我们靠猜都知道查询一个转换器,肯定是通过原类型和目标类型来查的,而且在查到转换器后我们会通过convert
方法来执行转换过程。
接口说明
那么这个ConversionService
的接口看起来应该是这样子:
public interface ConversionService {
boolean canConvert(Class<?> sourceType, Class<?> targetType);
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
<T> T convert(Object source, Class<T> targetType);
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
一对canConvert
来判断是否匹配原类型和目标类型,
一对convert
执行转换过程。其中TypeDescriptor
是类型的描述,里面包含该种类型的值、实际类型等等信息。
ConversionService
接口它还有一个好基友org.springframework.core.convert.converter.ConverterRegistry
,一般这两个接口都是同时出现,ConverterRegistry
的作用是对转换器的管理,做一个统一的注册工作。它包含一系列的增删转换器的操作。接口如下:
public interface ConverterRegistry {
void addConverter(Converter<?, ?> converter);
void addConverter(Class<?> sourceType, Class<?> targetType, Converter<?, ?> converter);
void addConverter(GenericConverter converter);
void addConverterFactory(ConverterFactory<?, ?> converterFactory);
void removeConvertible(Class<?> sourceType, Class<?> targetType);
方法名字比较直白就不翻译了。
对于众多转换器的注册管理,查询执行转换工作就给我们这两个接口未免实现起来也有点困难。所以Spring已经给我们提供了一个实现org.springframework.core.convert.support.GenericConversionService
,它实现了ConversionService
和ConverterRegistry
接口,但是它不能直接拿来使用。因为不能通过类似下面的配置往里面添加我们自己的转换器。
<mvc:annotation-driven conversion-service="myConversionService"/>
<bean id="myConversionService" class="com.demo.mvc.component.MyConversionService">
<property name="customConverters">
<set>
<bean class="com.demo.mvc.component.TelephoneConverter"/>
</set>
</property>
</bean>
所以这个地方我们可以用到一款经典的设计模式,那就是“装饰模式”,在GenericConversionService
上套上我们自己的装饰器。
package com.demo.mvc.component;
import java.util.Set;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.convert.support.GenericConversionService;
import lombok.Getter;
import lombok.Setter;
public class MyConversionService implements ConversionService {
@Autowired
private GenericConversionService conversionService;
@Getter
@Setter
private Set<?> customConverters;
@PostConstruct
public void afterInjectCustomConverters() {
if (customConverters != null) {
for (Object converter : customConverters) {
if (converter instanceof Converter<?, ?>) {
conversionService.addConverter((Converter<?, ?>) converter);
} else if (converter instanceof ConverterFactory<?, ?>) {
conversionService.addConverterFactory((ConverterFactory<?, ?>) converter);
} else if (converter instanceof GenericConverter) {
conversionService.addConverter((GenericConverter) converter);
}
}
}
}
@Override
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
return conversionService.canConvert(sourceType, targetType);
}
@Override
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
return conversionService.canConvert(sourceType, targetType);
}
@Override
public <T> T convert(Object source, Class<T> targetType) {
return conversionService.convert(source, targetType);
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return conversionService.convert(source, sourceType, targetType);
}
}
通过customConverters
集合可以把我们自定义的转换器设置进来,再调用afterInjectCustomConverters
方法设置到GenericConversionService
中,之后的其它操作都是调用原来的GenericConversionService
的方法。
除了以上这种自己实现的装饰器外,Spring已经为我们提供了一个既可以使用GenericConversionService
又可以添加自己的转换器的类,那就是org.springframework.context.support.ConversionServiceFactoryBean
。这个类提供了一个converters
属性让我们设置自己的转换器。在对象初始化完成之后它会new一个GenericConversionService
对象,并往GenericConversionService
中注册converters
属性指定的Converter
和Spring自身已经实现了的默认Converter
,之后每次返回的都是这个GenericConversionService
对象。注册时,我们可以这样配置:
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.demo.mvc.component.TelephoneConverter"/>
</set>
</property>
</bean>
GenericConversionService
的子类还有FormattingConversionService
,这个类既可以转换类型又可以格式化。它也有一个FactoryBean
来辅助注册:
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.demo.mvc.component.TelephoneConverter"/>
</set>
</property>
</bean>