Java SpringBoot上的参数校验JSR 303 Validation

JSR 303 – Bean Validation 是一个数据验证的规范,2009 年 11 月确定最终方案。
Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint
我们通常写接口时会对传来的参数进行校验判断,比如字符串非空判断,值在多少返回等,这些就要用到Spring 的参数校验,这里我们使用在spring-boot-starter-web包里面有hibernate-validator包,
参数校验有几种方式,如下

  • 使用@Valid+BindingResult
  • 注解使用@Valid +全局异常捕捉处理

    使用@Valid+BindingResult 参数验证

    1.符合国际JSP 303规范,先定义个Bean,别人在字段名上添加验证的注解,@NotBlank 字段名不能为null,同时长度大于0常有的校验类型有
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Constraint    详细信息

    @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(value) 被注释的元素必须符合指定的正则表达式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class User {

//账号
@NotBlank(message = "账号不能为空")
private String phone;
//密码
@NotBlank(message = "密码不能为空")
private String password;

public void setPhone(String phone) {
this.phone = phone;
}

public void setPassword(String password) {
this.password = password;
}

public String getPhone() {
return phone;
}

public String getPassword() {
return password;
}
}

2.在Controller类里面对相应的接口添加@Valid+BindingResult验证,加完以后,如果参数验证不通过,那就直接进入if语句里面,在语句里面做相应的返回结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@RestController
@RequestMapping(value = "/user")
public class UserController implements IUser {


@Override
@RequestMapping(value = "/login", method = RequestMethod.POST)
public User login( @Valid User userInfo, BindingResult bindingResult) {

if (bindingResult.hasErrors()) {
System.out.print(bindingResult.getFieldError().getDefaultMessage());
return null;
}
return userInfo;
}

}

好了,第一种验证我们已经说完了,但你仔细想想,如果我有多个接口,是不是每次有要写@Valid+BindgResult bingingResult,然后再到If语句里面进行判断,如果仅仅是错误信息不一致,但返回的客户端结构是一致的,比如

1
2

{"code":"1002","message":"parameters are missing","data":"{}"}

不同的验证只要改变message,那么是不是可以统一处理,来减少代码量,于是下面介绍第二种方式

使用@Valid+全局异常捕捉 参数校验

简单点说,由第一种方式去掉BindingResult,然后再定义一个全局异常类,同样的
1.还是定义POJO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class User {

//账号
@NotBlank(message = "账号不能为空")
private String phone;
//密码
@NotBlank(message = "密码不能为空")
private String password;

public void setPhone(String phone) {
this.phone = phone;
}

public void setPassword(String password) {
this.password = password;
}

public String getPhone() {
return phone;
}

public String getPassword() {
return password;
}
}

2.在Controller里面的方法定义要验证的@Valid

1
2
3
4
5
6
7
8
9
public class UserController implements IUser {

@Override
@RequestMapping(value = "/login2", method = RequestMethod.POST)
public User login2(@RequestBody @Valid User userInfo) {
return null;
}

}

3.定义全局异常类
所有验证失败的结果都会在GlobleExceptionHandler的defultExcepitonHandler方法里面捕捉到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@RestControllerAdvice
@Component
public class GlobleExceptionHandler {



@ResponseBody
@ExceptionHandler(Exception.class)
public String defultExcepitonHandler(Exception ex) {

ex.printStackTrace();
if(ex instanceof BindException){
//处理返回的错误信息
StringBuffer errorMsg = new StringBuffer();
BindException c = (BindException) ex;
List<ObjectError> errors = c.getBindingResult().getAllErrors();
for (ObjectError error : errors) {
errorMsg.append(error.getDefaultMessage()).append(";");
}

return errorMsg.toString();

}
return "";

}

}

作者:飞一样的猪
链接:https://juejin.im/post/5b2f4514f265da597a6108f8
来源:掘金

-------------本文结束感谢您的阅读-------------