【智能排班系统】Hibernate Validator 参数校验

news2024/11/13 9:42:13

🎯导读:本文档介绍了参数校验的重要性及其在软件开发中的作用,强调了数据完整性、安全性、用户体验、系统稳定性及开发效率等方面的关键价值。文档详细阐述了Hibernate Validator这一流行的Java验证框架的使用方法,展示了如何利用其内置注解(如@NotNull、@Size、@Email等)来对输入数据进行有效性检查。此外,还探讨了自定义校验规则的开发方式,以及如何通过分组校验来适应不同的业务场景需求。通过集成Hibernate Validator,开发者可以显著提升应用程序的质量与用户体验。

文章目录

  • 参数校验
  • Hibernate Validator 简介
  • 依赖
  • 基础使用
  • 常用校验注解
    • 字段校验注解
    • 其他注解
  • 分组校验
    • 定义分组
    • 使用
  • 自定义校验
    • 定义注解
    • 校验器实现
    • 使用
    • 排班系统实现(以添加节日为例)
      • 代码位置
      • 参数类
      • 接口
      • 统一异常处理
      • 测试
  • 嵌套校验

参数校验

参数校验是指在接收输入数据时,对传入的参数进行验证,以确保它们符合预期的格式、范围和有效性。这种校验对于保证软件的稳定性和安全性至关重要。以下是参数校验的一些关键作用和意义:

  1. 数据完整性:
    1. 参数校验可以帮助确保接收到的数据符合预期的格式和结构。例如,通过校验确保日期格式正确、数值在合理范围内、字符串长度合适等。
    2. 这样可以防止因输入数据错误而导致的程序异常或错误行为。
  2. 安全性:
    1. 校验可以防止恶意或意外的数据注入,如 SQL 注入、XSS 攻击等。通过严格的校验规则,可以降低这些安全风险。
    2. 正确的校验机制能够帮助过滤掉不安全的输入,保护系统免受攻击。
  3. 用户体验:
    1. 在用户界面上,及时反馈错误信息给用户,帮助他们更快地纠正输入错误,改善用户体验。
    2. 清晰的错误提示可以使用户更容易理解和操作系统,减少因输入错误造成的困惑和沮丧感。
  4. 系统稳定性:
    1. 通过在校验阶段捕获潜在的问题,可以提前处理错误情况,避免后续处理逻辑中出现未预见的异常。
    2. 这有助于确保系统在面对各种输入时都能保持一致的行为,提高系统的可靠性和稳定性。
  5. 开发效率:
    1. 自动化的参数校验减少了手工检查的需要,简化了开发过程,降低了出错的可能性。
    2. 开发者可以专注于核心业务逻辑,而不必担心基础的数据验证问题。
  6. 易于维护:
    1. 明确的校验规则使得代码更易于理解和维护。当需要调整业务逻辑或数据格式时,可以在一处修改校验逻辑即可。
    2. 这有助于保持代码的清晰和整洁,便于团队协作。

Hibernate Validator 简介

参数校验最直接的方式就是在方法中实现具体的逻辑来判断参数是否合理,但是如果每个方法都要这样判断,未免太过复杂,Hibernate Validator 定义了一些常用的校验注解可以帮助我们快速搞定一些常见的常数校验,如非空、长度限制、邮件是否合格……

Hibernate Validator 是一个强大的开源库,用于实现 Java Bean Validation(JSR 303 和 JSR 380)规范。它是 Java 应用程序中最广泛使用的验证框架之一。Hibernate Validator 提供了一套丰富的约束注解,允许开发者轻松地对实体对象中的属性进行约束定义,确保它们满足特定的业务规则。通过使用如 @NotNull@Size@Pattern 等内置注解,开发者可以方便地检查对象的状态,确保数据的完整性和一致性。

