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

java后端校验

Java 后端数据校验

一、概述

当我们想提供可靠的 API 接口,对参数的校验,以保证最终数据入库的正确性,是 必不可少 的活。比如下图就是 我们一个项目里 新增一个菜单校验 参数的函数,写了一大堆的 if else 进行校验,非常的不优雅,比起枯燥的 CRUD 来说,参数校验更是枯燥。

这只是一个创建菜单的校验,只需要判断菜单,菜单 url 以及菜单的父类 id 是否为空,上级菜单是否挂载正确,这样已经消耗掉了 30,40 行代码了,更不要说,管理后台这种参数贼多的接口。估计要写几百行校验代码了。

        if(mapper.get("customerId") == null){return RespBean.error("customerId is null!");}if(mapper.get("name") == null){return RespBean.error("name is null!");}if(mapper.get("userName") == null){return RespBean.error("userName is null!");}//查询条件 判断用户名是否重复Map<String,Object> args = new HashMap<>();args.put("userName",mapper.get("userName").toString());args.put("customerId",mapper.get("customerId").toString());Integer findNum = userService.findUserNameIsExist(args);if(!Objects.equals(findNum, 0)){    //查询结果不为0return RespBean.error("用户名重复,请重新输入!");}int ret = userService.addUser(mapper);if(ret >= 0){return RespBean.ok("UserController add user success");}else{return RespBean.error("UserController add User  ailed");}

二、注解

在开始入门之前,我们先了解下本文可能会涉及到的注解。javax.validation.constraints 包下,定义了一系列的约束( constraint )注解。共 22 个,如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HMb3Jaa9-1690357601543)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml16688\wps1.jpg)]

大致可以分为以下几类:

2.1 空和非空检查

@NotBlank :只能用于字符串不为 null ,并且字符串 #trim() 以后 length 要大于 0 。

@NotBlank(message = "文本不能为空")
private String text;

@NotEmpty :集合对象的元素不为 0 ,即集合不为空,也可以用于字符串不为 null 。

@NotEmpty(message = "密码不能为空")
private String password;

@NotNull :不能为 null 。

@NotNull(message = "用户名不能为null")
private String userName;

@Null :必须为 null 。

@Null(message = "精度必须为null")
private Double jd;

2.2 数值检查

@DecimalMax(value) :被注释的元素必须是一个数字,其值必须小于等于指定的最大值。

@DecimalMax(value = "50.5",message = "number1必须小于等于50.5")
private Double number1;

@DecimalMin(value) :被注释的元素必须是一个数字,其值必须大于等于指定的最小值。

@DecimalMin(value = "100.6",message = "number2必须大于等于100.6")
private Double number2;

@Max(value) :该字段的值只能小于或等于该值。不支持小数位判断

@Max(value = 100,message = "number7必须小于等于100")
private Long number7;

@Min(value) :该字段的值只能大于或等于该值。 不支持小数位判断

@Min(value = 60,message = "number6必须大于等于60")
private Integer number6;

@Digits(integer, fraction) :被注释的元素必须是一个数字,其值必须在可接受的范围内。

@Digits(integer = 4,fraction = 3,message = "整数位上限4,小数位上限3")
private Double number3;

@Positive :判断正数。

@Positive(message = "number4必须为正数")
private Double number4;

@PositiveOrZero :判断正数或 0 。

@PositiveOrZero(message = "number5必须为正数或0")
private Double number5; 

@Negative :判断负数。

@Negative(message = "number8必须为负数")
private Double number8;

@NegativeOrZero :判断负数或 0 。

@NegativeOrZero(message = "number9必须为负数或0")
private Double number9;

2.3 Boolean 值检查

@AssertFalse :被注释的元素必须为 true 。

@AssertTrue(message = "b1只能为true")
private Boolean b1;

@AssertTrue :被注释的元素必须为 false 。

@AssertFalse(message = "b2只能为false")
private Boolean b2;

2.4 长度检查

@Size(max, min) :检查该字段的 size 是否在 min 和 max 之间,可以是字符串、数组、集合、Map 等。

@Size(max = 5,min = 2,message = "字符串长度在2-5之间")
private String str;

