Spring使用Validator接口进行验证
简介
在之前的文档中,在SpringMVC中,可很方便的使用@Validated加Hibernate Validator中提供的注解实现参数校验功能。Spring也提供了扩展的验证功能,比如自定义验证器。
考虑将验证作为业务逻辑是有利有弊,Spring提供了一种验证设计。验证不应与Web层绑定,应该易于本地化,并且应该可以插入任何可用的验证器。考虑到这些问题,Spring提供了一个Validator机制,该机制可以在应用程序的每一层中使用。
Spring自己的验证器支持javabean验证。应用程序可以全局启用Bean验证一次,并可以专门用于所有验证需求。
Spring提供了DataBinder来做数据绑定,对于使用户输入数据动态绑定到应用程序的域模型(或用于处理用户输入的任何对象)非常有用。
使用Spring的Validator接口进行验证
Spring中的Validator可用于验证对象。该接口结合Errors对象来工作,以便在验证时,验证器可以向该Errors对象报告验证失败。
- 创建Java Bean
@Data
public class Person {
private String name;
private int age;
}
- 编写验证器类,实现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");
}
}
}
- 直接使用校验器校验对象,当然一般不这么用,比较繁琐。
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进行校验
全局校验器
- MVC添加全局校验器
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
/**
* 添加全局校验器
*/
@Override
public Validator getValidator() {
return new PersonValidator();
}
}
- 在controller接口中使用@Validated 开启校验
@GetMapping("/person")
public Object person(@Validated Person person) {
return person;
}
- 访问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;
}
}