当前位置: 首页 > news >正文

Spring中的数据校验--进阶

分组校验

场景描述

在实际开发中经常会遇到这种情况:添加用户时,id是由后端生成的,不需要校验id是否为空,但是修改用户时就需要校验id是否为空。如果在接收参数的User实体类的id属性上添加NotNull,显然无法实现。这时候就可以定义分组,在需要校验id的时候校验,不需要的时候不校验。

定义分组

校验的分组通过接口的形式定义。

代码准备


/*** @author lihz* @date 2023/2/18*/
@RestController
@RequestMapping("/group/validation/")
public class GroupValidationController {@PostMapping("/insert")public String testInsert(@RequestBody @Validated({UserValidGroup.Insert.class}) UserInfo userInfo) {System.out.println(userInfo);return "OK";}@PostMapping("/update")public String testUpdate(@RequestBody @Validated({UserValidGroup.Update.class}) UserInfo userInfo) {System.out.println(userInfo);return "OK";}@PostMapping("/delete")public String testDelete(@RequestBody @Validated({UserValidGroup.Delete.class}) UserInfo userInfo) {System.out.println(userInfo);return "OK";}
}@Data
class UserInfo {@Min(value = 1, message = "ID不能小于1", groups = {UserValidGroup.Delete.class, UserValidGroup.Update.class})private int id;@NotBlank(message = "用户名不能为空", groups = {UserValidGroup.Update.class, UserValidGroup.Insert.class})private String username;@NotBlank(message = "密码不能为空", groups = {UserValidGroup.Update.class, UserValidGroup.Insert.class})@Length(min = 8, max = 20, message = "密码长度在8-20之间", groups = {UserValidGroup.Update.class, UserValidGroup.Insert.class})private String password;
}class UserValidGroup {public interface Insert {}public interface Update {}public interface Delete {}@GroupSequence({Insert.class, Update.class, Delete.class})public interface All {}
}

数据准备

insert测试

{"id": null,"username": "demon","password": "123456"
}

输出:

{"code": 1,"msg": "Validation failed for argument [0] in public java.lang.String com.jurassic.cloud.project.controller.GroupValidationController.testInsert(com.jurassic.cloud.project.controller.UserInfo): [Field error in object 'userInfo' on field 'password': rejected value [12345]; codes [Length.userInfo.password,Length.password,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.password,password]; arguments []; default message [password],20,8]; default message [密码长度在8-20之间]] ","data": null
}

注意:没有校验 id 属性。

update测试

{"id": null,"username": "demon","password": "123456"
}

输出:

{"code": 1,"msg": "Validation failed for argument [0] in public java.lang.String com.jurassic.cloud.project.controller.GroupValidationController.testUpdate(com.jurassic.cloud.project.controller.UserInfo) with 2 errors: [Field error in object 'userInfo' on field 'id': rejected value [0]; codes [Min.userInfo.id,Min.id,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.id,id]; arguments []; default message [id],1]; default message [ID不能小于1]] [Field error in object 'userInfo' on field 'password': rejected value [123456]; codes [Length.userInfo.password,Length.password,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.password,password]; arguments []; default message [password],20,8]; default message [密码长度在8-20之间]] ","data": null
}

注意:校验了 id 属性。

delete测试

{"id": null,"username": "demon","password": "123456"
}

输出:

{"code": 1,"msg": "Validation failed for argument [0] in public java.lang.String com.jurassic.cloud.project.controller.GroupValidationController.testDelete(com.jurassic.cloud.project.controller.UserInfo): [Field error in object 'userInfo' on field 'id': rejected value [0]; codes [Min.userInfo.id,Min.id,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.id,id]; arguments []; default message [id],1]; default message [ID不能小于1]] ","data": null
}

注意:仅验证 id 属性。

总结

如果未指定分组,则是Default组,不属于Default组的属性不会验证。

指定了分组,则仅验证指定的分组涉及的约束。

分组的高级特性