Hibernate Validator 不仅支持标准的 JSR 规范中定义的约束,还提供了一些额外的注解,如 @Length@ScriptAssert,使得验证逻辑更加灵活和强大。此外,它还支持自定义约束注解的开发,允许根据具体的应用需求来扩展验证功能。通过集成 Hibernate Validator,开发者可以在运行时自动执行验证逻辑,减少手工编写验证代码的工作量,并提高代码的可读性和可维护性。

Hibernate Validator 的应用场景非常广泛,从简单的 Web 表单数据验证到复杂的业务规则检查,都可以看到它的身影。无论是前端还是后端开发,Hibernate Validator 都能帮助开发者确保数据的准确性和有效性,从而提升软件的质量和用户体验。

依赖

在父工程添加如下依赖来管理版本

<hibernate-validator.version>6.2.5.Final</hibernate-validator.version>

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>${hibernate-validator.version}</version>
</dependency>

sss-commonsss-enterprisesss-aggregation模块添加都如下依赖,你可能会疑惑,sss-enterprise模块不是已经导入了sss-common了吗,为什么还要重复引用。亲测不引用,参数会生效,这个bug我找了一个下午o(╥﹏╥)o

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
</dependency>

基础使用

首先给参数类的字段添加注解,例如给name定义非空检验

@Data
@TableName("festival")
@NoArgsConstructor
@AllArgsConstructor
public class FestivalEntity extends BaseEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 节日名称
     */
    @NotBlank(message = "节日名称不能为空")
    private String name;

    /**
     * 起始日期
     */
    @NotNull(message = "起始日期不能为空")
    private Date startDate;

    /**
     * 截止日期
     */
    @NotNull(message = "截止日期不能为空")
    private Date endDate;

    /**
     * 门店id
     */
    @JsonSerialize(using = ToStringSerializer.class)
    private Long storeId;

    /**
     * 0:农历 1:新历
     */
    private int type;
}

接在给Controller的方法添加校验注解,@Validated要添加在@RequestBody前面,这样接收到参数festival之后,就会按照所设定规则对里面的字段值进行校验

@PostMapping("/save")
public R save(@Validated @RequestBody FestivalEntity festival, HttpServletRequest httpServletRequest) {
    long storeId = Long.parseLong(JwtUtil.getStoreId(httpServletRequest.getHeader("token")));
    festival.setStoreId(storeId);
    festivalService.save(festival);

    return R.ok();
}

常用校验注解

字段校验注解

【布尔类】

  • **@AssertTrue**布尔表达式必须为true。
  • **@AssertFalse**布尔表达式必须为false。
@AssertTrue(message = "你必须同意服务条款")
private boolean agreeToTerms;

@AssertFalse(message = "您必须不是机器人")
private boolean isRobot;

【数字类】

  • **@Min**数值必须大于等于指定的最小值。
  • **@Max**数值必须小于等于指定的最大值。
  • **@DecimalMin**十进制数必须大于等于指定的最小值。
  • **@DecimalMax**十进制数必须小于等于指定的最大值。
  • **@Digits**检查数字的整数部分和小数部分的位数是否不超过指定的值。
  • **@Range**数字或日期必须在指定范围内。
  • **@Negative**数字必须是负数。
  • **@NegativeOrZero**数字必须是负数或零。
  • **@Positive**数字必须是正数。
  • **@PositiveOrZero**数字必须是正数或零。
// 确保年龄至少为 18 岁
@Min(value = 18)
private int age;
// 确保考试分数不能超过 100 分
@Max(value = 100)
private int score;

// 确保价格至少为 10.00。inclusive = true 表示包括 10.00 在内
@DecimalMin(value = "10.00", inclusive = true)
private BigDecimal price;
// 确保折扣率不能超过 0.99。inclusive = false 表示不包括 0.99
@DecimalMax(value = "0.99", inclusive = false)
private BigDecimal discountRate;

@Digits(integer = 10, fraction = 2, message = "交易金额的整数部分不能超过10位数,小数部分不能超过2位数")
private BigDecimal amount;

