添加依赖
| 12
 3
 4
 
 | <dependency><groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-validation</artifactId>
 </dependency>
 
 | 
注解
注解及意思
| 注解 | 功能 | 
| @AssertFalse | 必须是false | 
| @AssertTrue | 必须是true | 
| @DecimalMax | 小于等于给定的值 | 
| @DecimalMin | 大于等于给定的值 | 
| @Digits | 可设定最大整数位数和最大小数位数 | 
| @Email | 必须为一个邮箱 | 
| @Future | 必须是将来的时间 | 
| @FutureOrPresent | 当前或将来时间 | 
| @Max | 最大值 | 
| @Min | 最小值 | 
| @Negative | 负数(不包括0) | 
| @NegativeOrZero | 负数或0 | 
| @NotBlank | 必须包含一个非空字符, 不能是空字符串 | 
| @NotEmpty | 不能为空, 可以为空字符串 | 
| @NotNull | 不为null | 
| @Null | 为null | 
| @Past | 必须是过去的时间 | 
| @PastOrPresent | 必须是过去的时间,包含现在 | 
| @Pattern | 匹配正则表达式 | 
| @Positive | 正数 | 
| @PositiveOrZero | 正数或0 | 
| @Size | 校验容器的元素个数 | 
 
注解通用属性及意思
| 12
 3
 4
 5
 
 | # message:自定义消息String message() default "{javax.validation.constraints.Null.message}";
 
 # groups:在进行分组校验时候使用
 Class<?>[] groups() default { };
 
 | 
基本使用
实体类

再属性上面添加字段
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | @Data@ApiModel("用户信息")
 public class UserEntity {
 
 @ApiModelProperty("用户id")
 private Integer id;
 
 @NotEmpty
 @ApiModelProperty("用户名")
 private String username;
 
 @NotBlank
 @ApiModelProperty("用户密码")
 private String password;
 }
 
 | 
控制类

在控制类接收参数上面添加@Valid注解
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | @Api(tags = "用户信息")@RestController
 @RequestMapping("user")
 public class UserController {
 
 @Resource
 private UserService userService;
 
 
 
 
 
 
 @ApiOperation(value = "添加信息", httpMethod = "POST", response = ResponseUtils.class, produces = "application/json")
 @PostMapping
 public ResponseUtils<Boolean> add(@Valid @RequestBody UserEntity userEntity) {
 Boolean isSuccess = userService.add(userEntity);
 return new ResponseUtils<Boolean>().success(isSuccess ? "添加成功" : "添加失败", isSuccess);
 }
 }
 
 | 
测试
测试数据
| 12
 3
 4
 
 | { "password": "",
 "username": ""
 }
 
 | 
测试结果
| 12
 3
 4
 5
 
 | {"code": 400,
 "msg": "Validation failed for argument [0] in public com.xiaofei.validation.utils.ResponseUtils<java.lang.Boolean> com.xiaofei.validation.controller.UserController.add(com.xiaofei.validation.entity.UserEntity) with 2 errors: [Field error in object 'userEntity' on field 'username': rejected value []; codes [NotEmpty.userEntity.username,NotEmpty.username,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userEntity.username,username]; arguments []; default message [username]]; default message [不能为空]] [Field error in object 'userEntity' on field 'password': rejected value []; codes [NotBlank.userEntity.password,NotBlank.password,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userEntity.password,password]; arguments []; default message [password]]; default message [不能为空]] ",
 "data": null
 }
 
 | 
统一返回结果
由于上面的测试结果展示的数据不方便调试,由此可以统一返回测试结果,方便调试。测试未通过异常类型MethodArgumentNotValidException
统一返回异常处理类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | @RestControllerAdvicepublic class GlobalExceptionHandler {
 
 private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 
 
 
 
 @ExceptionHandler(MethodArgumentNotValidException.class)
 public ResponseUtils<Object> validException(MethodArgumentNotValidException e, HttpServletRequest request) {
 String requestURI = request.getRequestURI();
 log.error("\n请求地址:{}\n发生系统异常\n数据校验出现问题:{}\n异常类型:{}", requestURI, e.getMessage(), e.getClass());
 
 
 Map<String, String> resultMap = new HashMap<>();
 BindingResult bindingResult = e.getBindingResult();
 bindingResult.getFieldErrors().forEach(fieldError -> {
 
 resultMap.put(fieldError.getField(), fieldError.getDefaultMessage());
 });
 
 
 return new ResponseUtils<Object>().error(400, "数据校验出现问题", resultMap);
 }
 }
 
 | 
测试
测试数据
| 12
 3
 4
 
 | { "password": "",
 "username": ""
 }
 
 | 
测试结果
| 12
 3
 4
 5
 6
 7
 8
 
 | {"code": 400,
 "msg": "数据校验出现问题",
 "data": {
 "password": "不能为空",
 "username": "不能为空"
 }
 }
 
 | 
