springMVC4之强大类型转换器实例解析

我们以自定义格式转换器的实现思路,来理解新架构的类型转换器的使用方法,同时在实际开发中,我们可能会有自己的格式转换需求,这个时候我们也可以通过自定义格式转换器来完成这些个性化需求。

自定义格式转换器

完成自定义转换器需要实现以下三个中的任意一个接口: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);
}

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等重写方法
  }
}

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

public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {
}

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

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

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

3. ConvertorFacoty

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

public interface ConverterFactory<S, R> {

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

}

这个接口一个常见的实现类是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);

}

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 + "]";
  }

}

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> 

3. 配置控制器

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

@RequestMapping("convert")
public String convert(User user){
  System.out.println(user);
  return "model1";
}

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()
        + "]";
  }
}

除了配置上面的转换器,还需自定义我们的转换器工厂,在转换器工厂中,我们根据目标类型是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();
    }
  }
}

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> 

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";
}

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)

相关推荐

  • springmvc实现自定义类型转换器示例

    springmvc除了自带的部分类型转换之外,还可以自定义类型转换器,按照以下步骤: 1.写一个类实现Converter接口 package com.hy.springmvc.entities; import org.springframework.core.convert.converter.Converter; import com.google.gson.Gson; public class DepartmentConvertor implements Converter<String,

  • SpringMVC中日期格式的转换

    解决日期提交转换异常的问题 由于日期数据有很多种格式,所以springmvc没办法把字符串转换成日期类型.所以需要自定义参数绑定.前端控制器接收到请求后,找到注解形式的处理器适配器,对RequestMapping标记的方法进行适配,并对方法中的形参进行参数绑定.在springmvc这可以在处理器适配器上自定义Converter进行参数绑定.如果使用<mvc:annotation-driven/>可以在此标签上进行扩展. 1.自定义DataConvertor类, 并实现Convertor接口 p

  • SpringMVC中Json数据格式转换

    1  @RequestBody 作用: @RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容转换为json.xml等格式的数据并绑定到controller方法的参数上. List.action?id=1&name=zhangsan&age=12 本例子应用: @RequestBody注解实现接收http请求的json数据,将json数据转换为java对象  2  @ResponseBody 作

  • Spring MVC登录注册以及转换json数据

    项目结构; 代码如下: BookController package com.mstf.controller; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.codehaus.jackson.map.ObjectMapper; import com.mstf.

  • SpringMVC实现自定义类型转换器

    我们在使用SpringMVC时,常常需要把表单中的参数映射到我们对象的属性中,我们可以在默认的spring-servlet.xml加上如下的配置即可做到普通数据类型的转换,如将String转换成Integer和Double等: <mvc:annotation-driven /> 或 复制代码 代码如下: <bean id="conversionService" class="org.springframework.format.support.Formatt

  • 深入理解Spring MVC的数据转换

    本文主要给大家介绍了关于Spring MVC数据转换的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 数据绑定 SpringMVC负责将request中的信息以一定的方式转换并绑定到处理方法的参数上.整个过程的处理核心是由DataBinder完成.转换流程如下: 1.DataBinder从ServletRequest中获取参数信息: 2.DataBinder获取处理方法的参数: 3.DataBinder调用ConversionService组件数据类型转换和数据格式化

  • SpringMVC对日期类型的转换示例

    在做web开发的时候,页面传入的都是String类型,SpringMVC可以对一些基本的类型进行转换,但是对于日期类的转换可能就需要我们配置. 1.如果查询类使我们自己写,那么在属性前面加上@DateTimeFormat(pattern = "yyyy-MM-dd")  ,即可将String转换为Date类型,如下 @DateTimeFormat(pattern = "yyyy-MM-dd") private Date createTime; 2.如果我们只负责we

  • springMVC4之强大类型转换器实例解析

    我们以自定义格式转换器的实现思路,来理解新架构的类型转换器的使用方法,同时在实际开发中,我们可能会有自己的格式转换需求,这个时候我们也可以通过自定义格式转换器来完成这些个性化需求. 自定义格式转换器 完成自定义转换器需要实现以下三个中的任意一个接口:Convertor<S,T>.GenericConvertor或ConvertorFacoty.下面我们对这些接口进行逐一分析: 1. Convertor<S,T> 这是最为简单的一个接口,定义了从源类到目标类的转换方法.该接口的定义如

  • SpringMVC自定义类型转换器实现解析

    这篇文章主要介绍了SpringMVC自定义类型转换器实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 页面录入的字符串:2019/12/05可以映射到实体的日期属性上,但是如果是录入2019-12-05就会报错400 bad request,想要以2019-12-05日期格式的方式映射到实体的日期属性上,需要自定义类型转换器,主要步骤如下: 1. 自定义类实现Convertro<S,T>接口 2.Springmvc.xml中配置Conv

  • Spring MVC自定义日期类型转换器实例详解

    Spring MVC自定义日期类型转换器实例详解 WEB层采用Spring MVC框架,将查询到的数据传递给APP端或客户端,这没啥,但是坑的是实体类中有日期类型的属性,但是你必须提前格式化好之后返回给它们.说真的,以前真没这样做过,之前都是一口气查询到数据,然后在jsp页面上格式化,最后展示给用户.但是这次不同,这次我纯属操作数据,没有页面.直接从数据库拿数据给它们返数据.它们给我传数据我持久化数据,说到这里一个小问题就默默的来了. 首先把问题还原一下吧(这是一个数据导出功能),下图中用红框圈

  • Docker四种网络类型原理实例解析

    四种网络类型: None:不为容器配置任何网络功能,--net=none Container:与另一个运行中的容器共享Network Namespace,--net=container:containerID(K8S) Host:与宿主机共享Network Namespace,--net=host Bridge:Docker设计的NAT网络模型 下面分别讲解下: none: [root@docker1 centos_zabbix]# docker run -it --network none c

  • springboot日期转换器实现实例解析

    这篇文章主要介绍了springboot日期转换器实现实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 注:该功能并非springboot特有的功能,springmvc同样具有 一.使用方法 创建一个DateConverter类实现Converter接口 注:importorg.springframework.core.convert.converter.Converter; Converter<S,T> @param<S>t

  • python使用json序列化datetime类型实例解析

    使用python的json模块序列化时间或者其他不支持的类型时会抛异常,例如下面的代码: # -*- coding: cp936 -*- from datetime import datetime import json if __name__=='__main__': now = datetime.now() json.dumps({'now':now}) 运行会出现下面的错误信息: Traceback (most recent call last): File "C:\Users\xx\De

  • MySQL InnoDB锁类型及锁原理实例解析

    目录 锁 共享锁 排他锁 意向锁 记录锁 间隙锁 临键锁 死锁 死锁产生条件 行锁发生死锁 表锁发生死锁 锁的释放 事务阻塞 死锁的避免 锁的日志 行锁的原理 不带任何索引的表 带主键索引的表 带唯一索引的表 结论 1.表必定有索引 2.唯一索引数据行加锁,主键索引同样被锁 锁 锁是用来解决事务对数据的并发访问的问题的.MyISAM支持表锁,InnoDB同时支持表锁和行锁. 表加锁语法: lock tables xxx read; lock tables xxx write; unlock ta

  • Java Web开发入门书籍实例解析(总结一)

    从事Java Web开发这一段时间来,对Java 面向对象的思想和MVC开发模式可以说已经熟悉了.我当前参与的项目使用的框架是Spring.SpringMVC.Hibernate.下面我们小编给大家整理一篇教程帮助大家学习javaweb相关知识,感兴趣的朋友可以参考下. 一.基本概念 1.1.WEB开发的相关知识 WEB,在英语中web即表示网页的意思,它用于表示Internet主机上供外界访问的资源. Internet上供外界访问的Web资源分为: 1.静态web资源(如html 页面):指w

  • Python异常对代码运行性能的影响实例解析

    前言 Python的异常处理能力非常强大,但是用不好也会带来负面的影响.我平时写程序的过程中也喜欢使用异常,虽然采取防御性的方式编码会更好,但是交给异常处理会起到偷懒作用.偶尔会想想异常处理会对性能造成多大的影响,于是今天就试着测试了一下. Python异常(谷歌开源风格指南) tip: 允许使用异常, 但必须小心. 定义: 异常是一种跳出代码块的正常控制流来处理错误或者其它异常条件的方式. 优点: 正常操作代码的控制流不会和错误处理代码混在一起. 当某种条件发生时, 它也允许控制流跳过多个框架

  • 通过实例解析java8中的parallelStream

    这篇文章主要介绍了通过实例解析java8中的parallelStream,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 about Stream 什么是流? Stream是java8中新增加的一个特性,被java猿统称为流. Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator.原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作:高级版本的 Stream

随机推荐