Spring Boot 中使用 Valid 验证框架

1. 加入依赖

在pom.xml中加入以下内容

1
2
3
4
5
<!-- 参数校验框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

注意:校验框架和javaee-api会存在冲突,如果已经引入需删除

1
2
3
4
5
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>

2. 定义全局异常处理类

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;

/**
* 全局异常参数处理类
*/
@Configuration
@Slf4j
@RestControllerAdvice("com.hzjp.dev.controller") //指定异常处理的包名
public class GlobalExceptionHandler {

/**
* 忽略参数异常处理器
*
* @param e 忽略参数异常
* @return ResponseResult
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MissingServletRequestParameterException.class)
public ResponseResult parameterMissingExceptionHandler(MissingServletRequestParameterException e) {
log.error("", e);
return new ResponseResult(ResultEnum.PARAMETER_ERROR.getCode(), "请求参数 " + e.getParameterName() + " 不能为空");
}

/**
* 缺少请求体异常处理器
*
* @param e 缺少请求体异常
* @return ResponseResult
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseResult parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) {
log.error("", e);
return new ResponseResult(ResultEnum.PARAMETER_ERROR.getCode(), "参数体不能为空");
}

/**
* 参数效验异常处理器
*
* @param e 参数验证异常
* @return ResponseInfo
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseResult parameterExceptionHandler(MethodArgumentNotValidException e) {
log.error("", e);
// 获取异常信息
BindingResult exceptions = e.getBindingResult();
// 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
if (exceptions.hasErrors()) {
List<ObjectError> errors = exceptions.getAllErrors();
if (!errors.isEmpty()) {
// 这里列出了全部错误参数,按正常逻辑,只需要第一条错误即可
FieldError fieldError = (FieldError) errors.get(0);
return new ResponseResult(ResultEnum.PARAMETER_ERROR.getCode(), fieldError.getDefaultMessage());
}
}
return new ResponseResult(ResultEnum.PARAMETER_ERROR);
}

/**
* 自定义参数错误异常处理器
*
* @param e 自定义参数
* @return ResponseInfo
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({RuntimeException.class})
public ResponseResult paramExceptionHandler(RuntimeException e) {
log.error("", e);
// 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
if (!StringUtils.isEmpty(e.getMessage())) {
return new ResponseResult(ResultEnum.PARAMETER_ERROR.getCode(), e.getMessage());
}
return new ResponseResult(ResultEnum.PARAMETER_ERROR);
}
}

返回状态枚举类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public enum ResultEnum {

SUCCESS(1, "请求成功"),
PARAMETER_ERROR(0, "请求参数有误!"),
UNKNOWN_ERROR(500, "未知的错误!");

private Integer code;
private String message;

ResultEnum(Integer code, String message) {
this.code = code;
this.message = message;
}

public Integer getCode() {
return code;
}

public String getMessage() {
return message;
}
}

3.实体类中加入注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import lombok.Data;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Data
public class Param {

private Integer id;
@NotNull(message = "modelId不能为空")
private Integer Model_id;
@NotBlank(message = "间隔不能为空")
@NotNull(message = "间隔不能为空")
private String Jiange;
@NotBlank(message = "连续次数不能为空")
@NotNull(message = "连续次数不能为空")
private String Lianxu;
}

message中可填入报错时显示的信息。

以下是验证框架中的常用注解(参考连接):

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@Null
限制只能为null

@NotNull
限制必须不为null

@AssertFalse
限制必须为false

@AssertTrue
限制必须为true

@DecimalMax(value)
限制必须为一个不大于指定值的数字

@DecimalMin(value)
限制必须为一个不小于指定值的数字

@Digits(integer,fraction)
限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction

@Future
限制必须是一个将来的日期

@Max(value)
限制必须为一个不大于指定值的数字

@Min(value)
限制必须为一个不小于指定值的数字

@Past
限制必须是一个过去的日期

@Pattern(value)
限制必须符合指定的正则表达式

@Size(max,min)
限制字符长度必须在min到max之间

@Past
验证注解的元素值(日期类型)比当前时间早

@NotEmpty
验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)

@NotBlank
验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格

@Email
验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

注意:不要错用了异常类型,如Integer上不可用@NotBlank,int上不可用@size

4. 在第一层开启验证

在接口中加入@Valid注解,开启验证(以下为伪代码,仅添加了必要代码):

1
2
3
4
5
6
7
8
9
10
11
import javax.validation.Valid;

@PostMapping("/addHealthIndex")
public String addHealthIndex(@ModelAttribute @Valid ZysHealthIndex healthindex){
try {
//业务处理
}catch (Exception e){
e.printStackTrace();
}
return "";
}

目前仅测试了post请求中使用验证,get请求使用方式有一定差异,由于目前尚未用到,所以未测试,如需使用可自行搜索Spring框架之@Valid注解的使用