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

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

时间: 2024-12-06 06:08:24

请求参数到表述层的类型转换——SpringMVC的相关文章

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

一.简介 说明:HTTP 协议传输数据没有类型的概念,在服务器端是通过 request.getParameter().request.getParameterValue() 方法得到请求参数为 String 或 String[] 类型. 但是这样使用起来不方便,我们希望开源框架能自动的完成类型转换,到使用的时候能直接获取目标类型. 二.Struts2 类型转换 1. Struts2 本身完成了字符串类型到基本数据类型的自动转换,其他情况需要我们定义自己的类型转换器. 2.类型转换失败时的处理方式

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

一.简介 说明:HTTP 协议传输数据没有类型的概念,在服务器端是通过 request.getParameter().request.getParameterValue() 方法得到请求参数为 String 或 String[] 类型. 但是这样使用起来不方便,我们希望开源框架能自动的完成类型转换,到使用的时候能直接获取目标类型. 二.Struts2 类型转换 1. Struts2 本身完成了字符串类型到基本数据类型的自动转换,其他情况需要我们定义自己的类型转换器.= 2.类型转换失败时的处理方

springmvc源码分析之请求参数、类型转换、数据绑定

前言 通过前面的分析,我们知道了请求过来,怎么找到相应的handlerMethod.本篇对请求参数的转换进行讲解. 概述 在进行分析之前,我们回到DispatcherServlet的doDispatch方法去看一下,请求过来后真正执行业务控制器的入口是从HandlerAdapter的handle方法.我们熟悉一下几个类,HandlerAdapter.RequestMappingHandlerAdapter. HandlerAdapter接口我们关注supports方法.handle方法.supp

阶段3 3.SpringMVC&#183;_02.参数绑定及自定义类型转换_1 请求参数绑定入门

请求参数的绑定 参数绑定 创建新的页面 给方法加上注解 前面没有斜线 重新部署项目 传递一个username的值 后台方法接收 重新部署项目 再传一个password的值 再输出password javaBean 传递属性比较多的情况 原文地址:https://www.cnblogs.com/wangjunwei/p/11374284.html

SpringMVC简单映射请求参数介绍

1. @RequestMapping @RequestMapping除了修饰方法, 还可来修饰类 1). 类定义处: 提供初步的请求映射信息.相对于 WEB 应用的根目录 2). 方法处: 提供进一步的细分映射信息. 相对于类定义处的 URL.若类定义处未标注 @RequestMapping,则方法处标记的 URL相对于 WEB 应用的根目录 @RequestMapping("/testRequestMapping") public String testRequestMapping(

SpringMVC RequestMapping &amp; 请求参数

SpringMVC 概述 Spring 为展现层提供的基于 MVC 设计理念的优秀的Web 框架,是目前最主流的 MVC 框架之一 Spring3.0 后全面超越 Struts2,成为最优秀的 MVC 框架 Spring MVC 通过一套 MVC 注解,让 POJO 成为处理请求的控制器,而无须实现任何接口. 支持 REST 风格的 URL 请求 采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性 HelloWorld 步骤: –加入 jar 包 –在 web.xml 中配置

Springmvc之接受请求参数二

Springmvc之接受请求参数 准备工作 新建一个表单提交 请求地址: http://localhost:8080/ProjectName/user/login.do <form action="<%=request.getContextPath()%>/user/login.do" method="post"> username:<input type="text" name="username&quo

SpringMVC请求参数北京PK10平台出租和响应结果全局加密和解密

前段时间在做一个对外的网关项目,涉及到加密和解密模块,这里详细分析解决方案和适用的场景.为了模拟真实的交互场景,先定制一下整个交互流程.第三方传输(包括请求和响应)数据报文包括三个部分: 1.timestamp,long类型,时间戳.2.data,String类型,实际的业务请求数据转化成的Json字符串再进行加密得到的密文.3.sign,签名,生成规则算法伪代码是SHA-256(data=xxx&timestamp=11111),防篡改.为了简单起见,加密和解密采用AES,对称秘钥为"

SpringMVC 完美解决PUT请求参数绑定问题(普通表单和文件表单)

一 解决方案 修改web.xml配置文件 将下面配置拷贝进去(在原有的web-app节点里面配置 其它配置不变) <!-- 处理PUT提交参数(只对基础表单生效) --> <filter> <filter-name>httpPutFormContentFilter</filter-name> <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filt