一起学SF框架系列5.12-spring-beans-数据绑定dataBinding
数据绑定有助于将用户输入动态绑定到应用程序的域模型(或用于处理用户输入的任何对象),主要用于web层,但实际可用于任何层。Spring提供了DataBinder来做到这一点,并提供了Validator进行数据验证,两者组成了完整的数据输入数据处理机制。但数据绑定主要应用于 Spring 内部(如在SpringMVC中,http传入/返回参数如何绑定到具体参数或类上,就是通过数据绑定进行的),开发者直接使用的场景并不多。如果想要深入理解 Spring 内部的运行机制,数据绑定是必须了解的一块内容。
体验数据绑定
先以如下例子体验数据绑定:
@Component
public class DemoDatabinder{public void demo() {// 数据Address Address addr=new Address();addr.setProvince("四川");addr.setCity("成都");addr.setCounty("高新区");addr.setDesc("学习大道168");// 待绑定的数据driverDriver driver=new Driver();/* 准备绑定的数据(实际应用中看做前端输入的数据) */Map<String, Object> input = new HashMap<>();input.put("surname", "wang");input.put("name", "wang");// age是整形 注1input.put("age", 20);// address是对象input.put("address", addr);/* 绑定数据 *///把准备绑定的数据转换成绑定PropertyValues PropertyValues propertyValues = new MutablePropertyValues(input);// 用DataBinder 进行绑定DataBinder dataBinder = new DataBinder(driver);dataBinder.bind(propertyValues); BindingResult br = dataBinder.getBindingResult(); if(br.hasErrors())System.out.println("数据绑定错误");}
}
注1:age是整形,输入值可以是整形20,也可以是字符串“20”或“20 ”(包含空格)
从上例中可看出,数据绑定就是把输入数据(input)绑定到对象(driver)的对应属性上,绑定有以下要求:
1、输入数据名同对象属性名相同。
2、输入数据值的数据类型同对象属性的数据类型可以不一致,绑定会自动转换。
Spring数据绑定
功能
Spring中,DataBinder有两大功能:
1、设置对象属性值。
2、对数据进行校验(数据校验见:https://blog.csdn.net/davidwkx/article/details/131401699)。
作用
Spring作为一个成熟框架,数据绑定是重要特性之一,数据绑定主要作用体现如下:
1、在WEB环境下,Spring可自动把Http中的请求参数或者请求体中的Json字符串绑定到对应实体对象上,这样可大大提高开发人员的效率,这是开发人员直观感知到的数据绑定。非WEB环境,开发人员也可按需使用数据绑定技术,只不过很少使用而已。
2、Spring框架本身也用到数据绑定:在xml中配置bean属性或注解配置属性,也是用的数据绑定来实现的。
类关系图

从图中可以看出,除了DataBinder使用的数据PropertyValues,关系图比较简单,只是实现了PropertyEditorRegistry, TypeConverter。
BindingResult继承于Errors,保存绑定结果,包括错误信息。
PropertyEditorRegistry
设置bean属性值的属性编辑器,代码如下:
public interface PropertyEditorRegistry {// 为给定类型的所有属性设置属性编辑器void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor);void registerCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor);// 获取给定类型低属性编辑器@NullablePropertyEditor findCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath);
}
TypeConverter
转换数据到指定的类型,接口定义简单(仅参数不同):
public interface TypeConverter {@Nullable<T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType) throws TypeMismatchException;@Nullable<T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable MethodParameter methodParam) throws TypeMismatchException;@Nullable<T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable Field field) throws TypeMismatchException;@Nullabledefault <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,@Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {throw new UnsupportedOperationException("TypeDescriptor resolution not supported");}
}
源码跟踪
DataBinder.bind(PropertyValues pvs)
// 过渡类public void bind(PropertyValues pvs) {MutablePropertyValues mpvs = (pvs instanceof MutablePropertyValues mutablePropertyValues ?mutablePropertyValues : new MutablePropertyValues(pvs));doBind(mpvs);}// 绑定处理protected void doBind(MutablePropertyValues mpvs) {// 根据允许绑定的字段检查给定的属性值,删除不允许的字段的值checkAllowedFields(mpvs);// 根据所需绑定字段检查给定的属性值,对于必须有值的字段如果没有值,生成缺少值的错误信息checkRequiredFields(mpvs);// 赋值到对象属性applyPropertyValues(mpvs);}// 过渡类protected void applyPropertyValues(MutablePropertyValues mpvs) {try {// Bind request parameters onto target object.// 赋值到对象属性 注1getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());}catch (PropertyBatchUpdateException ex) {// 绑定过程发生错误,则生成错误放到BindingResultfor (PropertyAccessException pae : ex.getPropertyAccessExceptions()) {getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult());}}}
注1:此处实际调用BeanWrapperImpl.setPropertyValues,其类关系图如下:

