zoukankan      html  css  js  c++  java
  • SpringMVC类型转换器、属性编辑器

    对于MVC框架,参数绑定一直觉得是很神奇很方便的一个东西,在参数绑定的过程中利用了属性编辑器、类型转换器

    参数绑定流程

    参数绑定:把请求中的数据,转化成指定类型的对象,交给处理请求的方法

    编辑器转换器

    • 请求进入到DisptacherServlet,卸下请求中的数据
    • DisptacherServlet将请求中的数据发送给Controller
    • 获取Controller需要接收的参数类型,将参数类型和请求数据发送给DataBinder
    • DataBinder将参数类型和请求数据再发给TypeConverter,由TypeConverter装配成一个bean
    • TypeConverter根据bean中的成员类型,在PropertyEditorRegistry中查找已注册的PropertyEditor
    • PropertyEditor将数据setter进bean中的成员
    • TypeConverter将装配好的bean返回给DataBinder
    • DataBinder将装配bean交给处理请求的方法

    在参数绑定的过程TypeConverter和PropertyEditor是最核心的数据转化成对象(非序列化)的过程TypeConverter负责将数据转化成一个beanPropertyEditor负责将数据转化成一个成员字段

    属性编辑器

    PropertiesEditor负责转化简单对象,因为http请求都是以字符串的形式,所以一般都是根据String来转换springmvc提供了很多默认的属性编辑器,在org.springframework.beans.propertyeditors包中,比如

    微信截图_20160716120316

    • CustomBooleanEditor.class,String 转换 Boolean
    • CustomCollectionEditor.class,String 转换 Collection
    • CustomDateEditor.class,String 转换 Date
    • CustomMapEditor.class,String 转换 Map
    • CustomNumberEditor.class,String 转换  int、floot、double..

    所有的属性编辑器都是继承PropertiesEditorSupport,默认的属性编辑器,Spring在启动的时候会自动加载除此之外,如果要装配的属性没有合适的编辑器,还可以自定义属性编辑器注册了自定义的属性编辑器之后,在CustomEditorConfigurer中注册,应用全局都可以使用这个属性编辑器,因为属性编辑器的工厂是全局作用域的

    PropertiesEditor源码分析

    PropertiesEditor.java

    public class PropertiesEditor extends PropertyEditorSupport {
     //将String转成指定类型的对象
     @Override
     public void setAsText(String text) throws IllegalArgumentException {
      Properties props = new Properties();//Properties以key-value存值
       if (text != null) {
       try {
       //将String中表示的key=value或key:value信息,转化成Properties
       //key表示bean中字段名称
       //如果要转化成Date,则value是Date,String可以是"date=2012-12-12"的形式(date是字段名)
       props.load(new ByteArrayInputStream(text.getBytes("ISO-8859-1")));
      }
      catch (IOException ex) {
       throw new IllegalArgumentException(
       "Failed to parse [" + text + "] into Properties", ex);
       }
     }
      setValue(props);
     }
     //将old object转化成新object
     @Override
     public void setValue(Object value) {
       if (!(value instanceof Properties) && value instanceof Map) {
       Properties props = new Properties();
       props.putAll((Map<?, ?>) value);
       super.setValue(props);
     }
     else {
       //父类PropertyEditorSupport持有value对象,就是要转化后的对象
       super.setValue(value);
      }
     }
    }

    需要注意的是,setAsText通过一定格式的字符串来达到属性编辑的效果,"成员名称=value",或者是"成员名称:value",这样就会把value set到bean的指定成员中了编辑器中最重要的两个方法就是,setAsTest(String)和setValue(value),在这两个方法中完成从String——object,object——object

    CustomDateEditor源码分析

    CustomDateEditor是Spring的一个默认属性编辑器,负责将String转化成指定格式的Date对象同样他也是继承了PropertiesEditorSupport,重写了setAsTest方法

    public class CustomDateEditor extends PropertyEditorSupport {
     //指定的date格式,如"yyyy-MM-dd"
     private final DateFormat dateFormat;
     //是否允许字符串为空
     private final boolean allowEmpty;
     //严格的日期长度
     private final int exactDateLength;
    
     public CustomDateEditor(DateFormat dateFormat, boolean allowEmpty) {
     //构造器方法
     }
     public CustomDateEditor(DateFormat dateFormat, boolean allowEmpty, int exactDateLength) {
     //构造器方法
     }
     //String转化成Dtae
     @Override
     public void setAsText(String text) throws IllegalArgumentException {
       //判断字符串是否为空
       if (this.allowEmpty && !StringUtils.hasText(text)) {
        setValue(null);
       }
       //判断字符串长度是否等于exactDateLength
       else if (text != null && this.exactDateLength >= 0 && text.length() != this.exactDateLength) {
         throw new IllegalArgumentException(
         "Could not parse date: it is not exactly" + this.exactDateLength + "characters long");
        }
       else {
       try {
         //将text格式化成Date对象
         setValue(this.dateFormat.parse(text));
       }
       catch (ParseException ex) {
         throw new IllegalArgumentException("Could not parse date: " + ex.getMessage(), ex);
       }
       }
       }
     //从Date输出String
     @Override
     public String getAsText() {
       Date value = (Date) getValue();
       //返回格式化的String
       return (value != null ? this.dateFormat.format(value) : "");
     }
    }

    从CustomDateEditor的源码可以看出,最重要的是重写setAsText方法,先校验下字符串格式符不符合要求,不符合要求就抛出异常,再根据字符串转成指定DateFormat的Date对象

    类型转换器

    刚刚讲的属性编辑器是用来填充bean中的属性的,类型转换器是负责从数据转换成一个bean所以在转换的过程中,需要属性编辑器帮忙填充属性,那么应该持有一堆属性编辑器(bean有各种各样的属性),那么持有一个PropertyEditorRegistry(一个属性编辑器工厂)就可以了类型转化器的实现不像属性编辑器那么多,主要就是三个

    • TypeConverter,类型转换的接口
    • TypeConverterSupport,类型转换的实现,持有一个TypeConverterDelegate,具体转换工作交给TypeConverterDelegate完成
    • TypeConverterDelegate,类型转换的委托类,所有类型转换的工作都由他完成

    typeConverter

    要实现的方法就只有convertIfNecessary,从源对象转换为目标对象

    TypeConverterDelegate源码分析

    因为转换工作是由TypeConverterDelegate负责的,源码太长,就看看转换那一部分的代码

    /*
    @Param propertyName bean的名称
    @Param requiredType 需要的类型
    @Param typeDescriptor 类型描述器
    */
    public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {
     //从注册的属性编辑器中获取能编辑requiredType的属性编辑器
     PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
     //...
     //使用属性编辑器去把oldValue转化成requiredType
     convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
     //...
     return convertedValue;
     }
    /*
    @Param propertyName bean的名称
    @Param requiredType 需要的类型
    @Param editor 属性编辑器
    */
     private Object doConvertValue(Object oldValue, Object newValue, Class<?> requiredType, PropertyEditor editor) {
       Object convertedValue = newValue;
       if (editor != null && !(convertedValue instanceof String)) {
       try {
         //转换数据
         editor.setValue(convertedValue);
         //得到转换后的数据
         Object newConvertedValue = editor.getValue();
         if (newConvertedValue != convertedValue) {
         convertedValue = newConvertedValue;
         editor = null;
        }
     }
       catch (Exception ex) {
         if (logger.isDebugEnabled()) {
         logger.debug("PropertyEditor [" + editor.getClass().getName() + "] does not support setValue call", ex);
        }
       }
     }
     Object returnValue = convertedValue;
     //...
     return returnValue;
     }
    }

     查看原文:http://zswlib.com/2016/07/16/springmvc%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2%E5%99%A8%E3%80%81%E5%B1%9E%E6%80%A7%E7%BC%96%E8%BE%91%E5%99%A8/

  • 相关阅读:
    javascript的语法作用域你真的懂了吗
    网页的三种布局(固定宽度式,流体式,弹性式)
    css3系列之animation
    跟我学习css3之transition
    函数调用你知道几种方法
    javascript的那些事儿你都懂了吗
    css3的那些高级选择器二
    [转]影响Cache的几个HTTP头信息
    CSS属性合写
    defer 与 async
  • 原文地址:https://www.cnblogs.com/wewill/p/5676920.html
Copyright © 2011-2022 走看看