spring mvc学习心得(一)数据类型转换

来源:互联网 发布:mac office 生成目录 编辑:程序博客网 时间:2024/05/18 08:26

数据类型转换

一、摘要

在一次http请求到响应的过程中,存在各种数据转换操作,现在要分析的是spring mvc数据转换,它的上游数据来源是ServletRequest,下游是处理方法(也就是controller层的各个方法),总而言之就是把ServletRequest 请求参数封装到处理器方法入参中

1.使用场景

  • 一般场景,例如在form表单登录时,需要提交用户名和密码到处理器方法中
  • 状态int值转换为状态枚举(1正常、0禁用、-1删除)CommonStatusEnum(NORMAL、FORBIDDEN、DELETED)
  • 日期字符串转换为Date
  • 等等…

2. 相关类

  • Converter 接口
  • ConverterFactory 接口
  • GenericConverter 接口
  • ConversionService 接口
  • ConversionServiceFactoryBean

二、各个类使用及其分析

1. Converter

最简单的一个转换器接口,接口定义如下

public interface Converter<S, T> {  T convert(S var1);}  

2. ConverterFactory

可以实现很多同质转换器,也就是目标类存在同一个父类,例如:String转换成Number及其子类,其接口定义如下

public interface ConverterFactory<S, R> {      <T extends R> Converter<S, T> getConverter(Class<T> var1);  }  

下面是我自己定义的枚举转换器

public class ValueToEnumConverterFactory implements ConverterFactory<String, IEnum> {    //T为目标类型,也就是需要转换成什么类型,<T extends IEnum> 则说明目标类型要是IEnum的子类才会使用该转换器    public <T extends IEnum> Converter<String, T> getConverter(Class<T> targetType) {        Class<?> enumType = targetType;        while (enumType != null && !enumType.isEnum()) {            enumType = enumType.getSuperclass();        }        if (enumType == null) {            throw new IllegalArgumentException("The target type " + targetType.getName() + " does not refer to an enum");        }        return new StringToEnum(enumType);    }    private class StringToEnum<T extends IEnum> implements Converter<String, T> {        private final Class<T> enumType;        public StringToEnum(Class<T> enumType) {            this.enumType = enumType;        }        public T convert(String source) {            if (source.length() == 0)                 return null;            return EnumUtil.convert(this.enumType, Integer.valueOf(source.trim()));//根据id和具体枚举类型完成 从int 类型到对应枚举类型的转换        }    }}

通过这个转换器可以自动实现int型到枚举类型的自动转换

3. GenericConverter

这个接口是实现转换器最复杂的接口,因为他可以考虑源类型和目标类型所在宿主类的上下文信息,其接口定义如下

public interface GenericConverter {    Set<GenericConverter.ConvertiblePair> getConvertibleTypes();    Object convert(Object var1, TypeDescriptor var2, TypeDescriptor var3);    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;        }        public boolean equals(Object other) {            if(this == other) {                return true;            } else if(other != null && other.getClass() == GenericConverter.ConvertiblePair.class) {                GenericConverter.ConvertiblePair otherPair = (GenericConverter.ConvertiblePair)other;                return this.sourceType == otherPair.sourceType && this.targetType == otherPair.targetType;            } else {                return false;            }        }        public int hashCode() {            return this.sourceType.hashCode() * 31 + this.targetType.hashCode();        }        public String toString() {            return this.sourceType.getName() + " -> " + this.targetType.getName();        }    }}

不想写例子了,这个转换器不常用(主要是懒字当头)

4. ConversionService与ConversionServiceFactoryBean

以上三个转换器需要装载到ConversionService才会生效

     <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">        <property name="converters">            <set>                <bean class="com.ouryue.base.convert.ValueToEnumConverterFactory"/>                <bean class="com.ouryue.base.convert.StringToDateConverter"></bean>            </set>        </property>    </bean><mvc:annotation-driven conversion-service="conversionService"/><!--装配自定义的conversionService到spingweb上下文-->
  • conversionService 是spring类型转换体系的核心接口,ConversionServiceFactoryBean为其工厂方法
  • ConversionServiceFactoryBean会把其属性converters中的参数封装到创建的ConversionService中,且内建了很多默认转换器,可以完成大多数java类型转换工作。除了包括将String 转换为基本类型对象外,还包括String、Number、Array、Collection、Map、Properties及Object

三、总结

  • 对于这三个实现转换器的接口,绝大部分情况是使用Converter、ConverterFactory
  • 虽然从继承结构和内部属性来看,Converter、ConverterFactory和GenericConverter没有什么关系,注册到ConversionService时会被转换为GenericConverter
public void addConverter(Converter<?, ?> converter) {        ResolvableType[] typeInfo = this.getRequiredTypeInfo(converter.getClass(), Converter.class);        if(typeInfo == null && converter instanceof DecoratingProxy) {            typeInfo = this.getRequiredTypeInfo(((DecoratingProxy)converter).getDecoratedClass(), Converter.class);        }        if(typeInfo == null) {            throw new IllegalArgumentException("Unable to determine source type <S> and target type <T> for your Converter [" + converter.getClass().getName() + "]; does the class parameterize those types?");        } else {            this.addConverter((GenericConverter)(new GenericConversionService.ConverterAdapter(converter, typeInfo[0], typeInfo[1])));//此处进行转换        }    }

Converter、ConverterFactory存在的意义就是为了降低转换器的使用难度吧,认证了那句话:没有什么是封装一层解决不了的,太难了?那就封装一层吧

原创粉丝点击