SpringBoot数据校验

前提:要先引入validation依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Validation 2.x 的22个注解

注解验证的数据类型说明
Null 所有类型 验证元素值必须为 null
NotNull 所有类型 验证元素值必须不为 null
NotBlank CharSequence 验证元素值不能为 null,并且至少包含一个非空白字符。
NotEmpty CharSequence、Collection、Map、Array 验证元素值不能为 null,且不能为空
Size(min = min, max = max) 同 NotEmpty 验证元素的 size 必须在 min 和 max 之间(包含边界),认为 null 是有效的
AssertFalse boolean、Boolean 验证元素值必须为 false,认为 null 是有效的
AssertTrue 同 AssertFalse 验证元素值必须为 true,认为 null 是有效的
DecimalMax(value=, inclusive=) BigDecimal、BigInteger、CharSequence,byte、 short、int、long 及其包装类型,由于舍入错误,不支持double和float 验证元素值必须小于等于指定的 value 值,认为 null 是有效的
DecimalMin 同 DecimalMax 验证元素值必须大于等于指定的 value 值,认为 null 是有效的
Max 同 DecimalMax,不支持CharSequence 验证元素值必须小于等于指定的 value 值,认为 null 是有效的
Min 同 DecimalMax,不支持CharSequence 验证元素值必须大于等于指定的 value 值,认为 null 是有效的
Digits(integer =, fraction =) 同 DecimalMax 验证元素整数位数的上限 integer 与小数位数的上限 fraction,认为 null 是有效的
Positive BigDecimal、BigInteger,byte、short、int、long、float、double 及其包装类型 验证元素必须为正数,认为 null 是有效的
PositiveOrZero 同Positive 验证元素必须为正数或 0,认为 null 是有效的
Negative 同Positive 验证元素必须为负数,认为 null 是有效的
NegativeOrZero 同Positive 验证元素必须为负数或 0,认为 null 是有效的
Future Date、Calendar、Instant、LocalDate、LocalDateTime、LocalTime、MonthDay、OffsetDateTime、OffsetTime、Year、YearMonth、ZonedDateTime、HijrahDate、JapaneseDate、MinguoDate、ThaiBuddhistDate 验证元素值必须是一个将来的时间,认为 null 是有效的
FutureOrPresent 同 Future 验证元素值必须是当前时间或一个将来的时间,认为 null 是有效的
Past 同 Future 验证元素值必须是一个过去的时间,认为 null 是有效的
PastOrPresent 同 Future 验证元素值必须是当前时间或一个过去的时间,认为 null 是有效的
Email(regexp = 正则表达式,flag = 标志的模式) CharSequence 验证注解的元素值是Email,可以通过 regexp 和 flag 指定自定义的 email 格式,认为 null 是有效的
Pattern 同 Email 验证元素值符合正则表达式,认为 null 是有效的

 

一、实体类DTO校验

1、第一种Controller内部捕捉校验信息

①第一步定义dto,所有校验都在dto的属性上进行。

public class ValidatorDto {

    @NotEmpty(message = "名字不能为空!")
    public String name;
    @Email(message = "email格式不正确!")
    public String email;
    @Min(value = 10)
    public int age;
    @NotEmpty(message = "家庭住址至少填写一个")
    List<String> homList;
    public List<String> getHomList() {
        return homList;
    }
    public void setHomList(List<String> homList) {
        this.homList = homList;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

②第二步定义Controller,验证的参数dto属性要加@Validated,BindingResult参数中包含捕捉校验信息,程序执行过程会进入该方法体内。

@RestController
public class TestValidatorController {
    @RequestMapping("/testValidator")
    @ResponseBody
    public ValidatorDto testValidator(@Validated ValidatorDto dto, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            List<ObjectError> listObjectError = bindingResult.getAllErrors();
            for (ObjectError objectError : listObjectError) {
                System.out.println(objectError.getDefaultMessage());
            }
        }
        return dto;
    }
}

③访问参数及System.out.println输出的校验结果:

http://localhost:8080/testValidator?name=&email=@qq.com&age=5

最小不能小于10
家庭住址至少填写一个
名字不能为空!
email格式不正确!

 

2、第二种校验信息在抛出的异常中获取

①第一步定义dto,所有校验都在dto的属性上进行。

public class ValidatorDto {
    @NotEmpty(message = "名字不能为空!")
    public String name;
    @Email(message = "email格式不正确!")
    public String email;
    @Min(value = 10)
    public int age;
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

②第二步定义Controller,验证的参数dto属性要加@Validated,程序不会进入该方法体内,校验信息会在抛出的异常中被捕获(我使用的是全局异常@ControllerAdvice+@ExceptionHandler捕获异常信息)。

@RestController
public class TestValidatorController {
    @RequestMapping("/testValidator2")
    @ResponseBody
    public ValidatorDto testValidator(@Validated ValidatorDto dto) {
        return dto;
    }
}

③访问参数及校验结果:

http://localhost:8080/testValidator2?name=&email=@qq.com&age=5

 

3、分组校验

在不同情况下,可能对JavaBean对象的数据校验规则有所不同,有时需要根据数据状态对JavaBean中的某些属性字段进行单独验证,groups 属性将验证进行分组。

①第一步定义dto,所有校验都在dto的属性上进行。

分组一校验:name和age

分组二校验:email和age

public class ValidatorDto2 {
    @NotEmpty(message = "名字不能为空!", groups = ValidatorGroup1.class)
    public String name;
    @Email(message = "email格式不正确!", groups = ValidatorGroup2.class)
    public String email;
    @Min(value = 10, groups = { ValidatorGroup1.class, ValidatorGroup2.class })
    public int age;
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

②第二步定义分组(2个空接口类),这两空接口类,就是上面dto中的groups 分组。

public interface ValidatorGroup1 {}
public interface ValidatorGroup2 {}

③第三步定义Controller,验证的参数dto属性要加@Validated,分组的class要放到Validated中,BindingResult参数中包含捕捉校验信息,程序执行过程会进入该方法体内。

RestController
public class TestValidatorController {