2.5 日期检查

@Future :被注释的元素必须是一个将来的日期。

@Future
private Date date1;

@FutureOrPresent :判断日期是否是将来或现在日期。

@FutureOrPresent
private Date date2;

@Past :检查该字段的日期是在过去。

@Past
private Date date3;

@PastOrPresent :判断日期是否是过去或现在日期。

@PastOrPresent
private Date date4;

2.6 其它检查

@Email :被注释的元素必须是电子邮箱地址。

@Email
private String email;

@Pattern(value) :被注释的元素必须符合指定的正则表达式。注解需要传的参数:一般默认就填入正则表达式正则表达式即可,但是java中字符串需要转义

@Pattern(regexp = "^\\d{15}|\\d{18}$", message = "身份证号码在15-18位")
private String cardNum;

2.7 Hibernate Validator 附加的约束注解

org.hibernate.validator.constraints 包下,定义了一系列的约束( constraint )注解。如下:

@Range(min=, max=) :被注释的元素必须在合适的范围内。只判断整数位数值

@Range(min = 10,max = 20,message = "数值范围在10-20之间")
private Double range;

@Length(min=, max=) :被注释的字符串的大小必须在指定的范围内。

@Length(min = 20,max = 25,message = "字符串长度在20-25之间")
private String str1;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ctYx6pQh-1690357601545)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml16688\wps2.jpg)]

2.8 @Valid 和 @Validated

@Valid 注解,是 Bean Validation 所定义,可以添加在普通方法、构造方法、方法参数、方法返回、成员变量上,表示它们需要进行约束校验。

@Validated 注解,是 Spring Validation 锁定义,可以添加在类、方法参数、普通方法上,表示它们需要进行约束校验。同时,@Validated 有 value 属性,支持分组校验。属性如下:

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validated {/*** Specify one or more validation groups to apply to the validation step* kicked off by this annotation.* <p>JSR-303 defines validation groups as custom annotations which an application declares* for the sole purpose of using them as type-safe group arguments, as implemented in* {@link org.springframework.validation.beanvalidation.SpringValidatorAdapter}.* <p>Other {@link org.springframework.validation.SmartValidator} implementations may* support class arguments in other ways as well.*/Class<?>[] value() default {};}

对于初学的来说,很容易搞混 @Valid(javax.validation 包下) 和 @Validated (org.springframework.validation.annotation 包下)注解。两者大致有以下的区别:

名称Spring validation是否实现了声明式检验是否支持嵌套校验是否支持分组校验
@Validated
@Valid

总的来说,绝大多数场景下,我们使用 @Validated 注解即可。而在有嵌套校验的场景,我们使用 @Valid 注解添加到成员属性上。

三、快速入门

3.1 引入依赖

   <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--在一些高版本springboot中默认并不会引入这个依赖,需要手动引入-->
<!--        <dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId><scope>compile</scope></dependency>--><!-- 保证 Spring AOP 相关的依赖包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId></dependency><!--lombok相关 方便开发--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency><!--knife4j接口文档 方便待会进行接口测试--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.3</version></dependency></dependencies>

1) @Valid 的使用

首先,需要在实体类的相关字段上添加需要校验的注解。

public class User {private String id;  @NotBlank(message = "密码不能为空")private String password;@Min(value = 18,message = "未成年禁止入内")  private Integer age;
}

其次,在controller层的方法的要校验的参数上添加@Valid注解

@PostMapping("/action/register")public Result registerByForm(@Valid @RequestBody User user){return userService.register(user);}

嵌套功能的使用

在检验 Country对象的 provinces字段时,在provinces字段上添加 @Valid 注解后,就可以检验 list 中的 provinces的属性是否符合要求;

否则只会检验 citys的集合大小是否大于1,不会校验集合中的 citys对象,比如 citys对象的 name 是否符合要求。

    @GetMapping (value = "/test1")public RespBean test1(@RequestBody @Valid Country country) {log.info("country:"+country);return RespBean.sucess();}@Data
