Spring 类型转换、数值绑定与验证(一)— DataBinder

 DataBinder 是Spring用于数据绑定、类型转换及验证的类。使用场景有:1)xml配置文件定义bean,Spring 内部使用DataBinder 来完成属性的绑定;2)Web请求参数绑定,在Spring MVC 中,Controller的方法参数通常会自动绑定到请求参数中,主要用DataBinder来完成。3)自定义数据绑定,可手动创建DataBinder 对象,为其设置校验器和转换器,来满足特定需求。

1 DataBinder 类

图 DataBinder UML图

PropertyEditorRegistry:

PropertyEditor 注册商,用来管理及保存PropertyEditor(JDK自带接口,支持各种不同的方式来显示和更新属性值,比如在Spring的xml中,配置Bean 时,把字符串类型转化成对应的Integer、File等类型)。定义了注册PropertyEditor 的接口。

TypeConverter:

定义了类型转化方法。

public class DataBinderTest {public static void main(String[] args) throws BindException {User user = new User();DataBinder binder = new DataBinder(user);MutablePropertyValues propertyValues = new MutablePropertyValues();propertyValues.add("username","黄先生");propertyValues.add("address.province","广东");propertyValues.add("address.city","深圳");propertyValues.add("infos['job']","程序员");propertyValues.add("age",28);binder.bind(propertyValues);System.out.println(user); // User{username='黄先生', age=28, address=Address{province='广东', city='深圳'}, infos={job=程序员}}}public static class User {private String username;private Integer age;private Address address;private Map<String,Object> infos;public void setUsername(String username) {this.username = username;}public String getUsername() {return username;}public void setAge(Integer age) {this.age = age;}public Integer getAge() {return age;}public void setAddress(Address address) {this.address = address;}public Address getAddress() {return address;}public Map<String, Object> getInfos() {return infos;}public void setInfos(Map<String, Object> infos) {this.infos = infos;}@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +", age=" + age +", address=" + address +", infos=" + infos +'}';}}public static class Address {private String province;private String city;public void setProvince(String province) {this.province = province;}public String getProvince() {return province;}public void setCity(String city) {this.city = city;}public String getCity() {return city;}@Overridepublic String toString() {return "Address{" +"province='" + province + '\'' +", city='" + city + '\'' +'}';}}
}

2 数值绑定过程

如上代码。使用了DataBinder的bind(PropertyValues pvs) 来将属性值绑定到目标对象中。

图 DataBinder的bind 方法

图 数据绑定过程中的方法调用

2.1 PropertyValues

PropertyValues 用于保存一个或多个Property的接口。MutablePropertyValues是其实现类。新增了对Property 新增、删除等操作。

2.1.1 Property

图 Property UML

AttributeAccessor: 定义了对象属性的访问及设置值等操作的接口。

AttributeAccessorSupport: 是AttributeAccessor 的实现类,这里的属性操作对象是一个Map类型。

BeanMetadataElement:定义了一个方法getSource(),用于获取Bean元数据的源对象。这个源对象通常是源文件信息。

BeanMetadataAttributeAccessor: 会覆盖AttributeAccessorSupport中设置和获取属性的方法,会将属性转换为BeanMetadataAttribute,目的是为了跟踪Bean定义的源对象。

BeanMetadataAttribute: 在Spring容器中,Bean的定义来源与多种不同的配置方式,例如XML、注解、配置类等。当Spring容器解析Bean的定义时,它会将源信息(如XML文件的路径、注解的位置等)与Bean的定义关联起来,这样,在后续处理中,如果需要对Bean的定义进行查找、修改或报告错误,Spring可以使用这个源信息。

Property:与BeanMetadataAttributeAccessor 不同的是,Property将属性和值封装在一个对象中,而不是使用Map对象来保存所有属性。这种设计提供了更大的灵活性和便利性,并允许处理索引属性以进行优化。

2.2 applyPropertyValues方法

在该方法中,执行下面语句来完成对目标对象的赋值:

getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());

getPropertyAccessor()方法:

protected ConfigurablePropertyAccessor getPropertyAccessor() {return getInternalBindingResult().getPropertyAccessor();
}

getInternalBindingResult()方法:

protected AbstractPropertyBindingResult getInternalBindingResult() {if (this.bindingResult == null) {initBeanPropertyAccess();}return this.bindingResult;
}

调用关系为:

AbstractPropertyBindingResult.getPropertyAccessor() -> ConfigurablePropertyAccessor.setPropertyValues(参数) 完成对象属性赋值。

2.2.1 AbstractPropertyBindingResult

数据绑定的结果。BindingResult用于处理数据绑定的错误。主要用来收集、存储和管理在数据绑定过程中发生的错误。

图 AbstractPropertyBindingResult UML

AbstractPorpertyBindingResult 是一个抽象类,定义了一个抽象方法:getPropertyAccessor。返回ConfigurablePropertyAccessor类型。有两个实现类。

DirectFieldBindingResult

用于能直接访问的对象,而不是通过getter和setter方法访问的。

BeanPropertyBindingResult

