对于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包中,比如

  • 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,类型转换的委托类,所有类型转换的工作都由他完成

要实现的方法就只有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/

SpringMVC类型转换器、属性编辑器的更多相关文章

  1. springmvc 类型转换器 自定义类型转换器

    自定义类型转换器的步骤: 1.定义类型转换器 2.类型转换器的注册(在springmvc配置文件处理) 来解决多种日期格式的问题: springmvc 类型转换器 表单数据填错后返回表单页面(接上面的 ...

  2. springmvc 类型转换器 数据回显及提示信息

    处理器的写法: 类型转换器的写法: 类型转换器在springmvc.xml中的配置如下: index.jsp的写法:

  3. springmvc——自定义类型转换器

    一.什么是springmvc类型转换器? 在我们的ssm框架中,前端传递过来的参数都是字符串,在controller层接收参数的时候springmvc能够帮我们将大部分字符串类型的参数自动转换为我们指 ...

  4. 属性编辑器,即PropertyEditor-->Spring IoC

    在Spring配置文件里,我们往往通过字面值为Bean各种类型的属性提供设置值:不管是double类型还是int类型,在配置文件中都对应字符串类型的字面值.BeanWrapper填充Bean属性时如何 ...

  5. Spring 学习笔记 数据绑定,校验,BeanWrapper 与属性编辑器

    Spring 数据绑定,校验,BeanWrapper,与属性编辑器 Data Binding 数据绑定(Data binding)非常有用,它可以动态把用户输入与应用程序的域模型(或者你用于处理用户输 ...

  6. 《SpringMVC从入门到放肆》十二、SpringMVC自定义类型转换器

    之前的教程,我们都已经学会了如何使用Spring MVC来进行开发,掌握了基本的开发方法,返回不同类型的结果也有了一定的了解,包括返回ModelAndView.返回List.Map等等,这里就包含了传 ...

  7. SpringMVC源码阅读:属性编辑器、数据绑定

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

  8. SpringMVC自定义类型转换器

    SpringMVC 自定义类型转换器  我们在使用SpringMVC时,常常需要把表单中的参数映射到我们对象的属性中,我们可以在默认的spring-servlet.xml加上如下的配置即可做到普通数据 ...

  9. springMVC注解@initbinder日期类型的属性自动转换

    在实际操作中经常会碰到表单中的日期 字符串和Javabean中的日期类型的属性自动转换, 而springMVC默认不支持这个格式的转换,所以必须要手动配置, 自定义数据类型的绑定才能实现这个功能. 一 ...

随机推荐

  1. Centos 7.0 安装Mono 3.4 和 Jexus 5.6

    2013-07-26 写过一篇<CentOS 6.3下 安装 Mono 3.2 和Jexus 5.4>,CentOS 7在CentOS 6的基础上有很大的调整,本文是这篇文章的更新,主要介 ...

  2. 拥抱.NET Core,如何开发一个跨平台类库 (1)

    在此前的文章中详细介绍了使用.NET Core的基本知识,如果还没有看,可以先去了解“拥抱.NET Core,学习.NET Core的基础知识补遗”,以便接下来的阅读. 在本文将介绍如何配置类库项目支 ...

  3. DTO – 服务实现中的核心数据

    在一个Web服务的实现中,我们常常需要访问数据库,并将从数据库中所取得的数据显示在用户页面中.这样做的一个问题是:用于在用户页面上展示的数据和从数据库中取得的数据常常具有较大区别.在这种情况下,我们常 ...

  4. App开发的新趋势

    移动开发这些年,移动开发者人数越来越多,类似的培训公司发展也很快,不过伴随着的是移动应用的需求这几年发展更为旺盛.要开发好的App,纯原生开发肯定是最佳选择.但是这么多年发展,原生开发的难度并没有降低 ...

  5. 快速web开发中的前后端框架选型最佳实践

    这个最佳实践是我目前人在做的一个站点,主要功能: oauth登录 发布文章(我称为"片段"),片段可以自定义一些和内容有关的指标,如“文中人物:12”.支持自定义排版.插图.建立相 ...

  6. Marmoset Toolbag中的角色布光技巧 by Joe”EarthQuake”Wilson

    Sagat by Tim “spacemonkey” Appleby 有言在先 首先,我要感谢才华横溢的Tim“spacemonkey Appleby允许本教程中使用他那个极其NB的Sagat模型.不 ...

  7. Spark2 ML 学习札记

    摘要: 1.pipeline 模式 1.1相关概念 1.2代码示例 2.特征提取,转换以及特征选择 2.1特征提取 2.2特征转换 2.3特征选择 3.模型选择与参数选择 3.1 交叉验证 3.2 训 ...

  8. Android 开发环境在 Windows7 下的部署安装

    Android SDK Android SDK 为 Android 应用的开发.测试和调试提了必要的API库和开发工具. ADT Bundle 下载 如果你是一个android 开发新手,推荐你下载使 ...

  9. 【原】使用Bmob作为iOS后台开发心得——查询关联关系(BmobRelation)

    本文转载请注明出处 —— polobymulberry-博客园 简介 Bmob中的数据关联分为Pointer和Relation两种(数据关联在我开发app过程中使用还是很频繁的,也算个难点.虽然之前没 ...

  10. ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程

    从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...