简介
本文用示例说明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不能为空]] ]
请先
!