第四章:数据类型转换——深入浅出学Spring Web MVC

  
数据类型转换简介
当从页面提交数据到后台Action的时候,通过请求发送的数据,通常都是字符串类型的,不能满足后台Model中的数据类型的需要,因此需要进行数据类型转换。
从Spring3开始,我们可以使用如下架构进行类型转换、验证及格式化
 
n基本的流程
①:类型转换:内部的ConversionService会根据S源类型/T目标类型自动选择相应的Converter SPI进行类型转换,而且是强类型的,能在任意类型数据之间进行转换;
②:数据验证:支持JSR-303验证框架,如将@Valid放在需要验证的目标类型上即可;
③:格式化显示:其实就是任意目标类型---->String的转换,完全可以使用Converter SPI完成。
nSpring为了更好的诠释格式化/解析功能提供了Formatter SPI,支持根据Locale信息进行格式化/解析,而且该套SPI可以支持字段/参数级别的细粒度格式化/解析, 流程如下:
①:类型解析(转换):String---->T类型目标对象的解析,和PropertyEditor类似;
③:格式化显示:任意目标类型---->String的转换,和PropertyEditor类似。
Formatter SPI最大特点是能进行字段/参数级别的细粒度解析/格式化控制,即使是Converter SPI也是粗粒度的(到某个具体类型,而不是其中的某个字段单独控制),目前Formatter SPI还不是很完善。
Formatter SPI内部实现实际委托给Converter SPI进行转换,即约束为解析/格式化String<---->任意目标类型。
 
在Spring Web MVC环境中,数据类型转换、验证及格式化通常是这样使用的
①、类型转换:首先表单数据(全部是字符串)通过WebDataBinder进行绑定到命令对象,内部通过Converter SPI实现;
②:数据验证:使用JSR-303验证框架进行验证;
③:格式化显示:在表单页面可以通过如下方式展示通过内部通过Converter SPI格式化的数据和错误信息:
 
内建的类型转换器
第一组:标量转换器
1:StringToBooleanConverter :String----->Boolean
如:true:true/on/yes/1; false:false/off/no/0
2:ObjectToStringConverter :Object----->String ,调用toString方法转换
3:StringToNumberConverterFactory :String----->Number(如Integer、Long等)
4:NumberToNumberConverterFactory :Number子类型(Integer、Long、Double等)<——> Number子类型(Integer、Long、Double等)
5:StringToCharacterConverter :String----->java.lang.Character,取字符串第一个字符
6:NumberToCharacterConverter :Number子类型(Integer、Long、Double等)——> java.lang.Character
7:CharacterToNumberFactory :java.lang.Character ——>Number子类型(Integer、Long、Double等)
8:StringToEnumConverterFactory :String----->enum类型,通过Enum.valueOf将字符串转换为需要的enum类型
9:EnumToStringConverter :enum类型----->String,返回enum对象的name()值
10:StringToLocaleConverter :String----->java.util.Local
11:PropertiesToStringConverter :java.util.Properties----->String,默认通过ISO-8859-1解码
12:StringToPropertiesConverter :String----->java.util.Properties,默认使用ISO-8859-1编码
 
第二组:集合、数组相关转换器
1:ArrayToCollectionConverter :任意S数组---->任意T集合(List、Set)
2:CollectionToArrayConverter :任意T集合(List、Set)---->任意S数组
3:ArrayToArrayConverter :任意S数组<---->任意T数组
4:CollectionToCollectionConverter :任意T集合(List、Set)<---->任意T集合(List、Set),即集合之间的类型转换
5:MapToMapConverter :Map<---->Map之间的转换
6:ArrayToStringConverter :任意S数组---->String类型
7:StringToArrayConverter :String--->数组,默认“,”分割,且去除字符串的两边空格
8:ArrayToObjectConverter :任意S数组---->任意Object的转换,(如果目标类型和源类型兼容,直接返回源对象;否则返回S数组的第一个元素并进行类型转换)
9:ObjectToArrayConverter :Object----->单元素数组
10:CollectionToStringConverter :任意T集合(List、Set)---->String类型
11:StringToCollectionConverter :String----->集合(List、Set),默认通过“,”分割,且去除字符串的两边空格(trim)
12:CollectionToObjectConverter :任意T集合---->任意Object的转换,(如果目标类型和源类型兼容,直接返回源对象;否则返回S数组的第一个元素并进行类型转换)
13:ObjectToCollectionConverter :Object----->单元素集合
 