分组校验
当不同请求进行不同校验时,可以使用分组校验进行区分。当新增时,可以指定哪些校验生效。当修改时,可以指定哪些校验生效。实体类上校验注解,设置groups,在控制类上面@Valid改为@Validated注解,并设置其value值
添加分组接口类
接口内容为空


在实体类属性上添加分组

| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | @Data@ApiModel("用户信息")
 @TableName(value = "user")
 public class UserEntity implements Serializable {
 
 @ApiModelProperty("用户id")
 @Null(message = "新增id必须为空", groups = {AddGroup.class})
 private Integer id;
 
 @NotEmpty(message = "用户名不能为空", groups = {AddGroup.class, UpdateGroup.class})
 @ApiModelProperty("用户名")
 private String username;
 
 @NotBlank
 @ApiModelProperty("用户密码")
 private String password;
 
 @TableField(exist = false)
 private static final long serialVersionUID = 1L;
 }
 
 | 
在控制类上指定注解
当使用@Validated指定了分组校验后,未指定分组的校验注解将不会生效

| 12
 3
 4
 5
 6
 
 | @ApiOperation(value = "添加信息", httpMethod = "POST", response = ResponseUtils.class, produces = "application/json")@PostMapping
 public ResponseUtils<Boolean> add(@Validated(value = {AddGroup.class}) @RequestBody UserEntity userEntity) {
 Boolean isSuccess = userService.add(userEntity);
 return new ResponseUtils<Boolean>().success(isSuccess ? "添加成功" : "添加失败", isSuccess);
 }
 
 | 
测试


自定义校验注解

- 编写一个自定义的校验注解
- 编写一个自定义的校验器
- 关联自定义的校验器和自定义的校验注解
添加依赖
如果使用了spring-boot-starter-validation则不需要添加下面依赖,spring-boot-starter-validation自带该依赖
| 12
 3
 4
 
 | <dependency><groupId>javax.validation</groupId>
 <artifactId>validation-api</artifactId>
 </dependency>
 
 | 
自定义校验注解

| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | @Documented@Constraint(validatedBy = {ListValueConstraintValidator.class})
 @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
 @Retention(RUNTIME)
 public @interface ListValue {
 
 String message() default "必须为指定的值";
 
 Class<?>[] groups() default {};
 
 Class<? extends Payload>[] payload() default {};
 
 int[] values() default {};
 }
 
 | 
编写校验器
编写一个类,实现ConstraintValidator接口,实现initialize和isValid方法    
| 12
 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
 
 | 
 
 
 
 
 public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {
 
 private final Set<Integer> set = new HashSet<>();
 
 
 
 
 
 
 @Override
 public void initialize(ListValue listValue) {
 
 int[] values = listValue.values();
 for (int value : values) {
 
 set.add(value);
 }
 }
 
 
 
 
 
 
 @Override
 public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
 
 return set.contains(value);
 }
 }
 
 | 
使用
实体类

| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | @Data@ApiModel("用户信息")
 @TableName(value = "user")
 public class UserEntity implements Serializable {
 
 @ApiModelProperty("用户id")
 @Null(message = "新增id必须为空", groups = {AddGroup.class})
 private Integer id;
 
 @NotEmpty(message = "用户名不能为空", groups = {AddGroup.class, UpdateGroup.class})
 @ApiModelProperty("用户名")
 private String username;
 
 @NotBlank
 @ApiModelProperty("用户密码")
 private String password;
 
 @ListValue(values = {1, 2})
 @ApiModelProperty("状态")
 @TableField(exist = false)
 private Integer status;
 
 @TableField(exist = false)
 private static final long serialVersionUID = 1L;
 }
 
 | 
控制类

| 12
 3
 4
 5
 6
 
 | @ApiOperation(value = "添加信息", httpMethod = "POST", response = ResponseUtils.class, produces = "application/json")@PostMapping
 public ResponseUtils<Boolean> add(@Validated @RequestBody UserEntity userEntity) {
 Boolean isSuccess = userService.add(userEntity);
 return new ResponseUtils<Boolean>().success(isSuccess ? "添加成功" : "添加失败", isSuccess);
 }
 
 | 
常用的JSR303校验
下面的模板都是基于分组校验实现的,如果不使用分组校验,直接删除分组校验部分即可,下列可能不准确,参考即可
IP
| 12
 3
 
 | @Pattern(regexp = "((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])(?::(?:[0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?",message = "IP格式错误",
 groups = {AddGroup.class, UpdateGroup.class})
 
 | 
端口
| 12
 
 | @Min(value = 1, message = "端口格式错误,必须为1-65535", groups = {AddGroup.class, UpdateGroup.class})@Max(value = 65535, message = "端口格式错误,必须为1-65535", groups = {AddGroup.class, UpdateGroup.class})
 
 | 
其他
| 12
 
 | @Null(message = "新增时不能携带id", groups = {AddGroup.class})@NotBlank(message = "修改时必须携带id", groups = {UpdateGroup.class})
 
 |