Validation in Spring Boot

添加依赖

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

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

测试

PersonForm.java

@Data
public class PersonForm {

    @NotNull
    @Size(min=2, max=30)
    private String name;

    @NotNull
    @Min(18)
    private Integer age;
}

IndexController.java

@PostMapping("/check")
public String checkPersonInfo(@Valid PersonForm personForm, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        FieldError fieldError = (FieldError) bindingResult.getAllErrors().get(0);
        System.out.println(fieldError.getField() + "-" + fieldError.getRejectedValue() + "-" +fieldError.getCode() + "-" + fieldError.getDefaultMessage());
        // output: age-11-Min-最小不能小于18
        return "form";
    }

    return "redirect:/results";
}

通过参数 @Valid 表示需要对PersonForm实例进行验证。第二个参数BindingResult 查看是否验证有错误。这个参数必须紧跟@Valid的Bean后面。如果没有指定参数 BindingResult,那么将会抛出异常 MethodArgumentNotValidException

编程式验证

  • 在spring环境下直接注入
private final Validator validator;
  • 验证
@GetMapping("/form")
public String form(PersonForm personForm) throws BindException {
    validate(personForm);
    return "form";
}

private <T> void validate(T t) throws BindException {
    Map<String, Object> map = new HashMap<>(16);
    BindingResult errors =  new MapBindingResult(map, t.getClass().getName());
    validator.validate(t, errors);
    if (errors.hasErrors()) {
        throw new BindException(errors);
    }
}

自定义验证规则

  • 添加验证器 PhoneValidator 验证手机号码
public class PhoneValidator implements ConstraintValidator<PhoneValid, String> {

    private static final String MOBILE_REGEX = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(17[013678])|(18[0,5-9]))\\d{8}$";

    private static final int MOBILE_LENGTH = 11;

    @Override
    public boolean isValid(String phone, ConstraintValidatorContext context) {
        if (Objects.isNull(phone)) {
            return true;
        }

        if (phone.length() != MOBILE_LENGTH) {
            return false;
        } else {
            Pattern p = Pattern.compile(MOBILE_REGEX);
            Matcher m = p.matcher(phone);
            if (m.matches()) {
                return true;
            }
        }
        return false;
    }
}
  • 添加注解 PhoneValid
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(
    validatedBy = {PhoneValidator.class}
)
public @interface PhoneValid {
    String message() default "手机号码格式不正确";

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

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

PersonForm 添加属性手机号:

@PhoneValid
private String phone;

验证:

@GetMapping("/form")
public String form(PersonForm personForm) throws BindException {
    personForm.setName("Rick.Xu");
    personForm.setAge(19);
    personForm.setPhone("1232");
    validate(personForm);
    return "form";
}

控制台打印

.validation.BindException: org.springframework.validation.MapBindingResult: 1 errors
Field error in object 'com.rick.security.api.PersonForm' on field 'phone': rejected value [1232]; codes [PhoneValid.com.rick.security.api.PersonForm.phone,PhoneValid.phone,PhoneValid]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [com.rick.security.api.PersonForm.phone,phone]; arguments []; default message [phone]]; default message [手机号码格式不正确]]

参考文章