    @RequestMapping("/testValidatorGroup1")
    @ResponseBody
    public ValidatorDto2 testValidatorGroup1(@Validated(ValidatorGroup1.class) ValidatorDto2 dto,
            BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            List<ObjectError> listObjectError = bindingResult.getAllErrors();
            for (ObjectError objectError : listObjectError) {
                System.out.println(objectError.getDefaultMessage());
            }
        }
        return dto;
    }

    @RequestMapping("/testValidatorGroup2")
    @ResponseBody
    public ValidatorDto2 testValidatorGroup2(@Validated(ValidatorGroup2.class) ValidatorDto2 dto,
            BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            List<ObjectError> listObjectError = bindingResult.getAllErrors();
            for (ObjectError objectError : listObjectError) {
                System.out.println(objectError.getDefaultMessage());
            }
        }
        return dto;
    }

}

④访问参数及校验结果:

分组一:

http://localhost:8080/testValidatorGroup1?name=&email=@qq.com&age=5

名字不能为空!
最小不能小于10

分组二:

http://localhost:8080/testValidatorGroup2?name=&email=@qq.com&age=5

email格式不正确!
最小不能小于10

结果说明:name校验只属于分组一,email校验只属于分组二,age校验属于分组一和分组二,跟定义的dto定义一致。

 

二、直接参数校验

直接参数校验就是把dto中要校验的属性当做参数放到controller的参数内,所有的校验也都放到controller中参数中,其余处理和实体类DTO校验无差异。 

 

三、自定义校验注解

预期:做一个判断非0的注解

①定义一个注解(仿照已有的现成注解做),其中@Constraint(validatedBy = NotEqualZeroValidator.class)的NotEqualZeroValidator为自己定义的校验类

@Documented
@Constraint(validatedBy = NotEqualZeroValidator.class)
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
public @interface NotEqualZero 
    String message() default "必须不等于0";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
}

②定义自己的校验类,需要实现ConstraintValidator<NotEqualZero, Object>接口

public class NotEqualZeroValidator implements ConstraintValidator<NotEqualZero, Object>{
    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        return (Integer)value != 0;
    }
}

③使用自定义注解@NotEqualZero

public class ValidatorDto {

    @NotEmpty(message = "名字不能为空!")
    public String name;
    @Email(message = "email格式不正确!")
    public String email;
    @NotEqualZero
    public int age;
    @NotEmpty(message = "家庭住址至少填写一个")
    List<String> homeList;
    public List<String> getHomeList() {
        return homeList;
    }
    public void setHomeList(List<String> homeList) {
        this.homeList = homeList;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

④controller

@RestController
public class TestValidatorController {

    @RequestMapping("/testValidator")
    @ResponseBody
    public ValidatorDto testValidator(@Validated ValidatorDto dto, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            List<ObjectError> listObjectError = bindingResult.getAllErrors();
            for (ObjectError objectError : listObjectError) {
                System.out.println(objectError.getDefaultMessage());
            }
        }
        return dto;
    }
}

⑤结果

http://localhost:8080/testValidator?name=&email=@qq.com&age=0

名字不能为空!
email格式不正确!
家庭住址至少填写一个
必须不等于0

 

posted @ 2022-05-19 13:29  #庄生晓梦  阅读(686)  评论(0编辑  收藏  举报