Spring Boot 实现各种参数校验,写得太好了,建议收藏!

简单使用

Java API规范(JSR303)定义了Bean校验的标准validation-api,但没有提供实现。hibernate validation是对这个规范的实现,并增加了校验注解如@Email、@Length等。

Spring Validation是对hibernate validation的二次封装,用于支持spring mvc参数自动校验。接下来,我们以spring-boot项目为例,介绍Spring Validation的使用。

引入依赖

如果spring-boot版本小于2.3.x,spring-boot-starter-web会自动传入hibernate-validator依赖。如果spring-boot版本大于2.3.x,则需要手动引入依赖:

<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.1.Final</version> </dependency>

对于web服务来说,为防止非法参数对业务造成影响,在Controller层一定要做参数校验的!大部分情况下,请求参数分为如下两种形式:

  • POST、PUT请求,使用requestBody传递参数;
  • GET请求,使用requestParam/PathVariable传递参数。

下面我们简单介绍下requestBody和requestParam/PathVariable的参数校验实战!

requestBody参数校验

POST、PUT请求一般会使用requestBody传递参数,这种情况下,后端使用DTO对象进行接收。只要给DTO对象加上@Validated注解就能实现自动参数校验。比如,有一个保存User的接口,要求userName长度是2-10,account和password字段长度是6-20。

如果校验失败,会抛出MethodArgumentNotValidException异常,Spring默认会将其转为400(Bad Request)请求。

DTO表示数据传输对象(Data Transfer Object),用于服务器和客户端之间交互传输使用的。在spring-web项目中可以表示用于接收请求参数的Bean对象。

在DTO字段上声明约束注解

@Data public class UserDTO { private Long userId; @NotNull @Length(min = 2, max = 10) private String userName; @NotNull @Length(min = 6, max = 20) private String account; @NotNull @Length(min = 6, max = 20) private String password; }

在方法参数上声明校验注解

@PostMapping("/save") public Result saveUser(@RequestBody @Validated UserDTO userDTO) { // 校验通过,才会执行业务逻辑处理 return Result.ok(); }

这种情况下,使用@Valid和@Validated都可以。

requestParam/PathVariable参数校验

GET请求一般会使用requestParam/PathVariable传参。如果参数比较多(比如超过6个),还是推荐使用DTO对象接收。

否则,推荐将一个个参数平铺到方法入参中。在这种情况下,必须在Controller类上标注@Validated注解,并在入参上声明约束注解(如@Min等)。如果校验失败,会抛出ConstraintViolationException异常。

代码示例如下:

@RequestMapping("/api/user") @RestController @Validated public class UserController { // 路径变量 @GetMapping("{userId}") public Result detail(@PathVariable("userId") @Min(10000000000000000L) Long userId) { // 校验通过,才会执行业务逻辑处理 UserDTO userDTO = new UserDTO(); userDTO.setUserId(userId); userDTO.setAccount("11111111111111111"); userDTO.setUserName("xixi"); userDTO.setAccount("11111111111111111"); return Result.ok(userDTO); } // 查询参数 @GetMapping("getByAccount") public Result getByAccount(@Length(min = 6, max = 20) @NotNull String account) { // 校验通过,才会执行业务逻辑处理 UserDTO userDTO = new UserDTO(); userDTO.setUserId(10000000000000003L); userDTO.setAccount(account); userDTO.setUserName("xixi"); userDTO.setAccount("11111111111111111"); return Result.ok(userDTO); } }

统一异常处理

前面说过,如果校验失败,会抛出MethodArgumentNotValidException或者ConstraintViolationException异常。在实际项目开发中,通常会用统一异常处理来返回一个更友好的提示。

比如我们系统要求无论发送什么异常,http的状态码必须返回200,由业务码去区分系统的异常情况。

@RestControllerAdvice public class CommonExceptionHandler { @ExceptionHandler({MethodArgumentNotValidException.class}) @ResponseStatus(HttpStatus.OK) @ResponseBody public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) { BindingResult bindingResult = ex.getBindingResult(); StringBuilder sb = new StringBuilder("校验失败:"); for (FieldError fieldError : bindingResult.getFieldErrors()) { sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", "); } String msg = sb.toString(); return Result.fail(BusinessCode.参数校验失败, msg); } @ExceptionHandler({ConstraintViolationException.class}) @ResponseStatus(HttpStatus.OK) @ResponseBody public Result handleConstraintViolationException(ConstraintViolationException ex) { return Result.fail(BusinessCode.参数校验失败, ex.getMessage()); } }

进阶使用

分组校验

