spring validation

-


依赖

spring boot

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

spring mvc

1
2
3
4
5
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
</dependency>

JSR303/JSR-349 hibernate validation spring validation 注解

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 validation 注解

@NotBlank(message =) 验证字符串非 null,且长度必须大于 0
@Email 被注释的元素必须是电子邮箱地址
@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内

test

分组校验

  • 默认会采用 Default 分组。如果想要不标记分组的时候,也会去验证 Default 分组,可以去继承默认分组
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
public interface AddGroup  extends Default {
}
// ----
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserRequest {

@Null(groups = AddGroup.class)
@NotBlank(groups = UpdateGroup.class)
String id;

@NotBlank(message = "用户名不能为空")
String username;

@NotBlank(message = "密码不能为空")
String password;

@Email
@NotNull
String email;

String phone;

}


// ----
@PostMapping
public RestResponse<UserRequest> createUser(@RequestBody @Validated({ AddGroup.class }) UserRequest user) {

return RestResponse.ok(user);
}

@PutMapping("/{userId}")
public RestResponse<UserRequest> updateUser(@RequestBody @Validated({ UpdateGroup.class }) UserRequest user) {

return RestResponse.ok(user);
}

自定义注解

  • 自定义校验注解
  • 编写真正的校验者类
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
@Documented
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Constraint(validatedBy = { MobileValidator.class })
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Mobile.List.class)
public @interface Mobile {

/**
* 错误提示信息,可以写死,也可以填写国际化的key
*/
String message() default "手机号码不正确";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

String regexp() default "^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}$";

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List {
Mobile[] value();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MobileValidator implements ConstraintValidator<Mobile, String> {

/**
* 手机验证规则
*/
private Pattern pattern;

@Override
public void initialize(Mobile mobile) {
pattern = Pattern.compile(mobile.regexp());
}

@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}

return pattern.matcher(value).matches();
}
}

接口参数验证

  • 表单绑定到 java bean
  • 将请求体解析并绑定到 java bean
  • 普通参数(非 java bean)校验

A Spring beans's method parameters will not be validated if you don't annotated the bean with @Validated.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@GetMapping("/hello1")
public RestResponse<UserRequest> hello(@Validated UserRequest user) {

return RestResponse.ok(user);
}

public void test() {
System.out.println("test");
}

@PostMapping("/hello2")
public RestResponse<UserRequest> hello2(@RequestBody @Validated({ UpdateGroup.class }) UserRequest user) {

return RestResponse.ok(user);
}

@GetMapping("/hello3")
public String hello3(@NotBlank String username, @NotBlank String password) {

return username;
}

验证异常处理

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
/**
* 表单绑定到 java bean 出错时抛出 BindException 异常
*
* @param e
* @return
*/
@ExceptionHandler({ BindException.class })
@ResponseStatus(HttpStatus.OK)
protected Object handleBindException(BindException e) {
// log.error("参数绑定失败", e);
List<Map<String, String>> errors = new ArrayList<>();
for (ObjectError objectError : e.getAllErrors()) {
Map<String, String> map = new HashMap<>();
if (objectError instanceof FieldError) {
FieldError fieldError = (FieldError) objectError;
map.put("field", fieldError.getField());
map.put("message", fieldError.getDefaultMessage());
} else {
map.put("field", objectError.getObjectName());
map.put("message", objectError.getDefaultMessage());
}
errors.add(map);
}

return RestResponse.validationException(errors);
}

/**
* 将请求体解析并绑定到 java bean 时,如果出错,则抛出 MethodArgumentNotValidException 异常
*
* @param ex
* @param headers
* @param status
* @param request
* @return
*/
@ExceptionHandler({ MethodArgumentNotValidException.class })
@ResponseStatus(HttpStatus.OK)
protected Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
List<Map<String, String>> errors = new ArrayList<>();
for (ObjectError objectError : e.getBindingResult().getAllErrors()) {
Map<String, String> map = new HashMap<>();
if (objectError instanceof FieldError) {
FieldError fieldError = (FieldError) objectError;
map.put("field", fieldError.getField());
map.put("message", fieldError.getDefaultMessage());
} else {
map.put("field", objectError.getObjectName());
map.put("message", objectError.getDefaultMessage());
}
errors.add(map);
}

return RestResponse.validationException(errors);
}

/**
* 普通参数(非 java bean)校验出错时抛出 ConstraintViolationException 异常
*
* @param e
* @return
*/
@ExceptionHandler({ ConstraintViolationException.class })
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public Object handleConstraintViolationException(ConstraintViolationException e) {

List<Map<String, String>> errors = new ArrayList<>();
// e.getMessage() 的格式为 getUser.id: id不能为空, getUser.name: name不能为空
String[] msgs = e.getMessage().split(", ");
for (String msg : msgs) {
String[] fieldAndMsg = msg.split(": ");
String field = fieldAndMsg[0].split("\\.")[1];
String message = fieldAndMsg[1];

Map<String, String> map = new HashMap<>();
map.put("field", field);
map.put("message", message);
errors.add(map);
}
return RestResponse.validationException(errors);
}

  spring
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×