spring实体类(POJO)参数的赋值(form表单)原理
10、实体类(POJO)参数的赋值(form表单)原理
10.1、原理解析
测试用例
- 准备好两个实体类
public class Person {
private String name;
private Integer age;
private Pet pet;
} public class Pet {
private String name;
private Integer age;
}
html的form表单
注意这个 宠物Pet对象的name不能乱写 必须要和 person中定义的名称一样 才可以
<form action="/person" method="post">
<input type="text" name="name" value="水三丫">
<input type="text" name="age" value="18">
<input type="text" name="pet.name" value="阿猫">
<input type="text" name="pet.age" value="10">
<input type="submit" value="Person">
</form>
- Controller请求代码
@PostMapping("/person")
public Map person(Person person){
Map<String, Person> map = new HashMap<>();
map.put("person",person);
return map;
}
源码Debug
从DispatchServlet 的 doDispatch方法开始
DispatchServlet类中的
doDispatch方法
//RequestMappingHandlerAdapter这个处理器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
获取请求参数的处理器
HandlerMethodArgumentResolverComposite类中的
getArgumentResolver方法
//总共27个处理器
ServletModelAttributeMethodProcessor这个处理Pojo实体类的参数
创建实体类构造器和赋值
- 创造构造器
ModelAttributeMethodProcessor类中的
resolveArgument方法
// Create attribute instance
try {
attribute = createAttribute(name, parameter,
binderFactory, webRequest);
}
createAttribute方法 //反射获取空参构造器
Constructor<?> ctor = BeanUtils.getResolvableConstructor(clazz);
Constructor<?> ctor = BeanUtils.getResolvableConstructor(clazz);
Object attribute = constructAttribute(ctor, attributeName, parameter,
binderFactory, webRequest);
- 属性绑定和验证
ModelAttributeMethodProcessor类中的
resolveArgument方法
// Bean property binding and validation;
// skipped in case of binding failure on construction.
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute,
name);
- 获取请求的参数
ServletModelAttributeMethodProcessor类中订单
bindRequestParameters方法
servletBinder.bind(servletRequest);
ServletRequestDataBinder类中的
bind方法
MutablePropertyValues mpvs = new
ServletRequestParameterPropertyValues(request);
WebUtils方法类中
getParametersStartingWith方法
Enumeration<String> paramNames = request.getParameterNames();
Map<String, Object> params = new TreeMap<>();
准备开始数据绑定
ServletRequestDataBinder类中的
bind方法
doBind(mpvs);
WebDataBinder类中的
doBind方法
super.doBind(mpvs);
DataBinder类中的
doBind方法
applyPropertyValues(mpvs);
AbstractPropertyAccessor类中的
setPropertyValues方法
try {
setPropertyValue(pv);
}
第一步获取数据的绑定格式转换的处理器(因为浏览器以JSOn穿过了的都是字符串)需要格式转换
TypeConverterDelegate类中的
convertIfNecessary方法
try {
//传入的是请求的参数值 参数类型 需要转换的类型
return (T) conversionService.convert(newValue, sourceTypeDesc,
typeDescriptor);
}
GenericConversionService类中的
convert方法
GenericConverter converter = getConverter(sourceType, targetType);
getConverter方法
ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
GenericConverter converter = this.converterCache.get(key);
需要124个类型转换中寻找这次需要的
需要的是:
获取的转换器
第二步转换数据
GenericConversionService类中的
convert方法
Object result = ConversionUtils.invokeConverter(converter, source,
sourceType,targetType);
第三步开始赋值
AbstractNestablePropertyAccessor类中的
processLocalProperty方法
ph.setValue(valueToApply);
获取set方法
BeanWrapperImpl类中的
setValue方法
Method writeMethod = (this.pd instanceof
GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor)
this.pd).getWriteMethodForActualAccess() :
this.pd.getWriteMethod());
开始反射赋值
BeanWrapperImpl类中的
setValue方法
writeMethod.invoke(getWrappedInstance(), value);
赋值完成
10.2、定制化属性转换器
编写自定义配置转换规则
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Converter<String, Pet>() {//增加一个转换器
@Override
public Pet convert(String source) {//实现这个接口的方法
if(!StringUtils.isEmpty(source)){
Pet pet = new Pet();
String[] split = source.split(",");//以逗号为分隔符
pet.setName(split[0]);
pet.setAge(Integer.parseInt(split[1]));
return pet;
}
return null;
}
});
}
};
}
lambda表达式写法
@Bean
public WebMvcConfigurer webMvcConfigurer(){
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(String.class,Pet.class, source -> { if(!StringUtils.isEmpty(source)){
Pet pet = new Pet();
String[] split = source.split(",");
pet.setName(split[0]);
pet.setAge(Integer.parseInt(split[1]));
return pet;
}
return null;
});
}
};
}
测试用例
html页面form表单代码
<form action="/person1" method="post">
<input type="text" name="name" value="水三丫">
<input type="text" name="age" value="18">
<input type="text" name="pet" value="阿猫,10">
<input type="submit" value="Person1">
</form>
Debug测试
测试的时候就会在全部转换器中找到我们定制的哪一个
spring实体类(POJO)参数的赋值(form表单)原理的更多相关文章
- js 取值&赋值-form表单
form表单元素介绍 CreateTime--2016年9月22日10:25:54 Author:Marydon <form> 表单元素. 表单中的元素: <input>表 ...
- 1113 form表单与css选择器
目录 1.form表单 form元素 特点 参数 form元素内的控件 1.input的使用 2.select标签 3.textarea元素 4.autofocus属性 2.CSS 1.基础语法 cs ...
- Java如何实现form表单提交的数据自动对应实体类(源码)
原文出自:https://blog.csdn.net/seesun2012 原生Java+JQuery form表单serializeArray提交自动对应java实体,这是一个实际的例子: html ...
- @NamedEntityGraphs --JPA按实体类对象参数中的字段排序问题得解决方法
JPA按实体类对象参数中的字段排序问题得解决方法@Entity @Table(name="complaints") @NamedEntityGraphs({ @NamedEntit ...
- c# 实体类怎么给LIST赋值,table转LIST
/// <summary> /// 缓存客服集合信息 /// </summary> public class model { /// <summary> /// 客 ...
- 实体类相同属性间赋值与如何判断实体类中是否所有的字段都为null
1,实体类相同属性间赋值 /// <summary> /// 将实体2的值动态赋值给实体1(名称一样的属性进行赋值) /// </summary> /// <param ...
- SpringMVC中使用bean来接收form表单提交的参数时的注意点
这是前辈们对于SpringMVC接收表单数据记录下来的总结经验: SpringMVC接收页面表单参数 springmvc请求参数获取的几种方法 下面是我自己在使用时发现的,前辈们没有记录的细节和注意点 ...
- JsonResponse类的使用、form表单上传文件补充、CBV和FBV、HTML的模板语法之传值与过滤器
昨日内容回顾 Django请求生命周期 # 1.浏览器发起请求 到达Django的socket服务端(web服务网关接口) 01 wsgiref 02 uwsgi + nginx 03 WSGI协议 ...
- Form 表单提交参数
今天因为要额外提交参数数组性的参数给form传到后台而苦恼了半天,结果发现,只需要在form表单对应的字段html空间中定义name = 后台参数名 的属性就ok了. 后台本来是只有模型参数的,但是后 ...
随机推荐
- TinyMCE简介
TinyMCE是一款开源.易用.UI时新的富文本编辑器. 插件丰富,自带插件基本满足要求 可扩展性强,可自定义功能 界面好看,符合现代审美 提供经典.内联.沉浸无干扰三种模式 官网:https://w ...
- Springboot启动类及注解说明
Spring boot的启动是基于main方法的,其主要注解为: 1. @springBootApplication:项目的启动注解,是一个组合注解,包含@SpringbootConfiguratio ...
- python之三元表达式与生成式与匿名与内置函数(部分)
目录 三元表达式 各种生成式 列表生成式(可同样作用于集合) 字典生成式 匿名函数 重要内置函数 map() zip() filter() reduce() 常见内置函数(部分) 三元表达式 三元表达 ...
- BERT的优化演进方法汇总(持续更新)
模型结构演进 本文以演进方向和目的为线索梳理了一些我常见到但不是很熟悉的预训练语言模型,首先来看看"完全版的BERT":RoBERTa: A Robustly Optimized ...
- 关于『进击的Markdown』:第二弹
关于『进击的Markdown』:第二弹 建议缩放90%食用 众里寻他千百度,蓦然回首,Markdown却在灯火灿烂处 MarkdownYYDS! 各位早上好! 我果然鸽稿了 Markdown 语法 ...
- React history.push()无法跳转 url改变页面不渲染
一.history.push()无法跳转参考了很多文章 研究一下生命周期 render是要有state变化才会执行 BrowserHistory只有props变化 无法触发render 如下改造环境 ...
- 当运行npm install 命令的时候带上ignore-scripts,会发生什么?
摘要:运行npm install 命令的时候带上ignore-scripts, 可以避免一个恶意包里的病毒. 本文分享自华为云社区<运行npm install 命令的时候带上--ignore-s ...
- Ubuntu安装python固定版本
一. 安装python3.7 本篇文章使用python3.7安装步骤为例 1.直接使用apt-get安装python3.7 apt-get install python3.7 该方法经常会出现unab ...
- MySQL 千万数据库深分页查询优化,拒绝线上故障!
文章首发在公众号(龙台的技术笔记),之后同步到博客园和个人网站:xiaomage.info 优化项目代码过程中发现一个千万级数据深分页问题,缘由是这样的 库里有一张耗材 MCS_PROD 表,通过同步 ...
- 1.4 操作系统的其余功能 -《zobolの操作系统学习札记》
1.4 操作系统的其余功能 操作系统除了虚拟化.并发.存储管理三个主要功能,还有许多子功能,我主要介绍几种常见的功能比如 目录 1.4 操作系统的其余功能 稳定性 高性能 隔离保护 易用性(可视化) ...