见其他JSR 380文档。

i18n

在进行约束声明时,会指定message属性,用于设置约束校验失败之后的提示,如果需要支持多语言,则不能得到期望的结果。

不指定message属性

如果不指定message,则会采用框架的默认值,会提供主流的语言,

框架解析message默认值的相关逻辑在 org.hibernate.validator.internal.engine.ValidationContext

private String interpolate(String messageTemplate,Object validatedValue,ConstraintDescriptor<?> descriptor,Map<String, Object> messageParameters,Map<String, Object> expressionVariables) {MessageInterpolatorContext context = new MessageInterpolatorContext(descriptor,validatedValue,getRootBeanClass(),messageParameters,expressionVariables);try {//使用 MessageInterpolator 解析return validatorScopedContext.getMessageInterpolator().interpolate(messageTemplate,context); }catch (ValidationException ve) {throw ve;}catch (Exception e) {throw LOG.getExceptionOccurredDuringMessageInterpolationException( e );}}

在约束定义时,会设置message的默认值,是个消息插值。例如:@NotNull{javax.validation.constraints.NotNull.message},定义了消息参数,在Resource BundleValidationMessages中作为Key获取 获取属性值。

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
@Documented
@Constraint(validatedBy = { })
public @interface NotNull {String message() default "{javax.validation.constraints.NotNull.message}";Class<?>[] groups() default { };Class<? extends Payload>[] payload() default { };@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })@Retention(RUNTIME)@Documented@interface List {NotNull[] value();}
}

image-20230218150941153

ValidationMessages.properties

javax.validation.constraints.NotBlank.message        = must not be blank
javax.validation.constraints.NotEmpty.message        = must not be empty
javax.validation.constraints.NotNull.message         = must not be null
javax.validation.constraints.Null.message            = must be null

AbstractMessageInterpolator

消息解析主要是通过MessageInterpolator的实现类,默认都继承AbstractMessageInterpolator。 此类默认会根据JVM的Locale来获取对应的i18n消息(源码中的 defaultLocale = Locale.getDefault() ),不能根据request传递来的Locale来显示对应的消息。

缺陷

只能显示JVM的locale对应的消息。

自定义MessageInterpolator