第三组:默认(fallback)转换器
之前的转换器不能转换时调用
1:ObjectToObjectConverter :
Object(S)----->Object(T),首先尝试valueOf进行转换、没有则尝试new 构造器(S)
2:IdToEntityConverter :
Id(S)----->Entity(T),查找并调用public static T find[EntityName](S)获取目标对象,EntityName是T类型的简单类型
3:FallbackObjectToStringConverter :
Object----->String,ConversionService作为恢复使用,即其他转换器不能转换时调用(执行对象的toString()方法)
 
如上的转换器在使用转换服务实现DefaultConversionService和DefaultFormattingConversionService时会自动注册
 
n通过一个示例来说明,实现自定义String----->PhoneNumberModel的转换器
public class StringToPhoneNumberConverter implements Converter<String, PhoneNumberModel> {
Pattern pattern = Pattern.compile("^(\\d{3,4})-(\\d{7,8})$");
public PhoneNumberModel convert(String source) {
if(!StringUtils.hasLength(source)) {
//①如果source为空 返回null
return null;
}
Matcher matcher = pattern.matcher(source);
if(matcher.matches()) {
//②如果匹配 进行转换
PhoneNumberModel phoneNumber = new PhoneNumberModel();
phoneNumber.setAreaCode(matcher.group(1));
phoneNumber.setPhoneNumber(matcher.group(2));
return phoneNumber;
} else {
//③如果不匹配 转换失败
throw new IllegalArgumentException(String.format("类型转换失败,需要格式[010-12345678],但格式是[%s]", source));
}
}  }
 
n使用的PhoneNumberModel
public class PhoneNumberModel {
private String areaCode;//区号
private String phoneNumber;//电话号码
//省略getter/setter
}
n简单的测试代码如下:
public static void main(String[] args) {
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToPhoneNumberConverter());
 
String phoneNumberStr = "010-12345678";
PhoneNumberModel phoneNumber = conversionService.convert(phoneNumberStr, PhoneNumberModel.class);
System.out.println("phoneNumber=="+phoneNumber);
}
 
n集成到Spring Web MVC环境
1:注册ConversionService实现和自定义的类型转换器
<bean id= "conversionService" class= "org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name= "converters">
       <list>
        <bean class= "cn.javass.springmvc.convert.StringToPhoneNumberConverter"/>
        </list>
    </property>
</bean>
FormattingConversionServiceFactoryBean:是FactoryBean实现,默认使用DefaultFormattingConversionService转换器服务实现;
converters:注册我们自定义的类型转换器,此处注册了String--->PhoneNumberModel。
 
n2:通过ConfigurableWebBindingInitializer注册ConversionService
<bean id= "webBindingInitializer" class= "org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name= "conversionService" ref= "conversionService"/>
</bean>
 
n3:注册ConfigurableWebBindingInitializer到RequestMappingHandlerAdapter
<bean class= "org.springframework.web.servlet.mvc.method.annotation.RequestMappi ngHandlerAdapter">
<property name= "webBindingInitializer" ref= "webBindingInitializer"/>
</bean>
 
通过如上配置,我们就完成了Spring3.0的类型转换系统与Spring Web MVC的集成。
 
n如果是使用的<mvc:annotation-drive>的方式,那么上面的第2和3步就不用做了,直接在<mvc:annotation-drive>里面配置conversion-service属性即可,示例:
<mvc:annotation-driven
  conversion-service="conversionService"
>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值