springMVC4(10)强大类型转换器实例解析

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: <div class="markdown_views"><p>在<a href="http://blog.csdn.net/qwe6112071/article/details/51049743">《springMVC4(9)属性编辑器剖析入参类型转换原理 》</a>一文中,我们通过分析Sping内置的属性编辑器来理解springMVC是如何完成请求参数到入参的类型的转换的

《springMVC4(9)属性编辑器剖析入参类型转换原理 》一文中,我们通过分析Sping内置的属性编辑器来理解springMVC是如何完成请求参数到入参的类型的转换的。而在新版本中,SpringMVC使用了新的架构来完成类型转换的工作,而且它的工作更加强大,支持格式化参数输入输出,它的另一个实例可见我的另一篇文章《springMVC4(4)json与对象互转实例解析请求响应数据转换器》。在文中,我们使用了Spring内置的格式转换器完成了服务端输入输出过程中json字符串与java对象的相互转换。此外,还提到了其他多种的格式转换器,如xml、ByteArray等。下面,我们以自定义格式转换器的实现思路,来理解新架构的类型转换器的使用方法,同时在实际开发中,我们可能会有自己的格式转换需求,这个时候我们也可以通过自定义格式转换器来完成这些个性化需求。

自定义格式转换器

完成自定义转换器需要实现以下三个中的任意一个接口:Convertor<S,T>、GenericConvertor或ConvertorFacoty。下面我们对这些接口进行逐一分析:

1. Convertor<S,T>

这是最为简单的一个接口,定义了从源类到目标类的转换方法。该接口的定义如下

public interface ConverterFactory<S, R> {
    //将S类型的对象转换为T类型,R为目标类型T的基类
    <T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
AI 代码解读

2. GenericConvertor

GenericConvertor会根据源类对象及目标类对象所在宿主类的上下文信息进行类型转换工作,该接口的定义如下:

public interface GenericConverter {

    //ConvertiblePair包含了源类型和目标类型,它的定义在下面
    Set<ConvertiblePair> getConvertibleTypes();

    //TypeDescriptor包含了需转换类型对象所在宿主类的信息,我们根据此信息,完成源到目标类型的转换
    Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);


    /**
     * 内部类定义
     */
    public static final class ConvertiblePair {
        //源类型
        private final Class<?> sourceType;
        //目标类类型
        private final Class<?> targetType;

        /**
         * 创建一个源-目标对子
         */
        public ConvertiblePair(Class<?> sourceType, Class<?> targetType) {
            Assert.notNull(sourceType, "Source type must not be null");
            Assert.notNull(targetType, "Target type must not be null");
            this.sourceType = sourceType;
            this.targetType = targetType;
        }

        public Class<?> getSourceType() {
            return this.sourceType;
        }

        public Class<?> getTargetType() {
            return this.targetType;
        }
        //忽略hashCode\equals\toString等重写方法
    }
}
AI 代码解读

我们常使用其实现类接口:

public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {
}
AI 代码解读

它除了实现GenericConverter,还实现了另一个“条件转换器”:

public interface ConditionalConverter {
    /**
     * Should the conversion from {@code sourceType} to {@code targetType} currently under
     */
    //根据源类型和目标类型所在宿主类型的上下文信息判断是否要进行类型转换
    boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}
AI 代码解读

在实际开发中,我们能实现此接口自定义转换器,来根据具体类型上下文来灵活配置我们的类型转换

3. ConvertorFacoty

这是一个将我们源类转换为一个目标类或其子类的”多转换器共存“接口工厂。它的定义如下:

public interface ConverterFactory<S, R> {

    //获取将源类转换为特定R类或其子类的转换器
    <T extends R> Converter<S, T> getConverter(Class<T> targetType);

}
AI 代码解读

这个接口一个常见的实现类是StringToNumberConvertor,能将String类型数据转换为Number类型或其子类:Long,Integer,Double等。

注册自定义转换器

ConversionService

ConversionService则是Spring类型转换体系的核心接口,ConversionService接口的定义如下:


package org.springframework.core.convert;

public interface ConversionService {

    //判断sourceType是否可以转换为targetType
    boolean canConvert(Class<?> sourceType, Class<?> targetType);