自定义一个 MessageInterpolator 实现并改写其第一个interpolate方法,可以根据request传递的locale进行动态显示。

 
@Configuration
public class I18nConstrainValidator {@Beanpublic Validator validator() {return Validation.byDefaultProvider().configure().messageInterpolator(new ParameterMessageInterpolator() {@Overridepublic String interpolate(String message, Context context) {return interpolate(message, context, Locale.getDefault());}@Overridepublic String interpolate(String message, Context context, Locale locale) {// 获取当前请求所指定的语言对应的LocaleLocale requestLocale = I18nUtil.getLocaleFromCurrentRequest();if (null == requestLocale) {requestLocale = locale;}return super.interpolate(message, context, requestLocale);}}).buildValidatorFactory().getValidator();}}

缺陷

当request指定了一种框架中不存在的语种时无法得到准确的对应语种的消息而是得到JVM Locale对应的消息。

语种不存在时会获取Locale.getDefault()对应的Locale

ResourceBundleMessageInterpolator

 
@Slf4j
@Configuration
public class ConstrainValidatorConfig {@Value("${spring.messages.basename}")private String[] baseNames;@Beanpublic Validator validator() {return Validation.byDefaultProvider().configure().messageInterpolator(new RequesLocaleAwareMessageInterpolator(// 提供AggregateResourceBundleLocator使得除了用框架提供的Validation ConstrainViolation// Message外,还可以用自己指定的或覆盖框架提供的。new AggregateResourceBundleLocator(Arrays.asList(baseNames)))).buildValidatorFactory().getValidator();}/*** 自定义ResourceBundleMessageInterpolator的若干方法,使得可根据request指定的语言返回对应语种的Validation* ConstrainViolation Message*/public static class RequesLocaleAwareMessageInterpolator extends ResourceBundleMessageInterpolator {public RequesLocaleAwareMessageInterpolator(ResourceBundleLocator userResourceBundleLocator) {super(userResourceBundleLocator);}@Overridepublic String interpolate(String message, Context context) {return interpolate(message, context, Locale.getDefault());}@Overridepublic String interpolate(String message, Context context, Locale locale) {// 获取当前请求所指定的语言对应的LocaleLocale requestLocale =    LocaleContextHolder.getLocale();log.debug("locale for javax.validation.Validator resolved: {}", requestLocale);if (null == requestLocale) {requestLocale = locale;}return super.interpolate(message, context, requestLocale);}}}

若注解的message未指定——即用的是框架默认值(如 {javax.validation.constraints.Size.message} ),则对于框架未提供的i18n语种(如 zh_CHS),在你自己项目的i18n文件里补充相应值即可(如在messages_zh_CHS.properties文件里增加 javax.validation.constraints.Size.message = 长度不能超过{max} );

若注解的message不用默认值,而是自己指定message,如 message=“{custom.constraints.Size.message.name}” ,则在你自己项目的i18n文件里补充相应值即可(如 custom.constraints.Size.message.name = 姓名的长度不能超过{max} )。此时,注解的message仍支持EL表达式。实际使用中推荐用此方案,因为这种方案不仅支持EL表达式、i18n消息、还支持返回可直接弹窗显示给用户的i18n字段名。

设置的properties文件,可以不叫 ValidationMessages,可以是任何文件名。

设置语言的方式

1、设置header: Accept-Language,基于 AcceptHeaderLocaleResolver 实现

2、设置session / cookie:基于 CookieLocaleResolverSessionLocaleResolver 实现。自定义参数的名称,需要用到LocaleChangeInterceptor(需要启用,默认参数名为locale),用于监控哪个属性(可自定义)切换语言。

public static final String LOCALE_SESSION_ATTRIBUTE_NAME = SessionLocaleResolver.class.getName() + ".LOCALE";
public static final String LOCALE_REQUEST_ATTRIBUTE_NAME = CookieLocaleResolver.class.getName() + ".LOCALE";

CookieLocaleResolver,会把locale放到cookie中,cookieName:org.springframework.web.servlet.i18n.CookieLocaleResolver.LOCALE

3、固定locale。FixedLocaleResolver

spring.mvc.locale=zh_CN
//或者
spring:web:locale: zh_CNlocale-resolver: fixed

spring.web.locale-resolver 优先级比 spring.mvc.locale-resolver 高一些。

spring.web.localespring.mvc.locale 这两个配置属性,假如存在,就会成为AcceptHeaderLocaleResolver 的默认的Locale 区域对象。 并在请求响应的请求头中没有Accept-Language这个属性时,成为AcceptHeaderLocaleResolver返回的Locale 区域对象。

Spring实现原理

Spring会在启动时通过AOP对使用@Validated@Valid的类或其子类的对象生成一个代理对象。在代理对象中调用目标hanlder方法前后会分别进行参数、返回值的JSR校验。

MethodValidationPostProcessor

切面创建的相关逻辑在MethodValidationPostProcessor

//org.springframework.validation.beanvalidation
public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessorimplements InitializingBean {private Class<? extends Annotation> validatedAnnotationType = Validated.class;@Nullableprivate Validator validator;public void setValidatedAnnotationType(Class<? extends Annotation> validatedAnnotationType) {Assert.notNull(validatedAnnotationType, "'validatedAnnotationType' must not be null");this.validatedAnnotationType = validatedAnnotationType;}public void setValidator(Validator validator) {// Unwrap to the native Validator with forExecutables supportif (validator instanceof LocalValidatorFactoryBean) {this.validator = ((LocalValidatorFactoryBean) validator).getValidator();}else if (validator instanceof SpringValidatorAdapter) {this.validator = validator.unwrap(Validator.class);}else {this.validator = validator;}}public void setValidatorFactory(ValidatorFactory validatorFactory) {this.validator = validatorFactory.getValidator();}//此方法在bean自身初始化时会创建一个DefaultPointcutAdvisor用于向符合条件的对象添加进行方法验证的AOP advise@Overridepublic void afterPropertiesSet() {Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator));}//如果有 protected Advice createMethodValidationAdvice(@Nullable Validator validator) {return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());}}

MethodValidationPostProcessor实现了接口BeanPostProcessor定义的方法postProcessAfterInitialization(从父类AbstractAdvisingBeanPostProcessor继承),该方法会检查每个bean的创建(在该bean初始化之后),如果检测到该bean符合条件,会向其增加上述AOP advise

MethodValidationPostProcessor是被ValidationAutoConfiguration自动配置到IoC容器的。

ValidationAutoConfiguration

  package org.springframework.boot.autoconfigure.validation;@Configuration@ConditionalOnClass(ExecutableValidator.class)@ConditionalOnResource(resources = "classpath:META-INF/services/javax.validation.spi.ValidationProvider")@Import(PrimaryDefaultValidatorPostProcessor.class)public class ValidationAutoConfiguration {@Bean    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)@ConditionalOnMissingBean(Validator.class)public static LocalValidatorFactoryBean defaultValidator() {LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();factoryBean.setMessageInterpolator(interpolatorFactory.getObject());return factoryBean;}// 向容器注册一个 bean MethodValidationPostProcessor  @Bean@ConditionalOnMissingBeanpublic static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment, @Lazy Validator validator) {MethodValidationPostProcessor processor = new MethodValidationPostProcessor();boolean proxyTargetClass = environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);processor.setProxyTargetClass(proxyTargetClass);processor.setValidator(validator);return processor;}}

MethodValidationInterceptor

切面中进行参数验证、返回值验证的相关逻辑在MethodValidationInterceptor

@Override
@SuppressWarnings("unchecked")
public Object invoke(MethodInvocation invocation) throws Throwable {// Avoid Validator invocation on FactoryBean.getObjectType/isSingletonif (isFactoryBeanMetadataMethod(invocation.getMethod())) {return invocation.proceed();}//获取对哪些组进行校验Class<?>[] groups = determineValidationGroups(invocation);// Standard Bean Validation 1.1 APIExecutableValidator execVal = this.validator.forExecutables();Method methodToValidate = invocation.getMethod();Set<ConstraintViolation<Object>> result;try {result = execVal.validateParameters(invocation.getThis(), methodToValidate, invocation.getArguments(), groups);}catch (IllegalArgumentException ex) {// Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011// Let's try to find the bridged method on the implementation class...methodToValidate = BridgeMethodResolver.findBridgedMethod(ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));result = execVal.validateParameters(invocation.getThis(), methodToValidate, invocation.getArguments(), groups);}if (!result.isEmpty()) {throw new ConstraintViolationException(result);}Object returnValue = invocation.proceed();result = execVal.validateReturnValue(invocation.getThis(), methodToValidate, returnValue, groups);if (!result.isEmpty()) {throw new ConstraintViolationException(result);}return returnValue;
}

附录

Spring MVC localeResolver


@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(localeChangeInterceptor());}/*** Cookie方式** @return*/@Beanpublic LocaleResolver localeResolver() {return new CookieLocaleResolver();}/*** 切换语言按钮URL?language=zh_CN,切换后将语言信息存入cookie;** @return*/@Beanpublic LocaleChangeInterceptor localeChangeInterceptor() {LocaleChangeInterceptor lci = new LocaleChangeInterceptor();//不设置,默认为locale。lci.setParamName("language");return lci;}
}

相关文章:

Spring中的数据校验--进阶

分组校验 场景描述 在实际开发中经常会遇到这种情况&#xff1a;添加用户时&#xff0c;id是由后端生成的&#xff0c;不需要校验id是否为空&#xff0c;但是修改用户时就需要校验id是否为空。如果在接收参数的User实体类的id属性上添加NotNull&#xff0c;显然无法实现。这时…...

多种方法解决谷歌(chrome)、edge、火狐等浏览器F12打不开调试页面或调试模式(面板)的问题。

文章目录1. 文章引言2. 解决问题3. 解决该问题的其他方法1. 文章引言 不论是前端开发者&#xff0c;还是后端开发者&#xff0c;我们在调试web项目时&#xff0c;偶尔弹出相关错误。 此时&#xff0c;我们需要打开浏览器的调试模式&#xff0c;如下图所示&#xff1a; 通过浏…...

默认生成的接口实现方法体的问题

随着集成开发环境越来越强大&#xff0c;编程开发工作也变得越来越高效&#xff0c;很多的代码都不需要逐字输入&#xff0c;可以利用代码生成和自动补全来辅助开发。但是这样的便利也可能引起一些疏忽&#xff0c;本文就Java开发中默认生成的接口实现方法来谈谈以前遇到的问题…...

【OJ】十级龙王间的决斗

&#x1f4da;Description: 在《驯龙高手2》&#xff0c;最精彩的高潮出现在两只阿尔法决斗的时候。 驯龙高手中的十星龙王又称喷冰龙&#xff0c;有且只有两只&#xff0c;是最大型的龙&#xff0c;所有其他龙都要膜拜它&#xff08;当然&#xff0c;幼龙除外&#xff09;&…...

java 自定义注解

文章目录前言Annotation包自定义注解自定义注解示例参考文章&#xff1a;java 自定义注解 用处_java注解和自定义注解的简单使用参考文章&#xff1a;java中自定义注解的作用和写法前言 在使用Spring Boot的时候&#xff0c;大量使用注解的语法去替代XML配置文件&#xff0c;十…...

产品经理知识体系:2.如何进行商业需求分析?

商业需求分析 思考 笔记 用户细分&#xff1a; 核心用户、用户分级 用户关系&#xff1a; 如何维护用户关系、维护等成本 关系和商业模式的整合 核心价值&#xff1a; 解决什么问题&#xff0c;满足什么需求&#xff0c;最终带给用户什么价值 渠道通道&#xff1a; 如何触达…...

EditPlus正则表达式替换字符串详解

正则表达式是一个查询的字符串&#xff0c;它包含一般的字符和一些特殊的字符&#xff0c;特殊字符可以扩展查找字符串的能力&#xff0c;正则表达式在查找和替换字符串的作用不可忽视&#xff0c;它能很好提高工作效率。EditPlus的查找&#xff0c;替换&#xff0c;文件中查找…...

Go基础-环境安装

文章目录1 Go?Golang?2 下载Go3 windows安装4 测试是否成功1 Go?Golang? Go也称为Golang&#xff0c;是Google开发的一个开源的编译型的静态语言。 Golang的主要关注点是高可用、高并发和高扩展性&#xff0c;Go语言定位是系统级编程语言&#xff0c;对web程序具有很好的支…...

《NFL橄榄球》:纽约巨人·橄榄1号位

纽约巨人&#xff08;New York Giants&#xff09;是美国全国橄榄球联盟在新泽西州东卢瑟福的一支球队。巨人是在1925年作为五个成员之一加入国家美式橄榄球联盟。 在2018年时&#xff0c;球队市值为33亿美元&#xff0c;在世界前50名球队中并列第8名&#xff0c;同时在NFL高居…...

2023/02/18 ES6数组的解读

1 扩展运算符 扩展运算符&#xff08;spread&#xff09;是三个点&#xff08;…&#xff09;. 它好比 rest 参数的逆运算&#xff0c;将一个数组转为用逗号分隔的参数序列. console.log(...[1, 2, 3]) // 1 2 3console.log(1, ...[2, 3, 4], 5) // 1 2 3 4 5该运算符主要用于…...

Ubuntu 20 安装包下载(清华镜像)

Ubuntu 20 安装包下载在国内推荐使用清华大学镜像 清华镜像地址&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/ 在搜索框中输入Ubuntu&#xff0c;然后点击Ubuntu -release&#xff0c;这里面有近几年的Ubuntu镜像 点击你想下载的版本&#xff0c;我选择的是20.0413点击…...

华为OD机试 - 机器人走迷宫(JS)

机器人走迷宫 题目 房间有X*Y的方格组成&#xff0c;例如下图为6*4的大小。每一个放个以坐标(x,y)描述。 机器人固定从方格(0,0)出发&#xff0c;只能向东或者向北前进&#xff0c; 出口固定为房间的最东北角&#xff0c;如下图的方格(5,3)。 用例保证机器人可以从入口走到出…...

字节二面:10Wqps超高流量系统,如何设计?

超高流量系统设计思路 前言 在40岁老架构师 尼恩的**读者交流群(50)**中&#xff0c;大流量、高并发的面试题是一个非常、非常高频的交流话题。最近&#xff0c;有小伙伴面试字节时&#xff0c;遇到一个面试题&#xff1a; 10Wqps超高流量系统&#xff0c;该如何设计&#xf…...

基于springboot+html汽车维修系统汽车维修系统的设计与实现

基于springboothtml汽车维修系统汽车维修系统的设计与实现 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1…...

营销狂人杜国楹的两大顶级思维

“营销狂人”小罐茶 杜国楹两大顶级思维 1.一定要有【参照物思维】 2.一定要有【终局思维】 趣讲大白话&#xff1a;大牛的思考就是不同 *********** 杜国楹对茶行业思考 1.参照咖啡、酒的发展路径 2.中国茶工业化,品牌化是唯一壮大之路 3.龙头企业必须全品 没有参照物思维就没…...

面试题-前端开发JavaScript篇下(答案超详细)

文章目录 实现一个 once 函数,传入函数参数只执行一次将原生的 ajax 封装成 promisJS 监听对象属性的改变如何实现一个私有变量,用 getName 方法可以访问,不能直接访问==和===、以及 Object.is 的区别setTimeout、setInterval 和 requestAnimationFrame 之间的区别实现一个两…...

Android 9.0 修改Recovery字体图片的大小(正在清理)文字大小

1.概述 在9.0的系统产品定制化开发中,在系统中recovery功能也是非常重要的功能,所以说在进行recovery的时候,正在清理的 字体显示的有些小了,所以产品需求要求改大recovery的字体大小,所以这就需要在recovery页面看下字体大小的显示逻辑然后修改字体的显示大小,主要功能修…...

操作系统 五(文件系统)

一 文件定义&#xff1a;文件是指由创建者所定义的&#xff0c;具有文件名的一组相关元素的集合&#xff0c;可分为有结构文件和无结构文件两类。在有结构文件中&#xff0c;文件由若干个相关记录组成。而无结构文件则被看成一个字节流。文件在文件系统中是一个最大的数据单位&…...

华为OD机试 - 人数最多的站点(JS)

人数最多的站点 题目 公园园区提供小火车单向通行,从园区站点编号最小到最大, 通行如1~2~3~4~1万,然后供员工在各个办公园区穿梭, 通过对公司N个员工调研统计到每个员工的坐车区间,包含前后站点, 请设计一个程序计算出小火车在哪个园区站点时人数最多。 输入 输入的第…...

Mr. Cappuccino的第41杯咖啡——Kubernetes之Pod调度策略

Kubernetes之Pod调度策略Pod的4种调度策略定向调度nodeNamenodeSelector亲和性调度node亲和性硬限制软限制关系运算符pod亲和性pod反亲和性污点和容忍污点&#xff08;taints&#xff09;容忍&#xff08;tolerations&#xff09;默认情况下&#xff0c;Scheduler计算出一个Pod…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...