SpringBoot使用Validation校验参数

准备工作

引入相关依赖:

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>

约束性注解(简单)说明

@AssertFalse可以为null,如果不为null的话必须为false
@AssertTrue可以为null,如果不为null的话必须为true
@DecimalMax设置不能超过最大值
@DecimalMin设置不能超过最小值
@Digits设置必须是数字且数字整数的位数和小数的位数必须在指定范围内
@Future日期必须在当前日期的未来
@Past日期必须在当前日期的过去
@Max最大不得超过此最大值
@Min最大不得小于此最小值
@NotNull不能为null,可以是空
@Null必须为null
@Pattern必须满足指定的正则表达式
@Size集合、数组、map等的size()值必须在指定范围内
@Email必须是email格式
@Length长度必须在指定范围内
@NotBlank字符串不能为null,字符串trim()后也不能等于“”
@NotEmpty不能为null,集合、数组、map等size()不能为0;字符串trim()后可以等于“”
@Range值必须在指定范围内
@URL必须是一个URL

param:

@Data
public class User {@NotNull(message = "Name cannot be null")private String name;@Min(value = 18, message = "Age must be at least 18")private int age;}

test:

  @Testvoid test() {ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();Validator validator = validatorFactory.getValidator();User user = new User();user.setName(null); // 故意设置为 nulluser.setAge(15);    // 故意设置为小于 18Set<ConstraintViolation<User>> validate = validator.validate(user);for (ConstraintViolation<User> violation : validate) {System.out.println(violation.getMessage());}}

 ValidatorFactory

  • ValidatorFactory 是一个工厂类,用于创建 Validator 实例。

  • 它负责管理验证器的生命周期,并提供默认的验证器配置。

2. Validation.buildDefaultValidatorFactory()

  • Validation 是一个静态类,提供了构建默认 ValidatorFactory 的方法。

  • buildDefaultValidatorFactory() 方法会根据默认的配置(如 hibernate-validator 或其他实现)创建一个 ValidatorFactory

3. validatorFactory.getValidator()

  • 通过 ValidatorFactory 获取一个 Validator 实例。

  • Validator 是实际执行验证操作的接口,用于验证 Java Bean 中的约束(如 @NotNull@Size 等注解)。

@Validated的使用时机

@Validated的使用位置较多(可详见源码),但其主流的使用位置却是以下两种:

1、在Controller层中,放在模型参数对象前。
          当Controller层中参数是一个对象模型时,只有将@Validated直接放在该模型前,该模型内部的字段才会被校验(如果有对该模型的字段进行约束的话)。

2、在Controller层中,放在类上。
           当一些约束是直接出现在Controller层中的参数前时,只有将@Validated放在类上时,参数前的约束才会生效

import com.aspire.model.ValidationBeanModel;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.validation.constraints.DecimalMax;/*** Controller层 --- 初步简单测试 @Validated 的使用位置** 对比测试过程:*    方案一 : 不在类上加@Validated注解,访问这六个接口*    方案二 : 在类上加@Validated注解,再次访问这六个接口**    对比方案一和方案二,可初步得出@Validated的使用时机:*        1.当我们是在模型里面对模型字段添加约束注解,在Controller中使用模型接收数*          据时,@Validated要直接放在该模型参数前才有效。 如: "/test/one"*        2.当我们是直接在Controller层中的参数前,使用约束注解时,@Validated要直接放在类上,*          才会有效。如: /test/six*** @author JustryDeng* @date 2019/1/18 22:22*/
@RestController
@Validated
public class JustryDengController {@RequestMapping(value = "/test/one")public String validatioOne(@Validated ValidationBeanModel.AbcDecimalMax myDecimalMax) {System.out.println(myDecimalMax.getMyDecimalMax());return "one pass!";}@RequestMapping(value = "/test/two")@Validatedpublic String validatioTwo(ValidationBeanModel.AbcDecimalMax myDecimalMax) {System.out.println(myDecimalMax.getMyDecimalMax());return "two pass!";}@RequestMapping(value = "/test/three")public String validatioThree(ValidationBeanModel.AbcDecimalMax myDecimalMax) {System.out.println(myDecimalMax.getMyDecimalMax());return "three pass!";}@RequestMapping(value = "/test/four")public String validatioFour(@Validated  @DecimalMax(value = "12.3") String myDecimalMax) {System.out.println(myDecimalMax);return "four pass!";}@RequestMapping(value = "/test/five")@Validatedpublic String validatioFive(@DecimalMax(value = "12.3") String myDecimalMax) {System.out.println(myDecimalMax);return "five pass!";}@RequestMapping(value = "/test/six")@Validatedpublic String validatioSix(@DecimalMax(value = "12.3") String myDecimalMax) {System.out.println(myDecimalMax);return "six pass!";}
}

@Validated与@Valid的简单对比说明

 
        @Valid注解与@Validated注解功能大部分类似;两者的不同主要在于:@Valid属于javax下的,而@Validated属于spring下;@Valid支持嵌套校验、而@Validated不支持,@Validated支持分组,而@Valid不支持。笔者这里只简单介绍@Validated的使用时机。

自定义注解

        虽然Bean Validation和Hibernate Validator已经提供了非常丰富的校验注解,但是在实际业务中,难免会碰到一些现有注解不足以校验的情况;这时,我们可以考虑自定义Validation注解。

第一步:创建自定义注解

import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import javax.validation.Constraint;import static java.lang.annotation.ElementType.FIELD;/*** 自定义校验注解* 提示:*     1、message、contains、payload是必须要写的*     2、还需要什么方法可根据自己的实际业务需求,自行添加定义即可** 注:当没有指定默认值时,那么在使用此注解时,就必须输入对应的属性值** @author JustryDeng* @date 2019/1/15 1:17*/
@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
@Documented
// 指定此注解的实现,即:验证器
@Constraint(validatedBy ={MyValidationImpl.class})
public @interface MyValidation {// 当验证不通过时的提示信息String message() default "校验失败";// 根据实际需求定的方法String contains() default "";// 约束注解在验证时所属的组别Class<?>[] groups() default { };// 负载Class<? extends Payload>[] payload() default { };
}

第二步:编写(第一步中的校验器实现类)该注解

import org.hibernate.validator.internal.engine.ValidationContext;
import org.hibernate.validator.internal.engine.ValueContext;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree;import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;/*** ConstraintsJustryDeng注解 校验器 实现* <p>* 注:验证器需要实现ConstraintValidator<U, V>, 其中 U为对应的注解类, V为被该注解标记的字段的类型(或其父类型)** 注: 当项目启动后,会(懒加载)创建ConstraintValidator实例,在创建实例后会初始化调*     用{@link ConstraintValidator#initialize}方法。*     所以, 只有在第一次请求时,会走initialize方法, 后面的请求是不会走initialize方法的。** 注: (懒加载)创建ConstraintValidator实例时, 会走缓存; 如果缓存中有,则直接使用相*     同的ConstraintValidator实例; 如果缓存中没有,那么会创建新的ConstraintValidator实例。*     由于缓存的key是能唯一定位的, 且 ConstraintValidator的实例属性只有在*     {@link ConstraintValidator#initialize}方法中才会写;在{@link ConstraintValidator#isValid}*     方法中只是读。*     所以不用担心线程安全问题。** 注: 如何创建ConstraintValidator实例的,可详见源码*     @see ConstraintTree#getInitializedConstraintValidator(ValidationContext, ValueContext)** @author JustryDeng* @date 2019/1/15 1:19*/
public class MyValidationImpl implements ConstraintValidator<MyValidation, Object> {/** 错误提示信息 */private String contains;/*** 初始化方法, 在(懒加载)创建一个当前类实例后,会马上执行此方法** 注: 此方法只会执行一次,即:创建实例后马上执行。** @param constraintAnnotation*         注解信息模型,可以从该模型中获取注解类中定义的一些信息,如默认值等* @date 2019/1/19 11:27*/@Overridepublic void initialize(MyValidation constraintAnnotation) {System.out.println(constraintAnnotation.message());this.contains = constraintAnnotation.contains();}/*** 校验方法, 每个需要校验的请求都会走这个方法** 注: 此方法可能会并发执行,需要根据实际情况看否是需要保证线程安全。** @param value*         被校验的对象* @param context*         上下文** @return 校验是否通过*/@Overridepublic boolean isValid(Object value, ConstraintValidatorContext context) {if (value == null) {return false;}if (value instanceof String) {String strMessage = (String) value;return strMessage.contains(contains);} else if (value instanceof Integer) {return contains.contains(String.valueOf(value));}return false;}}

第三步:自定义注解简单使用测试

@Testvoid test2() {ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();Validator validator = validatorFactory.getValidator();User user = new User();user.setName("ddd"); // 故意设置为 nulluser.setAge(15);    // 故意设置为小于 18Set<ConstraintViolation<User>> validate = validator.validate(user);for (ConstraintViolation<User> violation : validate) {System.out.println(violation.getMessage());}}
@Data
public class User {@MyValidation(message = "校验测试",contains = "a")private String name;@Min(value = 18, message = "Age must be at least 18")private int age;}

效果:

对注解抛出的异常进行处理

 
说明:当注解校验不通过时,直接将异常信息返回给前端其实并不友好,我们可以将异常包装一下,返回给前端。

情况一:使用BindingResult类来容纳异常信息,当校验不通过时,不影响正常程
               序往下走。我们只需要处理BindingResult中的异常信息即可。

处理前:

参数模型是这样的:

Controller是这样的

使用postman测试,当校验不通过时显示如下:

处理后:

参数模型是这样的(没有变):

 Controller是这样的(在@Validated注解的参数后,紧接着加上BindingResult):

再次使用postman测试,当校验不通过时显示如下: 

postman中返回了数据,说明虽然参数错误,但是不影响程序的执行。

程序在控制台输出了如下信息:

可见,后台已经获悉了错误,至于怎么处理,这就看伟大的程序员们了。
 

情况二(推荐):通过SpringMVC全局异常处理器来处理异常。

 描述:如果不采用BindingResult来容纳异常信息时,那么异常会被向外抛出。注解校验不通过时,可能抛出的异常有BindException异常、ValidationException异常(或其子类异常)、
           MethodArgumentNotValidException异常。

处理前:

示例一:Controller和对应的参数模型是这样的:

使用postman测试,当校验不通过时显示如下: 

示例二:Controller是这样的: 

使用postman测试,当校验不通过时显示如下:

注:ConstraintViolationException异常是ViolationException异常的子异常。

示例三:Controller是这样的:

 

注:此处的User模型与情况一里给出的模型是一样的,这里就不再给出了。

使用postman测试,当校验不通过时显示如下:

 

进行处理:加入全局异常处理器: 

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.HashMap;
import java.util.Map;/*** SpringMVC统一异常处理** @author JustryDeng* @date 2019/10/12 16:28*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {/*** 处理Validated校验异常* <p>* 注: 常见的ConstraintViolationException异常, 也属于ValidationException异常** @param e*         捕获到的异常* @return 返回给前端的data*/@ResponseStatus(code = HttpStatus.BAD_REQUEST)@ExceptionHandler(value = {BindException.class, ValidationException.class, MethodArgumentNotValidException.class})public Map<String, Object> handleParameterVerificationException(Exception e) {log.error(" handleParameterVerificationException has been invoked", e);Map<String, Object> resultMap = new HashMap<>(4);resultMap.put("code", "100001");String msg = null;/// MethodArgumentNotValidExceptionif (e instanceof MethodArgumentNotValidException) {BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();// getFieldError获取的是第一个不合法的参数(P.S.如果有多个参数不合法的话)FieldError fieldError = bindingResult.getFieldError();if (fieldError != null) {msg = fieldError.getDefaultMessage();}/// BindException} else if (e instanceof BindException) {// getFieldError获取的是第一个不合法的参数(P.S.如果有多个参数不合法的话)FieldError fieldError = ((BindException) e).getFieldError();if (fieldError != null) {msg = fieldError.getDefaultMessage();}/// ValidationException 的子类异常ConstraintViolationException} else if (e instanceof ConstraintViolationException) {/** ConstraintViolationException的e.getMessage()形如*     {方法名}.{参数名}: {message}*  这里只需要取后面的message即可*/msg = e.getMessage();if (msg != null) {int lastIndex = msg.lastIndexOf(':');if (lastIndex >= 0) {msg = msg.substring(lastIndex + 1).trim();}}/// ValidationException 的其它子类异常} else {msg = "处理参数时异常";}resultMap.put("msg", msg);return resultMap;}}

 处理后,使用postman再次进行上述两个请求:

可见,异常处理成功! 



经常存在加参数校验后就不加触发注解的情况,前一段公司在做国际化的时候就发现了两个服务一个参数注解都没触发的情况,让人痛心疾首,那么有没有可以不加参数注解就能自动为我们触发参数方法呢?

AOP实现触发参数校验

公司部分服务是这样做的

/**** @Description:参数效验拦截器* Author	Version		Date		Changes* zjf 1.0  2020年11月30日 Created*/
@Aspect
@Component
@Slf4j
public class ValidateParameterAspectAdvice implements Ordered {@Autowiredprivate ParamCheckSpringUtils paramCheckSpringUtils;/*** (non-Javadoc)* @see Ordered#getOrder()*/@Overridepublic int getOrder() {return 1000;}@Before("execution(* com.echronos.iform.feign.*.*(..)) || execution(* com.echronos.iform.controller.*.*(..))")public void before(JoinPoint pjd) {Object[] args = pjd.getArgs();if (args.length > 0) {Object oneParam = args[0];MethodSignature signature = (MethodSignature) pjd.getSignature();Method method = signature.getMethod();Annotation[][] parameterAnnotations = method.getParameterAnnotations();List<Class<?>> list = new ArrayList<>();for (Annotation[] annotations : parameterAnnotations) {for (Annotation annotation : annotations) {if (annotation instanceof ConvertGroup) {list.add(Default.class);ConvertGroup convertGroup = (ConvertGroup) annotation;Class<?> curClass = convertGroup.to();list.add(curClass);}else if (annotation instanceof ConvertGroup.List) {ConvertGroup.List convertGroupList = (ConvertGroup.List) annotation;ConvertGroup[] groups = convertGroupList.value();for (ConvertGroup convertGroup : groups) {Class<?> curClass = convertGroup.to();list.add(curClass);}}}}Class<?> targetClass = method.getDeclaringClass();log.info("{}方法,入参为:{}", targetClass.getName() + "#" + method.getName(), FastJsonUtils.toJSONNoFeatures(oneParam));//异常处理String check = null;if(list.size() > 1){Class[] arrClass = list.toArray(new Class[list.size()]);check = paramCheckSpringUtils.checkParam(oneParam,arrClass);}else{check = paramCheckSpringUtils.checkParam(oneParam);}if (check != null) {throw new ParamsValidateException(CommonResultCode.CommonResultEnum.BAD_REQUEST.getCode(), check);}}}
}
@Component
public class ParamCheckSpringUtils {@Autowiredprivate Validator validator;public ParamCheckSpringUtils() {}public <T> String checkParam(final T obj, final Class<?>... group) {List<String> list = new ArrayList();Set<ConstraintViolation<T>> constraintViolations = this.validator.validate(obj, (Class[])group);StringBuilder strBuilder = new StringBuilder();if (constraintViolations != null && constraintViolations.size() > 0) {Iterator var6 = constraintViolations.iterator();while(var6.hasNext()) {ConstraintViolation<T> cv = (ConstraintViolation)var6.next();if (!list.contains(String.valueOf(cv.getPropertyPath()))) {list.add(String.valueOf(cv.getPropertyPath()));strBuilder.append(cv.getMessage()).append(";");}}return strBuilder.toString();} else {return null;}}public <T> String checkParam(final T obj, final Class<?> group, final String... args) {StringBuilder strBuilder = new StringBuilder("");if (args != null) {String[] var5 = args;int var6 = args.length;for(int var7 = 0; var7 < var6; ++var7) {String param = var5[var7];Set<ConstraintViolation<T>> constraintViolations = this.validator.validateProperty(obj, param, new Class[]{group});if (constraintViolations != null && constraintViolations.size() > 0) {Iterator var10 = constraintViolations.iterator();while(var10.hasNext()) {ConstraintViolation<T> cv = (ConstraintViolation)var10.next();strBuilder.append(cv.getMessage()).append(";");}}}}return strBuilder.toString().equals("") ? null : strBuilder.toString();}
}


 

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

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

相关文章

Websocket客户端从Openai Realtime api Sever只收到部分数据问题分析

目录 背景 分析 解决方案 背景 正常情况下&#xff0c;会从Openai Realtime api Sever收到正常的json数据,但是当返回音频数据时&#xff0c;总会返回非json数据。这是什么问题呢&#xff1f; 分析 期望的完整响应数据如下&#xff1a; {"session": {"inp…

dockerfile文档编写(1):基础命令

目录 Modelscope-agentARGFROMWORKDIRCOPYRUNENVCMD run_loopy Modelscope-agent ARG BASE_IMAGEregistry.cn-beijing.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.1.0-py310-torch2.1.2-tf2.14.0-1.12.0FROM $BASE_IMAGEWORKDIR /home/workspaceCOPY . /hom…

Redis-十大数据类型

Reids数据类型指的是value的类型&#xff0c;key都是字符串 redis-server:启动redis服务 redis-cli:进入redis交互式终端 常用的key的操作 redis的命令和参数不区分大小写 &#xff0c;key和value区分 查看当前库所有的key keys * 判断某个key是否存在 exists key 查看key是什…

数据结构之栈,队列,树

目录 一.栈 1.栈的概念及结构 2.栈的实现 3.实现讲解 1.初始化栈 2.销毁栈 3.压栈 4.出栈 5.返回栈顶元素 6.返回栈内元素个数 7.判断栈内是否为空 二.队列 1.队列的概念及结构 2.队列的实现 3.实现讲解 1.初始化队列 2.销毁队列 3.单个成员入队列 4.单个成员…

(六)循环神经网络_基本的RNN

一、提出背景 前馈神经网络不考虑数据之间的关联性&#xff0c;网络的输出只和当前时刻网络的输入相关。然而&#xff0c;现实问题中存在着很多序列型的数据&#xff08;文本、语音以及视频等&#xff09;。 例如&#xff1a;室外的温度是随着气候的变化而周期性的变化的&…

React引入Echart水球图

在搭建React项目时候&#xff0c;遇到了Echart官方文档中没有的水球图&#xff0c;此时该如何配置并将它显示到项目中呢&#xff1f; 目录 一、拓展网站 二、安装 三、React中引入 1、在components文件夹下新建一个组件 2、在组件中引入 3、使用水波球组件 一、拓展网站 …

微软edge浏览器 v131.0.2903.99便携版

前言 Microsoft Edge浏览器是个新浏览器&#xff0c;它用起来很简单&#xff0c;界面也很清爽。这个浏览器功能特别多&#xff0c;里面还带了微软的小助手Contana&#xff0c;能帮用户做不少贴心的事儿。它支持安装各种小工具&#xff08;插件&#xff09;&#xff0c;还能在网…

深度学习中batch_size

Batch size调整和epoch/iteration的关系 训练数据集总共有1000个样本。若batch_size10&#xff0c;那么训练完全体样本集需要100次迭代&#xff0c;1次epoch。 训练样本10000条&#xff0c;batchsize设置为20&#xff0c;将所有的训练样本在同一个模型中训练5遍&#xff0c;则…

使用“NodeMCU”、“红外模块”实现空调控制

项目思路 空调遥控器之所以能够实现对空调的控制&#xff0c;是因为它能够向空调发射出特定的红外信号。从理论上来说&#xff0c;任何能够发射出这种相同红外信号的红外发射器&#xff0c;都可以充当空调遥控器&#xff08;这也正是手机能够控制多种不同品牌空调的原因所在&a…

Git--tag标签远程管理

目录 一、git 标签 tag管理 1.创建一个轻量级标签 2.创建一个带有附注的标签 3.删除标签 二、标签推送 1.再创建两个分支 2.把多个标签推送到远程 三、标签拉取 四、删除远程标签 1.命令 2.查看远程仓库&#xff0c;标签被删除 3.远程标签删除后本地标签不会消失&a…

43. Three.js案例-绘制100个立方体

43. Three.js案例-绘制100个立方体 实现效果 知识点 WebGLRenderer&#xff08;WebGL渲染器&#xff09; WebGLRenderer是Three.js中最常用的渲染器之一&#xff0c;用于将3D场景渲染到网页上。 构造器 WebGLRenderer(parameters : Object) 参数类型描述parametersObject…

【论文阅读笔记】Scalable, Detailed and Mask-Free Universal Photometric Stereo

【论文阅读笔记】Scalable, Detailed and Mask-Free Universal Photometric Stereo 前言摘要引言Task 相关工作方法SDM-UniPS预处理尺度不变的空间光特征编码器像素采样变压器的非局部交互 PS-Mix数据集 实验结果训练细节评估和时间&#xff1a; 消融实验定向照明下的评估没有对…

【LuaFramework】服务器模块相关知识

目录 一、客户端代码 二、本地服务器代码 三、解决服务器无法多次接收客户端消息问题 一、客户端代码 连接本地服务器127.0.0.1:2012端口&#xff08;如何创本地服务器&#xff0c;放最后说&#xff09;&#xff0c;连接成功后会回调 协议号Connect是101&#xff0c;其他如下…

攻防世界 robots

开启场景 根据提示访问/robots.txt&#xff0c;发现了 f1ag_1s_h3re.php 拼接访问 /f1ag_1s_h3re.php 发现了 flag cyberpeace{d8b7025ed93ed79d44f64e94f2527a17}

gitlab克隆仓库报错fatal: unable to access ‘仓库地址xxxxxxxx‘

首次克隆仓库&#xff0c;失效了&#xff0c;上网查方法&#xff0c;都说是网络代理的问题&#xff0c;各种清理网络代理后都无效&#xff0c;去问同事&#xff1a; 先前都是直接复制的网页url当做远端url&#xff0c;或者点击按钮‘使用http克隆’ 这次对于我来说有效的远端u…

数字IC后端设计实现十大精华主题分享

今天小编给大家分享下吾爱IC社区星球上周十大后端精华主题。 Q1:星主&#xff0c;请教个问题&#xff0c;长tree的时候发现这个scan的tree 的skew差不多400p&#xff0c;我高亮了整个tree的schematic&#xff0c;我在想是不是我在这一系列mux前边打断&#xff0c;设置ignore p…

华为管理变革之道:管理制度创新

目录 华为崛起两大因素&#xff1a;管理制度创新和组织文化。 管理是科学&#xff0c;150年来管理史上最伟大的创新是流程 为什么要变革&#xff1f; 向世界标杆学习&#xff0c;是变革第一方法论 体系之一&#xff1a;华为的DSTE战略管理体系&#xff08;解决&#xff1a…

CentOS7下的vsftpd服务器和客户端

目录 1、安装vsftpd服务器和ftp客户端&#xff1b; 2、配置vsftpd服务器&#xff0c;允许普通用户登录、下载、上传文件&#xff1b; 3、配置vsftpd服务器&#xff0c;允许anonymous用户登录、下载、上传文件&#xff1b; 4、配置vsftpd服务器&#xff0c;允许root用户登录…

Python Polars快速入门指南:LazyFrames

前文已经介绍了Polars的Dataframe, Contexts 和 Expressions&#xff0c;本文继续介绍Polars的惰性API。惰性API是该库最强大的功能之一&#xff0c;使用惰性API可以设定一系列操作&#xff0c;而无需立即运行它们。相反&#xff0c;这些操作被保存为计算图&#xff0c;只在必要…

【论文阅读笔记】IC-Light

SCALING IN-THE-WILD TRAINING FOR DIFFUSION-BASED ILLUMINATION HARMONIZATION AND EDITING BY IMPOSING CONSISTENT LIGHT TRANSPORT 通过施加一致的光线传输来扩展基于扩散模型的真实场景光照协调与编辑训练 前言摘要引言相关工作基于学习的基于扩散模型的外观和光照操纵光…