@Digits(integer = 5, fraction = 2, message = "手续费的整数部分不能超过5位数,小数部分不能超过2位数")
private BigDecimal fee;

@Range(min = 18, max = 100, message = "年龄必须在18到100岁之间")
private int age;

@Negative(message = "温度必须低于零度")
private double temperature;

@NegativeOrZero(message = "海拔高度必须是负数或零")
private int altitude;

@Positive(message = "体重必须是正数")
private double weight;

@PositiveOrZero(message = "身高必须是正数或零")
private double height;

【日期类】

  • **@Past**日期必须在过去。
  • **@Future**日期必须在未来。
  • @PastOrPresent:用于验证日期是否在过去或当前日期。
  • @FutureOrPresent:用于验证日期是否在未来或当前日期。
@Past(message = "出生日期必须在过去")
private LocalDate birthDate;
@Future(message = "预约日期必须在未来")
private LocalDate appointmentDate;
@PastOrPresent
private LocalDate lastLogin;
@FutureOrPresent
private LocalDate nextAppointment;

【字符串类】

  • **@NotBlank**字符串不能为null且去除空白后长度必须大于零。
  • **@Length**字符串长度必须在指定范围内。
  • **@Email**字符串必须是有效的电子邮件地址。
  • **@Pattern**字符串必须匹配正则表达式。
  • **@CreditCardNumber**字符串必须是一个有效的信用卡号。
@NotBlank(message = "评论内容不能为空")
@Length(min = 5, max = 200, message = "评论内容长度必须在5到200个字符之间")
private String content;
@Email(message = "电子邮件地址无效")
private String email;
@NotBlank(message = "密码不能为空")
@Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8,}$", message = "密码必须包含字母和数字,且长度至少为8个字符")
private String password;
@CreditCardNumber(message = "信用卡号无效")
private String creditCardNumber;

【通用】

  • **@NotEmpty**字符串、集合、数组等不能为null且长度必须大于零。
  • **@NotNull**字段或属性不能为null。
  • **@Null**字段或属性必须为null。
  • **@Size**用于字符串、集合、数组等,检查大小是否在指定范围内。
@NotNull(message = "用户名不能为空")
private String username;

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

@Size(min = 3, max = 20, message = "用户名长度必须在3到20个字符之间")
private String username;
@Size(min = 1, message = "至少需要选择一项兴趣")
private List<String> interests;

@NotEmpty(message = "用户名不能为空")
private String username;

其他注解

  • **@Constraint**用于创建自定义约束。
  • **@ConstraintValidator**用于创建自定义约束的验证器。
  • **@ConstraintViolation**用于描述约束违反的情况。
  • **@ConstraintDescriptor**用于描述约束元数据。
  • **@ValidationGroups**允许你对验证逻辑进行分组,从而控制哪些约束在何时被应用。
  • **@Valid**应用于对象,验证对象的所有属性。
  • **@Validated**通常用于框架集成,比如Spring,以启用方法参数验证。

分组校验

同一个字段,不同方法中可能对其有不同的要求。例如名字这个字段,添加用户的时候要求该字段非空,但修改用户信息的时候,如果不修改名字,该字段可以为空。

为了满足上面的需求,我们需要定义不同的小组来进行校验隔离

定义分组

新增分组

/**
 * @Author dam
 * @create 2024/8/31 10:32
 */
public interface AddGroup {
}

修改分组

/**
 * @Author dam
 * @create 2024/8/31 10:32
 */
public interface UpdateGroup {
}

使用

在使用注解的时候,使用groups属性来定义即可

@NotNull(message = "起始日期不能为空", groups = {AddGroup.class})
private Date startDate;

@NotNull(message = "起始日期不能为空", groups = {AddGroup.class, UpdateGroup.class})
private Date startDate;

自定义校验