public class Country {@NotNull(message = "国家id不能为null")private Long countryId;@Valid@Size(min = 1,max = 2,message = "省份数量在1-2之间")private List<Province> provinces;@Size(min = 1,message = "城市大于1")private List<City> citys;}@Data
public class Province {@NotNull(message = "省份id不能为null")private Long id;@NotBlank(message = "省份名称不能为空")private String name;}@Data
public class City {@NotNull(message = "城市id不能为null")private Long id;@NotBlank(message = "城市名称不能为空")private String name;}

2)@Validated 的使用

@Validated 是 @Valid 的一次封装,在@Valid的基础上增加了分组以及验证排序的功能。

分组功能的使用

当一个实体类需要多种验证方式时,比如:添加时需要对姓名进行非空验证,修改时需要对id进行验证,而添加时就不需要对id进行验证。

首先,定义两个分组的接口:

public interface Add{
}public interface Update{
}

其次,在实体类上使用@Validated的分组功能。

@Data
public class Person {@NotNull(groups = Update.class, message = "更新时候id不能为空")private Long id;@NotEmpty(groups = Add.class, message = "姓名不能为空")private String name;
}在controller中,使用分组进行接口验证。
@RestController
@Slf4j
public class VerifyController {@PostMapping(value = "/validated/add")public void add(@Validated(value = Add.class) @RequestBody Person person) {...}@PostMapping(value = "/validated/update")public void update(@Validated(value = Update.class) @RequestBody Person person) {...}
}

3)定义全局异常处理,才能返回参数校验信息

异常共四种
BindException:处理所有RequestParam注解数据验证异常
MethodArgumentNotValidException:处理所有RequestBody注解参数验证异常
ConstraintViolationException

UnexpectedTypeException

@RestControllerAdvice
@Slf4j
public class GlobalDefaultExceptionHandler {/*** 处理所有RequestBody注解参数验证异常* @param exception* @return*/@ExceptionHandler(MethodArgumentNotValidException.class)public RespBean methodArgumentNotValidException(MethodArgumentNotValidException exception){//封装需要返回的错误信息List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();log.error("参数绑定异常,ex = {}", fieldErrors.get(0).getDefaultMessage());return RespBean.error(fieldErrors.get(0).getDefaultMessage());}/*** 处理所有RequestParam注解数据验证异常* @param e* @return*/@ExceptionHandler(BindException.class)public RespBean validationBodyException(BindException e){e.printStackTrace();//打印校验住的所有的错误信息StringBuilder sb = new StringBuilder("参数错误:[");List<ObjectError> list = ((BindException) e).getAllErrors();for (ObjectError item : list) {sb.append(item.getDefaultMessage()).append(',');}sb.deleteCharAt(sb.length()-1);sb.append(']');String msg  =  sb.toString();return RespBean.error(msg);}@ExceptionHandler(UnexpectedTypeException.class)public RespBean unexpectedTypeException(UnexpectedTypeException exception){//封装需要返回的错误信息log.error("参数绑定异常,ex = {}", exception.getMessage());return RespBean.error(exception.getMessage());}@ExceptionHandler(value = ConstraintViolationException.class)public RespBean ConstraintViolationExceptionHandler(ConstraintViolationException ex) {Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();List<String> msgList = new ArrayList<>();while (iterator.hasNext()) {ConstraintViolation<?> cvl = iterator.next();msgList.add(cvl.getMessageTemplate());}return RespBean.error(msgList.toString());}
}

补充:分组功能使用多个组检验数据

contoller层使用{}添加多个组别

    @PostMapping(value = "/validated/del")public RespBean dealMore(@Validated(value = {Add.class,Update.class}) @RequestBody Person person) {return RespBean.sucess();}

自定义注解

1-添加自定义注解类接口

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {MobileValidator.class})
public @interface MobileCheck {boolean required() default true;String message() default "手机号码格式有误!";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}

2-实现自定义校验器类

