1.前言

SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧

本文将通过源码(基于Spring4.3.7)分析,弄清楚SpringMVC如何通过类型转换完成数据绑定和属性编辑器的原理,并自定义属性编辑器

2.源码分析

进入RequestMappingHandlerAdapter,该类支持参数解析和数据返回,进入invokeHandlerMethod方法

794行构造WebDataBinderFactory,传入HandlerMethod参数

点进去getDataBinderFactory方法,看看它做什么

886行获取@InitBinder方法

891行查找带有@ControllerAdvice注解支持的Controller

看下RequestParamMethodArgumentResolver的父类AbstractNamedValueMethodArgumentResolver的resolveArgument方法

117行获取到@InitBinder注解修饰的方法和@ControllerAdvice中的@InitBinder注解修饰的方法

118行创建一个ExtendedServletRequestDataBinder

120行arg获取参数转换结果

binderFactory变量是WebDataBinderFactory类型,打开WebDataBinderFactory,该类在Spring3.1引入,用来创建WebDataBinder

进入WebDataBinder,该类用于处理Web请求参数和JavaBean之间的数据绑定,ctrl+alt+h打开类继承图,WebDataBinder继承DataBinder

打开DataBinder类,该类允许在目标对象上设置属性值,支持数据验证和绑定,实现了PropertyEditorRegistry和TypeConverter

先打开PropertyEditorRegistry,该类给注册的JavaBean封装方法,注释提到被BeanWrapper继承,由BeanWrapperImpl实现

BeanWrappert接口提供操作JavaBean的方法,配置set/get方法

再打开TypeConverter,该类是定义类型转换方法的接口,和PropertyEditorRegistry组合使用

最后我们找到PropertyEditor,它是属性编辑的核心接口,看它的子类

稍后我们自定义属性编辑器要继承该类,重写setAsText方法

3.实例

3.1 测试BeanWrapper

创建实体类TestModel

public class TestModel {

    private int age;

    private Date birth;

    private String name;

    private boolean good;

    private long times;

    public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public Date getBirth() {
return birth;
} public void setBirth(Date birth) {
this.birth = birth;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public boolean isGood() {
return good;
} public void setGood(boolean good) {
this.good = good;
} public long getTimes() {
return times;
} public void setTimes(long times) {
this.times = times;
}
}

测试方法

    @RequestMapping(value = "/testWrapper", produces={"application/json; charset=UTF-8"})
@ResponseBody
public TestModel testWrapper() {
TestModel tm = new TestModel();
BeanWrapper bw = new BeanWrapperImpl(tm);
bw.setPropertyValue("good", "1");
return tm;
}

浏览器输入http://localhost:8080/springmvcdemo/test/testWrapper

在PropertyEditorSupport(实现PropertyEditor)的子类CustomBooleanEditor中,setAsText方法对上述现象进行了处理

3.2 测试不使用BeanWrapper

    @RequestMapping(value = "/testNotUseWrapper", produces={"application/json; charset=UTF-8"})
@ResponseBody
public TestModel testNotUseWrapper() {
TestModel tm = new TestModel();
BeanWrapperImpl bw = new BeanWrapperImpl(false);
bw.setWrappedInstance(tm);
bw.setPropertyValue("good", "1");
return tm;
}

浏览器输入http://localhost:8080/springmvcdemo/test/testNotUseWrapper

因为没有对应的属性编辑器,导致String类型“1”无法转换成Boolean类型

3.3 测试无注解对象参数绑定

SpringMVC源码阅读:Controller中参数解析我说过,ServletModelAttributeMethodProcessor处理无注解对象

    @RequestMapping(value = "testObj", produces={"application/json; charset=UTF-8"})
@ResponseBody
public Map testObj(Employee e) {
Map resultMap = new HashMap();
resultMap.put("Employee",e);
return resultMap;
}

浏览器输入http://localhost:8080/springmvcdemo/test/testObj?id=1&name=s&age=12&dept.id=1&dept.name=20

resolveArgument方法在ServletModelAttributeMethodProcessor已废弃,在其父类ModelAttributeMethodProcessor被实现

99行获取参数别名

100行获取属性列表

110行创建ExtendedServletRequestDataBinder,前文已经说过

113行绑定请求参数,此时属性列表参数绑定完毕

4.编写自定义属性编辑器

自定义属性编辑器,实现PropertyEditorSupport

public class CustomDeptEditor extends PropertyEditorSupport {

    @Override
public void setAsText(String text) throws IllegalArgumentException {
if(text.indexOf(",") > 0) {
Dept dept = new Dept();
String[] arr = text.split(",");
dept.setId(Integer.parseInt(arr[0]));
dept.setName(arr[1]);
setValue(dept);
} else {
throw new IllegalArgumentException("dept param is error");
}
} }

在TestController添加@InitBinder

    @InitBinder
public void initBinderDept(WebDataBinder binder) {
binder.registerCustomEditor(Dept.class, new CustomDeptEditor());
}

添加@ControllerAdvice,保证InitBinder应用到RequestMapping,就是说Controller里定义的@InitBinder和自定义的@ControllerAdvice里@InitBinder存在一个即可

@ControllerAdvice
public class InitBinderControllerAdvice { @InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Dept.class, new CustomDeptEditor());
} }

