spring-boot-starter-validation

官方提供的注解

spring-boot-starter-validation 是 Spring Boot 提供的一个 starter,是一个用于验证 Java Bean 的标准,它提供了一套注解和相应的运行时 API 来定义和执行校验规则。

具体来说,当你在项目中引入 spring-boot-starter-validation 后,你可以使用一系列预定义的约束注解(如 @NotNull, @Size, @Min, @Max 等等)来标注你的 Java Bean 的字段、方法参数或方法返回值,以定义相应的校验规则。

引入依赖:

  <!--引入Validation -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

 

接下来讲解几个常用的注解:

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

@NotBlank注解可以使Bean校验的Bean属性不能为空,如果为空则会抛出异常,输出注解的message中的值

 @NotNull注解会校验""一个空字符串通过,而@NotBlank注解这会不通过,应当保证包含字符长度大于等于1

@Null则与@NotNull相反,它只能有一个取值就是null

@Length(min = 6,max = 32,message = "密码长度应当在6~32之间")
    private String password;

@Length注解标志Bean的属性值可使用的长度使多少,如上图的例子:最短长度为6个字符,最长的长度为多少

@Min(value = 0,message = "最小年龄为0")
    @Max(value = 150,message = "最大年龄为150")
    private Integer age;

@Min 和@Max都是用来校验Bean的数值属性的,最大值和最小值为多少

@Positive用于确保被注解的数值大于 0。这个注解可以应用于数字类型的字段、方法参数或方法返回值上,以保证这些数值是正数。

@Email(message = "邮箱格式错误")
    private String email;

 

@email注解用于判断是否符合邮箱的格式

@Pattern(regexp = "^1[3-9]\\d{9}$", message = "电话号码必须是11位且符合中国大陆手机号格式")
    @NotBlank(message = "电话号码不能为空")
    private String phoneNumber;

 

 

@Pattern注解可以实现正则表达式验证属性值

解释一下这个正则表达式的各个部分:

  • ^ 表示字符串的开始。
  • 1 表示手机号码的第一位必须是1。
  • [3-9] 表示手机号码的第二位必须在3到9之间。
  • \\d{9} 表示接下来的9位可以是任何数字(总共11位)。
  • $ 表示字符串的结束。

其它注解:

@Size 是 Bean Validation API 提供的一个非常灵活的约束注解,用于限制集合、数组、映射或字符串等类型的元素数量或长度,它允许你指定最小值和/或最大值来约束被注解元素的大小。

@Size(min = 1, max = 10, message = "数组大小应在1到10之间")
    private int[] numbers;
@Size(max = 5, message = "最多只能选择5个兴趣爱好")
    private List<String> hobbies;
@Size(min = 2, max = 30, message = "用户名长度应在2到30个字符之间")
    private String username;

 

自定义注解

在Java中,ConstraintValidator<S,T> 是 Bean Validation API 中的一个接口,用于定义自定义的约束验证器。通过实现这个接口,你可以创建自己的校验逻辑来检查特定的数据是否符合你设定的条件。

ConstraintValidator<S, T> 参数说明
S:代表与该验证器关联的注解类型(即你自己定义的注解类)。这意味着你的验证器是为特定类型的注解服务的。
T:代表要校验的数据类型。也就是说,你希望对哪种数据类型应用这种校验逻辑。
例如,如果你有一个自定义注解 SexAnnotation 用来标记性别字段,并且你想对字符串类型的值进行校验(比如"男", "女"),那么你需要实现 ConstraintValidator<SexAnnotation, String> 接口。

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;

import java.util.Arrays;
import java.util.List;

public class SexValidator implements ConstraintValidator<SexAnnotation,String> {
    // 定义一个List类型的sexType变量
    private List<String> sexType;
    // 初始化方法,获取注解中的sexType值
    @Override
    public void initialize(SexAnnotation constraintAnnotation) {
        sexType = Arrays.asList(constraintAnnotation.sexType());
        // 调用父类的初始化方法
        ConstraintValidator.super.initialize(constraintAnnotation);
    }

    // 校验方法,判断传入的值是否在sexType中
    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        if (s!=null){
            //判断当前的属性值是否已经包含在注解的值中
            if (sexType.contains(s)){
                return true;
            }
        }
        return false;
    }
}

 

自定义注解:

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

// 定义一个注解,用于验证性别
@Target({ElementType.FIELD,ElementType.PARAMETER}) // 注解可以用于字段和方法参数
@Retention(RetentionPolicy.RUNTIME) // 注解在运行时有效
@Documented // 注解将被包含在javadoc中
@Constraint(validatedBy = {SexValidator.class}) // 注解由SexValidator类进行验证
public @interface SexAnnotation {
    // 性别类型,默认为空
    String[] sexType() default {};
    // 验证失败时的错误信息,默认为"性别有误,只能为boy or girl"
    String message() default "性别有误,只能为boy or girl";
    // 验证组,默认为空
    Class<?>[] groups() default {};
    // 负载,默认为空
    Class<? extends Payload>[] payload() default {};
}

 

注解在属性上:

    @SexAnnotation(sexType = {"boy","girl"})
    private String sex;

 

接下来进行属性验证的时候sex就只能使 boy 或者 girl 两个值中的任意一个,其它的值就会抛出 性别有误,只能为boy or girl的错误信息

配置全局异常拦截

这一项啊是用于优化用户体验的,如果在不配置全局异常拦截的情况下,默认注解校验错误会抛出整个异常出来,用户也看不懂,用户体验很差,故而我们可以使用全局异常拦截,将出错的信息拦截后,提取出错误提示信息在发送给前端,由valid注解抛出的异常为BindException,故需要对其进行拦截

Java代码:

import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
@Slf4j
public class GlobalException {
    // 处理所有异常
    @ExceptionHandler(Exception.class)
    public String exceptionHandler(Exception e){
        log.error("出现了异常"+e);
        return e.getMessage();
    }
    // 处理绑定异常
    @ExceptionHandler(BindException.class)
    public String bindExceptionHandler(BindException e){
        log.error("出现异常"+e);
        return e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
    }
}

 

return e.getBindingResult().getAllErrors().get(0).getDefaultMessage(); 这里是取出注解自定义的message的文本内容返回

@RestControllerAdvice 是一个非常有用的注解,它用于定义全局异常处理器。这个注解实际上是 @ControllerAdvice 和 @ResponseBody 的组合,专门用来处理被 @RestController 方法抛出的异常,并将它们转换为适当的 HTTP 响应。

主要用途
全局异常处理:通过使用 @ExceptionHandler 注解的方法来处理特定类型的异常或所有异常,可以在一个地方集中处理应用中的异常,而不是分散在各个控制器中。
统一响应格式:可以确保对客户端返回的错误信息具有统一的格式,提升API的专业性和用户体验。

@Slf4j 是 Lombok 提供的一个注解,用于简化日志记录的代码。

@ExceptionHandler 是 Spring 框架中的一个注解,主要用于定义异常处理方法。这些方法可以捕获控制器层抛出的特定异常或一组异常,并返回自定义的响应给客户端。

全局异常拦截测试

没有使用全局异常拦截:后端控制台输出校验失败的异常,但是前端会抛出一个400的异常,对于前端开发中或者用户都是无感的,根本不知道哪里错了

使用全局异常拦截:后端也抛出了异常,但是前端也得到了很好的提示,因为@RestControllerAdvice注解包含了@ResponseBody注解,可以向前端返回文本数据

 

 

-----END-----

 

posted @ 2025-03-20 18:06  回忆也交给时间  阅读(391)  评论(0)    收藏  举报