默认实现,标准bean,通过getter和setter方法访问的。

表 AbstractPropertyBindingResult两个实现类

图 BeanPropertyBindingResult的getPropertyAccessor方法

图 BeanPropertyBindingResult 类的代码

PropertyAccessorFactory 是一个简单的工厂类,根据对象属性是否直接访问来创建对应的ConfigurablePropertyAccessor。

2.2.2 ConfigurablePropertyAccessor

提供了灵活的方式来访问和操作Bean对象的属性,并支持类型转化和属性编辑等功能。该接口新增了设置及获取ConversionService的方法。

图 ConfigurablePropertyAccessor接口 UML

PropertyAccessor接口:提供了可以访问命名属性(bean属性或对象中的字段)的接口。提供了对JavaBean属性的读取和写入操作。

图 PropertyAccessor 接口的方法

2.3 BeanWrapperImpl

为标准bean属性的访问实现的方法。还支持类型转化及自定义属性编辑等功能。

图 BeanWrapperImpl UML

BeanWrapper 继承了ConfigurablePropertyAccessor 接口,并增加了getWrappedInstance()获取将目标对象包装后的对象等方法。

AbstractNestablePropertyAccessor 主要用于支持嵌套属性的访问和类型转换。

2.3.1 AbstractNestablePropertyAccessor

图 AbstractPropertyAccessor 中的setPropertyValues方法部分截图

通过遍历属性值的List集合,来为每个属性值进行绑定。

图 AbstractNestablePropertyAccessor 中的setPropertyValue 方法

AbstractNestrablePropertyAccessor 中实现了父类抽象类的抽象方法setPropertyValue,来完成对单个属性值的绑定。

PropertyTokenHolder 是AbstractNestrablePropertyAccessor 的一个内部类,主要作用是解析和处理嵌套属性的名称,并将它们转换成可访问和操作的形式。

actualName

属性的实际名称。可能包含了方括号和引号等元素格式。

canonicalName

属性的规范名称。会去除属性名称中的方括号和引号,并将属性名称转换为规范的形式。例如,person[‘address’][‘city’]转换为address.city。

keys:String[]

保存了属性的键列表,例如上面的属性保存为[“address”,“city”]

表 PropertyTokenHolder 的字段

图 PropertyTokenHolder 代码

2.4 processLocalProperty方法完成属性类型转换及绑定

图 processLocalProperty方法中的关键代码

2.4.1 PropertyHandler

是一个抽象类,用于处理属性的读取和写入操作。定义了获取/设置属性值及检查属性是否可读可写的方法。其默认实现是BeanPropertyHandler, 针对JavaBean属性,使用JavaBean规范来操作属性。如果不是通过getter和setter方法访问的,则使用LocalPropertyHandler。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/696019.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Stable Diffusion 模型分享:Indigo Furry mix(人类与野兽的混合)

本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十

开启智能互动新纪元——ChatGPT提示词工程的引领力

目录 提示词工程的引领力 高效利用ChatGPT提示词方法 提示词工程的引领力 近年来&#xff0c;随着人工智能技术的迅猛发展&#xff0c;ChatGPT提示词工程正逐渐崭露头角&#xff0c;为智能互动注入了新的活力。这一技术的引入&#xff0c;使得人机交流更加流畅、贴近用户需求&…

2.22作业

test.c #include "test.h" seq_p creat_list(){seq_p L(seq_p)malloc(sizeof(seq_list));if(LNULL){printf("申请空间失败\n");return 0;}L->len0;return L; } int seq_p_empt(seq_p L){if(LNULL){return -12;}return L->len0?1:0; } int seq_p_fu…

华为OD机试真题-寻找最富裕的小家庭-2023年OD统一考试(C卷) --Python--开源

题目&#xff1a; 考察内容&#xff1a; dict–update—for sum max 代码&#xff1a; """ 题目分析&#xff1a;输入&#xff1a; N int 1,1000 成员总数 list len(list)N int 1, 1000000 财富值 N-1行&#xff0c; N1 N2, N1是N2的父节点 输出&#xff…

操作系统导论-课后作业-ch19

1. 本书在第6章中有过介绍&#xff0c;gettimeofday函数最多精确到us&#xff0c;并且大致精确&#xff08;并不完全精确&#xff09;&#xff0c;需要多迭代几次减少误差&#xff0c;循环次数太多也会导致结束时间小于开始时间&#xff08;即回滚&#xff09;的现象&#xff…

两数相加

2. 两数相加 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个…

C语言—指针(1)

碎碎念:做指针题的时候我仿佛回到了原点&#xff0c;总觉得目的是为了把框架搭建起来&#xff0c;我胡说的哈31 1.利用指针变量将一个数组中的数据反向输出。 /*1.利用指针变量将一个数组中的数据反向输出。*/#include <stdio.h> #include <time.h> #include <…

一文读懂:AWS 网络对等互连(VPC peering)实用操作指南