自定义校验规则是为了让我们可以定义一些项目通用,但是Hibernate Validator不具备的校验方法。下面的例子会实现一个校验 传入参数 是否被 指定数组 所包含,例如参数是被在{1,2,3,4,5}当中

定义注解

import com.dam.valid.validator.TypeValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

/**
 * 注解:校验是否在所包含的数字中
 *
 * @Author dam
 * @create 2024/8/31 10:48
 */
@Documented
@Constraint(validatedBy = {TypeValidator.class})
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface TypeAnno {

    //--------------- 必须包含字段 ----------------

    String message() default "字段必须是0或1";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    //--------------- 自定义字段 ----------------
    /**
     * 用来接收所包含的值
     **/
    int[] values() default {};
}
  • @Documented:当你生成Javadoc文档时,该注解将被记录下来,方便其他开发者查阅
  • @Constraint(validatedBy = {TypeValidator.class}):表示这是一个验证约束注解,并指定了一个验证器类 TypeValidator,用于执行具体的验证逻辑。 validatedBy属性用来指定一个或多个验证器类,这些类负责实现具体的验证逻辑
  • @Target:定义此注解可以应用的目标元素类型。
    • ElementType.METHOD:方法。
    • ElementType.FIELD:字段。
    • ElementType.CONSTRUCTOR:构造函数。
    • ElementType.PARAMETER:方法或构造函数的参数。
  • @Retention(RetentionPolicy.RUNTIME):定义了注解的保留策略,这里设置为 RUNTIME,意味着该注解将在编译时保留,并且可以在运行时通过反射访问。

校验器实现

import com.dam.valid.annotations.TypeAnno;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;

/**
 * 校验器:校验是否在所包含的数字中
 *
 * @Author dam
 * @create 2024/8/31 10:52
 */
public class TypeValidator implements ConstraintValidator<TypeAnno, Integer> {

    /**
     * 存储类型
     */
    private Set<Integer> typeSet = new HashSet<>();

    @Override
    public void initialize(TypeAnno constraintAnnotation) {
        for (int value : constraintAnnotation.values()) {
            typeSet.add(value);
        }
    }

    /**
     * 校验字段是否有效
     *
     * @param value 要校验的值
     * @param context
     * @return
     */
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        System.out.println("触发校验");
        return typeSet.contains(value);
    }
}

使用

/**
 * 0:农历 1:新历
 */
@TypeAnno(values = {0, 1}, groups = {AddGroup.class}, message = "节日日期类型只能是农历(0)、新历(1)")
private int type;

排班系统实现(以添加节日为例)

代码位置

在这里插入图片描述

参数类

import com.baomidou.mybatisplus.annotation.TableName;
import com.dam.model.entity.BaseEntity;
import com.dam.valid.annotations.TypeAnno;
import com.dam.valid.groups.AddGroup;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Date;

/**
 * 门店节日表
 *
 * @author dam
 * @email 1782067308@qq.com
 * @date 2023-03-13 16:42:08
 */
@Data
@TableName("festival")
@NoArgsConstructor
@AllArgsConstructor
public class FestivalEntity extends BaseEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 节日名称
     */
    @NotBlank(message = "节日名称不能为空")
    private String name;

    /**
     * 起始日期
     */
    @NotNull(message = "起始日期不能为空", groups = {AddGroup.class})
    private Date startDate;

    /**
     * 截止日期
     */
    @NotNull(message = "截止日期不能为空", groups = {AddGroup.class})
    private Date endDate;

    /**
     * 门店id
     */
    @JsonSerialize(using = ToStringSerializer.class)
    private Long storeId;

    /**
     * 0:农历 1:新历
     */
    @TypeAnno(values = {0, 1}, groups = {AddGroup.class}, message = "节日日期类型只能是农历(0)、新历(1)")
    private int type;
}

接口

/**
 * 保存
 */