在实际项目中,可能多个方法需要使用同一个DTO类来接收参数,而不同方法的校验规则很可能是不一样的。这个时候,简单地在DTO类的字段上加约束注解无法解决这个问题。因此,spring-validation支持了分组校验的功能,专门用来解决这类问题。

还是上面的例子,比如保存User的时候,UserId是可空的,但是更新User的时候,UserId的值必须>=10000000000000000L;其它字段的校验规则在两种情况下一样。这个时候使用分组校验的代码示例如下:

约束注解上声明适用的分组信息groups

@Data public class UserDTO { @Min(value = 10000000000000000L, groups = Update.class) private Long userId; @NotNull(groups = {Save.class, Update.class}) @Length(min = 2, max = 10, groups = {Save.class, Update.class}) private String userName; @NotNull(groups = {Save.class, Update.class}) @Length(min = 6, max = 20, groups = {Save.class, Update.class}) private String account; @NotNull(groups = {Save.class, Update.class}) @Length(min = 6, max = 20, groups = {Save.class, Update.class}) private String password; /** * 保存的时候校验分组 */ public interface Save { } /** * 更新的时候校验分组 */ public interface Update { } }

@Validated注解上指定校验分组

@PostMapping("/save") public Result saveUser(@RequestBody @Validated(UserDTO.Save.class) UserDTO userDTO) { // 校验通过,才会执行业务逻辑处理 return Result.ok(); } @PostMapping("/update") public Result updateUser(@RequestBody @Validated(UserDTO.Update.class) UserDTO userDTO) { // 校验通过,才会执行业务逻辑处理 return Result.ok(); }

嵌套校验

前面的示例中,DTO类里面的字段都是基本数据类型和String类型。但是实际场景中,有可能某个字段也是一个对象,这种情况先,可以使用嵌套校验。

比如,上面保存User信息的时候同时还带有Job信息。需要注意的是,此时DTO类的对应字段必须标记@Valid注解。

@Data public class UserDTO { @Min(value = 10000000000000000L, groups = Update.class) private Long userId; @NotNull(groups = {Save.class, Update.class}) @Length(min = 2, max = 10, groups = {Save.class, Update.class}) private String userName; @NotNull(groups = {Save.class, Update.class}) @Length(min = 6, max = 20, groups = {Save.class, Update.class}) private String account; @NotNull(groups = {Save.class, Update.class}) @Length(min = 6, max = 20, groups = {Save.class, Update.class}) private String password; @NotNull(groups = {Save.class, Update.class}) @Valid private Job job; @Data public static class Job { @Min(value = 1, groups = Update.class) private Long jobId; @NotNull(groups = {Save.class, Update.class}) @Length(min = 2, max = 10, groups = {Save.class, Update.class}) private String jobName; @NotNull(groups = {Save.class, Update.class}) @Length(min = 2, max = 10, groups = {Save.class, Update.class}) private String position; } /** * 保存的时候校验分组 */ public interface Save { } /** * 更新的时候校验分组 */ public interface Update { } }

嵌套校验可以结合分组校验一起使用。还有就是嵌套集合校验会对集合里面的每一项都进行校验,例如List<Job>字段会对这个list里面的每一个Job对象都进行校验

集合校验

如果请求体直接传递了json数组给后台,并希望对数组中的每一项都进行参数校验。此时,如果我们直接使用java.util.Collection下的list或者set来接收数据,参数校验并不会生效!我们可以使用自定义list集合来接收参数:

包装List类型,并声明@Valid注解

public class ValidationList<E> implements List<E> { @Delegate // @Delegate是lombok注解 @Valid // 一定要加@Valid注解 public List<E> list = new ArrayList<>(); // 一定要记得重写toString方法 @Override public String toString() { return list.toString(); } }

@Delegate注解受lombok版本限制,1.18.6以上版本可支持。如果校验不通过,会抛出NotReadablePropertyException,同样可以使用统一异常进行处理。

比如,我们需要一次性保存多个User对象,Controller层的方法可以这么写:

@PostMapping("/saveList") public Result saveList(@RequestBody @Validated(UserDTO.Save.class) ValidationList<UserDTO> userList) { // 校验通过,才会执行业务逻辑处理 return Result.ok(); }

自定义校验

业务需求总是比框架提供的这些简单校验要复杂的多,我们可以自定义校验来满足我们的需求。

自定义spring validation非常简单,假设我们自定义加密id(由数字或者a-f的字母组成,32-256长度)校验,主要分为两步:

自定义约束注解

@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER}) @Retention(RUNTIME) @Documented @Constraint(validatedBy = {EncryptIdValidator.class}) public @interface EncryptId { // 默认错误消息 String message() default "加密id格式错误"; // 分组 Class<?>[] groups() default {}; // 负载 Class<? extends Payload>[] payload() default {}; }

实现ConstraintValidator接口编写约束校验器

public class EncryptIdValidator implements ConstraintValidator<EncryptId, String> { private static final Pattern PATTERN = Pattern.compile("^[a-f\\d]{32,256}$"); @Override public boolean isValid(String value, ConstraintValidatorContext context) { // 不为null才进行校验 if (value != null) { Matcher matcher = PATTERN.matcher(value); return matcher.find(); } return true; } }

这样我们就可以使用@EncryptId进行参数校验了!

编程式校验

上面的示例都是基于注解来实现自动校验的,在某些情况下,我们可能希望以编程方式调用验证。这个时候可以注入javax.validation.Validator对象,然后再调用其api。

@Autowired private javax.validation.Validator globalValidator; // 编程式校验 @PostMapping("/saveWithCodingValidate") public Result saveWithCodingValidate(@RequestBody UserDTO userDTO) { Set<ConstraintViolation<UserDTO>> validate = globalValidator.validate(userDTO, UserDTO.Save.class); // 如果校验通过,validate为空;否则,validate包含未校验通过项 if (validate.isEmpty()) { // 校验通过,才会执行业务逻辑处理 } else { for (ConstraintViolation<UserDTO> userDTOConstraintViolation : validate) { // 校验失败,做其它逻辑 System.out.println(userDTOConstraintViolation); } } return Result.ok(); }

快速失败(Fail Fast)

Spring Validation默认会校验完所有字段,然后才抛出异常。可以通过一些简单的配置,开启Fali Fast模式,一旦校验失败就立即返回。

@Bean public Validator validator() { ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class) .configure() // 快速失败模式 .failFast(true) .buildValidatorFactory(); return validatorFactory.getValidator(); }

@Valid和@Validated区别

实现原理

requestBody参数校验实现原理

在spring-mvc中,RequestResponseBodyMethodProcessor是用于解析@RequestBody标注的参数以及处理@ResponseBody标注方法的返回值的。显然,执行参数校验的逻辑肯定就在解析参数的方法resolveArgument()中:

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor { @Override public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { parameter = parameter.nestedIfOptional(); //将请求数据封装到DTO对象中 Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType()); String name = Conventions.getVariableNameForParameter(parameter); if (binderFactory != null) { WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name); if (arg != null) { // 执行数据校验 validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { throw new MethodArgumentNotValidException(parameter, binder.getBindingResult()); } } if (mavContainer != null) { mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); } } return adaptArgumentIfNecessary(arg, parameter); } }

可以看到,resolveArgument()调用了validateIfApplicable()进行参数校验。

protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) { // 获取参数注解,比如@RequestBody、@Valid、@Validated Annotation[] annotations = parameter.getParameterAnnotations(); for (Annotation ann : annotations) { // 先尝试获取@Validated注解 Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class); //如果直接标注了@Validated,那么直接开启校验。 //如果没有,那么判断参数前是否有Valid起头的注解。 if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) { Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann)); Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); //执行校验 binder.validate(validationHints); break; } } }

看到这里,大家应该能明白为什么这种场景下@Validated、@Valid两个注解可以混用。我们接下来继续看WebDataBinder.validate()实现。

@Override public void validate(Object target, Errors errors, Object... validationHints) { if (this.targetValidator != null) { processConstraintViolations( //此处调用Hibernate Validator执行真正的校验 this.targetValidator.validate(target, asValidationGroups(validationHints)), errors); } }

最终发现底层最终还是调用了Hibernate Validator进行真正的校验处理。

方法级别的参数校验实现原理

上面提到的将参数一个个平铺到方法参数中,然后在每个参数前面声明约束注解的校验方式,就是方法级别的参数校验。

实际上,这种方式可用于任何Spring Bean的方法上,比如Controller/Service等。其底层实现原理就是AOP,具体来说是通过MethodValidationPostProcessor动态注册AOP切面,然后使用MethodValidationInterceptor对切点方法织入增强。

public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessorimplements InitializingBean { @Override public void afterPropertiesSet() { //为所有`@Validated`标注的Bean创建切面 Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true); //创建Advisor进行增强 this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator)); } //创建Advice,本质就是一个方法拦截器 protected Advice createMethodValidationAdvice(@Nullable Validator validator) { return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor()); } }

接着看一下MethodValidationInterceptor:

public class MethodValidationInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { //无需增强的方法,直接跳过 if (isFactoryBeanMetadataMethod(invocation.getMethod())) { return invocation.proceed(); } //获取分组信息 Class<?>[] groups = determineValidationGroups(invocation); ExecutableValidator execVal = this.validator.forExecutables(); Method methodToValidate = invocation.getMethod(); Set<ConstraintViolation<Object>> result; try { //方法入参校验,最终还是委托给Hibernate Validator来校验 result = execVal.validateParameters( invocation.getThis(), methodToValidate, invocation.getArguments(), groups); } catch (IllegalArgumentException ex) { ... } //有异常直接抛出 if (!result.isEmpty()) { throw new ConstraintViolationException(result); } //真正的方法调用 Object returnValue = invocation.proceed(); //对返回值做校验,最终还是委托给Hibernate Validator来校验 result = execVal.validateReturnValue(invocation.getThis(), methodToValidate, returnValue, groups); //有异常直接抛出 if (!result.isEmpty()) { throw new ConstraintViolationException(result); } return returnValue; } }

实际上,不管是requestBody参数校验还是方法级别的校验,最终都是调用Hibernate Validator执行校验,Spring Validation只是做了一层封装。

AI大模型学习福利

作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获取

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。


因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

四、AI大模型商业化落地方案

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量

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

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

相关文章

导师严选8个论文写作工具,一键生成论文工具助MBA高效完成毕业论文!

导师严选8个论文写作工具&#xff0c;一键生成论文工具助MBA高效完成毕业论文&#xff01; 论文写作的难题&#xff0c;AI 工具能帮你轻松破解 在 MBA 学习过程中&#xff0c;撰写毕业论文是一项既重要又充满挑战的任务。无论是选题构思、资料收集&#xff0c;还是逻辑梳理与语…

高效论文搜索网站推荐:快速查找学术资源的实用平台

做科研的第一道坎&#xff0c;往往不是做实验&#xff0c;也不是写论文&#xff0c;而是——找文献。 很多新手科研小白会陷入一个怪圈&#xff1a;在知网、Google Scholar 上不断换关键词&#xff0c;结果要么信息过载&#xff0c;要么完全抓不到重点。今天分享几个长期使用的…

SpringBoot对接飞书机器人

账号创建本地是在电脑端&#xff0c;点击左上角的加号&#xff0c;选择创建群组&#xff0c;之后在对应群组页面的右上角打开设置&#xff0c;点击群机器人&#xff0c;添加机器人&#xff0c;选择下面这一个即可点击创建机器人后可以获取到对应的 webhook 地址签名校验&#x…

从“记住我”到“控制我”:Apache Shiro默认密钥反序列化攻击(CVE-2016-4437)深度攻防解析

一、漏洞背景&#xff1a;一个“小功能”引发的全网安全危机 Apache Shiro是Apache基金会旗下的一款轻量级Java安全框架&#xff0c;凭借简单易用、灵活可扩展的特性&#xff0c;被广泛应用于各类Java Web项目的身份认证、授权、会话管理等场景。其中&#xff0c;「记住我&…

Python就业前景好不好?

Python凭借“低门槛广应用”的双重优势&#xff0c;成为当下最具竞争力的编程语言之一。它覆盖数据分析、AI研发、Web开发等多个热门赛道&#xff0c;那么学Python就业前景好吗?以下是详细内容介绍。Python语言具有简单易学、代码可读性高、应用广泛等特点&#xff0c;使其成为…

String、String StringBuffer 和 StringBuilder 的区别是什 么?

String、String StringBuffffer 和 StringBuilder 的区别是什么?String是只读字符串&#xff0c;它并不是基本数据类型&#xff0c;而是一个对象。从底层源码来看是一个final类型的字符数组&#xff0c;所引用的字符串不能被改变&#xff0c;一经定义&#xff0c;无法再增删改…

450万天价零日突袭:通杀Android12-16的静默攻击,数十亿设备安全重构迫在眉睫

2026年1月&#xff0c;暗网与Telegram频道同步引爆一则震撼安全圈的消息&#xff1a;名为“OZDMessage Parser”的Android 0day漏洞及完整利用链以450万美元天价挂牌售卖&#xff0c;宣称可通杀Android12至Android16全版本&#xff0c;覆盖ARM 32/64位架构&#xff0c;无需用户…

JVM中的锁优化

锁优化Jvm 在加锁的过程中&#xff0c;会采用自旋、自适应、锁消除、锁粗化等优化手段来提升代码执行效率。什么是锁升级&#xff0c;降级&#xff1f;锁的4中状态&#xff1a;无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态&#xff08;级别从低到高&#xff09;。 所谓的…

【计算机毕业设计案例】基于SpringBoot+微信小程序的微信电影院票务系统管理系统(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

Python编程最好的就业方向是什么?

Python的就业表现一直稳居编程语言第一梯队&#xff0c;凭借场景广、门槛低的优势成为求职热门。它覆盖AI、数据分析、Web 开发等多个高薪赛道&#xff0c;岗位需求年均增长显著&#xff0c;应届生与转行人群都能找到适配机会。那么Python编程最好的就业方向是什么?请看下文。…

Github千星项目之.Net(四)

01.machinelearning Star&#xff1a;8.1k ML.NET是.NET的开放源码和跨平台机器学习框架。 ML.NET是一个用于.NET的跨平台开源机器学习&#xff08;ML&#xff09;框架。 ML.NET允许开发人员在其.NET应用程序中轻松构建、训练、部署和使用自定义模型&#xff0c;而无需事先…

APP/小程序个人信息保护合规自查手册(附整改方案)

本指南基于《中华人民共和国个人信息保护法》《数据安全法》《网络安全法》《常见类型App必要个人信息范围规定》及GB/T 35273-2020《个人信息安全规范》等核心法规标准&#xff0c;结合2025-2026年监管执法趋势&#xff08;如常态化专项整治、跨境数据监管收紧、AI应用数据合规…

Linux文件权限777和755的区别!

Linux 文件权限是系统安全的核心基石&#xff0c;它通过严格的权限划分&#xff0c;决定了不同用户、用户组对文件和目录的访问、修改、执行权限&#xff0c;直接关系到系统的稳定性与数据安全。那么Linux文件权限777和755的区别是什么?请看下文。Linux文件权限使用三位数字来…

文件脱敏程序设计思路

文件脱敏的核心是&#xff1a;识别敏感信息 → 生成可追溯的替换结果 → 保持文件可用性&#xff08;格式/结构不破坏&#xff09;→ 输出合规审计证据。下面给你一套可落地的设计框架。1) 先定“脱敏目标与边界”&#xff08;否则做不准&#xff09; 1.1 明确敏感信息范围&…

电路架构的三维呈现:利用芯片3D动画解锁IC设计的视觉奥义

将抽象的电路架构转化为易于理解的3D逻辑模型是当前IC设计中的一项创新技术。特别是随着半导体工艺向5nm及更小的节点不断推进&#xff0c;传统平面设计图已难以有效呈现其复杂性。3D动画在此背景下应运而生&#xff0c;为工程师、设计师甚至市场专家提供了一种全新的视角&…

亲测Meta-Llama-3-8B-Instruct:8K上下文对话效果超出预期

亲测Meta-Llama-3-8B-Instruct&#xff1a;8K上下文对话效果超出预期 1. 引言&#xff1a;为何选择 Meta-Llama-3-8B-Instruct&#xff1f; 在当前开源大模型快速迭代的背景下&#xff0c;如何在有限算力条件下实现高质量的对话与指令执行能力&#xff0c;成为个人开发者和中…

小程序计算机毕设之基于springboot+微信小程序的电影院票务、在线购票话剧票务管理系统(完整前后端代码+说明文档+LW,调试定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

误差反向传播法(链式法则)

链式法则 前面介绍的计算图的正向传播将计算结果正向&#xff08;从左到右&#xff09;传递&#xff0c;其计 算过程是我们日常接触的计算过程&#xff0c;所以感觉上可能比较自然。而反向传播将局部导数向正方向的反方向&#xff08;从右到左&#xff09;传递&#xff0c;一开…

2026企业认证体系迎大洗牌:Net-NTLMv1彩虹表数据库 敲响NTLMv1丧钟

2026年1月15日&#xff0c;谷歌旗下网络安全巨头Mandiant的一则公告&#xff0c;在全球网络安全圈掀起轩然大波——其正式发布了一套完整的Net-NTLMv1彩虹表数据库&#xff0c;将这一存续近40年的老旧认证协议推向淘汰边缘。这套托管于Google Cloud、总容量达数百GB的工具集&am…

李飞飞的World Labs联手光轮智能,具身智能进入评测驱动时代!

具身智能生态中最受关注的两家公司双刃合璧&#xff0c;原因无他&#xff0c;正是瞄准困扰行业已久的「规模化评测」问题&#xff0c;发起一波攻势。最火世界模型&#xff0c;最火具身智能基建&#xff0c;联手了&#xff01;前者&#xff0c;是李飞飞旗下的World Labs&#xf…