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

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

之前也写过一篇关于Spring Validation使用的文章不过自我感觉还是浮于表面本次打算彻底搞懂Spring Validation。本文会详细介绍Spring Validation各种场景下的最佳实践及其实现原理死磕到底简单使用Java API规范(JSR303)定义了Bean校验的标准validation-api但没有提供实现。hibernate validation是对这个规范的实现并增加了校验注解如Email、Length等。Spring Validation是对hibernate validation的二次封装用于支持spring mvc参数自动校验。接下来我们以spring-boot项目为例介绍Spring Validation的使用。引入依赖如果spring-boot版本小于2.3.xspring-boot-starter-web会自动传入hibernate-validator依赖。如果spring-boot版本大于2.3.x则需要手动引入依赖dependency ????groupIdorg.hibernate/groupId ????artifactIdhibernate-validator/artifactId ????version6.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-10account和password字段长度是6-20。如果校验失败会抛出MethodArgumentNotValidException异常Spring默认会将其转为400Bad Request请求。DTO表示数据传输对象Data Transfer Object用于服务器和客户端之间交互传输使用的。在spring-web项目中可以表示用于接收请求参数的Bean对象。在DTO字段上声明约束注解Datapublic?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都可以。这或许是一个对你有用的开源项目mall项目是一套基于 SpringBoot Vue uni-app 实现的电商系统Github标星60K采用Docker容器化部署后端支持多模块和微服务架构。包括前台商城项目和后台管理系统能支持完整的订单流程涵盖商品、订单、购物车、权限、优惠券、会员、支付等功能Boot项目https://github.com/macrozheng/mallCloud项目https://github.com/macrozheng/mall-swarm视频教程https://www.macrozheng.com/video/项目演示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其它字段的校验规则在两种情况下一样。这个时候使用分组校验的代码示例如下约束注解上声明适用的分组信息groupsDatapublic?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?{ ????} }嵌套校验可以结合分组校验一起使用。还有就是嵌套集合校验会对集合里面的每一项都进行校验例如ListJob字段会对这个list里面的每一个Job对象都进行校验。集合校验如果请求体直接传递了json数组给后台并希望对数组中的每一项都进行参数校验。此时如果我们直接使用java.util.Collection下的list或者set来接收数据参数校验并不会生效我们可以使用自定义list集合来接收参数包装List类型并声明Valid注解public?class?ValidationList?implements?List?{???Delegate?//?Delegate是lombok注解???Valid?//?一定要加Valid注解???public?List?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)?ValidationListUserDTO?userList)?{ ????//?校验通过才会执行业务逻辑处理 ????return?Result.ok(); }自定义校验业务需求总是比框架提供的这些简单校验要复杂的多我们可以自定义校验来满足我们的需求。自定义spring validation非常简单假设我们自定义加密id由数字或者a-f的字母组成32-256长度校验主要分为两步自定义约束注解Target({METHOD,?FIELD,?ANNOTATION_TYPE,?CONSTRUCTOR,?PARAMETER})Retention(RUNTIME)DocumentedConstraint(validatedBy??{EncryptIdValidator.class})public?interface?EncryptId?{???//?默认错误消息???String?message()?default?“加密id格式错误”;???//?分组???Class?[]?groups()?default?{};???//?负载???Class??extends?Payload[]?payload()?default?{};}实现ConstraintValidator接口编写约束校验器public?class?EncryptIdValidator?implements?ConstraintValidatorEncryptId,?String?{???private?static?final?Pattern?PATTERN??Pattern.compile(“1{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)?{ ????SetConstraintViolationUserDTO?validate??globalValidator.validate(userDTO,?UserDTO.Save.class); ????//?如果校验通过validate为空否则validate包含未校验通过项 ????if?(validate.isEmpty())?{ ????????//?校验通过才会执行业务逻辑处理 ????}?else?{ ????????for?(ConstraintViolationUserDTO?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区别区别ValidValidated提供者JSR-303规范Spring是否支持分组不支持支持标注位置METHOD, FIELD,CONSTRUCTOR, PARAMETER, TYPE_USETYPE, METHOD, PARAMETER嵌套校验支持不支持实现原理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()); ????} }接着看一下MethodValidationInterceptorpublic?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(); ????????SetConstraintViolationObject?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只是做了一层封装。项目源码地址https://github.com/chentianming11/spring-validationa-f\d ↩︎

