码迷,mamicode.com
首页 > 编程语言 > 详细

请求参数到表述层的类型转换——SpringMVC

时间:2016-08-15 20:44:53      阅读:222      评论:0      收藏:0      [点我收藏+]

标签:

一、不论是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 方法是另一套逻辑,整个流程现在还没有理太明白。 也没有对调用类型转换器的时机进行说明,在介绍完数据校验后作统一说明。

请求参数到表述层的类型转换——SpringMVC

标签:

原文地址:http://www.cnblogs.com/solverpeng/p/5774185.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!