VPC peering connection-网络对等互连在您的 Atlas VPC 和云提供商的 VPC 之间建立私有连接。该连接将流量与公共网络隔离以提高安全性。本篇文章有VPC peering的操作指南以及价格等信息。如还有疑问请联系我们MongoDB的销售&#xff0c;客户成功经理或解决方案架构师。 1 使用…

2000-2022年各省环境规制数据(原始数据+计算过程+计算结果)

2000-2022年各省环境规制数据&#xff08;原始数据计算过程计算结果&#xff09; 1、时间&#xff1a;2000-2022年 2、范围&#xff1a;30省 3、来源&#xff1a;各省年鉴、国家统计局、统计年鉴 4、指标&#xff1a;年份、省份、工业污染源治理投资完成实际额、工业增加值…

gitlab,从A仓库迁移某个工程到B仓库,保留提交记录

从A仓库&#xff0c;拷贝 git clone --bare ssh://git192.168.30.88:22/framework/platform.git 在B仓库新建工程&#xff0c;注意&#xff1a;一定要去掉默认的生成README文件进入platform.git 文件夹下&#xff0c;推送到B仓库 git push --mirror ssh://git192.168.30.100…

压缩感知常用的重建算法

重建算法的基本概念 在压缩感知&#xff08;Compressed Sensing, CS&#xff09;框架中&#xff0c;重建算法是指将从原始信号中以低于奈奎斯特率采集得到的压缩测量值恢复成完整信号的数学和计算过程。由于信号在采集过程中被压缩&#xff0c;因此重建算法的目标是找到最符合…

文件上传漏洞--Upload-labs--Pass20--数组绕过

一、漏洞原理 漏洞来源&#xff1a;count()函数漏洞。 现自定义一个数组 arr[]&#xff0c;定义arr[0]1,arr[3]2, 此时count(arr)的值为2&#xff0c;则arr[count[arr]]即为arr[2]&#xff0c;但是arr[2]未定义&#xff0c;即为一个空值&#xff0c;若使用count()函数的本意是…

图形系统开发实战课程:进阶篇(上)——6.图形交互操作:拾取

图形开发学院&#xff5c;GraphAnyWhere 课程名称&#xff1a;图形系统开发实战课程&#xff1a;进阶篇(上)课程章节&#xff1a;“图形交互操作:拾取”原文地址&#xff1a;https://www.graphanywhere.com/graph/advanced/2-6.html 第六章 图形交互操作:拾取 \quad 在图形系统…

【网络编程】okhttp深入理解

newCall 实际上是创建了一个 RealCall 有三个参数&#xff1a;OkHttpClient&#xff08;通用配置&#xff0c;超时时间等&#xff09; Request(Http请求所用到的条件&#xff0c;url等) 布尔变量forWebSocket&#xff08;webSocket是一种应用层的交互方式&#xff0c;可双向交互…

2.22使用GPIO子系统编写LED灯驱动,应用程序测试//注册三个按键的中断

使用GPIO子系统编写LED灯驱动 驱动程序 #include <linux/init.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/gpio.h> #include <linux/timer.h> #include <linux/interrupt.h>…

ubuntu22.04@Jetson Orin Nano之CSI IMX219安装

ubuntu22.04Jetson Orin Nano之CSI IMX219安装 1. 源由2. 安装2.1 硬件安装2.2 软件配置2.3 新增摄像头 3. 效果4. 参考资料 1. 源由 折腾半天时间&#xff0c;捣鼓这个套装摄像头(IMX219)的安装&#xff0c;死活就是没有这个设备。世界总是这么小&#xff0c;看看遇到问题的大…

排序算法之——快速排序

快速排序 1.基本思想2.图示详解——以升序排列为例3.对基本思想和图示的补充说明4.代码实现5.空间、时间复杂度5.1最好情况5.2最坏情况 6.区间按照基准值划分的方法6.1 Hoare法6.2 挖坑法 7.优化措施7.1三数取中法7.1.1三数取中法——核心代码7.1.2优化效果7.1.3补充说明 7.2 递…

docker 容器内服务随容器自动启动

docker 容器内服务随容器自动启动 背景准备工作方案一&#xff0c;直接修改.bashrc文件&#xff08;简单粗暴&#xff09;方案二&#xff0c;编写启动脚本加入.bashrc文件&#xff08;文明一点&#xff09;制作nginx服务自启动镜像测试新镜像&#xff0c;nginx服务随容器自动启…

回显服务器的制作方法

文章目录 客户端和服务器TCP和UDP的特点UDP socket api的使用DatagramSocketDatagramPacketInetSocketAddress API 做一个简单的回显服务器UDP版本的回显服务器TCP版本的回显服务器 客户端和服务器 在网络中&#xff0c;主动发起通信的一方是客户端&#xff0c;被动接受的这一方…

Rman全备和增量备份说明

RMAN备份分为全备和增量备份&#xff0c;全备不能成为增量备份策略的一部分&#xff0c;它也不能作为后续增量备份的基础。 RMAN增量备份分为0、1、2三级&#xff0c;其中0级备份是增量备份的基础&#xff0c;备份内容也跟全备份一样&#xff0c;要使用增量备份&#xff0c;必…