04springMVC数据类型转换

  •  数据类型转换简介
  •  Spring Web MVC中的数据类型转换
  •  内建的类型转换器
  •  自定义类型转换器

1      数据类型转换简介

    当从页面提交数据到后台Action的时候,通过请求发送的数据,通常都是字符串类型的,不能满足后台Model中的数据类型的需要,因此需要进行数据类型转换。

从Spring3开始,我们可以使用如下架构进行类型转换、验证及格式化:

 

 

基本的流程:

①     类型转换:内部的ConversionService会根据S源类型/T目标类型自动选择相应的Converter SPI进行类型转换,而且是强类型的,能在任意类型数据之间进行转换;

②     数据验证:支持JSR-303验证框架,如将@Valid放在需要验证的目标类型上即可;

②     格式化显示:其实就是任意目标类型---->String的转换,完全可以使用Converter SPI完成。

 

Spring为了更好的诠释格式化/解析功能提供了Formatter SPI,支持根据Locale信息进行格式化/解析,而且该套SPI可以支持字段/参数级别的细粒度格式化/解析。

Formatter SPI最大特点是能进行字段/参数级别的细粒度解析/格式化控制,即使是Converter SPI也是粗粒度的(到某个具体类型,而不是其中的某个字段单独控制),目前Formatter SPI还不是很完善。Formatter SPI内部实现实际委托给Converter SPI进行转换,即约束为解析/格式化String<---->任意目标类型。

2      Spring Web MVC中的数据类型转换

在Spring Web MVC环境中,数据类型转换、验证及格式化通常是这样使用的:

 

①类型转换:首先表单数据(全部是字符串)通过WebDataBinder进行绑定到命令对象,内部通过Converter SPI实现;

②数据验证:使用JSR-303验证框架进行验证;

③格式化显示:展示通过Converter SPI格式化的数据和错误信息。

3      内建的类型转换器

第一组:标量转换器

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时会自动注册。

4      自定义类型转换器

通过一个示例来说明,实现自定义String--->PhoneNumberModel的转换器:

 

需求:将座机号码转换成区号和号码两个部分保存

1)         转换器

 1 package com.inspur.converter;
 2 
 3 import java.util.regex.Matcher;
 4 import java.util.regex.Pattern;
 5 import org.springframework.core.convert.converter.Converter;
 6 import org.springframework.util.StringUtils;
 7 import com.inspur.pojo.PhoneNumberModel;
 8 
 9 public class StringToPhoneNumberConverter implements Converter<String, PhoneNumberModel> {
10     Pattern pattern = Pattern.compile("^(\\d{3,4})-(\\d{7,8})$");
11 
12     public PhoneNumberModel convert(String source) {
13         if (!StringUtils.hasLength(source)) {
14             // ①如果source为空返回null
15             return null;
16         }
17         Matcher matcher = pattern.matcher(source);
18         if (matcher.matches()) {
19             // ②如果匹配进行转换
20             PhoneNumberModel phoneNumber = new PhoneNumberModel();
21             phoneNumber.setAreaCode(matcher.group(1));
22             phoneNumber.setPhoneNumber(matcher.group(2));
23             return phoneNumber;
24         } else {
25             // ③如果不匹配转换失败
26             throw new IllegalArgumentException(String.format(
27                     "类型转换失败,需要格式[010-12345678],但格式是[%s]", source));
28         }
29     }
30 }

2)         使用的model 

1 public class PhoneNumberModel {
2     private String areaCode;//区号
3     private String phoneNumber;//电话号码
4     //省略get/set……
5 }

3)         简单的测试代码 

 1 package com.inspur.test;
 2 import org.springframework.core.convert.support.DefaultConversionService;
 3 import com.inspur.converter.StringToPhoneNumberConverter;
 4 import com.inspur.pojo.PhoneNumberModel;
 5 public class ConverterTest {
 6     /**
 7      * 需求:将座机号码转换成区号和号码两个部分保存
 8      * @param args
 9      */
10     public static void main(String[] args) {
11         DefaultConversionService conversionService = new DefaultConversionService();
12         conversionService.addConverter(new StringToPhoneNumberConverter());
13         String phoneNumberStr = "010-12345678";
14         PhoneNumberModel phoneNumber = conversionService.convert(phoneNumberStr, PhoneNumberModel.class);
15         System.out.println("区号==" + phoneNumber.getAreaCode()+"  号码==" + phoneNumber.getPhoneNumber());
16     }
17 }

注册ConversionService实现和自定义的类型转换器

4)         集成到Spring Web MVC环境

1 <!-- 注册ConversionService实现和自定义的类型转换器 -->
2 <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
3     <property name="converters">
4         <list>
5             <bean class="com.inspur.converter.StringToPhoneNumberConverter" />
6         </list>
7     </property>
8 </bean>

converters:注册我们自定义的类型转换器,此处注册了String--->PhoneNumberModel。FormattingConversionServiceFactoryBean:是FactoryBean实现,默认使用DefaultFormattingConversionService转换器服务实现;

  • 在<mvc:annotation-drive>里面配置conversion-service属性

示例:<mvc:annotation-driven conversion-service="conversionService">

 

posted @ 2018-02-05 17:50  silvan_happy  阅读(453)  评论(0编辑  收藏  举报