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了. 后台本来是只有模型参数的,但是后 ...
随机推荐
- TENSEAL: A LIBRARY FOR ENCRYPTED TENSOR OP- ERATIONS USING HOMOMORPHIC ENCRYPTION 解读
本文记录阅读该paper的笔记,这篇论文是TenSeal库的原理介绍. 摘要 机器学习算法已经取得了显著的效果,并被广泛应用于各个领域.这些算法通常依赖于敏感和私有数据,如医疗和财务记录.因此,进一步 ...
- 专家PID控制仿真学习
目录 专家控制 专家系统 专家控制 学习笔记,用于记录学习 资料:<智能控制>(第四版)--刘金琨 专家系统 一.专家系统的定义 专家系统是一类包含知识和推理的智能计算机程序,其内部包含某 ...
- MASA Auth - 从用户的角度看整体设计
用户 在系统里,用户是一个核心概念.它代表了一个人的唯一身份标识,除了与角色.团队.组织架构等有关,甚至还会影响到在同一个界面不同的用户操作流程与显示内容都会发生变化,再复杂一点的话,或许在同一个系统 ...
- conda创建/移除虚拟环境
conda创建python虚拟环境 前言 conda常用的命令: conda list 查看安装了哪些包. conda env list 或 conda info -e 查看当前存在哪些虚拟环境 co ...
- Linux切换中英文输入
使用xshell登录Linux服务器后,输入的命令正确但是提示命令不存在,这是什么鬼. 通过移动光标可以发现两种字体的宽度不一样 解决方法 shift + 空格 进行切换
- Jenkins之配置GitHub-Webhook
前提条件1: 运行Jenkins的机器需要安装git,并且git.exe文件在系统的环境变量里面,或者手动在 Manage Jenkins -> Global Tool Configuratio ...
- Centos7 中安装Elasticsearch
1.下载安装包 1.1 下载elasticsearch 7.13.3 curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/e ...
- ExtJS 布局-Accordion布局(Accordion layout)
更新记录: 2022年6月2日 开始. 2022年6月3日 发布. 1.说明 accordion(手风琴)布局一次仅显示一个子组件,内置支持 折叠 和 展开.当需要堆叠多个子组件,并每次只显示一次时, ...
- 使用PowerShell校验文件MD5
更新记录 2022年4月16日:本文迁移自Panda666原博客,原发布时间:2021年7月14日. 方法1:使用Get-FileHash命令 (Get-FileHash ".\SQLSer ...
- 记一次学习kibaba踩过的坑(Windows环境)
下载地址 ElasticSearch:https://www.elastic.co/cn/downloads/elasticsearchLogstash:https://www.elastic.co/ ...