相关文章:

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

之前也写过一篇关于Spring Validation使用的文章,不过自我感觉还是浮于表面,本次打算彻底搞懂Spring Validation。本文会详细介绍Spring Validation各种场景下的最佳实践及其实现原理,死磕到底! 简单使用 Java API规范(JSR303)定…...

基于语音识别的智能家居设计(有完整资料)

资料查找方式:特纳斯电子(电子校园网):搜索下面编号即可编号:T0852204C设计简介:本设计是基于语音识别的智能家居设计系统,主要实现以下功能:1.可以进行温湿度检测,并且可…...

Docker——镜像

Docker 镜像是容器化技术的核心,它是一个轻量级、独立且可执行的软件包,包含了运行应用程序所需的一切:代码、运行时环境、系统工具、库和配置。可以把镜像想象成一个只读的"模具"或"安装包",而容器则是这个模具运行时的实体实例 1、相关概念 分层存储…...

【datawhale】hello agents开源课程第1章学习记录:初识智能体

章节概述 本章作为《Hello Agents:智能体开发入门》的起点,系统性地构建了关于智能体的基础认知框架。从最基本的定义“智能体是什么”出发,逐步深入探讨了传统智能体的演进路径、大语言模型驱动的新范式、多维度分类体系、PEAS任务环境模型、…...

巧用 AxureShow 插件:将 HTML 一键转换为可编辑 Axure 原型文件

在产品原型设计工作中,我们常会遇到需要将已有的 HTML 页面转换为 Axure 可编辑原型的场景,手动复刻不仅耗时耗力,还容易丢失页面细节。AxureShow 浏览器插件为这个需求提供了高效的解决方案,能实现 HTML 元素到 Axure 原型的一键…...

day115(3.17)——leetcode面试经典150

221. 最大正方形 221. 最大正方形 题目&#xff1a; 题解&#xff1a; class Solution {public int maximalSquare(char[][] matrix) {int n matrix.length;int m matrix[0].length;if(matrixnull||n<1||m<1) {return 0;}int[][] dp new int[n1][m1];int maxSum0;f…...

分布式光伏气象站:光伏发电环境监测系统

分布式光伏气象站&#xff0c;是适配分布式光伏发电场景的环境监测设备&#xff0c;主要用于光伏电站运行监控与数据分析&#xff0c;可实时监测太阳总辐射、环境温湿度、风速风向、光伏组件温度、气压等多项指标&#xff0c;数据可接入监控系统做展示、记录与分析&#xff0c;…...

安装OpenClaw - 阿里百炼->选择模型->飞书界面

官网教程&#xff1a; https://openclaw.ai/ 安装命令&#xff1a;curl -fsSL https://openclaw.ai/install.sh | bash 等待下载安装 常用命令&#xff1a; 安装&#xff1a; # 官方脚本 curl -fsSL https://openclaw.ai/install.sh | bash# 国内网络慢可用加速脚本 # c…...

2026年中秋手抄报模板返工一次后,我总结的模板筛选与修改经验

2026年中秋手抄报模板返工一次后&#xff0c;我总结的模板筛选与修改经验我是小学三年级的语文老师兼班主任&#xff0c;临近中秋&#xff0c;学校要求每个班出一期主题手抄报&#xff0c;下周三就要贴在文化墙上。往年都是让孩子们自由发挥&#xff0c;但效果参差不齐&#xf…...

gstack:让 Claude Code 变身专属全栈开发团队

在日常开发中&#xff0c;我们常常陷入一种困境&#xff1a;向 AI 助手请求功能&#xff0c;它确实写出了代码&#xff0c;但代码能跑却不符合业务逻辑&#xff0c;或者缺少关键的错误处理。我们花费大量时间修正 AI 生成的“字面正确但语义错误”的代码&#xff0c;本质上是因…...

金属外壳屏蔽导致传导超标

一、前言在汽车电子行业&#xff0c;EMC&#xff08;电磁兼容&#xff09;测试是产品上市前必须跨越的“技术门槛”&#xff0c;而传导电流法测试&#xff08;Conducted Emission Current Method&#xff09;更是让不少工程师头疼的“拦路虎”。尤其是随着新能源汽车的快速发展…...