    //TypeDescriptor描述了转换类的各类上下文信息,在类型转换实现方法中可以根据这些信息进行灵活控制
    //比如这里通过源类和目标类的上下文信息判断是否可以进行转换
    boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);

    //将source转换为targetType
    <T> T convert(Object source, Class<T> targetType);

    //利用源、目标类的上下文信息,将源类型转换为目标类型
    Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);

}
AI 代码解读

ConversionServiceFactoryBean

实现以上类型完成我们的自定义转换器定义后,我们还要在Spring容器中通过ConversionServiceFactoryBean注册创建后才能使用。
ConversionServiceFactoryBean创建了我们的ConversionService很多内置转换器,利用这些转换器,我们可以完成大部分常见的类型转换工作
而如果我们想使用自定义的类型转换器,可以通过ConversionServiceFactoryBean的convertor属性来注册。

实例分析1:测试Convertor

通过以上的分析,我们接下来尝试自定实现Convert

1. 自定义属性转换器

public class MyConvertor implements Converter<String, User>{

    @Override
    public User convert(String source) {//source为要转换的字符串
        String[] values = source.split(",");//根据我们的需求,用逗号来区分
        Integer id = Integer.valueOf(values[0]);
        User user = new User(id,values[1],values[2]);
        return user;
    }
}
/**********下面是我们的UserPOJO类**********/
public class User {
    public User() {
        super();
    }
    private Integer id;
    private String userName;
    private String password;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public User(Integer id, String userName, String password) {
        super();
        this.id = id;
        this.userName = userName;
        this.password = password;
    }
    //忽略get和set方法
    @Override
    public String toString() {
        return "User [id=" + id + ", userName=" + userName + ", password="
                + password + "]";
    }

}
AI 代码解读

2. 注册自定义属性转换器

<!-- 通过:annotation-driven的conversion-service属性来装配我们的类型转换器 -->
<mvc:annotation-driven conversion-service="factoryBean" />
<!-- 通过ConversionServiceFactoryBean注册我们的自定义转换器 -->
<bean class="org.springframework.context.support.ConversionServiceFactoryBean" id="factoryBean" >
    <property name="converters"><!-- 在属性converters注册 -->
        <list>
            <bean class="com.mvc.convertor.MyConvertor" />
        </list>
    </property>
</bean> 
AI 代码解读

3. 配置控制器

在控制层,我们通过以下方法测试我们的转换器

@RequestMapping("convert")
public String convert(User user){
    System.out.println(user);
    return "model1";
}
AI 代码解读

4. 测试

启动服务器,在游览器中访问[项目根路径]/convert?user=11,myUserName,myPassword。
控制台会打印信息:User [id=11, userName=myUserName, password=myPassword]。即springMVC帮我们完成了字符串到User类型的转换。**这里需注意的是,我们的请求参数名”user”是和控制层方法入参变量User user像对应的,才能完成参数绑定进而转换类型

实例分析2:测试ConvertorFactory

1. 自定义类型转换器

在实例1的基础上,我们添加User的一个子类:SuperUser,作为”super”子类,它拥有了自己的专属名字,我们将字符串”11,myUserName,myPassword,myName“转换为我们的superUser对象,下面相对应的自定义转换器和POJO类

public class MySuperConvertor implements Converter<String, SuperUser>{

    @Override
    public SuperUser convert(String source) {
        String[] values = source.split(",");
        Integer id = Integer.valueOf(values[0]);
        SuperUser superUser = new SuperUser(values[3],  new User(id,values[1],values[2]));
        return superUser;
    }
}
/**********下面是SuperUser POJO类*********/
package com.mvc.model;

public class SuperUser extends User {
    private String name;
    //忽略get和set方法

    public SuperUser(String name,User user) {
        super(user.getId(),user.getUserName(),user.getPassword());
        this.name = name;
    }

    public SuperUser() {
        super();
    }

    @Override
    public String toString() {
        return "SuperUser [name=" + name + ", toString()=" + super.toString()
                + "]";
    }
}
AI 代码解读

除了配置上面的转换器,还需自定义我们的转换器工厂,在转换器工厂中,我们根据目标类型是User还是其子类SuperUser来调用相应的自定义转换器:

public class MyConvertorFactory implements ConverterFactory<String, User>{

    @Override
    //T类型必须是User或其子类,Stirng是我们的转换源类
    public <T extends User> Converter<String, T> getConverter(

            Class<T> targetType) {
        if(targetType == User.class){
            return  (Converter<String, T>) new MyConvertor();
        }else{
            return (Converter<String, T>) new MySuperConvertor();
        }
    }
}
AI 代码解读

