SpringMVC源码阅读:属性编辑器、数据绑定
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/current/javadoc-api/
http://www.cnblogs.com/fangjian0423/p/springMVC-databind-typeconvert.html
https://github.com/spring-projects/spring-framework
文中难免有不足,还望指出
年三十晚上完成了这篇文章,新年快乐
SpringMVC源码阅读:属性编辑器、数据绑定的更多相关文章
- SpringMVC源码阅读:过滤器
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...
- SpringMVC源码阅读系列汇总
1.前言 1.1 导入 SpringMVC是基于Servlet和Spring框架设计的Web框架,做JavaWeb的同学应该都知道 本文基于Spring4.3.7源码分析,(不要被图片欺骗了,手动滑稽 ...
- SpringMVC源码阅读:Controller中参数解析
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...
- SpringMVC源码阅读:拦截器
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...
- SpringMVC源码阅读:核心分发器DispatcherServlet
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将介绍SpringMVC的核 ...
- SpringMVC源码阅读:定位Controller
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码分析,弄清楚Spr ...
- SpringMVC源码阅读:Json,Xml自动转换
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...
- SpringMVC源码阅读:视图解析器
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...
- SpringMVC源码阅读:异常解析器
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...
随机推荐
- CMUSphinx Learn - Before you start
Before you start 开始之前 Before you start the development of the speech application, you need to consid ...
- verilog选择数据类型时常犯的错误
• 信号可以分为端口信号和内部信号.出现在端口列表中的信号是端口信号,其它的信号为内部信号. • 对于端口信号,输入端口只能是net类型.输出端口可以是net类型,也可以是register ...
- vnc搭建
PS:偶以前基本不用Linux的远程图形桌面,前几天有开发的同事配置CentOS的vnc有问题,找我解决,就顺便记录总结一下,这个总结是比较完整的.下面的配置在CentOS5.x和6.x.SUSE企业 ...
- [NewCoder 3] 二维数组中的查找
题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 来分析下,假设在数 ...
- Entity Framework Core 生成跟踪列-阴影属性
摘自:https://www.cnblogs.com/tdfblog/p/entity-framework-core-generate-tracking-columns.html Ef Core 官方 ...
- Lily-一个埋点管理工具
本文来自网易云社区 前言 在很多项目中,埋点数据使用表格来统计的,随着项目的进行,数据量越来越复杂,越来越难以维护.所以很多公司都已经开发了一整套系统,从埋点的录入到代码的输出. 我们项目中iOS和A ...
- Java基础巩固计划
3.26-4.1 JVM 虚拟机的内容写五篇博客 解决以下问题: 1. Java的内存模型以及GC算法 2. jvm性能调优都做了什么 3. 介绍JVM中7个区域,然后把每个区域可能造成内存的溢出的情 ...
- scanf的拓展用法——匹配特定字符
scanf的基本用法除了常规的输入操作外还有一些特殊的用法,使用这些用法可以很方便的在输入中读取想要的数据 1.限制输入数据的长度 这个应该算不上拓展用法,大多数读者应该都曾经使用过,这里简单提一下 ...
- IPv6 Can't assign requested address
今天试了下 bind IPv6 的地址,报错 Can't assign requested address http://stackoverflow.com/questions/24780404/p ...
- Zookeeper客户端Curator使用详解
Zookeeper客户端Curator使用详解 前提 最近刚好用到了zookeeper,做了一个基于SpringBoot.Curator.Bootstrap写了一个可视化的Web应用: zookeep ...