一:前言
- SpringValidation是对hibernate validation的二次封装,添加自动校验的功能,并将校验结果封装到特定的结果类中。
- hibernate validation是校验框架,是JSR303标准的实践结果。
- 引入hibernate validatior:导入spring-boot-starter-web依赖即可,已经包括所需jar包。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
二:Demo
2.1 简单Demo
常用的检验规则:
JSR提供的校验注解:
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max=, min=) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
Hibernate Validator提供的校验注解:
@NotBlank(message =) 验证字符串非null,且长度必须大于0
@Email 被注释的元素必须是电子邮箱地址
@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内
在实体类上添加校验规则:
@Data
@AllArgsConstructor
public class User {
@NotBlank(message = "用户姓名不能为空")
private String name;
@Min(value = 18,message = "18岁以下禁止入内")
private int age;
}
在controller上添加注解:@validated
@RestController
@RequestMapping("user")
@Slf4j
public class UserController {
@GetMapping("validate")
public void userValidates(@RequestBody @Validated() User user, BindingResult bindingResult){
if(bindingResult.hasErrors()){
bindingResult.getAllErrors().forEach(s->System.out.println(s.getDefaultMessage()));
//我们可以在这里抛出一个异常
log.info("用户登录信息出现异常");
}
}
}
校验错误的结果会封装到BindingResult 对象中,每一个校验的对象对应着一个结果对象。
2.2:分组校验
有时候我们对不同场景需要有不同的校验。
bean:
@Data
@AllArgsConstructor
public class User {
@NotBlank(message = "用户姓名不能为空")
@EndName
private String name;
@Min(value = 18,message = "18岁以下禁止入内",groups = {admin.class})
private int age;
//这里定义一个接口
public interface admin{}
}
这样就会出现两个分组default和admin。
controller:
@GetMapping("validate2")
public void userValidates2(@RequestBody @Validated(value = User.admin.class) User user, BindingResult bindingResult){
if(bindingResult.hasErrors()){
bindingResult.getAllErrors().forEach(s->System.out.println(s.getDefaultMessage()));
//我们可以在这里抛出一个异常
log.info("用户登录信息出现异常");
}
}
2.3 自定义校验
目标: 用户输入的名称必须包含我们所规定的文字。
我们通过这个注解校验@EndName(value = “哈哈”,message = “名字必须包含哈哈”)。
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
//实现类
@Constraint(validatedBy = {EndNameValidator.class})
public @interface EndName {
//返回一个值,也就是返回value属性的值
String value();
//默认错误消息
String message() default "xxxxx";
//分组
Class<?>[] groups() default {};
//负载
Class<? extends Payload>[] payload() default {};
//一个页面可以多个注解
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@interface List {
EndName[] value();
}
}
实现类:
public class EndNameValidator implements ConstraintValidator<EndName, String> {
String value;
@Override
public void initialize(EndName constraintAnnotation) {
//调用value方法来返回规定包含的字符串
this.value=constraintAnnotation.value();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context ) {
if(value.contains(this.value)){
return true;
}
return false;
}
}
如何需要试一试其他自定义注解的写法,去看看源码就ok了,我这个注解仿照的是@Min注解。
2.4 手动校验
Spring已经对validation全面支持,并封装了LocalValidatorFactoryBean作为validator的实现。So,我们直接拿来用就好了。
//这个是javax.validation.Validator包下的
@Autowired
private Validator globalValidator ;
@GetMapping("hello")
public void hello(){
//校验规则添加在user实体类上
User user = new User("张三", 24);
//校验结果都在这里面
Set<ConstraintViolation<User>> validate = validator.validate(user);
validate.forEach(s->System.out.println(s));
}
基于方法的校验:
@Validated
@RestController
@Slf4j
public class validateController {
@GetMapping("hello")
public void test(@Min(value = 18,message = "这个不行") @RequestParam("age") int number){
//这个验证不通过会报错
}
@ExceptionHandler(value = ConstraintViolationException.class)
public void test2(){
log.info("异常我就收下了");
}
}
在类上添加@Validated注解,在需要的属性上添加自己的校验规则,当校验不通过的时候,会抛出ConstraintViolationException,我们可以自定义一个异常捕获的方法,来进行捕获。