@PostMapping("/save")
@OperationLog(title = FestivalController.title, businessType = BusinessTypeEnum.INSERT, detail = "新增节日")
@PreAuthorize("hasAuthority('bnt.festival.add')")
public R save(@Validated({AddGroup.class}) @RequestBody FestivalEntity festival, HttpServletRequest httpServletRequest) {
    long storeId = Long.parseLong(JwtUtil.getStoreId(httpServletRequest.getHeader("token")));
    festival.setStoreId(storeId);
    festivalService.save(festival);

    return R.ok();
}

统一异常处理

当请求参数未能通过 Spring MVC 的数据绑定和校验时,会抛出 MethodArgumentNotValidException。该方法捕捉此类异常,并将校验错误信息整理后返回给客户端。

import com.dam.model.enums.ResultCodeEnum;
import com.dam.model.result.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 参数校验异常
     * @param exception
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public R handleValidException(MethodArgumentNotValidException exception) {
        // 创建一个 Map 用来存储每个字段的错误信息
        Map<String, String> map = new HashMap<>();
        
        // 获取数据校验的错误结果
        BindingResult bindingResult = exception.getBindingResult();
        
        // 遍历所有的 FieldError 对象,将每个字段的错误信息存入 map 中
        bindingResult.getFieldErrors().forEach(fieldError -> {
            // 获取错误信息
            String message = fieldError.getDefaultMessage();
            // 获取字段名
            String field = fieldError.getField();
            // 将字段名和错误信息放入 map
            map.put(field, message);
        });
        
        // 记录错误日志
        log.error("数据校验出现问题{}, 异常类型{}", exception.getMessage(), exception.getClass());
        
        // 获取错误信息并格式化成字符串
        StringBuilder sb = new StringBuilder();
        int id = 1;
        for (String key : map.keySet()) {
            // 格式化错误信息,每条错误信息前加上编号
            sb.append(id++).append(") ").append(key).append("->").append(map.get(key)).append("<br/>");
        }
        
        // 打印错误信息到控制台
        System.out.println(sb.toString());
        
        // 返回包含错误代码和错误信息的 R 对象
        return R.error(ResultCodeEnum.ARGUMENT_VALID_ERROR.getCode(), ResultCodeEnum.ARGUMENT_VALID_ERROR.getMessage() + ":<br/>" + sb.toString());
        
    }
}

测试

使用ApiFox软件来进行接口测试

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

定义请求头参数

在这里插入图片描述

发送请求

在这里插入图片描述

嵌套校验

嵌套校验指在进行数据验证时,不仅仅检查顶层对象的属性是否符合预期,同时也深入到对象的子对象或者集合中去验证它们的属性是否满足特定规则的过程。这种校验方式常见于复杂的数据结构中,比如对象的属性可能是一个列表,而列表中的每个元素本身又是一个对象;或者是对象的某个属性是一个具有多个字段的另一个对象。这时需要使用@Valid来修饰该属性

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;

// 订单实体类
public class Order {

    @NotNull(message = "用户信息不能为空")
    @Valid
    private User user;

    @NotEmpty(message = "订单中至少需要包含一个产品")
    @Valid
    private List<Product> products;

    // Getters and Setters
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public List<Product> getProducts() {
        return products;
    }

    public void setProducts(List<Product> products) {
        this.products = products;
    }
}

// 用户实体类
public class User {

    @NotNull(message = "用户名不能为空")
    private String name;
    