2. 注册自定义属性转换器

<!-- 通过:annotation-driven的conversion-service属性来装配我们的类型转换器 -->
<mvc:annotation-driven conversion-service="factoryBean" />
<!-- 通过ConversionServiceFactoryBean注册我们的自定义转换器 -->
<bean class="org.springframework.context.support.ConversionServiceFactoryBean" id="factoryBean" >
    <property name="converters"><!-- 在属性converters注册 -->
        <list>
            <!--这里只要注册我们自定义的转换器工厂即可-->
            <bean class="com.mvc.convertor.MyConvertorFactory" />
        </list>
    </property>
</bean> 
AI 代码解读

3. 配置控制器

在实例1的基础上,我们添加一个新方法

//这是原来的
@RequestMapping("convert")
public String convert( User user){
    System.out.println(user);
    return "model1";
}
//下面是新添加的方法
@RequestMapping("convertSuper")
public String convert( SuperUser user){
    System.out.println(user);
    return "model1";
}
AI 代码解读

4. 测试

运行服务器,我们在游览器中输入:
1. root/convert?user=10,myUserName,myPassword
控制台输出:User [id=10, userName=myUserName, password=myPassword]
2. root/convertSuper?superUser=11,myUserName,myPassword,myName
控制台输出:SuperUser [name=myName, toString()=User [id=11, userName=myUserName, password=myPassword]]

我们根据入参类型,并通过ConvertFactory,完成对同一系列(某一类及其子类)的类型转换

源码下载

本篇文章测试源码可到https://github.com/jeanhao/spring的dataConvertor文件夹下下载

目录
打赏
0
0
0
0
58
分享
相关文章
阿里云服务器经济型e实例解析:性能、稳定性与兼顾成本
阿里云经济型e云服务器以其高性价比、稳定可靠的性能以及灵活多样的配置选项,成为了众多企业在搭建官网时的首选。那么,阿里云经济型e云服务器究竟怎么样?它是否能够满足企业官网的搭建需求?本文将从性能表现、稳定性与可靠性、成本考虑等多个方面对阿里云经济型e云服务器进行深入剖析,以供大家参考选择。
147 37
|
2月前
|
Spring底层架构核心概念解析
理解 Spring 框架的核心概念对于开发和维护 Spring 应用程序至关重要。IOC 和 AOP 是其两个关键特性,通过依赖注入和面向切面编程实现了高效的模块化和松耦合设计。Spring 容器管理着 Beans 的生命周期和配置,而核心模块为各种应用场景提供了丰富的功能支持。通过全面掌握这些核心概念,开发者可以更加高效地利用 Spring 框架开发企业级应用。
89 18
Java二维数组的使用技巧与实例解析
本文详细介绍了Java中二维数组的使用方法
59 15
智慧工地云平台的技术架构解析:微服务+Spring Cloud如何支撑海量数据?
慧工地解决方案依托AI、物联网和BIM技术,实现对施工现场的全方位、立体化管理。通过规范施工、减少安全隐患、节省人力、降低运营成本,提升工地管理的安全性、效率和精益度。该方案适用于大型建筑、基础设施、房地产开发等场景,具备微服务架构、大数据与AI分析、物联网设备联网、多端协同等创新点,推动建筑行业向数字化、智能化转型。未来将融合5G、区块链等技术,助力智慧城市建设。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
让UE自动运行Python脚本:实现与实例解析
本文介绍如何配置Unreal Engine(UE)以自动运行Python脚本,提高开发效率。通过安装Python、配置UE环境及使用第三方插件,实现Python与UE的集成。结合蓝图和C++示例,展示自动化任务处理、关卡生成及数据分析等应用场景。
224 5
【C语言】进制转换无难事:二进制、十进制、八进制与十六进制的全解析与实例
进制转换是计算机编程中常见的操作。在C语言中,了解如何在不同进制之间转换数据对于处理和显示数据非常重要。本文将详细介绍如何在二进制、十进制、八进制和十六进制之间进行转换。
124 5
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
289 2
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
98 2
深入解析:如何用 Spring Boot 实现分页和排序
深入解析:如何用 Spring Boot 实现分页和排序
206 2

推荐镜像

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等