SpringBoot的validation参数校验
文章目录
- 前言
- 一、引入validation 依赖
- 二、validation中的注解说明
-
- (1)@Validated
- (2)@Valid
- (3)@NotNull
- (4)@NotBlank
- (5)@NotEmpty
- (6)@Pattern
- (7) @Email
- (8)@Size
- 三、validation的使用
-
- 1.一般校验
- 2.嵌套验证
- 3.分组校验
- 4.自定义校验注解
- 5.反射加自定义注解实现动态校验
- 四、validation 校验失败处理
- 总结
前言
在项目开发过程,后端经常会对前端传递的参数进行各种校验,只有在校验通过时,才会执行后续的业务代码,否则抛出异常信息给前端。当参数较多时,刚开始会使用大量的 if…else…来逐一对参数进行检验,或则使用策略模式来方法来减少 if…else…的检验代码。但是将这些代码写在控制层或则业务层都会让代码过于臃肿。而且如果后期参数校验变了,或则参数不需要校验时,还需要大量删除,或修改检验参数的逻辑代码,因此采用 validation来对参数进行校验简化代码。
一、引入validation 依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId><version>3.3.1</version></dependency>
二、validation中的注解说明
(1)@Validated
用于在 Spring 控制器层方法参数进行验证
@PostMapping("/validator")
public String ValidatorTest(@RequestBody @Validated UserParam user) {return "success";}
(2)@Valid
是 Java 标准的一部分,用于声明需要对嵌套对象进行递归验证。在 Spring 框架中,通常用于处理复杂对象结构的验证,如验证对象中的集合或对象引用的属性
@Data
public class EmpParam implements Serializable {@NotBlank(message = "员工姓名不能为空")private String empName;@NotBlank(message = "员工手机号不能为空")private String empPhone;@Valid@NotNull(message = "部门信息不能为空")private DeptParam deptParam;
}@Data
public class DeptParam implements Serializable {@NotNull(message = "部门ID不能为空")private Long deptId;@NotBlank(message = "部门名称不能为空")private String deptName;
}
(3)@NotNull
注解用于检查被注解的元素值不为 null。适用于字符串、集合、Map 等任何对象类型,但不适用于基本数据类型(如 int、long 等)
常用于检查对象是否为 null
@NotNull(message = "员工ID不能为空")
private Long empId;@NotNull(message = "部门信息不能为空")
private DeptParam deptParam;
(4)@NotBlank
用于检查被注解的字符串元素不为 null 且去除两端空白字符后长度大于 0。只适用于字符串类型。
@NotBlank(message = "员工身份证号不能为空")
private String empIdCard;
(5)@NotEmpty
注解用于检查被注解的元素不为 null 且不为空,适用于字符串、集合、Map 等。
如果是字符串,相当于同时检查 null 和长度大于 0
@NotEmpty
private List<String> emails;
(6)@Pattern
指定字段必须符合指定的正则表达式
@Pattern(regexp ="^1[3|4|5|6|7|8|9][0-9]d{8}$")
private String phone
(7) @Email
指定字段必须符合Email格式。
@Email
private String email;
(8)@Size
指定字段的长度范围
@Size(min = 6, max = 20)
private String password;
三、validation的使用
1.一般校验
一般校验:这里指的是,后端参数是一个实体类对象来接收参数,并且校验实体类中各个属性(被注解标注过的)
@RestController
@RequestMapping("/test")
public class ValidatorTestController {@PostMapping("/validator")public String ValidatorTest(@RequestBody @Validated UserParam user) {UserParam contractParam = new UserParam();BeanUtils.copyProperties(user, contractParam);System.out.println(contractParam);return "success";}
}
实体类中的属性分别添加注解进行校验
@Data
public class UserParam {@NotBlank(message = "用户名不能为空")private String username;@NotBlank(message = "密码不能为空")@Size(min = 6, max = 20, message = "密码长度在6-20位之间")private String password;@NotBlank(message = "手机号不能为空")private String phone;@NotBlank(message = "身份证不能为空")private String idCard;@NotBlank(message = "身份证姓名不能为空")private String idCardName;@NotBlank(message = "车牌号不能为空")private String carNumber;@NotBlank(message = "银行卡号不能为空")private String bankCardNumber;}
用postman测试注解是生效的。注意响应的结果,是将所有参数没校验通过都一并响应给前端,方便前端处理。
2.嵌套验证
嵌套检验:后端接收参数是个实体类对象,并且实体类对象中还有一个实体或者是一个List类型对象
比如:添加员工信息时,为员工分配部门
控制层一定得使用 @Validated标注参数
@RestController
@RequestMapping("/emp")
public class EmpController {@PostMapping("/add")public String addEmp(@RequestBody @Validated EmpParam empParam) {System.out.println(empParam);return "success";}
}
员工实体类参数:DeptParam 必须加上 @Valid注解才能校验 DeptParam 中的字段(被注解标注的)
@Data
public class EmpParam implements Serializable {@NotBlank(message = "员工姓名不能为空")private String empName;@NotBlank(message = "员工手机号不能为空")private String empPhone;@NotBlank(message = "员工邮箱不能为空")private String empEmail;@NotBlank(message = "员工身份证号不能为空")private String empIdCard;@Valid@NotNull(message = "部门信息不能为空")private DeptParam deptParam;
}@Data
public class DeptParam implements Serializable {@NotNull(message = "部门ID不能为空")private Long deptId;@NotBlank(message = "部门名称不能为空")private String deptName;
}
使用postman测试
3.分组校验
分组校验指的是,不通场景,参数检验方式不同。比如添加员工时候,由于empId在数据库是自增的,所以添加员工时 empParam 参数中empId 可以为空,但是在修改用户时,就要求empId不能为空。前提是 emp 新增和修改接口来接收前端的参数都是同一个 empParam 类
(1)自定义分组接口
public interface ValidationGroup {interface Create extends Default{}interface Update extends Default{}
}
(2)实体类中属性添加校验分组
@Data
public class EmpParam implements Serializable {@NotNull(message = "员工ID不能为空", groups = {ValidationGroup.Update.class}) //注意查看添加接口和修改接口验证分组校验是否正确private Long empId;@NotBlank(message = "员工姓名不能为空",groups = {ValidationGroup.Create.class})private String empName;@NotBlank(message = "员工手机号不能为空")private String empPhone;@NotBlank(message = "员工邮箱不能为空")private String empEmail;@NotBlank(message = "员工身份证号不能为空")private String empIdCard;@Valid@NotNull(message = "部门信息不能为空")private DeptParam deptParam;
}
(3)控制层测试类
@RestController
@RequestMapping("/emp")
public class EmpController {@PostMapping("/add")public String addEmp(@RequestBody @Validated({ValidationGroup.Create.class}) EmpParam empParam) {System.out.println(empParam);return "success";}@PutMapping("/update")public String updateEmp(@RequestBody @Validated(ValidationGroup.Update.class) EmpParam empParam) {System.out.println(empParam);return "success";}
}
(4)使用posman测试
4.自定义校验注解
从上述方法中发现 validation这个框架所提供的校验注解,只是一些基本的判空,字符长度的校验。在日常开发中可能需要校验:比如手机号不能为空同时,必须是11位数字,以及添加用户时,用户手机号必须唯一(需要查询数据库)等等。显然是不满足日常开发的需求。因此我们可以根据 自身的需求来做校验注解。
接下来我们将自定义一个注解来专门校验身份证号
@Constraint(validatedBy = IdCardNumberValidator.class) // @IdCardNumber 注解校验类的具体实现类
@Target({ElementType.FIELD,ElementType.METHOD}) // 表示注解可以应用于字段和方法上
@Retention(RetentionPolicy.RUNTIME) // 表示注解在运行时保留,因此可以通过反射机制读取。强调,可以通过反射获取,
public @interface IdCardNumber {String message() default "身份证错误";Class<?>[] groups() default {};Class<?>[] payload() default {};
}
IdCardNameValidator 校验类来实现 ConstraintValidator接口即可
import com.personal.validation.annotations.IdCardName;
import com.personal.validation.utils.ValidatorUtils;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;public class IdCardNameValidator implements ConstraintValidator<IdCardName, String> {@Overridepublic void initialize(IdCardName constraintAnnotation) {ConstraintValidator.super.initialize(constraintAnnotation);}@Overridepublic boolean isValid(String idCardName, ConstraintValidatorContext constraintValidatorContext) {return ValidatorUtils.isValidName(idCardName);}
}
校验工具类
public class ValidatorUtils {//判断身份证号是否有效/*** '^':表示匹配字符串的开头* '[1-9]':表示匹配1-9之间的数字,确保身份证号码的前6位不为0* '\d{5}':表示匹配5位数字,确保身份证号码的前6位为数字,用于匹配地区码* '(18|19|([23]\d))':表示匹配18或19或20-23之间的数字,确保身份证号码的前2位为18或19或20-23之间的数字,用于匹配年份* '\d{2}':表示接下来的2位是月份,范围是01-12之间的数字* '((0[1-9])|(1[0-2]))':表示匹配月份,范围是01-12之间的数字* '(([0-2][1-9])|10|20|30|31)':表示日期,前两位0-2表示01-29,10、20、30、31分别单独列出* '\d{3}':表示匹配3位数字,确保身份证号码的第18位为数字,用于匹配顺序码* '[0-9Xx]':表示匹配0-9或X或x,确保身份证号码的第17位为数字或X或x,用于匹配校验位** @param idCard* @return*/public static boolean isValidIdCard(String idCard) {return Pattern.matches("^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$", idCard);}
}
实体类上加上 @IdCardNumber 注解
@Data
public class UserParam {@NotBlank(message = "用户名不能为空")private String username;@NotBlank(message = "密码不能为空")@Size(min = 6, max = 20, message = "密码长度在6-20位之间")private String password;@NotBlank(message = "手机号不能为空")private String phone;@NotBlank(message = "身份证不能为空")@IdCardNumber(message = "身份证不正确")// 自定义注解来校验,并不会跟原有注解冲突private String idCard;@NotBlank(message = "身份证姓名不能为空")private String idCardName;@NotBlank(message = "车牌号不能为空")private String carNumber;@NotBlank(message = "银行卡号不能为空")private String bankCardNumber;}
测试自定义注解是生效的,虽然身份证没空,但是校验没能通过的自定义注解的校验类
以上只是简单写了一个案例,如何自定义一个注解,以后可以自定义一个注解来校验前端传递过来的参数必须在数据库是唯一的,例如手机号,不能多个用户使用同个手机号,身份证也是如此。
5.反射加自定义注解实现动态校验
现在有这样一个场景,系统中客户表中有两个类型客户:个体工商户和企业客户两类,系统的客户认证只是一个接口,但是呢,企业客户和个体客户校验信息不一样,企业校验是,企业名称,企业信用代码,法人,营业执照等。个体工商户验证时客户身份证,名字,电话等。简单来说就是通过一个 authType 认证类型 字段 来判断那些那些参数不能为空
(1)添加客户实体类参数
如果前端传递的 authType =1,就校验 SingleCustomerParam 对象不能为空,并且 SingleCustomerParam 类中被 @NotBlank注解标注也不能为空。如果authType = 2,就检验 FirmCustomerParam 对象不能为空,并且 FirmCustomerParam 类中被 @NotBlank注解标注也不能为空。如果authType != 1 或则 2 就返回认证类型错误给前端
@Data
public class AddCustomerParam implements Serializable {/*** 客户类型 1个体工商户 2:企业客户*/@NotBlank(message = "客户类型不能为空")private String authType;/*** 1个体工商户*/private SingleCustomerParam singleCustomerParam;/*** 2企业客户*/private FirmCustomerParam firmCustomerParam;
}
SingleCustomerParam 实体类参数类
@Data
public class SingleCustomerParam implements Serializable {/*** 客户名称*/
// @NotBlank(message = "客户名称不能为空") //private String customerName;/*** 客户身份证照片*/@NotBlank(message = "客户身份证照片不能为空")private String idCardImg;/*** 认证图片和视频*/@NotBlank(message = "认证图片和视频不能为空")private String verifyImg;/*** 客户真是姓名*/@NotBlank(message = "客户真是姓名不能为空")private String realName;/*** 客户身份证号*/@NotBlank(message = "客户身份证号不能为空")private String idCard;/*** 客户手机号*/@NotBlank(message = "客户手机号不能为空")private String phone;
}
FirmCustomerParam 实体参数类
@Data
public class FirmCustomerParam implements Serializable {/*** 企业营业执照*/@NotBlank(message = "企业营业执照不能为空")private String businessLicense;/*** 企业名称*/@NotBlank(message = "企业名称不能为空")private String firmName;/*** 企业信用代码*/@NotBlank(message = "企业信用代码不能为空")private String creditCode;/*** 企业地址*/@NotBlank(message = "企业地址不能为空")private String address;/*** 企业联系人*/@NotBlank(message = "企业联系人不能为空")private String linkman;/*** 企业联系人电话*/@NotBlank(message = "企业联系人电话不能为空")private String mobile;}
(2)自定义参数校验注解 @CustomerParamTwo
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CustomerParamValidatorTwo.class)//注解校验类
public @interface CustomerParamTwo {String message() default "Invalid customer parameters";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}
CustomerParamValidatorTwo 实现 ConstraintValidator接口 重写具体校验规则
import com.personal.validation.annotations.CustomerParamTwo;
import com.personal.validation.param.AddCustomerParam;
import com.personal.validation.param.FirmCustomerParam;
import com.personal.validation.param.SingleCustomerParam;
import com.personal.validation.utils.ValidatorUtils;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import jakarta.validation.constraints.NotBlank;import java.lang.reflect.Field;public class CustomerParamValidatorTwo implements ConstraintValidator<CustomerParamTwo, AddCustomerParam> {@Overridepublic void initialize(CustomerParamTwo constraintAnnotation) {ConstraintValidator.super.initialize(constraintAnnotation);}@Overridepublic boolean isValid(AddCustomerParam customerParam, ConstraintValidatorContext constraintValidatorContext) {String authType =customerParam.getAuthType();if ("1".equals(authType)) {if(customerParam.getSingleCustomerParam() instanceof SingleCustomerParam){return customerParam.getSingleCustomerParam() != null&& isValidSingleCustomerParam(customerParam.getSingleCustomerParam(), constraintValidatorContext);}else//当authType = 1 时,singleCustomerParam不能为空addConstraintViolation(constraintValidatorContext, "singleCustomerParam","个人客户信息不能为空");return false;}else if ("2".equals(authType)) {if(customerParam.getFirmCustomerParam() instanceof FirmCustomerParam){return customerParam.getFirmCustomerParam() != null&& isValidFirmCustomerParam(customerParam.getFirmCustomerParam(), constraintValidatorContext);}else//当authType = 2 时,firmCustomerParam不能为空addConstraintViolation(constraintValidatorContext, "firmCustomerParam","企业客户信息不能为空");return false;}//单独校验authType类型if(!("1".equals(authType) || "2".equals(authType) || "".equals(authType))){addConstraintViolation(constraintValidatorContext, "authType","认证类型不正确");return false;}return false;}private boolean isValidSingleCustomerParam(SingleCustomerParam param, ConstraintValidatorContext context) {boolean isValid = true ;Field[] fields = SingleCustomerParam.class.getDeclaredFields();//反射获取对象的所有字段for (Field field : fields) {if (field.isAnnotationPresent(NotBlank.class)) {//获取属性上是否标注了校验注解// 如果字段有 @NotBlank 注解,则进行非空验证if (!validateField(param, field, context)) {isValid = false;}}}if(!ValidatorUtils.isValidPhoneNumber(param.getPhone())){addConstraintViolation(context, "phone","手机号不正确");isValid = false;}return isValid;}private boolean isValidFirmCustomerParam(FirmCustomerParam param, ConstraintValidatorContext context) {boolean isValid = true ;Field[] fields = FirmCustomerParam.class.getDeclaredFields();for (Field field : fields) {if (field.isAnnotationPresent(NotBlank.class)) {// 如果字段有 @NotBlank 注解,则进行非空验证if (!validateField(param, field, context)) {isValid = false;}}}return isValid;}// 字段校验不通过后,获取校验错误信息private boolean validateField(Object param, Field field, ConstraintValidatorContext context) {try {field.setAccessible(true);Object value = field.get(param);if (value == null || value.toString().trim().isEmpty()) {String message = field.getAnnotation(NotBlank.class).message();addConstraintViolation(context, field.getName(),message);return false;}return true;} catch (IllegalAccessException e) {return false;}}//将所有校验不通过的错误信息,封装返回给前端private void addConstraintViolation(ConstraintValidatorContext context, String field, String message) {context.disableDefaultConstraintViolation();context.buildConstraintViolationWithTemplate(message).addPropertyNode(field).addConstraintViolation();}
}
校验控制层接口类
@RestController
@RequestMapping("/customer")
public class CustomerController {/*** @param addCustomerParam* @return*/@PostMapping("/add")public String addCustomer(@RequestBody @Validated AddCustomerParam addCustomerParam) {System.out.println(addCustomerParam);// 客户认证参数全部交给自定义注解校验,我们后续只关注业务代码,将 检验逻辑 与 业务代码逻辑 分离return "add customer success";}
}
在校验类加上自定义的注解 @CustomerParamTwo
@Data
@CustomerParamTwo
public class AddCustomerParam implements Serializable {/*** 客户类型 1个体工商户 2:企业客户*/@NotBlank(message = "客户类型不能为空")private String authType;/*** 1个体工商户*/private SingleCustomerParam singleCustomerParam;/*** 2企业客户*/private FirmCustomerParam firmCustomerParam;
}
接下来我们进行测试:
测试authType 为空 或则 authType !=1 或则 2
authType = 1 校验 singleCustomerParam 个体工商户参数
校验成功:
authType = 2 校验 firmCustomerParam 企业客户参数
四、validation 校验失败处理
从上述案例中,校验失败错误信息原本抛出的异常不是如此的,validation 校验异常需要自己手动拦截并封装错误信息返回。接下来将如何捕获 validation 的异常信息,并封装成一个对象返回给前端
(1)自定义封装结果类
public class R {private int code;private String message;private Object data;public R() {}public R(int code, String message) {this.code = code;this.message = message;}public static R ok() {return new R(200, "Success");}public static R fail(int code, String message) {return new R(code, message);}// Getters and setters// You may want to add additional methods for data handlingpublic int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}
}
(2)自定义ValidationException 异常
public class ValidationException extends RuntimeException {public ValidationException(String message) {super(message);}
}
(3)自定义拦截器
直接在官网复制 validation 拦截器
@ControllerAdvice
public class CustomGlobalExceptionHandler {// Handle ConstraintViolationException@ExceptionHandler(ConstraintViolationException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic R handleValidationException(ConstraintViolationException ex) {List<String> errors = new ArrayList<>();for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {errors.add(violation.getPropertyPath() + ": " + violation.getMessage());}return R.fail(HttpStatus.BAD_REQUEST.value(), errors.toString());}// Handle MethodArgumentTypeMismatchException@ExceptionHandler(MethodArgumentTypeMismatchException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic R handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException ex) {String error = ex.getName() + " should be of type " + ex.getRequiredType().getName();return R.fail(HttpStatus.BAD_REQUEST.value(), error);}// Handle BindException@ExceptionHandler(BindException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic R handleBindException(BindException ex) {List<String> errors = new ArrayList<>();for (FieldError error : ex.getFieldErrors()) {errors.add(error.getField() + ": " + error.getDefaultMessage());}return R.fail(HttpStatus.BAD_REQUEST.value(), errors.toString());}// Handle custom ValidationException@ExceptionHandler(ValidationException.class) // 在这里进行拦截的@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic R handleValidationException(ValidationException ex) {return R.fail(HttpStatus.BAD_REQUEST.value(), ex.getMessage()); //拦截运行错误时的状态吗以及错误信息}// Handle generic exceptions@ExceptionHandler(Exception.class)@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)@ResponseBodypublic R handleException(Exception ex) {return R.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage());}
}
总结
例如:以上就是关于日常开发过程参数校验及封装错误信息返回给前端
相关文章:
SpringBoot的validation参数校验
文章目录 前言一、引入validation 依赖二、validation中的注解说明 (1)Validated(2)Valid(3)NotNull(4)NotBlank(5)NotEmpty(6)Patte…...
RPC与HTTP调用模式的架构差异
RPC(Remote Procedure Call,远程过程调用)和 HTTP 调用是两种常见的通信模式,它们在架构上有以下一些主要差异: 协议层面 RPC:通常使用自定义的二进制协议,对数据进行高效的序列化和反序列化&am…...
R语言机器学习论文(六):总结
文章目录 介绍参考文献介绍 本文采用R语言对来自进行数据描述、数据预处理、特征筛选和模型构建。 最后我们获得了一个能有效区分乳腺组织的随机森林预测模型,它的性能非常好,这意味着它可能拥有非常好的临床价值。 在本文中,我们利用R语言对来自美国加州大学欧文分校的B…...
工业—使用Flink处理Kafka中的数据_ProduceRecord2
使用 Flink 消费 Kafka 中 ProduceRecord 主题的数据,统计在已经检验的产品中,各设备每 5 分钟 生产产品总数,将结果存入HBase 中的 gyflinkresult:Produce5minAgg 表, rowkey“...
【嵌套查询】.NET开源 ORM 框架 SqlSugar 系列
.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…...
SpringBoot整合JWT
一. JWT简介 1. 什么是JWT? JWT(JSON Web Token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。 它将用户信息加密到token里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证&…...
使用docker创建cloudstack虚拟主机
文章目录 概要 环境准备: 1.使用rockyLinux:8镜像 2.配置yum源 3.添加vim cloudstack.repo为以下内容 4.前期我们已经搭好了cloudstack平台,这里需要映射几个目录到容器里面, 5.创建Dockerfile 6.构建镜像 7.使用命令创建…...
mybatis-xml映射文件及mybatis动态sql
规范 XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。 XML映射文件的namespace属性为Mapper接口全限定名一致。 XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致…...
Qt | TCP服务器实现QTcpServer,使用线程管理客户端套接字
点击上方"蓝字"关注我们 01、QTcpServer >>> QTcpServer 是 Qt 网络模块中的一个类,用于实现TCP服务器。它允许创建一个服务器,可以接受来自客户端的连接。QTcpServer 是事件驱动的,这意味着它将通过信号和槽机制处理网络事件。 常用函数 构造函数: QT…...
rustdesk远程桌面使用
文章目录 简介1.客户端rustdesk使用2.基于 S6-overlay 的镜像 服务端部署3.声明 简介 为什么使用rustdesk,因为向日葵,todesk,免费版本的有各种各样的坑,比如限制你的登录,需要你重新登录使用,画面模糊&am…...
C#中图片的Base64编码与解码转换详解
在C#中,我们可以使用Base64编码将图片转换为字符串,也可以将Base64编码的字符串转换回图片。这通常用于在需要文本表示图像数据的场合(例如在Web开发中传输图像数据)。 将图片转换为Base64字符串 要将图片文件转换为Base64字符串…...
瑞芯微方案主板Linux修改系统串口波特率教程,触觉智能RK3562开发板演示
遇到部分串口工具不支持1500000波特率,这时候就需要进行修改,本文以触觉智能RK3562开发板修改系统波特率为115200为例,介绍瑞芯微方案主板Linux修改系统串口波特率教程。 温馨提示:瑞芯微方案主板/开发板串口波特率只支持115200或…...
阿里云整理(二)
阿里云整理 1. 访问网站2. 专业名词2.1 域名2.2 域名备案2.3 云解析DNS2.4 CDN2.5 WAF 1. 访问网站 用户使用浏览器访问网站大体分为几个过程: 用户在浏览器输入域名URL,例如www.baidu.com。 不过,浏览器并不知道为该域名提供服务的服务器具…...
python实现一个简单的不断发送dns查询的功能
the code below: import socket import struct import time import randomdef create_dns_query(domain"example123.com"):# DNS HeaderID random.randint(0, 65535) # 随机查询IDFLAGS 0x0100 # Standard queryQDCOUNT 1 # One questionANCOUNT 0 # …...
鲲鹏麒麟使用Docker部署Redis5
本次部署采用Docker方式进行部署,服务器为鲲鹏服务器,CPU架构为ARM64,操作系统版本信息为 # cat /etc/kylin-release Kylin Linux Advanced Server release V10 (Tercel)镜像 下载镜像鲲鹏麒麟Redis5镜像包 部署 1、上传镜像到服务器 2、…...
MySQL悲观锁和乐观锁
MySQL悲观锁和乐观锁 在数据库中,锁是用来管理并发控制的一种机制,确保数据的一致性和完整性。MySQL中的悲观锁和乐观锁是两种不同的并发控制策略,它们在处理并发事务时采用不同的方法。 悲观锁(Pessimistic Locking)…...
【AI模型对比】Kimi与ChatGPT的差距:真实对比它们在六大题型中的全面表现!
文章目录 Moss前沿AI语义理解文学知识数学计算天文学知识物理学知识英语阅读理解详细对比列表总结与建议 Moss前沿AI 【OpenAI】获取OpenAI API Key的多种方式全攻略:从入门到精通,再到详解教程!! 【VScode】VSCode中的智能AI-G…...
一根网线如何用软路由给手机、电脑分配设置不同IP
众所周知,在同一个网络下,我们的互联网IP是一样的,即外网只有一个IP。很多互联网公司、游戏工作室、营利工作室都需要利用它们来实现同一网络下多台设备IP地址不同的效果。对此我们该怎么办?下面给大家简单分享一下! 在…...
面经自测——自我介绍
前言 这是作者新开的坑,一切题目都是从网上找的原题,为了总结网上有关的面经,以便在真实面试中较为流利的回答面试官的问题 面试之——自我介绍 自我介绍是面试中最常见的问题之一,主要目的是让面试官了解你的背景、技能和职业…...
uniapp 小程序 监听全局路由跳转 获取路由参数
uniapp 小程序 监听全局路由跳转 获取路由参数 app.vue中 api文档 onLaunch: function(options) {let that this;let event [navigateTo, redirectTo, switchTab, navigateBack];event.forEach(item > {uni.addInterceptor(item, { //监听跳转//监听跳转success(e) {tha…...
【LeetCode每日一题】——204.计数质数
文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时空频度】九【代码实现】十【提交结果】 一【题目类别】 数组 二【题目难度】 中等 三【题目编号】 204.计数质数 四【题目描述】 给定整数 n &…...
TCP的“可靠性”(下)——三次握手四次挥手
目录 建立连接(三次握手)为啥要进行握手??意义何在??常见面试题:为啥必须是三次握手? 断开连接(四次挥手)三次握手和四次挥手的相同点和不同点连接过程中涉及…...
【笔记2-5】ESP32:freertos消息队列
主要参考b站宸芯IOT老师的视频,记录自己的笔记,老师讲的主要是linux环境,但配置过程实在太多问题,就直接用windows环境了,老师也有讲一些windows的操作,只要代码会写,操作都还好,开发…...
java操作doc(二)——java利用Aspose.Words动态创建自定义doc文档
有关java动态操作word文档,上一篇写了如何使用模板动态设置对于内容以及相关单元格的动态合并问题,详细请参看如下文档: java利用Aspose.Words操作Word动态模板文档并动态设置单元格合并 这篇文档说说,如何利用Aspose.Words动态…...
计算机光电成像理论基础
一、透过散射介质成像 1.1 光在散射介质中传输 光子携带物体信息并进行成像的过程是一个涉及光与物质相互作用的物理现象。这个过程可以分为几个步骤来理解: 1. **光的发射或反射**: - 自然界中的物体可以发射光(如太阳)&am…...
【Qt中实现屏幕录制】
在Qt中实现屏幕录制可以通过使用QScreen和QVideoEncoder类来完成。以下是一个简单的示例代码,演示如何捕获屏幕并将其保存为视频文件。请确保已经安装了Qt Multimedia模块,因为我们将使用其中的类来处理视频编码。 下面是一个基本的实现步骤:…...
repo仓库转移到自己本地的git服务器
前提条件:搭建好gitolite 以转移正点原子rk3568_linux工程为例子,将其转移到自己的git服务器。 获取完整repo仓库 将正点原子epo仓库sync出来 evanevan-X99:~/SRC/atk$ .repo/repo/repo sync -l -j10 evanevan-X99:~/SRC/atk$ .repo/repo/repo list -n…...
java操作文件(一)——java如何实现多文件打包压缩并下载
在实际开发项目过程中,文件下载是异常频繁的操作,但是多文件zip打包下载并非常见使用场景,本文介绍如何使用io流操作多文件实现压缩并下载。 特别说明: 无需依赖任何第三方包或者拆件 一、效果展示: 1.打包前文件列…...
Git仓库移除文件的暂存和修改
在使用Git进行版本控制时,有时需要移除文件的暂存状态或者撤销对文件的修改。根据不同的需求和场景,可以采取不同的命令来完成这些操作。下面将详细介绍如何在Git中移除文件的暂存以及撤销文件的修改。 请注意,在执行这些命令之前࿰…...
Kube-Prometheus-Stack安装时初始化导入自定义Grafana dashboards
获取Grafana dashboards的JSON文件 这里是获取已经编辑好的Grafana dashboards的JSON文件;以便内置到Kube-Prometheus-Stack的helm charts的安装zip文件中。 编辑自定义dashboards JSON文件 获取dashboards JSON文件模板 其实Kube-Prometheus-Stack内部本身已经内…...
2024-12-05OpenCV高级-滤波与增强
OpenCV高级-滤波与增强 文章目录 OpenCV高级-滤波与增强1-OpenCV平滑滤波1. 均值滤波 (cv2.blur())2. 高斯滤波 (cv2.GaussianBlur())3. 中值滤波 (cv2.medianBlur())4. 双边滤波 (cv2.bilateralFilter())总结 2-OpenCV边缘检测1. Sobel算子 (cv2.Sobel())2. Canny边缘检测 (cv…...
taro小程序进入腾讯验证码
接入原因 昨天突然晚上有人刷我们公司的登录发送短信接口,紧急将小程序的验证码校验更新上去了 接下来就是我们的接入方法,其实很简单,不过有时候可能大家着急就没有仔细看文档,腾讯验证码文档微信小程序地址,注意这里…...
微信小程序怎么实现非tabbar页面显示tabbar,自定义组件实现
微信小程序没有发现可以实现非tabbar页面显示tabbar的方法,但是可以在tabbar页面当中隐藏tabbar,使用wx.hideTabBar()方法就可以实现,在非tabbar页面调用wx.showTabBar()方法却会显示失败,不能显示tabbar onLoad() {wx.showTabBar…...
001集—— 创建一个WPF项目 ——WPF应用程序入门 C#
本例为一个WPF应用(.NET FrameWork)。 首先创建一个项目 双击xaml文件 双击xaml文件进入如下界面,开始编写代码。 效果如下: 付代码: <Window x:Class"WpfDemoFW.MainWindow"xmlns"http://schema…...
【LeetCode: 316. 去除重复字母 + 栈 + 哈希表】
🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…...
基于Python的Selenium详细教程
一、PyCharm安装配置Selenium 本文使用环境:windows11、Python 3.10.5、PyCharm 2022.1.3、Selenium 4.3.0 需要你懂的技术:Python、HTML、CSS、JavaScript 1.Seleium安装: 在PyCharm终端或window命令窗口输入以下命令 #查看已安装的Pytho…...
金仓KDTS迁移工具报错ERROR: 对访问方法 “btree“ 数据类型 unknown 没有默认的操作符表
ERROR: 对访问方法 "btree" 数据类型 unknown 没有默认的操作符表 查看错误日志 com.kingbase8.util.KSQLException: ERROR: 对访问方法 "btree" 数据类型 unknown 没有默认的操作符表Hint: 你必须指定一个操作符表给索引或定义一个默认的操作符表给数据…...
前端开发入门指南Day 17:TypeScript高级类型(泛型,类型守卫,Partial<T>和 Required<T>等)
泛型:代码的"变色龙" 🦎 为什么需要泛型? 想象一个快递员,每天要处理不同类型的包裹。如果为每种类型的包裹都写一套处理程序,那会很麻烦。泛型就像是一个"通用的包裹处理系统",它能…...
数据链路层(四)---PPP协议的工作状态
1 PPP链路的初始化 通过前面几章的学习,我们学了了PPP协议帧的格式以及组成,那么对于使用PPP协议的链路是怎么初始化的呢? 当用户拨号上网接入到ISP后,就建立起了一条个人用户到ISP的物理链路。这时,用户向ISP发送一…...
EasyNVR中HTTP-FLV协议无法播放怎么解决?
在科技日新月异的今天,摄像头作为公共安全领域的重要一环,其技术的不断提升正显著地改变着社会的安全格局。从最初的简单监控到如今的高清智能分析,我们可以对特定区域进行实时监控和记录,为社会的安全稳定提供了强有力的保障。 问…...
微服务监控prometheus+Grafana
目录 Prometheus 概述 核心组件 特点 使用场景 Grafana 概述 功能特点 使用场景 PrometheusGrafana组合 部署和配置 一、准备工作 二、部署Prometheus 三、部署Grafana 四、创建监控仪表盘 五、验证和调优 总结 微服务监控是确保微服务架构稳定运行的关键环节…...
C++编程:模拟实现CyberRT的DataVisitor和DataDispatcher
文章目录 0. 引言1. 设计概要1.1 主要组件1.2 类关系图1.3 工作流程 2. 代码实现2.1. 定义数据结构2.2. 实现 DataVisitor2.3. 实现 DataDispatcher2.4. 实现 Receiver2.5. 实现具体的 DataVisitor2.6. 示例主程序2.7. 编译和运行 0. 引言 使用 C 实现一个类似CyberRT 架构的 …...
TongRDS分布式内存数据缓存中间件
命令 优势 支持高达10亿级的数据缓冲,内存优化管理,避免GC性能劣化。 高并发系统设计,可充分利用多CPU资源实现并行处理。 数据采用key-value多索引方式存储,字段类型和长度可配置。 支持多台服务并行运行,服务之间可互…...
银河麒麟v4/v10 Ubuntu上添加服务过程-以编译postgressql数据库为例
1 首先联网安装依赖 apt-get install build-essential zlib1g-dev libssl-dev libreadline-dev libxml2-dev python-setuptools 2 下载安装包 下载地址:https://ftp.postgresql.org/pub/source/v16.3/postgresql-16.3.tar.gz 3 编译安装 mkdir -p /data/pgsql…...
电子商务人工智能指南 1/6 - 搜索、广告和发现
介绍 81% 的零售业高管表示, AI 至少在其组织中发挥了中等至完全的作用。然而,78% 的受访零售业高管表示,很难跟上不断发展的 AI 格局。 近年来,电子商务团队加快了适应新客户偏好和创造卓越数字购物体验的需求。采用 AI 不再是一…...
JAVA面试基础(总结了很多)
最近帮整理了一份JAVA的面试基础,不过很基础后面还回继续更新。 java的专业技能 2.1 java的基础部分 2.1.1 简单讲一下java的跨平台原理 由于各操作系统(windows,liunx等)支持的指令集,不是完全一致的。就会让我们的程序在不同的操…...
PPT怎样做的更加精美
目录 PPT怎样做的更加精美 3D的GIF图片 3维空间图编辑 结果有明显的对比 阅读高质量文献,采用他们的图 PPT怎样做的更加精美 3D的GIF图片 3维空间图 结果有明显的对比...
postgresql与pgvector安装与使用
环境变量修改 打开 .bashrc 文件进行编辑: vim ~/.bashrc在文件的末尾添加上面的环境变量配置 # 添加 PostgreSQL 可执行文件路径到系统 PATH export PATH/home/....../pg/postgresql-12.4/bin:$PATH# 设置 PostgreSQL 数据目录 export PGDATA/home/....../pg/pos…...
Tomcat,javaweb, servlet , springBoot
在server.xml里配置服务器 <scope>provided</scope>打包的时候,这个jar包不会被打进去,因为tomcat已将封装了这个jar包,没必要要这个...
vue 通过 image-conversion 实现图片压缩
简介 vue项目中,上传图片时如果图片很大,通过 image-conversion 压缩到指定大小 1. 安装依赖 npm i image-conversion --save2. 引用 import * as imageConversion from image-conversion3. 使用 const newFile new Promise((resolve) > {// 压…...