简介
本文用示例说明SpringBoot的@Valid的用法。
依赖
必须引入此依赖,否则校验会无效。而且@Valid是validator的依赖,所以可以引入下边任意一个依赖都可以。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
它里边依赖了hibernate validator,就是下边这个。
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> </dependency>
测试代码
Controller
package com.knife.example.business.user.controller;
import com.knife.example.business.user.bo.UserBO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
@Api(tags = "valid测试")
@RestController
@RequestMapping("valid")
public class ValidController {
@ApiOperation("正常用法")
@PostMapping("normal")
public UserBO normal(@Valid @RequestBody UserBO userBO) {
return userBO;
}
@ApiOperation("获得BindingResult")
@PostMapping("bindingResult")
public UserBO bindingResult(@Valid @RequestBody UserBO userBO, BindingResult bindingResult) {
if (bindingResult.hasErrors()){
List<ObjectError> list = bindingResult.getAllErrors();
for (ObjectError objectError : list) {
System.out.println(objectError.getDefaultMessage());
}
//System.out.println(bindingResult.getFieldError().getDefaultMessage());
}
return userBO;
}
}
BO
package com.knife.example.business.user.bo;
import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
@Data
public class UserBO {
@NotBlank(message = "名字不能为空")
private String name;
private Integer age;
@NotBlank(message = "密码不能为空")
private String password;
@NotEmpty(message = "分数不能为空")
private List<Integer> scoreArray;
@Valid
@NotNull(message = "账户不能为空")
private AccountBO accountBO;
@Valid
@NotEmpty(message = "账户列表不能为空")
private List<AccountBO> accountBOList;
}
package com.knife.example.business.user.bo;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
public class AccountBO {
@NotNull(message = "账户ID不能为空")
private Long id;
@NotBlank(message = "电话号码不能为空")
private String phoneNumber;
private String[] emails;
}
测试
本文knife4j这个接口工具,它能自动识别是否为空的注解,并在前端进行显示。
访问:http://localhost:8080/doc.html

测试1:缺参数测试单个对象入参

可以看到:所有位置的校验都是有效的,包括:顶层实体类、普通字段、数组字段、包装类字段、包装类列表字段。
请求体:
{
"accountBO": {
"emails": [],
"id": 2,
"phoneNumber": ""
},
"accountBOList": [
{
"emails": [],
"id": null,
"phoneNumber": "12345"
}
],
"age": 0,
"name": "",
"password": "",
"scoreArray": []
}
测试2:不缺参数测试单个对象入参

可以看到,接口没有报错。
请求体:
{
"accountBO": {
"emails": ["123@qq.com"],
"id": 2,
"phoneNumber": "123"
},
"accountBOList": [
{
"emails": ["11@qq.com"],
"id": 3,
"phoneNumber": "12345"
}
],
"age": 0,
"name": "Tony",
"password": "abbb",
"scoreArray": [95,98]
}
测试3:缺参数测试对象列表入参(失效)

可以发现:校验失效了!解决方法是:这里
入参
[
{
"accountBO": {
"emails": [],
"id": 2,
"phoneNumber": ""
},
"accountBOList": [
{
"emails": [],
"id": null,
"phoneNumber": "12345"
}
],
"age": 0,
"name": "",
"password": "",
"scoreArray": []
}
]
测试4:缺少字段,后端获取BindResult

可以看到,没有报错。
后端结果:
分数不能为空 密码不能为空 电话号码不能为空 名字不能为空 账户ID不能为空
请求体:
{
"accountBO": {
"emails": [],
"id": 2,
"phoneNumber": ""
},
"accountBOList": [
{
"emails": [],
"id": null,
"phoneNumber": "12345"
}
],
"age": 0,
"name": "",
"password": "",
"scoreArray": []
}
代码
下载源码
此隐藏内容仅限VIP查看升级VIP
代码结构

将错误提示出来
本文将参数非法这种异常统一提示到了前端,用了全局异常处理(捕获MethodArgumentNotValidException异常)。如果不用异常处理,后端打印信息会很多:
2023-10-15 19:45:17.549 WARN 1920 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public com.example.demo.business.valid.entity.User com.example.demo.business.valid.controller.ValidController.normal(com.example.demo.business.valid.entity.User) with 5 errors: [Field error in object 'user' on field 'account.phoneNumber': rejected value []; codes [NotBlank.user.account.phoneNumber,NotBlank.account.phoneNumber,NotBlank.phoneNumber,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.account.phoneNumber,account.phoneNumber]; arguments []; default message [account.phoneNumber]]; default message [电话号码不能为空]] [Field error in object 'user' on field 'name': rejected value []; codes [NotBlank.user.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.name,name]; arguments []; default message [name]]; default message [名字不能为空]] [Field error in object 'user' on field 'password': rejected value []; codes [NotBlank.user.password,NotBlank.password,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.password,password]; arguments []; default message [password]]; default message [密码不能为空]] [Field error in object 'user' on field 'scoreArray': rejected value [[]]; codes [NotEmpty.user.scoreArray,NotEmpty.scoreArray,NotEmpty.java.util.List,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.scoreArray,scoreArray]; arguments []; default message [scoreArray]]; default message [分数不能为空]] [Field error in object 'user' on field 'accountList[0].id': rejected value [null]; codes [NotNull.user.accountList[0].id,NotNull.user.accountList.id,NotNull.accountList[0].id,NotNull.accountList.id,NotNull.id,NotNull.java.lang.Long,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.accountList[0].id,accountList[0].id]; arguments []; default message [accountList[0].id]]; default message [账户ID不能为空]] ]

请先 !