转换器的知识大致可以分为两个部分
- 第一部分介绍将配置信息转换为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,它只是整合之前三种接口的功能,应用到了门面模式,步骤和注册方式和之前三种情形基本没什么区别。