    // Getters and Setters
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

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

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

相关文章

适马相机cf卡剪切的数据还能恢复吗?可尝试这几种方法

“本想把适马相机CF卡里的珍贵数据剪切到电脑上&#xff0c;‌以备不时之需&#xff0c;‌但是不知道怎么回事&#xff0c;剪切后数据既不在电脑上&#xff0c;‌CF卡里也没了&#xff0c;这可真是让我心急如焚&#xff01;‌求大神指点迷津&#xff0c;‌帮我找回那些重要的文…

Vue 选项式api和组合式api 路由嵌套

选项式api和组合式api是两种不同的语法习惯&#xff0c;<template>标签内还是该怎么写就怎么写&#xff0c;不一样的只是<script>里面的语法改变了。 目录 选项式api&#xff1a; 组合式api&#xff1a; 1)省略各种关键字&#xff1a; 省略前&#xff1a; 省略后…

【Qt】菜单栏

目录 菜单栏 例子&#xff1a;创建菜单栏、菜单、菜单项 例子&#xff1a;给菜单设置快捷键 例子&#xff1a;给菜单项设置快捷键 例子&#xff1a;添加子菜单 例子&#xff1a;添加分隔线 例子&#xff1a;添加图标 菜单栏 Qt中的菜单栏是通过QMenuBar这个类实现的&…

LeetCode --- 412周赛

题目列表 3264. K 次乘运算后的最终数组 I 3266. K 次乘运算后的最终数组 II 3265. 统计近似相等数对 I 3267. 统计近似相等数对 II 一、K次乘预算后的最终数组 I & II I 数据范围比较小&#xff0c;可以暴力模拟&#xff0c;代码如下 class Solution { public:vecto…

Day52 | dijkstra(堆优化版)Bellman_ford 算法

dijkstra&#xff08;堆优化版&#xff09; 题目 47. 参加科学大会 47. 参加科学大会&#xff08;第六期模拟笔试&#xff09; 题目描述 小明是一位科学家&#xff0c;他需要参加一场重要的国际科学大会&#xff0c;以展示自己的最新研究成果。 小明的起点是第一个车站&a…

vscode 未定义标识符 “uint16_t“C/C++(20) 但是可以顺利编译

这是没有指定编译器的原因 解决方法&#xff1a; 打开 或c_cpp_properties.json&#xff0c;添加编译器

★ 算法OJ题 ★ 力扣611 - 有效三角形的个数

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;椎名日和将和大家一起做一道双指针算法题--有效三角形的个数~ 目录 一 题目 二 算法解析 三 编写算法 一 题目 二 算法解析 给三个数&#xff0c;判断是否能构成三角形的条件&#xff1a;两个较小的数相加大于…

机器学习数学公式推导之高斯分布

文章目录 1、介绍引入1.1 频率派的观点1.2 贝叶斯派的观点1.3 小结 2、数学基础2.1 二阶中心矩2.2 样本方差2.3 高斯分布2.3.1 一维情况 MLE2.3.2 多维情况 本文参考 B站UP: shuhuai008 跳转 &#x1f339;&#x1f339; 1、介绍引入 在统计学和概率论中&#xff0c; P ( x ∣ …

史上最全的MybatisPlus学习教程从入门到精通

一、MybatisPlus是什么 1.1 MyBatis-Plus简介 MyBatis-Plus&#xff08;简称MP&#xff09;是一个MyBatis的增强工具&#xff0c;它在MyBatis的基础上进行了增强&#xff0c;但并没有改变原有的MyBatis框架。MyBatis-Plus的主要目标是简化开发和提高开发效率。它提供了诸如分…

源码阅读-SpirngBoot Mybatis 自动配置

MybatisPlusAutoConfiguration ObjectProvider#getIfAvailable ObjectProvider为我们提供了拓展&#xff0c;我们可以自定义一些插件或者类型转换器&#xff0c;同时也可以定义一些Customizer用来配置SqlSessionFactoryBean,MybatisPlusProperties等。 通过源码我们可以看到最…

Redis从入门到入门(上)

1.Redis概述 文章目录 1.Redis概述1.1 什么是Redis1.2 Redis的应用场景 2.Linux下Redis的安装与使用2.1 Redis下载2.2 Redis的启动2.3 Redis配置2.4 连接Redis 1.1 什么是Redis Redis是用C语言开发的一个开源的高性能键值对&#xff08;key-value&#xff09;数据库&#xff0…

数学建模--K-Means聚类分析

目录 1.聚类分析步骤 1.1简单介绍 1.2两个概念 1.3几种距离 1.4更新质心 1.5终止条件 2.归一化处理 3.肘部法则 4.搭建K-Means分析模型 5.选择最佳K值 6.绘制3D图形 1.聚类分析步骤 1.1简单介绍 K-Means聚类分析是属于聚类分析的一种&#xff0c;这个数据机器学习的…

YOLOv8改进 | Neck篇 | YOLOv8引入Slim-Neck(超轻量)

1. Slim-Neck介绍 摘要:目标检测是计算机视觉中重要的下游任务。 对于车载边缘计算平台来说,巨大的模型很难达到实时检测的要求。 而且,由大量深度可分离卷积层构建的轻量级模型无法达到足够的精度。 我们引入了一种新的轻量级卷积技术 GSConv,以减轻模型重量但保持准确性。…

《软件工程导论》(第6版)第4章 形式化说明技术 复习笔记

第4章 形式化说明技术 一、概述 按照形式化的程度&#xff0c;可以把软件工程使用的方法划分成非形式化、半形式化和形式化3类。用自然语言描述需求规格说明&#xff0c;是典型的非形式化方法。用数据流图或实体联系图建立模型&#xff0c;是典型的半形式化方法。所谓形式化…

idea的springboot里面的resources是什么

在IDEA&#xff08;IntelliJ IDEA&#xff09;中的Spring Boot项目中&#xff0c;resources目录扮演着非常重要的角色。这个目录主要用于存放项目的非代码资源&#xff0c;包括但不限于配置文件、静态资源文件&#xff08;如图片、CSS、JavaScript等&#xff09;、模板文件&…

YOLO缺陷检测学习笔记(2)

YOLO缺陷检测学习笔记&#xff08;2&#xff09; 残差连接1. **YOLO 的残差连接结构**2. **YOLO 使用残差连接的目的**3. **YOLO 中的残差块**4. **YOLOv3 和 YOLOv4 的残差连接架构** YOLO网络架构概述1. 特征提取网络2. 预测头&#xff08;Detection Head&#xff09;3. 后处…

Android CCodec Codec2 (五)C2Param - Ⅲ

这一节我们来看看简单参数的定义方式 1、C2SimpleValueStruct Codec2框架提供了模板类C2SimpleValueStruct来帮助我们定义非灵活数组的简单参数。C2SimpleValueStruct的定义如下&#xff1a; template<typename T> struct C2SimpleValueStruct {T value; ///< simpl…

阿里 “通义灵码” 真的 “灵吗”,全保姆级实操

最近很多朋友&#xff0c;都在关注阿里公测的“通义灵码”&#xff0c;我索性也安装了&#xff0c;准备看看它真的有说的那么“灵吗”&#xff1f; 一、安装 官网&#xff1a;https://tongyi.aliyun.com/lingma/ 安装方式&#xff1a;https://tongyi.aliyun.com/lingma/downl…

Redis 集群:引领企业级 NoSQL 数据库新潮流

一 、关系型数据库和 NoSQL 数据库 在当今的数据库领域&#xff0c;关系型数据库和非关系型数据库都占据着重要的地位。 关系型数据库 关系型数据库是建立在关系模型基础上的数据库&#xff0c;它通过表与表之间的关系来存储和管理数据。 特点 数据结构清晰&#xff1a;以二…

“微服务革命”之后...

曾几何时&#xff0c;我记得我的手指疯狂地敲打键盘&#xff0c;与庞大而杂乱的代码库搏斗。那是巨石的时代&#xff0c;代码就像古老的城堡一样&#xff0c;由一块块石头砌成一个令人印象深刻的庞然大物。 几年过去了&#xff0c;时代变了。开发人员口中的流行语变成了“微服…