Java入门第154课——Oracle 数据库入门与基础操作

一、数据库基础概念 数据库核心定义 数据库(Database,简称 DB):按照数据结构组织、存储和管理数据的仓库。 数据库管理系统(Database Management System,简称 DBMS):管理数据库的专用软件。 关系数据库:采用关系模型,将数据组织到二维数据表(Table)中,主流产品包括…...

2026 年域名注册价格表:.com/.cn 多少钱?

在 2026 年&#xff0c;域名不仅是网站的地址&#xff0c;更是企业重要的数字资产。随着 ICANN(互联网名称与数字地址分配机构)对基础费用的周期性调整&#xff0c;2026 年的域名注册与续费价格较往年略有上浮。 2026 年域名注册价格表&#xff1a;.com/.cn 多少钱? 一、 2026…...

在职转大模型,要不要裸辞?边工作边学跟得上吗?

小伙伴们有没有过这种崩溃时刻&#xff1a; 每天加班到9点&#xff0c;周末还要on-call&#xff0c;好不容易挤出的2小时学习时间&#xff0c;刚打开教程就被工作消息打断。想裸辞全力冲刺&#xff0c;又怕3个月找不到工作心态崩&#xff1b;想边工作边学&#xff0c;又觉得时间…...

京东商品详情 API 开发实战:JD 商品详情接口调用与返回值解析

在电商API开发中&#xff0c;京东商品详情API是最常用、最核心的接口之一&#xff0c;无论是做比价工具、选品分析、ERP对接&#xff0c;还是第三方服务集成&#xff0c;都离不开它。本文将从实战角度出发&#xff0c;手把手教你完成京东商品详情API的调用、签名生成、数据解析…...

【OpenClaw从入门到精通】第32篇:云厂商OpenClaw托管服务深度对比:阿里云/腾讯云/华为云2026实测指南

摘要:2026年OpenClaw爆发式增长,各大云厂商纷纷推出托管服务,让“云上养虾”成为主流选择。本文从成本构成、部署实操、生态适配、安全特性四大核心维度,深度拆解阿里云、腾讯云、华为云的OpenClaw托管服务。详解三大厂商的服务器配置、模型计费模式,提供从购买到部署的完…...

AI三维卷疯了!Chaos Vantage使用上要做什么改变?看完少走3年弯路

做三维、建筑可视化的兄弟姐妹们&#xff0c;谁懂啊&#x1f62d;&#xff01;2026年AI三维实时渲染卷疯了&#xff0c;Chaos Vantage这实时光追神器是真好用&#xff0c;但对电脑配置的要求也跟着水涨船高。 本地装个高配动辄几万&#xff0c;钱包扛不住啊&#xff01;其实选…...

MEmu模拟器下载和抓包

1.打开MEmu下载——PC上最佳安卓模拟器 然后下载&#xff08;点击此文件即可&#xff0c;可以自定义路径&#xff09; 等待加载好就行了 然后点击桌面的图标打开 点击右侧的这个逍遥模拟器即可&#xff0c;&#xff08;不是逍遥多开器&#xff01;&#xff09; 然后让逍遥模…...

解决大模型长链路指令遗忘!GLM-5-Turbo“龙虾增强”原理解析与 OpenClaw 部署实战

在生成式AI狂飙突进的今天&#xff0c;开发者们往往陷入一个怪圈&#xff1a;模型参数越来越大&#xff0c;但在真实业务流中的表现却常常“掉链子”。尤其是在处理需要多步推理、跨工具调用的长链路任务时&#xff0c;模型经常出现指令遗忘或逻辑断裂。这正是智谱推出GLM-5-Tu…...

低成本私域获客实战:不靠砸钱,靠流程和工具稳拉客

做私域这几年&#xff0c;见过太多老板被获客问题逼得头疼 —— 公域投钱烧得快&#xff0c;拉来的客户留不住&#xff1b;线下地推费人力&#xff0c;最后加的不是羊毛党就是无效客&#xff1b;好不容易有老客&#xff0c;却不知道怎么让他们带新&#xff0c;白白浪费社交资源…...

Rust Cargo 构建系统深入解析

