我们以自定义格式转换器的实现思路,来理解新架构的类型转换器的使用方法,同时在实际开发中,我们可能会有自己的格式转换需求,这个时候我们也可以通过自定义格式转换器来完成这些个性化需求。
自定义格式转换器
完成自定义转换器需要实现以下三个中的任意一个接口:Convertor<S,T>、GenericConvertor或ConvertorFacoty。下面我们对这些接口进行逐一分析:
1. Convertor<S,T>
这是最为简单的一个接口,定义了从源类到目标类的转换方法。该接口的定义如下
public interface ConverterFactory<S, R> {
//将S类型的对象转换为T类型,R为目标类型T的基类
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
2. GenericConvertor
GenericConvertor会根据源类对象及目标类对象所在宿主类的上下文信息进行类型转换工作,该接口的定义如下:
public interface GenericConverter {
//ConvertiblePair包含了源类型和目标类型,它的定义在下面
Set<ConvertiblePair> getConvertibleTypes();
//TypeDescriptor包含了需转换类型对象所在宿主类的信息,我们根据此信息,完成源到目标类型的转换
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
/**
* 内部类定义
*/
public static final class ConvertiblePair {
//源类型
private final Class<?> sourceType;
//目标类类型
private final Class<?> targetType;
/**
* 创建一个源-目标对子
*/
public ConvertiblePair(Class<?> sourceType, Class<?> targetType) {
Assert.notNull(sourceType, "Source type must not be null");
Assert.notNull(targetType, "Target type must not be null");
this.sourceType = sourceType;
this.targetType = targetType;
}
public Class<?> getSourceType() {
return this.sourceType;
}
public Class<?> getTargetType() {
return this.targetType;
}
//忽略hashCode\equals\toString等重写方法
}
}
我们常使用其实现类接口:
public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {
}
它除了实现GenericConverter,还实现了另一个“条件转换器”:
public interface ConditionalConverter {
/**
* Should the conversion from {@code sourceType} to {@code targetType} currently under
*/
//根据源类型和目标类型所在宿主类型的上下文信息判断是否要进行类型转换
boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}
在实际开发中,我们能实现此接口自定义转换器,来根据具体类型上下文来灵活配置我们的类型转换
3. ConvertorFacoty
这是一个将我们源类转换为一个目标类或其子类的”多转换器共存“接口工厂。它的定义如下:
public interface ConverterFactory<S, R> {
//获取将源类转换为特定R类或其子类的转换器
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
这个接口一个常见的实现类是StringToNumberConvertor,能将String类型数据转换为Number类型或其子类:Long,Integer,Double等。
注册自定义转换器
ConversionService
ConversionService则是Spring类型转换体系的核心接口,ConversionService接口的定义如下:
package org.springframework.core.convert;
public interface ConversionService {
//判断sourceType是否可以转换为targetType
boolean canConvert(Class<?> sourceType, Class<?> targetType);
//TypeDescriptor描述了转换类的各类上下文信息,在类型转换实现方法中可以根据这些信息进行灵活控制
//比如这里通过源类和目标类的上下文信息判断是否可以进行转换
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
//将source转换为targetType
<T> T convert(Object source, Class<T> targetType);
//利用源、目标类的上下文信息,将源类型转换为目标类型
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
ConversionServiceFactoryBean
实现以上类型完成我们的自定义转换器定义后,我们还要在Spring容器中通过ConversionServiceFactoryBean注册创建后才能使用。
ConversionServiceFactoryBean创建了我们的ConversionService很多内置转换器,利用这些转换器,我们可以完成大部分常见的类型转换工作
而如果我们想使用自定义的类型转换器,可以通过ConversionServiceFactoryBean的convertor属性来注册。
实例分析1:测试Convertor
通过以上的分析,我们接下来尝试自定实现Convert
1. 自定义属性转换器
public class MyConvertor implements Converter<String, User>{
@Override
public User convert(String source) {//source为要转换的字符串
String[] values = source.split(",");//根据我们的需求,用逗号来区分
Integer id = Integer.valueOf(values[0]);
User user = new User(id,values[1],values[2]);
return user;
}
}
/**********下面是我们的UserPOJO类**********/
public class User {
public User() {
super();
}
private Integer id;
private String userName;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public User(Integer id, String userName, String password) {
super();
this.id = id;
this.userName = userName;
this.password = password;
}
//忽略get和set方法
@Override
public String toString() {
return "User [id=" + id + ", userName=" + userName + ", password="
+ password + "]";
}
}
2. 注册自定义属性转换器
<!-- 通过:annotation-driven的conversion-service属性来装配我们的类型转换器 -->
<mvc:annotation-driven conversion-service="factoryBean" />
<!-- 通过ConversionServiceFactoryBean注册我们的自定义转换器 -->
<bean class="org.springframework.context.support.ConversionServiceFactoryBean" id="factoryBean" >
<property name="converters"><!-- 在属性converters注册 -->
<list>
<bean class="com.mvc.convertor.MyConvertor" />
</list>
</property>
</bean>
3. 配置控制器
在控制层,我们通过以下方法测试我们的转换器
@RequestMapping("convert")
public String convert(User user){
System.out.println(user);
return "model1";
}
4. 测试
启动服务器,在游览器中访问[项目根路径]/convert?user=11,myUserName,myPassword。
控制台会打印信息:User [id=11, userName=myUserName, password=myPassword]。即springMVC帮我们完成了字符串到User类型的转换。**这里需注意的是,我们的请求参数名”user”是和控制层方法入参变量User user像对应的,才能完成参数绑定进而转换类型
实例分析2:测试ConvertorFactory
1. 自定义类型转换器
在实例1的基础上,我们添加User的一个子类:SuperUser,作为”super”子类,它拥有了自己的专属名字,我们将字符串”11,myUserName,myPassword,myName“转换为我们的superUser对象,下面相对应的自定义转换器和POJO类
public class MySuperConvertor implements Converter<String, SuperUser>{
@Override
public SuperUser convert(String source) {
String[] values = source.split(",");
Integer id = Integer.valueOf(values[0]);
SuperUser superUser = new SuperUser(values[3], new User(id,values[1],values[2]));
return superUser;
}
}
/**********下面是SuperUser POJO类*********/
package com.mvc.model;
public class SuperUser extends User {
private String name;
//忽略get和set方法
public SuperUser(String name,User user) {
super(user.getId(),user.getUserName(),user.getPassword());
this.name = name;
}
public SuperUser() {
super();
}
@Override
public String toString() {
return "SuperUser [name=" + name + ", toString()=" + super.toString()
+ "]";
}
}
除了配置上面的转换器,还需自定义我们的转换器工厂,在转换器工厂中,我们根据目标类型是User还是其子类SuperUser来调用相应的自定义转换器:
public class MyConvertorFactory implements ConverterFactory<String, User>{
@Override
//T类型必须是User或其子类,Stirng是我们的转换源类
public <T extends User> Converter<String, T> getConverter(
Class<T> targetType) {
if(targetType == User.class){
return (Converter<String, T>) new MyConvertor();
}else{
return (Converter<String, T>) new MySuperConvertor();
}
}
}
2. 注册自定义属性转换器
<!-- 通过:annotation-driven的conversion-service属性来装配我们的类型转换器 -->
<mvc:annotation-driven conversion-service="factoryBean" />
<!-- 通过ConversionServiceFactoryBean注册我们的自定义转换器 -->
<bean class="org.springframework.context.support.ConversionServiceFactoryBean" id="factoryBean" >
<property name="converters"><!-- 在属性converters注册 -->
<list>
<!--这里只要注册我们自定义的转换器工厂即可-->
<bean class="com.mvc.convertor.MyConvertorFactory" />
</list>
</property>
</bean>
3. 配置控制器
在实例1的基础上,我们添加一个新方法
//这是原来的
@RequestMapping("convert")
public String convert( User user){
System.out.println(user);
return "model1";
}
//下面是新添加的方法
@RequestMapping("convertSuper")
public String convert( SuperUser user){
System.out.println(user);
return "model1";
}
4. 测试
运行服务器,我们在游览器中输入:
1. root/convert?user=10,myUserName,myPassword
控制台输出:User [id=10, userName=myUserName, password=myPassword]
2. root/convertSuper?superUser=11,myUserName,myPassword,myName
控制台输出:SuperUser [name=myName, toString()=User [id=11, userName=myUserName, password=myPassword]]
我们根据入参类型,并通过ConvertFactory,完成对同一系列(某一类及其子类)的类型转换
源码下载
本篇文章测试源码可到https://github.com/jeanhao/spring的dataConvertor文件夹下下载
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持亿速云。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。