所有分类
  • 所有分类
  • 未分类

​SpringBoot-@Valid的用法

简介

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

1

评论4

请先

  1. 能不能不引入依赖?怎么自己手搓一个相同效果的工具类(或者框架)
    543862544 2023-09-26 0
    • 这个必须得引入依赖。手写一个的话,是很麻烦的,要支持那么多的注解,支持很多种数据类型。
      自学精灵 2023-09-26 0
  2. 这个实用!!!
    543862544 2023-09-26 0
    • 是的,很方便、实用
      自学精灵 2023-09-26 0
显示验证码
没有账号?注册  忘记密码?

社交账号快速登录