Rust Cargo构建系统深入解析 Rust作为一门现代系统编程语言&#xff0c;凭借其安全性、并发性和高性能吸引了大量开发者。而Cargo作为Rust官方的构建系统和包管理器&#xff0c;是Rust生态中不可或缺的工具。它不仅简化了项目的创建、编译和依赖管理&#xff0c;还提供了丰富的…...

为什么 synchronized 不能防止指令重排序?

在某乎看到一个提问&#xff0c;大家讨论 synchronized 能不能防止指令冲排序&#xff0c;咋说的都有&#xff0c;我发现大家学习底层技术很多时候会有误区。先说我的观点&#xff1a;synchronized 绝对不能防止它内部代码的指令重排序&#xff01;下边说说我的分析哈&#xff…...

all-in-rag零散的笔记(自存/持续更新)

2026.3.17原文说的很详尽&#xff0c;写这么一篇只是为了让自己背的更顺。------1.让代码只输出content&#xff1f;print(answer.content)补充&#xff1a;其中&#xff0c;answer llm.invoke(prompt.format(questionquestion, contextdocs_content))该代码先把 question&…...

COMSOL煤矿模型仿真合集:‘瓦斯抽采与热流固耦合、采空区耦合性分析、倾斜煤层下的采空区参数...

comsol煤矿模型仿真合集 comsol煤矿&#xff08;地下水流&#xff09;模型整理合集&#xff0c; 1.图1-2为瓦斯抽采热流固耦合&#xff0c;采用固体力学、达西和多孔介质传热研究瓦斯抽采下煤层温度、应力、瓦斯渗流的变化情况。 2.图3-4为采空区耦合性分析&#xff0c;贴合一篇…...

AI聊天机器人安全漏洞:暴力诱导与风险警示

AI聊天机器人暴力诱导事件时间线与影响规模近期&#xff0c;一个倡导组织公布了对10款人工智能聊天机器人的研究结果。自去年11月至12月进行测试后&#xff0c;几家聊天机器人制造商称已做出改进以提升安全性。今日&#xff0c;与CNN记者合作开展研究的反数字仇恨中心&#xff…...

目前主流AI绘画工具排名,功能参数全对比

本文对2026年主流AI绘画工具进行功能维度的详细盘点&#xff0c;包括核心功能、技术参数、模型生态、价格等&#xff0c;供开发者和专业用户参考选型。一、主流AI绘画工具概览工具开发方核心技术部署方式访问方式MidjourneyMidjourney Inc.自研模型SaaS需海外访问Stable Diffus…...

MySQL分库分表的实现(二)--水平分表

本文介绍下使用Sharding-JDBC实现水平分表 Sharding-JDBC是轻量级的 java 框架&#xff0c;是增强版的 JDBC 驱动,使用Sharding-JDBC可以简化对分库分表之后数据相关操作。下面分别介绍下水平分表的方法。 1、准备好数据库和数据表 先创建一个course_db数据库&#xff0c;然…...

B2B战略咨询在行业竞争中实现差异化突围

在激烈的行业竞争中&#xff0c;B2B战略咨询发挥了重要作用。通过创新解决方案和个性化服务&#xff0c;企业能够实现显著的差异化&#xff0c;从而提升市场竞争力。咨询公司首先需要进行深入的市场需求分析&#xff0c;以识别客户的真实需求和痛点。这一过程帮助企业围绕客户体…...

第七届人工智能、网络与信息技术国际学术会议(AINIT 2026)

第七届人工智能、网络与信息技术国际学术会议&#xff08;AINIT 2026&#xff09;将于2026年5月15-17日在中国大连举行。本届会议将主要关注人工智能、网络与信息技术面临的新的挑战问题和研究方向&#xff0c;着力反映国际人工智能、网络与信息技术相关技术研究的最新进展。大…...

3·15曝光后深度解析:AI“投毒”与幻觉乱象,GEO技术困局与破局之道

2026年央视315晚会曝光的GEO&#xff08;生成式引擎优化&#xff09;黑产&#xff0c;给所有AI领域技术从业者&#xff08;程序员、算法工程师、数据工程师等&#xff09;敲响了警钟——批量虚假信息“投毒”污染大模型&#xff0c;导致多个主流大模型在“2026年315晚会”这一基…...