BeanWrapperImpl是BeanWrapper的默认实现,BeanWrapper是Spring服务于JavaBeans的底层接口,主要提供分析和操作JavaBeans,包括:获取和设置属性值(单独或批量)、获取属性描述符以及查询属性可读性/可写性的能力等。BeanWrapperImpl关系图比较复杂,这里不具体分析,只关注数据绑定用到的实现在AbstractPropertyAccessor.setPropertyValues
AbstractPropertyAccessor.setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
设置对象属性。
@Overridepublic void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)throws BeansException {List<PropertyAccessException> propertyAccessExceptions = null;// 把数据转换成MutablePropertyValues List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues mpvs ?mpvs.getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));if (ignoreUnknown) {this.suppressNotWritablePropertyException = true;}try {// 按数据逐一设置for (PropertyValue pv : propertyValues) {try {setPropertyValue(pv);}catch (NotWritablePropertyException ex) {if (!ignoreUnknown) {throw ex;}// Otherwise, just ignore it and continue...}catch (NullValueInNestedPathException ex) {if (!ignoreInvalid) {throw ex;}// Otherwise, just ignore it and continue...}catch (PropertyAccessException ex) {if (propertyAccessExceptions == null) {propertyAccessExceptions = new ArrayList<>();}propertyAccessExceptions.add(ex);}}}finally {if (ignoreUnknown) {this.suppressNotWritablePropertyException = false;}}// 如果有属性可访问性异常,组合成一个异常抛出if (propertyAccessExceptions != null) {PropertyAccessException[] paeArray = propertyAccessExceptions.toArray(new PropertyAccessException[0]);throw new PropertyBatchUpdateException(paeArray);}}// 过渡方法@Overridepublic void setPropertyValue(PropertyValue pv) throws BeansException {// 实现在AbstractNestablePropertyAccessor setPropertyValue(pv.getName(), pv.getValue());}
AbstractNestablePropertyAccessor .setPropertyValue(String propertyName, @Nullable Object value)
// 列出这个类便于后续理解-AbstractNestablePropertyAccessor内部类:用于存储属性token的Holder类protected static class PropertyTokenHolder {public PropertyTokenHolder(String name) {this.actualName = name;this.canonicalName = name;}public String actualName;public String canonicalName;@Nullablepublic String[] keys;}// 本类设置属性值入口@Overridepublic void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException {AbstractNestablePropertyAccessor nestedPa;try {// 获取属性访问器nestedPa = getPropertyAccessorForPropertyPath(propertyName);}catch (NotReadablePropertyException ex) {throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,"Nested property in path '" + propertyName + "' does not exist", ex);}// 将属性名称解析为相应的属性名称标记PropertyTokenHolder PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));// setPropertyValue在AbstractNestablePropertyAccessor 实现nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value));}// 分两种情况处理protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {if (tokens.keys != null) {// 集合类属性赋值processKeyedProperty(tokens, pv);}else {// 单个(非集合类)属性赋值processLocalProperty(tokens, pv);}}// 集合类属性赋值@SuppressWarnings({"unchecked", "rawtypes"})private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) {Object propValue = getPropertyHoldingValue(tokens);PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);if (ph == null) {throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.actualName, "No property handler found");}Assert.state(tokens.keys != null, "No token keys");String lastKey = tokens.keys[tokens.keys.length - 1];// 属性是数组类型if (propValue.getClass().isArray()) {Class<?> requiredType = propValue.getClass().getComponentType();int arrayIndex = Integer.parseInt(lastKey);Object oldValue = null;try {if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {oldValue = Array.get(propValue, arrayIndex);}// 转换数据为属性值类型Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),requiredType, ph.nested(tokens.keys.length));int length = Array.getLength(propValue);if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {Class<?> componentType = propValue.getClass().getComponentType();Object newArray = Array.newInstance(componentType, arrayIndex + 1);System.arraycopy(propValue, 0, newArray, 0, length);int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');String propName = tokens.canonicalName.substring(0, lastKeyIndex);setPropertyValue(propName, newArray);propValue = getPropertyValue(propName);}// Array赋值Array.set(propValue, arrayIndex, convertedValue);}catch (IndexOutOfBoundsException ex) {throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,"Invalid array index in property path '" + tokens.canonicalName + "'", ex);}}// 属性是list类型else if (propValue instanceof List list) {Class<?> requiredType = ph.getCollectionType(tokens.keys.length);int index = Integer.parseInt(lastKey);Object oldValue = null;if (isExtractOldValueForEditor() && index < list.size()) {oldValue = list.get(index);}Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),requiredType, ph.nested(tokens.keys.length));int size = list.size();if (index >= size && index < this.autoGrowCollectionLimit) {for (int i = size; i < index; i++) {try {list.add(null);}catch (NullPointerException ex) {throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,"Cannot set element with index " + index + " in List of size " +size + ", accessed using property path '" + tokens.canonicalName +"': List does not support filling up gaps with null elements");}}// list赋值-增加list.add(convertedValue);}else {try {// list赋值-增加或修改list.set(index, convertedValue);}catch (IndexOutOfBoundsException ex) {throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,"Invalid list index in property path '" + tokens.canonicalName + "'", ex);}}}// 属性是Map 类型else if (propValue instanceof Map map) {Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);// IMPORTANT: Do not pass full property name in here - property editors// must not kick in for map keys but rather only for map values.TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);Object convertedMapKey = convertIfNecessary(null, null, lastKey, mapKeyType, typeDescriptor);Object oldValue = null;if (isExtractOldValueForEditor()) {oldValue = map.get(convertedMapKey);}// Pass full property name and old value in here, since we want full// conversion ability for map values.Object convertedMapValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),mapValueType, ph.nested(tokens.keys.length));// map赋值map.put(convertedMapKey, convertedMapValue);}else {throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,"Property referenced in indexed property path '" + tokens.canonicalName +"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");}}// 单个(非集合类)属性赋值private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);if (ph == null || !ph.isWritable()) {if (pv.isOptional()) {if (logger.isDebugEnabled()) {logger.debug("Ignoring optional value for property '" + tokens.actualName +"' - property not found on bean class [" + getRootClass().getName() + "]");}return;}if (this.suppressNotWritablePropertyException) {// Optimization for common ignoreUnknown=true scenario since the// exception would be caught and swallowed higher up anyway...return;}throw createNotWritablePropertyException(tokens.canonicalName);}Object oldValue = null;try {Object originalValue = pv.getValue();Object valueToApply = originalValue;if (!Boolean.FALSE.equals(pv.conversionNecessary)) {/* 数据类型转换 */if (pv.isConverted()) {// 已转换直接取转换后的值valueToApply = pv.getConvertedValue();}else {if (isExtractOldValueForEditor() && ph.isReadable()) {try {oldValue = ph.getValue();}catch (Exception ex) {if (ex instanceof PrivilegedActionException pae) {ex = pae.getException();}if (logger.isDebugEnabled()) {logger.debug("Could not read previous value of property '" +this.nestedPath + tokens.canonicalName + "'", ex);}}}// 数据类型转换valueToApply = convertForProperty(tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());}pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);}// 赋值ph.setValue(valueToApply);}catch (TypeMismatchException ex) {throw ex;}catch (InvocationTargetException ex) {PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());if (ex.getTargetException() instanceof ClassCastException) {throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());}else {Throwable cause = ex.getTargetException();if (cause instanceof UndeclaredThrowableException) {// May happen e.g. with Groovy-generated methodscause = cause.getCause();}throw new MethodInvocationException(propertyChangeEvent, cause);}}catch (Exception ex) {PropertyChangeEvent pce = new PropertyChangeEvent(getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());throw new MethodInvocationException(pce, ex);}}
注:关于数据类型转换详见:https://blog.csdn.net/davidwkx/article/details/131913840
相关文章:
一起学SF框架系列5.12-spring-beans-数据绑定dataBinding
数据绑定有助于将用户输入动态绑定到应用程序的域模型(或用于处理用户输入的任何对象),主要用于web层,但实际可用于任何层。Spring提供了DataBinder来做到这一点,并提供了Validator进行数据验证,两者组成了…...
火热报名中 | 赛宁独家技术支持第七届“蓝帽杯”网络安全技能大赛
由公安部网络安全保卫局、教育部教育管理信息中心、中国教育协会指导,中国人民公安大学主办,奇安信科技集团股份有限公司协办,南京赛宁信息技术有限公司提供技术支持的2023第七届“蓝帽杯”全国大学生网络安全技能大赛于近日正式开启报名。 …...
无涯教程-jQuery - Ajax Tutorial函数
AJAX是用于创建交互式Web应用程序的Web开发技术。如果您了解JavaScript,HTML,CSS和XML,则只需花费一个小时即可开始使用AJAX。 为什么要学习Ajax? AJAX代表 A 同步 Ja vaScript和 X ML。 AJAX是一项新技术,可借助XML,HTML,CSS和Java Script创建更好,更快,更具交互性的Web应用…...
Android日志
Android中的日志工具类是Log(android.util.Log),这个类中提供了如下5个方法来供我们打印日志。 Log.v()。用于打印那些最为琐碎的、意义最小的日志信息。对应级别verbose,是Android日志里面级别最低的一种。 Log.d()。用于打印一…...
【Golang 接口自动化08】使用标准库httptest完成HTTP请求的Mock测试
目录 前言 http包的HandleFunc函数 http.Request/http.ResponseWriter httptest 定义被测接口 测试代码 测试执行 总结 资料获取方法 前言 Mock是一个做自动化测试永远绕不过去的话题。本文主要介绍使用标准库net/http/httptest完成HTTP请求的Mock的测试方法。 可能有…...
SpringBoot自定义注解 + AOP+分布式Redis 防止重复提交
第一步 引入依赖pom.xml: <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.16.3</version> <!-- 使用最新版本 --></dependency><dependency><groupId&g…...
3.yum安装分布式LNMP--剧本
文章目录 修改hosts创建剧本文件 修改hosts vim /etc/ansible/hosts[webservers] 192.168.242.67[dbservers] 192.168.242.68[phpservers] 192.168.242.69创建剧本文件 vim lnmp.yaml- name: nginx playhosts: webserversremote_user: rootvars:- http_port: 192.168.242.67:…...
论文笔记:Fine-Grained Urban Flow Prediction
2021 WWW 1 intro 细粒度城市流量预测 两个挑战 细粒度数据中观察到的网格间的转移动态使得预测变得更加复杂 需要在全局范围内捕获网格单元之间的空间依赖性单独学习外部因素(例如天气、POI、路段信息等)对大量网格单元的影响非常具有挑战性——>论…...
系统集成|第八章(笔记)
目录 第八章 进度管理8.1 主要过程8.1.1 规划进度管理8.1.2 定义活动8.1.3 排列活动顺序8.1.4 估算活动资源8.1.5 估算活动持续时间8.1.6 制定进度计划8.1.7 控制进度 8.2 注意与问题 上篇:第七章、范围管理 第八章 进度管理 8.1 主要过程 包括: 规划进…...
【分布式】分布式唯一 ID 的 几种生成方案以及优缺点snowflake优化方案
在互联网的业务系统中,涉及到各种各样的ID,如在支付系统中就会有支付ID、退款ID等。那一般生成ID都有哪些解决方案呢?特别是在复杂的分布式系统业务场景中,我们应该采用哪种适合自己的解决方案是十分重要的。下面我们一一来列举一…...
FFmpeg5.0源码阅读——av_interleaved_write_frame
摘要:本文主要详细描述FFmpeg中封装时写packet到媒体文件的函数av_interleaved_write_frame的实现。 关键字:av_interleaved_write_frame 读者须知:读者需要熟悉ffmpeg的基本使用。 1 基本调用流程 av_interleaved_write_frame的基本…...
力扣 70. 爬楼梯
题目来源:https://leetcode.cn/problems/climbing-stairs/description/ C题解(来源代码随想录): 本质上是一道斐波那契数题。 动规五部曲:定义一个一维数组来记录不同楼层的状态 确定dp数组以及下标的含义。dp[i]&am…...
AVFoundation - 媒体捕捉
文章目录 注意使用 NSCameraUsageDescriptioniOS 的摄像头可能比 Mac 更多功能特性@interface Capture ()<AVCaptureFileOutputRecordingDelegate>@property (strong, nonatomic) AVCaptureSession *captureSession; @property (weak, nonatomic) AVCaptureDeviceInput *…...
【新版系统架构补充】-嵌入式技术
嵌入式微处理体系结构 冯诺依曼结构 传统计算机采用冯诺依曼结构,也称普林斯顿结构,是一种将程序指令存储器和数据存储器合并在一起的存储器结构 冯诺依曼的计算机程序和数据共用一个存储空间,程序指令存储地址和数据存储地址指向同一个存…...
fpga开发--蜂鸣器发出连续不同的音调
描述 使用fpga蜂鸣器连续发出do,re,mi,fa,so,la,xi七个不同的音调,每个音调的持续时间为0.5s。 思路 采用状态机实现音调的转化,当do状态持续了0.5s之后转移到re状态,…...
Redis 主从同步原理
一、什么是主从同步? 主从同步,就是将数据冗余备份,主库(Master)将自己库中的数据,同步给从库(Slave)。 从库可以一个,也可以多个,如图所示: 二…...
opencv-28 自适应阈值处理-cv2.adaptiveThreshold()
什么是自适应阈值处理? 对于色彩均衡的图像,直接使用一个阈值就能完成对图像的阈值化处理。但是,有时图像的色彩是不均衡的,此时如果只使用一个阈值,就无法得到清晰有效的阈值分割结果图像。 有一种改进的阈值处理技术ÿ…...
Java泛型5——泛型通配符
注:以下内容基于Java 8,所有代码都已在Java 8环境下测试通过 目录: Java泛型1——概述Java泛型2——泛型类Java泛型3——泛型接口Java泛型4——泛型方法Java泛型5——泛型通配符Java泛型6——类型擦除 什么是通配符 在Java中,类…...
牛客 AB25 ranko的手表 JAVA 枚举
描述 ranko 的手表坏了,正常应该显示 xx:xx 的形式(4 个数字),比如下午 1 点半应该显示 13:30 ,但现在经常会有一些数字有概率无法显示。 ranko 在 �1t1 时刻看了下时间,过了一段时间在 &am…...
常微分方程建模R包ecode(二)——绘制相速矢量场
本节中我们考虑一个更为复杂的常微分方程模型, d X C d t ν ( X A Y A ) − β ⋅ X C ⋅ ( Y C Y A ) − ( μ g ) ⋅ X C , ( 1 ) d Y C d t β ⋅ X C ⋅ ( Y C Y A ) − ( μ g ρ ) ⋅ Y C , ( 2 ) d X A d t g ⋅ X C − β ⋅ X A ⋅ ( Y C Y A …...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)
cd /home 进入home盘 安装虚拟环境: 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境: virtualenv myenv 3、激活虚拟环境(激活环境可以在当前环境下安装包) source myenv/bin/activate 此时,终端…...
【java面试】微服务篇
【java面试】微服务篇 一、总体框架二、Springcloud(一)Springcloud五大组件(二)服务注册和发现1、Eureka2、Nacos (三)负载均衡1、Ribbon负载均衡流程2、Ribbon负载均衡策略3、自定义负载均衡策略4、总结 …...
渗透实战PortSwigger Labs指南:自定义标签XSS和SVG XSS利用
阻止除自定义标签之外的所有标签 先输入一些标签测试,说是全部标签都被禁了 除了自定义的 自定义<my-tag onmouseoveralert(xss)> <my-tag idx onfocusalert(document.cookie) tabindex1> onfocus 当元素获得焦点时(如通过点击或键盘导航&…...
GAN模式奔溃的探讨论文综述(一)
简介 简介:今天带来一篇关于GAN的,对于模式奔溃的一个探讨的一个问题,帮助大家更好的解决训练中遇到的一个难题。 论文题目:An in-depth review and analysis of mode collapse in GAN 期刊:Machine Learning 链接:...
