springboot参数校验总结(一)

背景

我们在练习项目的时候,往往会涉及参数校验的问题,有时候是前端进行大部分校验,如用户名唯一性,生日格式,邮箱格式校验等等常用的校验。但是为了避免用户绕过浏览器,使用http工具直接向后端请求一些违法数据,服务端的数据校验也是必要的,可以防止脏数据落到数据库中,如果数据库中出现一个非法的邮箱格式,也会让运维人员头疼不已,所以后端校验也是有必要的。

校验框架validation依赖

首先添加校验框架validation的依赖,实际上在springboot项目,我们只需要入spring-boot-starter-web依赖即可

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

查看其子依赖,发现它已经添加了validation依赖了。

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>

这是对于springboot项目是这样,对于传统的springmvc项目还是需要添加

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

参数校验的具体步骤

第一步:在实体类需要校验的属性上加上校验的注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Data
public class User {
private int id;
@NotBlank
private String username;
@NotBlank(message = "密码不能为空")
private String password;
@Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$",message = "手机号码格式错误")
@NotBlank(message = "手机号码不能为空")
private String phone;

@Email(message = "邮箱格式错误")
private String email;
@Past
private Date birthday;
}

每个注解都包含一个message字段,用于校验失败后的提示信息。特殊的校验注解,如Pattern(正则校验),还可以自己添加正则表达式。

第二步:在controller请求方法上添加@Validated注解,开启请求参数的校验。

1
2
3
4
5
6
7
8
9
10
11
@PutMapping(value = "{id:\\d+}")
public User updateUser(@Validated @RequestBody User user, BindingResult errors) {
if (errors.hasErrors()) {
errors.getAllErrors().stream().forEach(error -> System.out.println(error.getDefaultMessage()));
}
System.out.println(user.getUsername());
System.out.println(user.getId());
System.out.println(user.getPassword());
System.out.println(user.getBirthday());
return user;
}

注意:

  • @Valid注解需放置在需被校验的参数前面,表明spring将对其进行校验,校验信息会存放在其后的BindingResult里面。
  • 如果有多个参数需要校验,形式可以如下。updateUser(@Valid User user, BindingResult userError ,@Valid Student student, BindingResult studentError);即一个校验类对应一个校验结果。

对于校验结果的处理,可以直接在controller方法中处理

1
2
3
if (errors.hasErrors()) {
errors.getAllErrors().stream().forEach(error -> System.out.println(error.getDefaultMessage()));
}

也可以将校验错误交由异常处理器处理

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
@RestControllerAdvice
public class ExceptionController {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseResult<Map<String, String>> handlerValidaException(MethodArgumentNotValidException ex) {
ResponseResult<Map<String, String>> result = new ResponseResult<>();
result.setCode(1);
result.setMsg("校验失败");
result.setData(getErrors(ex.getBindingResult()));
return result;
}

/**
* 返回校验字段错误的提示信息
*
* @param result
* @return
*/
private Map<String, String> getErrors(BindingResult result) {
Map<String, String> map = new HashMap<>();
//得到所有的属性错误
List<FieldError> list = result.getFieldErrors();
//将其组成键值对的形式存入map
for (FieldError fieldError : list) {
map.put(fieldError.getField(), fieldError.getDefaultMessage());
}
return map;
}
}

分组校验

如果同一个类,在不同的情形有不同的校验规则,可以进行分组校验

实体类改写

1
2
3
4
5
6
@Data
public class User {
public interface Group1{}
public interface Group2{}
@Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$",message = "手机号码格式错误",group=Group1.class)
}

控制器类改写

1
2
3
4
5
6
7
@PutMapping(value = "{id:\\d+}")
public User updateUser(@Validated({User.Group1.class}) @RequestBody User user, BindingResult errors) {
if (errors.hasErrors()) {
errors.getAllErrors().stream().forEach(error -> System.out.println(error.getDefaultMessage()));
}
return user;
}

框架提供的注解信息

@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格式
Bagikan Komentar