/** 手机号校验器* */
public class MobileValidator implements ConstraintValidator<MobileCheck, String> {private boolean required = false;private static final Pattern mobile_pattern = Pattern.compile("1\\d{10}");public static boolean isMobile(String src){if (StringUtils.isEmpty(src)){return false;}Matcher matcher = mobile_pattern.matcher(src);return matcher.matches();}@Overridepublic void initialize(MobileCheck isMobile) {required = isMobile.required();}@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {if (required) { //如果必须(不能为空),进行校验return isMobile(value);} else {  //如果不必须,非空进行校验if (StringUtils.isEmpty(value)) {return true;}return isMobile(value);}}
}

3-使用

@Data
public class Country {@MobileCheckprivate String phone;}@PostMapping(value = "/checkPhone")
public RespBean checkPhone(@Valid @RequestBody Country country) {return RespBean.sucess();
}

}

@Override
public boolean isValid(String value, ConstraintValidatorContext context) {if (required) { //如果必须(不能为空),进行校验return isMobile(value);} else {  //如果不必须,非空进行校验if (StringUtils.isEmpty(value)) {return true;}return isMobile(value);}
}

}


3-使用

@Data
public class Country {
@MobileCheck
private String phone;

}

@PostMapping(value = “/checkPhone”)
public RespBean checkPhone(@Valid @RequestBody Country country) {
return RespBean.sucess();
}


相关文章:

java后端校验

Java 后端数据校验 一、概述 当我们想提供可靠的 API 接口&#xff0c;对参数的校验&#xff0c;以保证最终数据入库的正确性&#xff0c;是 必不可少 的活。比如下图就是 我们一个项目里 新增一个菜单校验 参数的函数&#xff0c;写了一大堆的 if else 进行校验&#xff0c;…...

PowerPoint如何修改“默认保存路径”?

很多时候&#xff0c;我们做好PPT后都要保存&#xff0c;一般会保存在创建PPT的文件夹里&#xff0c;或者另外设置保存的路径。 如果经常需要制作PPT&#xff0c;又不想每次都要重新选择保存位置&#xff0c;我们可以创建或修改“默认保存路径”&#xff0c;这样每次关闭PPT后…...

【PMP】有没有项目经理能看得懂这九张图?求挑战

这九张图&#xff0c;全是圈圈我的肺腑之言啊&#xff01;谁痛谁知道&#xff01; 做技术时&#xff0c;就想着30岁就转管理&#xff0c;管理岗位赚得多&#xff0c;结果发现全是烟雾弹。 做技术和代码打交道&#xff0c;做管理跟人打交道。天天开不完的会、说不完的话&#xf…...

ES6学习记录—自己记录一直更新版

1. 什么是ECMA 全称&#xff1a;European computer manufacturers association欧洲计算机制造联合会; 2、它的标准名单中的&#xff1a;ECMA — 262脚本语言的规范&#xff1a;规范化脚本语言&#xff0c;叫ECMAScript ( 一定要记住)&#xff1b;像ES5 ES6就是这样来的&#xf…...

linux操作gpio的一些记录

在linux里面使用GPIO的一些知识点记录如下&#xff1a; 一、驱动里面操作GPIO 在linux内核里面如果 pinctrl 子系统将一个 PIN 复用为 GPIO 的话&#xff0c;那么就可以用gpio 子系统提供的 API 函数操做gpio&#xff0c;比如设置 GPIO为输入输出&#xff0c;读取 GPIO 的值等…...

目前新能源汽车充电桩的发展受到哪些不利因素的影响?

目前新能源汽车充电桩的发展受到哪些不利因素的影响? 一是安装难&#xff0c;很多老旧小区没有充电桩配套施工规范&#xff0c;充电桩建设比较难&#xff0c;受到充电容量不足电表箱供电等局限性的制约&#xff0c;同时缺乏充电桩配套设施的统一规划&#xff0c;小区内只能安装…...

jenkins

Gitlab添加钩子 测试钩子 添加完成后&#xff0c;下面会出现钩子选择。点击test中的&#xff0c;push event。 出现successful&#xff0c;既添加成功。 如果添加失败&#xff0c;报错&#xff0c;更改Network...

基于深度学习的图像分割技术探究

导言&#xff1a; 图像分割是计算机视觉领域的重要任务&#xff0c;旨在将图像划分为不同的语义区域&#xff0c;实现对图像中感兴趣物体的定位和提取。深度学习作为图像分割的新兴技术&#xff0c;通过卷积神经网络&#xff08;CNN&#xff09;等模型&#xff0c;取得了显著的…...

【c++】vector的使用与模拟实现

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a;初阶数据结构 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对…...

记录安装stable diffusion webui时,出现的gfpgan安装卡住的问题

参考链接&#xff1a;(145条消息) 使用stable diffusion webui时&#xff0c;安装gfpgan失败的解决方案&#xff08;windows下的操作&#xff09;_新时代原始人的博客-CSDN博客...

【开发环境】Windows下搭建TVM编译器

关于搭建TVM编译器的官方文档&#xff1a;Install from Source — tvm 0.14.dev0 documentation (apache.org) 1. 安装Anaconda 首先我们需要安装Anaconda&#xff0c;因为其中包含着我们所需要的各类依赖&#xff1a; 进入Anaconda官网https://www.anaconda.com/products/d…...

了解Unity编辑器之组件篇Video(二)

Video Player组件&#xff1a;用于在游戏中播放视频的组件。它提供了一系列属性来控制视频的播放、显示和交互。 1.Source&#xff08;视频源&#xff09;&#xff1a;用于指定视频的来源。可以选择两种不同的视频源类型&#xff1a; &#xff08;1&#xff09;Vieo Clip&#…...

安全杂记 - 状态码,DNS,编码

目录 1.状态码2.DNS解析过程3.URL编码4.HTML实体编码5.FORM表单 1.状态码 200 - 请求成功 301 - 资源&#xff08;网页等&#xff09;被永久转移到其它URL 302 - 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI 304 - 未修改。所请求的资源未修改&#…...

微信小程序 Page页面

新建页面只需要在app.json配置好路径&#xff0c;编译器自动新增了页面 项目首页&#xff0c;在app.json哪个页面是第一位&#xff0c;哪个页面就是小程序首页...

C语言实现基于Linux,epoll和多线程的WebServer服务器

代码结构&#xff1a; Server.h 头文件&#xff0c;对函数进行了声明 #pragma once #include<stdio.h> // 新建一个用于TCP监听的socket文件描述符&#xff0c;并返回 int initListenFd(unsigned short port);// 启动epoll int epollRun(int lfd);// accept建立连接 vo…...

微信小程序数字键盘(仿微信转账键盘)

微信小程序input自带数字输入键盘&#xff0c;不过是直接调用的系统键盘&#xff0c;无法个性化。 代码中使用使用了Vant WeappVant UI小程序版&#xff0c;这里就不介绍相关安装说明了&#xff0c;大家自行安装Vant Weapp。 json 用到的组件 {"usingComponents": …...

mac电脑强大的解压缩软件BetterZip 5.3.4 for Mac中文版及betterzip怎么压缩

BetterZip 5.3.4 for Mac 是Mac系统平台上一款功能强大的文件解压缩软件&#xff0c;不必解压就能快速地检查压缩文档。它能执行文件之间的合并并提供密码。使用它&#xff0c;用户可以更快捷的向压缩文件中添加和删除文件。它支持包括zip、gz、bz、bz2、tar、tgz、tbz、rar、7…...

Llama 2 来袭 - 在 Hugging Face 上玩转它

&#x1f917; 宝子们可以戳 阅读原文 查看文中所有的外部链接哟&#xff01; 引言 今天&#xff0c;Meta 发布了 Llama 2&#xff0c;其包含了一系列最先进的开放大语言模型&#xff0c;我们很高兴能够将其全面集成入 Hugging Face&#xff0c;并全力支持其发布。Llama 2 的社…...

linux操作历史history定制

history记录 Linux中历史操作记录history是一个很有用的功能&#xff0c;有时忘记了&#xff0c;翻翻以前的命令&#xff0c;十分方便。 # 展示所有历史记录 history # 筛选历史记录 history | grep nginx # 清除全部记录 -c history -c # 指定删除某一行,15是行号 history -…...

微信小程序 wx.showModal

微信小程序--wx.showModal_海轰Pro的博客-CSDN博客...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

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 提…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...