转换器的知识大致可以分为两个部分
- 第一部分介绍将配置信息转换为bean对象或bean属性的类型。Spring大部分的配置信息都是字符串
- 第二部分介绍任意的类型转换,将A--->B,A,B都可以是任意的类型。
1、Str2Obj
Str2Obj的意思是指String to Object。Spring将配置信息转换为bean对象或者bean属性类型至少需要两个步骤
- 将字符串转换为属性或对象需要的类型。
- 如果是属性,调用对象的setXX方法。
负责第一步的接口为PropertyEditor,负责调用set方法的接口是BeanWrapper。
1.1 PropertyEditor
PropertyEditor接口的职责是将字符串转换为正确的对象类型。
PropertyEditor接口有很多实现类,spring有许多内置的XXEditor,它们大部分都在org.springframework.beans.propertyeditors。例如最为常见的CustomBooleanEditor,将字符串转换为布尔;CustomDateEditor,将字符串转换为日期。我们也可以自定义XXEditor,实现将字符串转换为自定义类型。
要使PropertyEditor接口实现类生效,需要实现两个步骤:
- 第一步编写PropertyEditor的实现类,或者使用spring框架内置的实现类。
- 第二步注册PropertyEditor的实现类。
第一步较为简单,如果要使用内置的PropertyEditor实现类,参考3.3.2的内容。
注册PropertyEditor实现类的方式有三种:
- 第一种直接将XXPropertyEditor与XX对象放置在同一个包下,例如User类,直接将UserPropertyEditor放置到相同包下即可。
- 第二种配置CustomEditorConfigurer的customEditors属性
<!-- 注入customEditorConfigurer, 并配置customEditors属性 --> <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <!-- 该属性是Map对象,其中key值为转换的对象类型,value值为PropertyEditor接口的实现类 --> <property name="customEditors"> <map> <!-- User类为自定义对象,UserPropertyEditor为自定义PropertyEditor接口实现类 --> <entry key="com.bean.User" value="com.propertyEditor.UserPropertyEditor"/> </map> </property> </bean>
3.第三种通过实现PropertyEditorRegistrar接口,并将实现类添加到customPropertyEditorRegistrar属性中。
第一步,编写自定义实现类,实现register方法。
/** * * @Title: UserPropertyEditorRegistrar.java * @Package com.propertyEditor * @Description: UserPropertyEditor的注册器 * @version V1.0 */ public class UserPropertyEditorRegistrar implements PropertyEditorRegistrar { public void registerCustomEditors(PropertyEditorRegistry registry) { // 第一个参数为对象的类型,这里是User.class,第二个参数为UserPropertyEditor的实例 registry.registerCustomEditor(User.class, new UserPropertyEditor()); } }
第二步,配置CustomEditorConfigurer的propertyEditorRegistrars属性。
<!-- 注入XXPropertyRegistrars --> <bean id="userEditorRegistrar" class="com.propertyEditor.UserPropertyEditorRegistrar"/> <!-- 注入customEditorConfigurer, 并配置customEditors属性 --> <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <!-- 配置propertyEditorRegistrars属性 --> <property name="propertyEditorRegistrars"> <list> <ref bean="userEditorRegistrar"> </list> </property> </bean>
第三步,在Controller类中获取XXPropertyRegistrars,在initBinder方法中调用registerCustomEditors。
public final class RegisterUserController { @Autowired private final PropertyEditorRegistrar customPropertyEditorRegistrar; public RegisterUserController(PropertyEditorRegistrar propertyEditorRegistrar) { this.customPropertyEditorRegistrar = propertyEditorRegistrar; } protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception { // 这一步是关键 this.customPropertyEditorRegistrar.registerCustomEditors(binder); } }
可以看到第三种注册方式非常繁琐,第一种虽然简单,但是有时候却并不想PropertyEditor放在实体类的包下,spring框架也是将所有的propertyEditor实现类单独放在一个包下,综合比较,第二种方式最优。
1.2 BeanWrapper
通过BeanWrapper设置对象的某个属性,下例中有两种设置User的name属性的方式。
BeanWrapper user = new BeanWrapperImpl(new User()); // 设置user的名称 user.setPropertyValue("name", "张三"); // 第二种方式,通过创建PropertyValue对象设置user的名称 PropertyValue value = new PropertyValue("name", "张三"); user.setPropertyValue(value);
2、Obj2Obj
对象与对象之间的转换有很多种实现方式,spring框架只是其中的一种方式。对象转对象大致可以归为三类:
- 单个对象转换为单个对象
- 单个对象转换为类体系结构,例如String转换为Enum。
- 集合相互转换,例如List<String>转换为List<Integer>。
2.1 Single2Single
单个对象转换为单个对象有两个步骤:
- 第一步实现Convert接口,它只有一个方法convert,参数代表source,方法的返回值为target。
- 第二步注册XXConvert。
注册XXConvert的方式为配置ConversionServiceFactoryBean的converters属性。
<!-- 注入ConversionServiceFactoryBean --> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <!-- 配置converters属性 --> <property name="converters"> <set> <!-- 自己编写的convert接口实现类 --> <bean class="com.converts.XXConverter" /> </set> </property> </bean>
之后就可以获取ConversionServiceFactoryBean的实例,并调用它的API实现转换的功能。
2.2 Single2ClassHierarchy
单个对象转换为类体系结构有两个步骤:
- 第一步编写ConvertFactory接口的实现类,实现getConverter方法,其中参数代表类结构中具体的类型。返回值为Converter接口实现类,它实现具体的转换逻辑。
- 第二步,注册,方法同Converter。
官网的原示例将String转换为具体的枚举类型,代码如下:
/** * * @Title: StringToEnumConverterFactory.java * @Package com.propertyEditor * @Description: 这个类将String对象转换为具体的枚举类型 * @version V1.0 */ final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> { // 这个是ConvertFactory接口中的方法,它只是获取具体的Converter public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) { return new StringToEnumConverter(targetType); } // Converter接口的实现类,不必是内部类的形式 private final class StringToEnumConverter<T extends Enum> implements Converter<String, T> { private Class<T> enumType; public StringToEnumConverter(Class<T> enumType) { this.enumType = enumType; } public T convert(String source) { return (T) Enum.valueOf(this.enumType, source.trim()); } } }
2.3 Coll2Coll
多个对象转换为多个对象的步骤和之前类似,区别在于实现GenericConvert接口。待补充。
注:Spring还提供了ConversionService,它只是整合之前三种接口的功能,应用到了门面模式,步骤和注册方式和之前三种情形基本没什么区别。