数据校验是开发过程中一个常见的环节,一般来说,为了提高系统运行效率,都会在前端进行数据校验,但是这并不意味着不必在后端做数据校验了,因为用户还是可能在获取数据接口后手动传入非法数据,所以后端还是需要做数据校验。 Spring Boot 对此也提供了相关的自动化配置解决方案。
普通校验
添加依赖:
<dependency>-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
项目创建成功后,查看 LocalValidatorFactoryBean
类的源码,发现默认的 ValidationMessageSource
(校验出错时的提示文件) 是 resources 目录下的 ValidationMessages.properties
文件,因此在 resource 目录下创建该文件:
user.name.size=用户名长度介于 5 到 10 个字符之间
user.address.notnull=用户地址不能为空
user.age.size=年龄输入不正确
user.email.notnull=邮箱不能为空
user.email.pattern=邮箱格式不正确
接下来创建 User 类,配置数据校验:
import javax.validation.constraints.*;
public class User {
private Integer id;
@Size(min = 5, max = 10, message = "{user.name.size}")
private String name;
@NotNull(message = "{user.address.notnull}")
private String address;
@DecimalMax(value = "200", message = "{user.age.size}")
@DecimalMin(value = "1", message = "{user.age.size}")
private Integer age;
@Email(message = "{user.email.pattern}")
@NotNull(message = "{user.email.notnull}")
private String email;
// 省略 getter / setter
}
代码解释:
- @Size 表示一个字符串的长度或者一个集合的大小必须在某一个范围中。min 参数表示范围的下限,max参数表示范围的上限,message 表示校验失败时的提示信息。
- @NotNull 注解表示该字段不能为空。
- @DecimalMin 注解表示对应属性值的下限,@DecimalMax 阻注解表示对应属性值的上限。
- @Email 注解表示对应属性格式是一个 Email。
配置完成后,接下来创建 Controlle:
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xyz.ther.boot.validation.User;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/validation")
public class UserValidationController {
@PostMapping("/user")
public List<String> addUser(@Validated User user, BindingResult bindingResult) {
List<String> errors = new ArrayList<>();
if (bindingResult.hasErrors()) {
List<ObjectError> allErrors = bindingResult.getAllErrors();
for (ObjectError error : allErrors) {
errors.add(error.getDefaultMessage());
}
}
return errors;
}
}
代码解释:
- 给 User 参数添加
@Validated
注解,表示需要对该参数做校验,BindingResult 参数表示在校验出错时保存的出错信息。 - 如果 BindingResult 中的 hasErrors 方法返回 true,表示有错误信息,此时遍历错误信息并返回给前端。
使用 Postman 进行测试,直接访问接口:
[
"邮箱不能为空",
"用户地址不能为空"
]
分组校验
有的时候开发者在某一个实体类中定义了很多校验规则 ,但是在某一次业务处理中并不需要这么多校验规时就可以使用分组校验。步骤如下:
首先创建两个分组接口:
public interface ValidationGroup1 {
}
public interface ValidationGroup2 {
}
然后在实体类中添加分组信息:
import javax.validation.constraints.*;
public class User {
private Integer id;
@Size(min = 5, max = 10, message = "{user.name.size}", groups = ValidationGroup1.class)
private String name;
@NotNull(message = "{user.address.notnull}", groups = ValidationGroup2.class)
private String address;
@DecimalMax(value = "200", message = "{user.age.size}")
@DecimalMin(value = "1", message = "{user.age.size}")
private Integer age;
@Email(message = "{user.email.pattern}")
@NotNull(message = "{user.email.notnull}", groups = ValidationGroup2.class)
private String email;
// 省略 getter / setter
}
这次在部分注解中添加了 groups 属性,表示该校验规则所属的分组, 接下来在 @Validated 注解中指定校验分组:
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xyz.ther.boot.validation.User;
import xyz.ther.boot.validation.ValidationGroup1;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/validation")
public class UserValidationController {
@PostMapping("/user")
public List<String> addUser(@Validated(ValidationGroup1.class) User user, BindingResult bindingResult) {
List<String> errors = new ArrayList<>();
if (bindingResult.hasErrors()) {
List<ObjectError> allErrors = bindingResult.getAllErrors();
for (ObjectError error : allErrors) {
errors.add(error.getDefaultMessage());
}
}
return errors;
}
}
测试请求中不包含 address 和 email 也不会产生错误信息。