SpringBoot数据校验

发布于 2022年 05月 19日 17:40

前提:要先引入validation依赖

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

Validation 2.x 的22个注解

 

一、实体类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

 

推荐文章