• 在spring中使用Validated和@Valid对参数进行校验


    两者差别

    在Controller中校验方法参数时,使用@Valid和@Validated并无特殊差异(若不需要分组校验的话):@Valid:标准JSR-303规范的标记型注解,用来标记验证属性和方法返回值,进行级联和递归校验@Validated:Spring的注解,是标准JSR-303的一个变种(补充),提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制。

    方法级别:@Validated注解可以用于类级别,用于支持Spring进行方法级别的参数校验。@Valid可以用在属性级别约束,用来表示级联校验。@Validated只能用在类、方法和参数上,而@Valid可用于方法、字段、构造器和参数上。

    常用注解

    常用注解如下:
    在这里插入图片描述
    使用步骤:

    1.先创建我们的参数类

    
    import lombok.Data;
    
    import javax.validation.constraints.*;
    import java.math.BigDecimal;
    import java.util.List;
    
    
    @Data
    public class AddUserReq {
    
        /**
         * 名字
         */
        @NotBlank(message = "名字不能为空")
        private String firstName;
    
        /**
         * 姓
         */
        @Size(min = 0, max = 10, message = "姓要在1-10长度")
        private String lastName;
    
        /**
         * 昵称
         */
        @NotEmpty(message = "至少有一个昵称")
        private List<String> nickName;
    
        /**
         * 性别
         */
        @NotBlank(message = "性别不能为空")
        private String sex;
    
        /**
         * 年龄
         */
        @NotNull(message = "年龄不能为空")
        private Integer age;
    
        /**
         * 收入
         */
         // integer表示整数位,fraction表示小数位
        @Digits(integer = 10000000, fraction = 6)
        private BigDecimal income;
    
    }
    
    
    • 1
    • 2
    • 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
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    2.在controller层接受参数时,再参数对象上使用@Validated注解

    代码如下:

    import ai.flkj.material.server.controller.bom.dto.AddUserReq;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    
    @RestController
    @RequestMapping("user")
    public class UserController {
    
        @PostMapping
        public void addUser(@Validated @RequestBody AddUserReq addUserReq) {
            System.out.println(addUserReq.getFirstName());
            return;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    对参数是List的验证

    如果接受参数是一个List,如下:

    import ai.flkj.material.server.controller.bom.dto.AddUserReq;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    
    
    @RestController
    @RequestMapping("user")
    public class UserController {
    
        @PostMapping
        public void batchAddUser(@Validated @RequestBody List<AddUserReq> batchUserReq) {
            return;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    如果再像上面那样,数据验证不会生效。

    解决方法:在controller类上面增加@Validated注解,在参数上使用Valid注解。

    代码如下:

    import ai.flkj.material.server.controller.bom.dto.AddUserReq;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.validation.Valid;
    import java.util.List;
    
    
    @RestController
    @RequestMapping("user")
    @Validated
    public class UserController {
    
        @PostMapping
        public void batchAddUser(@Valid @RequestBody List<AddUserReq> batchUserReq) {
            return;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    嵌套参数验证

    有时候,可能参数类里还有其他引用的类,如下,创建user时,引用了部门:

    package ai.flkj.material.server.controller.bom.dto;
    
    import lombok.Data;
    
    import javax.validation.constraints.*;
    import java.math.BigDecimal;
    import java.util.List;
    
    /**
     * @author Ethan
     * @date 2022/11/7
     * @description
     */
    @Data
    public class AddUserReq {
    
        /**
         * 名字
         */
        @NotBlank(message = "名字不能为空")
        private String firstName;
    
        /**
         * 姓
         */
        @Size(min = 0, max = 10, message = "姓要在1-10长度")
        private String lastName;
    
        /**
         * 昵称
         */
        @NotEmpty(message = "至少有一个昵称")
        private List<String> nickName;
    
        /**
         * 性别
         */
        @NotBlank(message = "性别不能为空")
        private String sex;
    
        /**
         * 年龄
         */
        @NotNull(message = "年龄不能为空")
        private Integer age;
    
        /**
         * 收入
         */
        @Digits(integer = 10000000, fraction = 6)
        private BigDecimal income;
    
        /**
         * 部门
         */
        private Department department;
        
    }
    
    
    • 1
    • 2
    • 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
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    部门的代码如下,也有参数验证:

    package ai.flkj.material.server.controller.bom.dto;
    
    import lombok.Data;
    
    import javax.validation.constraints.NotBlank;
    import javax.validation.constraints.NotNull;
    
    /**
     * @author Ethan
     * @date 2022/11/7
     * @description
     */
    @Data
    public class Department {
    
        /**
         * id
         */
        @NotNull(message = "部门id不能为空")
        private Integer id;
    
        /**
         * 名称
         */
        @NotBlank(message = "部门名称不能为空")
        private String name;
    }
    
    • 1
    • 2
    • 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

    像上面那种,是无法验证部门参数的。

    解决办法:在AddUserReq的department属性上增加@Valid注解。

    代码如下:

    import lombok.Data;
    
    import javax.validation.Valid;
    import javax.validation.constraints.*;
    import java.math.BigDecimal;
    import java.util.List;
    
    
    @Data
    public class AddUserReq {
    
        /**
         * 名字
         */
        @NotBlank(message = "名字不能为空")
        private String firstName;
    
        /**
         * 姓
         */
        @Size(min = 0, max = 10, message = "姓要在1-10长度")
        private String lastName;
    
        /**
         * 昵称
         */
        @NotEmpty(message = "至少有一个昵称")
        private List<String> nickName;
    
        /**
         * 性别
         */
        @NotBlank(message = "性别不能为空")
        private String sex;
    
        /**
         * 年龄
         */
        @NotNull(message = "年龄不能为空")
        private Integer age;
    
        /**
         * 收入
         */
        @Digits(integer = 10000000, fraction = 6)
        private BigDecimal income;
    
        /**
         * 部门
         */
        @Valid
        private Department department;
    }
    
    • 1
    • 2
    • 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
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    全局异常捕获

    注意上面如果参数验证不通过,会抛出ConstraintViolationException异常(也有可能是MethodArgumentNotValidException异常,具体看版本和代码),并给前端抛出500,这不是我们想要的。我们想要抛出自定义的一个异常,并把验证里的message抛给前端。

    这就需要自定义一个全局异常捕获,代码如下:

    import com.wyq.firstdemo.common.ServerResponse;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    
    import javax.validation.ConstraintViolation;
    import javax.validation.ConstraintViolationException;
    import java.util.Set;
    
    @Slf4j
    @RestControllerAdvicepublic 
    class ControllerExceptionHandler {
    	@ExceptionHandler
        @ResponseBody
        public ServerResponse<String> handle(ConstraintViolationException exception) {
            log.error(String.valueOf(exception));
            Set<ConstraintViolation<?>> violations = exception.getConstraintViolations();
            StringBuilder builder = new StringBuilder();
            for (ConstraintViolation violation : violations) {
                builder.append(violation.getMessage());
                break;
            }
            return ServerResponse.createByErrorMessage(builder.toString());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    参考:
    https://blog.csdn.net/weixin_39803022/article/details/110238210

  • 相关阅读:
    109.(leaflet篇)leaflet实现沿轨迹线播放
    计算机视觉岗实习面经
    【UE5 Cesium】18-Cesium for Unreal 建立飞行跟踪器(3)
    安装elasticsearch
    【SpringBoot】lombok 简化开发
    解决npm install遇到的问题:Error while executing:
    【实战-08】flink DataStream 如何实现去重
    @FeignClient使用详细教程(图解)
    第六章 图(中)【图的基本操作和遍历】
    大模型必备 - 中文最佳向量模型 acge_text_embedding
  • 原文地址:https://blog.csdn.net/qq_43745578/article/details/127739766