dispatcher-servlet需要配置component-scan,扫描到我们定义的ControllerAdvice

<context:component-scan base-package="org.format.demo.controlleradvice" />

浏览器输入http://localhost:8080/springmvcdemo/test/testObj?id=1&name=s&age=12&dept=1,research

5.总结

PropertyEditor是属性编辑器的接口,setAsText是核心方法,实现类PropertyEditorSupport

PropertyEditorRegistry接口给JavaBean注册对应的属性编辑器,实现类PropertyEditorRegistrySupport的createDefaultEditors创建默认的属性编辑器

TypeConverter接口,通过该接口,可以将value转换为指定类型对象,实现类TypeConverterSupport将类型转换委托给TypeConverterDelegate处理

BeanWrapper接口操作JavaBean,配置set/get方法和查询数据的可读可写性,实现类为BeanWrapperImpl

DataBinder用来set值和数据验证,WebDataBinder处理对Web请求参数到JavaBean的数据绑定

RequestMappingHandlerAdapter调用invokeHandlerMethod方法创建WebDataBinderFactory,WebDataBinderFactory创建WebDataBinder

最后HandlerMethodArgumentResolver解析参数

6.参考

https://docs.spring.io/spring/docs/4.3.7.RELEASE/spring-framework-reference/htmlsingle/#beans-beans-conversion

https://docs.spring.io/spring/docs/current/javadoc-api/

http://www.cnblogs.com/fangjian0423/p/springMVC-databind-typeconvert.html

https://github.com/spring-projects/spring-framework

文中难免有不足,还望指出

年三十晚上完成了这篇文章,新年快乐

SpringMVC源码阅读:属性编辑器、数据绑定的更多相关文章

  1. SpringMVC源码阅读:过滤器

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

  2. SpringMVC源码阅读系列汇总

    1.前言 1.1 导入 SpringMVC是基于Servlet和Spring框架设计的Web框架,做JavaWeb的同学应该都知道 本文基于Spring4.3.7源码分析,(不要被图片欺骗了,手动滑稽 ...

  3. SpringMVC源码阅读:Controller中参数解析

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

  4. SpringMVC源码阅读:拦截器

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

  5. SpringMVC源码阅读:核心分发器DispatcherServlet

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

  6. SpringMVC源码阅读:定位Controller

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

  7. SpringMVC源码阅读:Json,Xml自动转换

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

  8. SpringMVC源码阅读:视图解析器

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

  9. SpringMVC源码阅读:异常解析器

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

随机推荐

  1. bootstrap2.2相关文档

    本节课我们主要学习一下 Bootstrap表单和图片功能,通过内置的 CSS定义,显示各种丰富的效果. 一.表单 Bootstrap提供了一些丰富的表单样式供开发者使用. 1.基本格式 //实现基本的 ...

  2. 用户访问网页流程、DNS 解析流程

    一.用户访问流程 二.DNS解析流程 DNS( Domain Name System)是“域名系统”的英文缩写,是一种组织成域层次结构的计算机和网络服务命名系统,它用于 TCP/IP 网络,它所提供的 ...

  3. Swift3 今日(TodayExtension)扩展图文笔记

    >图片1(创建今日扩展) >图片2  >图片3(设置大小)  >图片4(绘画控件) >图片5(设置共享文件)  >图片6(设置群组ID) >图片7(设置URL ...

  4. Android-Kotlin简单计算器功能

    上一篇博客 Android-Kotlin-配置/入门 配置好了 AndroidStudio Kotlin 的环境: 选择包名,然后右键: 选择Class类型,会有class: 创建CounterCla ...

  5. Android-Java-类与对象的关系

    类class 例如:class Student {},很多人把class Student {}称为对象或实体,其实这样并不合理,应该称为描述实体/描述对象: 因为被称为对象或实体的是,new Stud ...

  6. Win10家庭版无法远程桌面连接的解决方法

    远程桌面连接服务器,是大家常用的一个桌面功能.在XP.Win7时代,大部分同学都是使用“盗版”操作系统,分分钟弄个“旗舰版”没有问题.可是,到了Win8.Win10时代,许多电脑都是预装的Window ...

  7. .net core中Quartz的使用

    原来工作中有用到定时任务Quartz,不过是在MVC项目中,现在net core项目中也要用到,就开始改版.中间发现在网上的教程只有执行定时计划的过程,却很少有人写注册的过程,觉得有点略坑.所以写此文 ...

  8. 关于WordCount的作业

    一.开发者:201631062418 二.代码地址:https://gitee.com/YsuLIyan/WordCount 三.作业地址:https://edu.cnblogs.com/campus ...

  9. C++获取系统信息(IP地址、硬件信息等)

    #include<stdio.h> #include<winsock2.h> //该头文件需在windows.h之前 #include<windows.h> #in ...

  10. Python 私有变量中两个下划线 _ _item 与 一个下划线的区别 _item

    python中没有常量的说法, 但是可以通过元组实现一个常量 在python的私有变量中, 存在两个下划线 _ _item 与一个下划线 _item 的区别 前面带两个下划线的私有变量: 只能在本类中 ...