Validation的使用

轩辕鸿祯
2023-12-01

springboot中使用Validation
(一)常用注解

//开启验证,标注在待验证的Object对象上
@Valid

//标注在待验证的字段上
@NotNull
@Null
@Size
@Min
@Max

(二)具体使用
1、添加依赖

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

2、创建待验证的Object,并添加验证注解

public class Person {
    /**
     * @PersonName(prefix = "潘"):自定义注解
     */
    @NotNull
    @PersonName(prefix = "潘")
    private String name;
    @Min(value = 12)
    @Max(value = 30, message = "超过30岁的不要!")
    private Integer age;
}

3、创建自定义校验注解类@PersonName
  备注:
  重点一:所有的自定义注解类都可以参照下面的类创建。
  重点二:必须注意@Constraint注解,绑定具体的校验实现类

/**
 * 自定义校验注解
 * @author 咸鱼
 * @date 2018/10/14 17:57
 * 重点:使用@Constraint(validatedBy = {PersonNameConstraintValidator.class})绑定具体的校验实现类
 */
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(PersonName.List.class)
@Documented
@Constraint(validatedBy = {PersonNameConstraintValidator.class})
public @interface PersonName {
    String message() default "";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };

    /**
     * 定义名字必须以**前缀开始
     */
    String prefix() default "";

    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    @Documented
    @interface List {

        PersonName[] value();
    }
}

4、创建自定义校验注解的具体实现类

/**
 * ConstraintValidator<PersonName, String>:
 * 泛型一:校验的注解类
 * 泛型二:被校验的对象类型
 */
public class PersonNameConstraintValidator implements ConstraintValidator<PersonName, String> {
    private String prefix;

    /**
     * @param constraintAnnotation 待校验注解的所有信息
     */
    @Override
    public void initialize(PersonName constraintAnnotation) {
        //取出注解中的数据
        this.prefix = constraintAnnotation.prefix();
    }

    /**
     * 在这里面定义校验规则
     * @param value 待校验对象
     * @param context
     * @return true 通过校验 false 无法通过校验
     */
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        //校验规则为:名字必须以#{prefix}开头
        if (!value.startsWith(prefix)){
            /**
             * 自定义校验错误信息
             */
            context.disableDefaultConstraintViolation();
            ConstraintValidatorContext.ConstraintViolationBuilder builder =
                    context.buildConstraintViolationWithTemplate("人的名字必须以\"" + prefix + "\"起始");
            builder.addConstraintViolation();
            return false;
        }
        return true;
    }
}

5、使用案例

/**
 * 开启校验注解:@Valid
 */
@RestController
public class PersonController {
    @PostMapping("/person")
    public Person savePerson(@Valid @RequestBody Person person){
        return person;
    }
}

(三)校验拓展,统一异常处理
  问题:以上的案例,当无法通过校验时,会返回400错误,但是我们一般都会做全局异常处理,返回400错误,将导致我们没法统一处理这个异常?

解决办法:
  当无法通过校验时,校验结果会存到BindingResult对象中,我们可以通过该对象截取校验信息,然后将该异常抛出去,进行统一异常处理。

/**
     * 增
     * “@Valid”开启校验
     * BindingResult:存放校验结果
     */
    @PostMapping("/girls")
    public Girl addGirl(@Valid Girl girl, BindingResult bindingResult){
        //若不符合约束
        if (bindingResult.hasErrors()){
            //获取不符合约束时,自定义的异常信息
            throw new **Exception(bindingResult.getFieldError().getDefaultMessage());
        }
        return girlService.addGirl(girl);
    }
 类似资料: