Springboot @Valid 嵌套校验,看完这篇立刻上手!

@Valid嵌套校验 = 入参@Valid + 属性上@Valid
用在方法入参上无法单独提供嵌套验证功能。
能配合嵌套验证注解@Valid进行嵌套验证。
能够用在成员属性(字段)上,提示验证框架进行嵌套验证。

@Validated: 嵌套校验 = 入参@Validated + 属性上@Valid
用在方法入参上无法单独提供嵌套验证功能。
能配合嵌套验证注解@Valid进行嵌套验证。
不能用在成员属性(字段)上,也无法提示框架进行嵌套验证。

参考:https://blog.csdn.net/qq_27680317/article/details/79970590


pom

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.4.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
            <version>2.4.5</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
            <version>2.4.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-json</artifactId>
            <version>2.4.5</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>
        <!--swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
    </dependencies>

结果类 状态码类

/**
 * @Author: Huishi
 * @Date: 2021/10/15 13:17
 */
public enum ApiCode {
    
    

    SUCCESS(200, "操作成功"),

    FAIL(500, "操作失败"),

    SYSTEM_EXCEPTION(5000, "系统异常!"),

    PARAMETER_EXCEPTION(5001, "请求参数校验异常"),
    ;

    private final int code;
    private final String msg;

    ApiCode(final int code, final String msg) {
    
    
        this.code = code;
        this.msg = msg;
    }

    public static ApiCode getApiCode(int code) {
    
    
        ApiCode[] ecs = ApiCode.values();
        for (ApiCode ec : ecs) {
    
    
            if (ec.getCode() == code) {
    
    
                return ec;
            }
        }
        return SUCCESS;
    }

    public int getCode() {
    
    
        return code;
    }

    public String getMsg() {
    
    
        return msg;
    }

}
/**
 * @Author: Huishi
 * @Date: 2021/10/15 13:16
 */
@Data
@Accessors(chain = true)
@Builder
@AllArgsConstructor
public class ApiResult<T> implements Serializable {
    
    
    /**
     * 响应码
     */
    private int code;

    /**
     * 响应消息
     */
    private String msg;

    /**
     * 是否成功
     */
    private boolean success;

    /**
     * 响应数据
     */
    private T data;

    /**
     * 响应时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date time  = new Date();

    public ApiResult() {
    
    

    }

    public static ApiResult result(boolean flag){
    
    
        if (flag){
    
    
            return ok();
        }
        return fail();
    }

    public static ApiResult result(ApiCode apiCode){
    
    
        return result(apiCode,null);
    }

    public static ApiResult result(ApiCode apiCode,Object data){
    
    
        return result(apiCode,null,data);
    }

    public static ApiResult result(ApiCode apiCode,String msg,Object data){
    
    
        boolean success = false;
        if (apiCode.getCode() == ApiCode.SUCCESS.getCode()){
    
    
            success = true;
        }
        String message = apiCode.getMsg();
        if (StringUtils.isNotBlank(msg)){
    
    
            message = msg;
        }
        return ApiResult.builder()
                .code(apiCode.getCode())
                .msg(message)
                .data(data)
                .success(success)
                .time(new Date())
                .build();
    }

    public static ApiResult ok(){
    
    
        return ok(null);
    }

    public static ApiResult ok(Object data){
    
    
        return result(ApiCode.SUCCESS,data);
    }

    public static ApiResult ok(Object data,String msg){
    
    
        return result(ApiCode.SUCCESS,msg,data);
    }

    public static ApiResult okMap(String key,Object value){
    
    
        Map<String,Object> map = new HashMap<>();
        map.put(key,value);
        return ok(map);
    }

    public static ApiResult fail(ApiCode apiCode){
    
    
        return result(apiCode,null);
    }

    public static ApiResult fail(String msg){
    
    
        return result(ApiCode.FAIL,msg,null);

    }

    public static ApiResult fail(ApiCode apiCode,Object data){
    
    
        if (ApiCode.SUCCESS == apiCode){
    
    
            throw new RuntimeException("失败结果状态码不能为" + ApiCode.SUCCESS.getCode());
        }
        return result(apiCode,data);

    }

    public static ApiResult fail(String key,Object value){
    
    
        Map<String,Object> map = new HashMap<>();
        map.put(key,value);
        return result(ApiCode.FAIL,map);
    }

    public static ApiResult fail() {
    
    
        return fail(ApiCode.FAIL);
    }
}

两个实体类

参考:https://blog.csdn.net/qq_27680317/article/details/79970590

public class Item {
    
    

    @NotNull(message = "id不能为空")
    @Min(value = 1, message = "id必须为正整数")
    private Long id;

    @Valid // 嵌套验证必须用@Valid
    @NotNull(message = "props不能为空")
    @Size(min = 1, message = "props至少要有一个自定义属性")
    private List<Prop> props;
}
————————————————

public class Prop {
    
    

    @NotNull(message = "pid不能为空")
    @Min(value = 1, message = "pid必须为正整数")
    private Long pid;

    @NotNull(message = "vid不能为空")
    @Min(value = 1, message = "vid必须为正整数")
    private Long vid;

    @NotBlank(message = "pidName不能为空")
    private String pidName;

    @NotBlank(message = "vidName不能为空")
    private String vidName;
}

全局异常

/**
 * @Author: Huishi
 * @Date: 2021/10/15 13:10
 */
@ControllerAdvice
@RestController
@Slf4j
public class GlobalExceptionHandler {
    
    

