一、参数校验(类属性)
在开发中经常需要写一些字段校验的代码,比如字段非空,字段长度限制,邮箱格式验证等等。 会导致如下情况:
- 验证代码繁琐
- 方法内代码显得冗长
- 修改相同逻辑验证代码时需要修改涉及到同样逻辑的所有地方
hibernate validator(官方文档)提供了一套比较完善、便捷的验证实现方式。
spring-boot-starter-web 包里面有hibernate-validator包,不需要再引入依赖。
使用@Valid对参数进行校验在使用对象进行参数接收时,我们可以对参数进行校验录入我们可以对属性username和password加上如下注解:
public class User{
@NotNull(message = "用户名不能为空")
private String username; // 用户名
@Max(value = 999999,message = "超过最大数值")
@Min(value = 000000,message = "密码设定不正确")
@NotNull(message = "密码不能为空")
private String password; // 密码
}
然后我们给Controller层的方法中接收的对象前加入@Valid注解,并在参数中加入BindingResult来获取错误信息。
在逻辑处理中我们判断BindingResult知否含有错误信息,如果有错误信息,则直接返回错误信息。
// 添加用户
@PostMapping("/createuser") // 多个 @Valid 则对应多个 BindingReslt
public String createUser(@Valid User user, BindingResult bindingResult){
if (bindingResult.hasErrors()){
return bindingResult.getFieldError().getDefaultMessage();
}else{
userService.createUser(userInfo.getTel(),userInfo.getPassWord(); return "OK";
}
}
Hibernate validator的校验只能对Object的属性进行校验,不能对单个的参数进行校验,spring 在此基础上进行了扩展,添加了++MethodValidationPostProcessor拦截器++后可以实现对方法参数的校验。
二、参数校验(方法参数)
1 实例化MethodValidationPostProcessor拦截器
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
2 在所要实现方法参数校验的类上面添加@Validated,如下
@Validated // 加入注释
@RestController
@RestMapping("/validate")
public class ValidateController {
3 在方法上面添加校验规则
@GetMapping("/paramcheck")
public String paramCheck(@Length(min = 10) @RequestParam String name) {
System.out.println(name);
return null;
}
4 当方法上面的参数校验失败,spring 框架就回抛出异常
{
"timestamp": 1476108200558,
"status": 500,
"error": "Internal Server Error",
"exception": "javax.validation.ConstraintViolationException",
"message": "No message available",
"path": "/paramcheck"
}
三、hibernate的校验模式
通常的校验会验证所有属性并返回一个错误消息集合,而快速失败模式通常按顺序验证到第一个字段不符合验证要求时,就可以直接拒绝请求了。
Hibernate Validator有以下两种验证模式:
普通模式(默认)
会校验完所有的属性,然后返回所有的验证失败信息
快速失败返回模式
只要有一个验证失败,则返回此条验证失败信息
两种验证模式配置方式:
@Configuration
public class ValidatorConfiguration {
@Bean
public Validator validator(){
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure() // true-快速失败返回模式 false-普通模式
.addProperty( "hibernate.validator.fail_fast", "true" )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
return validator;
}
}
四、分组校验
有这样一种场景,新增用户信息的时候,不需要验证userId(因为系统生成);
修改的时候则需要验证userId,这时候可用分组验证功能。
public interface GroupA {
}
public interface GroupB {
}
public class Person {
@NotBlank
@Range(min = 1,max = Integer.MAX_VALUE,message = "必须大于0",groups = {GroupA.class})
private Integer userId;// 用户id
@NotBlank
@Length(min = 4,max = 20,message = "必须在[4,20]",groups = {GroupB.class})
private String userName;// 用户名
@NotBlank
@Range(min = 0,max = 100,message = "年龄必须在[0,100]",groups={Default.class})
private Integer age;// 年龄
@NotNull(message = "地址不能为空",groups = {GroupB.class})
private String address;// 地址
}
如上Person所示,3个分组分别验证字段如下:
GroupA验证字段userId;
GroupB验证字段userName,address;
Default验证字段age(默认分组)
A情景
只验证GroupA或GroupB标记的分组:
(可叠加 GroupA,GroupB)
// 添加用户
@PostMapping("/createuser2") // 多个@Valid对应则多个BindingReslt
public String createuser2(@Validated(GroupA.class) User user, BindingResult bindingResult){
if (bindingResult.hasErrors()){
return bindingResult.getFieldError().getDefaultMessage();
}else{
userService.createUser(userInfo.getTel(),userInfo.getPassWord());
return "OK";
}
}
B情景
指定验证组的顺序:
除了按组指定是否验证之外,还可以指定组的验证顺序,前面组验证不通过的,后面组不进行验证:
(GroupA>GroupB>Default)
@GroupSequence({GroupA.class, GroupB.class, Default.class})
public interface GroupOrder {
}
五、常见的注解
JSR303中内置的注解
注解名 作用
@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对JSR303的扩展注解
注解名 作用
@NotBlank(message =) 字符串非null,且长度必须大于0
@Email 元素必须是电子邮箱地址
@Length(min=,max=) 字符串的大小必须在指定的范围内
@NotEmpty 字符串非空
@Range(min=,max=,message=) 元素必须在合适的范围内