Spring使用Validator接口进行验证

简介

在之前的文档中,在SpringMVC中,可很方便的使用@Validated加Hibernate Validator中提供的注解实现参数校验功能。Spring也提供了扩展的验证功能,比如自定义验证器。

考虑将验证作为业务逻辑是有利有弊,Spring提供了一种验证设计。验证不应与Web层绑定,应该易于本地化,并且应该可以插入任何可用的验证器。考虑到这些问题,Spring提供了一个Validator机制,该机制可以在应用程序的每一层中使用。

Spring自己的验证器支持javabean验证。应用程序可以全局启用Bean验证一次,并可以专门用于所有验证需求。

Spring提供了DataBinder来做数据绑定,对于使用户输入数据动态绑定到应用程序的域模型(或用于处理用户输入的任何对象)非常有用。

使用Spring的Validator接口进行验证

Spring中的Validator可用于验证对象。该接口结合Errors对象来工作,以便在验证时,验证器可以向该Errors对象报告验证失败。

  1. 创建Java Bean
@Data
public class Person {
    private String name;
    private int age;
}
  1. 编写验证器类,实现Validator接口
public class PersonValidator implements Validator {

    /**
     * 配置校验器支持的对象=》该验证器仅验证Person实例
     * 为True时进行校验,False反之
     *
     * @param aClass 校验对象的Class
     * @return 是否校验
     */
    @Override
    public boolean supports(Class<?> aClass) {
        return Person.class.equals(aClass);
    }

    /**
     * 校验逻辑
     *
     * @param obj    校验对象
     * @param errors 错误对象
     */
    @Override
    public void validate(Object obj, Errors errors) {
        // 校验name是否为空
        // 在static rejectIfEmpty(..)对方法ValidationUtils类用于拒绝该name属性,如果它是null或空字符串
        ValidationUtils.rejectIfEmpty(errors, "name", "name不能为空");
        // 校验年龄只能在0-110之间
        Person p = (Person) obj;
        if (p.getAge() < 1) {
            errors.rejectValue("age", "年龄不能小于1");
        } else if (p.getAge() > 110) {
            errors.rejectValue("age", "年龄不能大于110");
        }
    }
}
  1. 直接使用校验器校验对象,当然一般不这么用,比较繁琐。
public class Test001 {
    public static void main(String[] args) {
        // 创建一个校验器
        PersonValidator personValidator = new PersonValidator();
        // 创建对象
        Person person = new Person();
        person.setAge(1000);
        Map<String, Object> map = new HashMap<>();
        // 创建结果对象
        MapBindingResult result = new MapBindingResult(map, "person");
        // 进行校验并将错误信息封装到result
        personValidator.validate(person, result);
        // 打印错误信息
        List<FieldError> fieldErrors = result.getFieldErrors();
        fieldErrors.forEach(e -> {
            System.out.println(e.getField() + e.getCode());
        });
    }
}

结合Spring MVC进行校验

全局校验器
  1. MVC添加全局校验器
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    /**
     * 添加全局校验器
     */
    @Override
    public Validator getValidator() {
        return new PersonValidator();
    }
}
  1. 在controller接口中使用@Validated 开启校验
@GetMapping("/person")
    public Object person(@Validated Person person) {
        return person;
    }
  1. 访问http://localhost:8000/test/person,校验生效
Controller类添加校验器

@InitBinder用于在@Controller中标注于方法,表示为当前控制器注册一个属性编辑器或者其他,只对当前的Controller有效。案例中表示为当前Controller注册一个数据校验器。

@InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.addValidators(new PersonValidator());
    }

    @GetMapping("/person")
    public Object person(@Validated Person person) {
        return person;
    }

也可以在方法中添加BindingResult ,校验器会把校验结果放入当前对象,用户可以根据错误信息实现自己的处理逻辑。

@GetMapping("/person")
    public Object person(@Validated Person person, BindingResult result) {
        // 参数校验
        if (result.hasErrors()) {
            List<FieldError> fieldErrors = result.getFieldErrors();
            fieldErrors.forEach(e -> {
                System.out.println(e.getField() + e.getCode());
            });
            throw new IllegalArgumentException("参数输入错误");
        }
        return person;
    }
}