    /**
     * 非法参数验证异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public ApiResult handleMethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException ex) {
    
    
        BindingResult bindingResult = ex.getBindingResult();
        List<String> list = new ArrayList<>();
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        for (FieldError fieldError : fieldErrors) {
    
    
            list.add(fieldError.getDefaultMessage());
        }
        Collections.sort(list);
        log.error("fieldErrors" + JSON.toJSONString(list));
        return ApiResult.fail(ApiCode.PARAMETER_EXCEPTION, list);
    }
}

Swagger

@Configuration
@EnableSwagger2  //开启Swagger2
public class SwaggerConfig
{
    
    
    //配置
    @Bean
    public Docket docket(){
    
    
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
    }
    //作者信息
    private ApiInfo apiInfo() {
    
    
        Contact contact = new Contact("Huishi", "https://blog.csdn.net/qq_36937684?spm=1001.2101.3001.5343", "[email protected]");
        return new ApiInfo("文档","测试 Spring-boot-valid","v1.0","https://mvnrepository.com/search?q=springfox++swagger",contact,"Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList());
    }
}

控制层

@RestController
public class ItemController {
    
    

    @Autowired
    ItemService itemService;

    @PostMapping("/item/add")    // 或者用@Validated也是一样的
    public @ResponseBody ApiResult<Boolean> addItem(@Valid @RequestBody Item item) throws Exception {
    
    
        int add = itemService.add(item);
        return ApiResult.ok(add);
    }
}

测试

①正常
{
    
    
  "id": 2,
  "props": [
    {
    
    
      "pid": 3,
      "pidName": "string",
      "vid": 8,
      "vidName": "string"
    }
  ]
}
返回
{
    
    
  "code": 200,
  "msg": "操作成功",
  "success": true,
  "data": 2,
  "time": "2021-10-15 06:08:54"
}
②Item类 id属性为空
{
    
    
  "props": [
    {
    
    
      "pid": 3,
      "pidName": "string",
      "vid": 8,
      "vidName": "string"
    }
  ]
}
返回
{
    
    
  "code": 5001,
  "msg": "请求参数校验异常",
  "success": false,
  "data": [
    "id不能为空"
  ],
  "time": "2021-10-15 06:10:51"
}
③Prop类 不满足条件
{
    
    
  "id": 3,
  "props": [
    {
    
    
      "pid": 0,
      "pidName": "string",
      "vid": 8,
      "vidName": "string"
    }
  ]
}
返回
{
    
    
  "code": 5001,
  "msg": "请求参数校验异常",
  "success": false,
  "data": [
    "pid必须为正整数"
  ],
  "time": "2021-10-15 06:11:58"
}

おすすめ

転載: blog.csdn.net/qq_36937684/article/details/120782450