标签:
一、不论是SpringMVC 的 JSR-303 数据校验还是自定义类型转换器,都需要配置 <mvc:annotation-driven/>,而添加这个配置后,会自动注册RequestMappingHandlerMapping、
RequestMappingHandlerAdapter 与 ExceptionHandlerExceptionResolver 三个bean。在没添加前,正常的请求都是由 AnnotationMethodHandlerAdapter 进行处理的。我之前
的几篇文章都是以 AnnotationMethodHandlerAdapter 的 handler() 进行分析。在添加后,正常请求是由 RequestMappingHandlerAdapter 的 handler() 进行处理的。它们的
逻辑是不同的。这里就不对源码进行具体说明。
二、Spring 引入了 core.convert 包,提供了一个通用的类型转换系统。
1.在 core.convert.support 包下提供了许多默认的类型转化器,为类型转换提供和极大的方便。
2.自定义类型转换器
(1)实现 Converter 接口
package org.springframework.core.convert.converter; public interface Converter<S, T> { T convert(S source); }
创建自定义类型转换器,只需要实现该接口,参数 S 表示需要转换的类型,T 表示转换后的类型。对于每次调用 convert() 方法,必须保证参数 source 不能为 null。
如果转换失败,可能会抛出异常。特别的,一个 IllegalArgumentException 会被抛出来指明无效的 source 值。
请注意,需要保证转换器是线程安全的。
e1: 需要将 person=name:lily|age:23 转换为对应的 person 对象
自定义的类型转换器:
/** * @author solverpeng * @create 2016-08-15-14:50 */ public class PersonConversionService implements Converter<String, Person>{ Person person = null; @Override public Person convert(String s) { try { if(s != null && s.length() > 0) { String[] strings = s.split("\\|"); person = Person.class.newInstance(); for(String str : strings) { String[] properties = str.split(":"); Field field = Person.class.getDeclaredField(properties[0]); field.setAccessible(true); Class<?> type = field.getType(); if(type.equals(Integer.class)) { field.set(person, Integer.parseInt(properties[1])); continue; } field.set(person, properties[1]); } } } catch(InstantiationException | IllegalAccessException | NoSuchFieldException e) { e.printStackTrace(); } return person; } }
需要在 SpringMVC Config 文件中添加的配置如下:
<bean id="customizeConversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.nucsoft.springmvc.converter.PersonConversionService"/> </set> </property> </bean> <mvc:annotation-driven conversion-service="customizeConversionService"/>
请求:
<a href="testConverter?person=name:lily|age:23">test converter</a>
目标 handler 方法:
@RequestMapping("/testConverter") public String testSpring2Person(Person person) { System.out.println("persont:" + person); return "success"; }
控制台输出:
persont:Person{name=‘lily‘, age=23}
说明:这里不对 <mvc:annotation-driven /> 进行说明,以后会写文章介绍。
在介绍参数获取问题时,对 @RequestParam 的“如果方法的入参类型是一个 Map,不包含泛型类型,并且请求参数名称是被指定” 这种情况没有进行详细说明,这里通过一个例子说明。
参见:http://www.cnblogs.com/solverpeng/p/5733310.html
e2:将 String 转换为 Map,将 params=a:1|b:2 转换为 Map 类型。
创建自定义的类型转换器:
/** * @author solverpeng * @create 2016-08-15-15:40 */ public class String2MapConversionService implements Converter<String, Map<String, Object>>{ @Override public Map<String, Object> convert(String s) { Map<String, Object> map = new HashMap<>(); if(s != null & s.length() > 0) { String[] strings = s.split("\\|"); for(String string : strings) { String[] split = string.split(":"); map.put(split[0], split[1]); } } return map; } }
SpringMVC Config 文件:
<bean id="customizeConversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.nucsoft.springmvc.converter.PersonConversionService"/> <bean class="com.nucsoft.springmvc.converter.String2MapConversionService"/> </set> </property> </bean> <mvc:annotation-driven conversion-service="customizeConversionService"/>
请求:
<a href="testConverter2?params=a:1|b:2">test converter2</a>
目标 handler 方法:
@RequestMapping("/testConverter2") public String testString2Map(@RequestParam("params") Map map) { System.out.println(map); return "success"; }
控制台输出:
{b=2, a=1}
(2)ConverterFactory
package org.springframework.core.convert.converter; public interface ConverterFactory<S, R> { <T extends R> Converter<S, T> getConverter(Class<T> targetType); }
如果希望将一种类型转换为另一种类型及其子类对象时,那么使用这个接口。
e:num=23&num2=33.33 将 num 转换为对应的 Integer 类型,将 num2 转换为对应的 Double 类型。
类型转换器参见:org.springframework.core.convert.support.StringToNumberConverterFactory
final class StringToNumberConverterFactory implements ConverterFactory<String, Number> { @Override public <T extends Number> Converter<String, T> getConverter(Class<T> targetType) { return new StringToNumber<T>(targetType); } private static final class StringToNumber<T extends Number> implements Converter<String, T> { private final Class<T> targetType; public StringToNumber(Class<T> targetType) { this.targetType = targetType; } @Override public T convert(String source) { if (source.length() == 0) { return null; } return NumberUtils.parseNumber(source, this.targetType); } } }
请求:
<a href="testString2Number?num=23&num2=33.33">test String to Number</a>
目标 handler 方法:
@RequestMapping("/testString2Number") public String testString2Number(@RequestParam("num") Integer num, @RequestParam("num2") Double num2) { System.out.println("num:" + num); System.out.println("num2:" + num2); return "success"; }
控制台输出:
num:23
num2:33.33
还有一个 GenericConverter ,我没看太明白,不做说明。待以后掌握了再做补充。
三、总结
介绍了 Spring 默认的类型转换器,以及如何自定义类型转换器,通常情况下,通过实现 Convert 接口就能完成大部分转换。没有对原理进行说明,因为使用 RequestMappingHandlerAdapter 后,
它的 handler 方法是另一套逻辑,整个流程现在还没有理太明白。 也没有对调用类型转换器的时机进行说明,在介绍完数据校验后作统一说明。
标签:
原文地址:http://www.cnblogs.com/solverpeng/p/5774185.html