• 使用@validated注解校验参数


    准备工作

    maven依赖

    		
    			org.springframework.boot
    			spring-boot-starter-validation
    		
    
    • 1
    • 2
    • 3
    • 4

    新建参数对象:TestValidateDTO

    @Data
    @ToString
    public class TestValidateDTO {
    
        @NotBlank
        private String name;
    
        @Email
        private String email;
    
        @Pattern(regexp = "0?(13|14|15|17|18|19)[0-9]{9}")
        private String phone;
    
        @NotBlank
        private String word;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    调用关系

    @RestController
    @RequestMapping("/validate")
    public class TestValidateWeb {
    
        @Autowired
        private TestValidateService tvs;
    
        @PostMapping("/test1")
        public String test1(@Validated @RequestBody TestValidateDTO dto){
            return tvs.test1(dto);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    @Service
    public class TestValidateService {
    
        public String test1(TestValidateDTO dto){
            return dto.toString();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试效果

    正常数据验证:

    在这里插入图片描述

    修改name,email,phone,word的内容,故意不符合规则:

    在这里插入图片描述

    在这里插入图片描述

    虽然有报错但是报错提示400,很不人性化,继续修改报错提示。

    修改抛出异常提示

    @RestControllerAdvice
    public class ResponseException {
    
        @ExceptionHandler(value = MethodArgumentNotValidException.class)
        public String  validateException(MethodArgumentNotValidException exc){
            return "出现问题:"+exc.getBindingResult().getFieldError().getDefaultMessage();
        }
    
        @ExceptionHandler(value = Exception.class)
        public String  exception(Exception exc){
            return "出现问题:"+exc.getMessage();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    @Data
    @ToString
    public class TestValidateDTO {
    
        @NotBlank(message = "姓名不能为空")
        private String name;
    
        @Email(message = "不是符合格式的邮箱")
        private String email;
    
        @Pattern(regexp = "0?(13|14|15|17|18|19)[0-9]{9}", message = "手机号码不符合格式")
        private String phone;
    
        @NotBlank(message = "说句话")
        private String word;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在参数对象的注解上加上message。

    在这里插入图片描述

    符合预期效果。

    分组校验

    同样的一个参数对象,可能两个接口对参数对象的校验规则是不一样的,可以使用groups实现在同一个参数对象上不同接口有不同的校验规则。

    新建一个类,里面有两个内部接口,新建内部接口是因为**@Validated**(**value **= {})中value只接受接口类型

    public class TestValidateGroups {
    
        public interface  test1{};
    
        public interface test2 {};
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    接口参数中加上**@Validated**(**value **= {TestValidateGroups.test2.class}),不同接口加上不同内部接口。

    @RestController
    @RequestMapping("/validate")
    @Validated
    public class TestValidateWeb {
    
        @Autowired
        private TestValidateService tvs;
    
        @PostMapping("/test1")
        public String test1(@Validated(value = {TestValidateGroups.test1.class}) @RequestBody TestValidateDTO dto) {
            return tvs.test1(dto);
        }
    
        @PostMapping("/test2")
        public String test2(@Validated(value = {TestValidateGroups.test2.class}) @RequestBody TestValidateDTO dto) {
            return tvs.test1(dto);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    参数对象中name和word指定内部接口,和接口层的关系对应上。

    @Data
    @ToString
    public class TestValidateDTO {
    
        @NotBlank(message = "姓名不能为空", groups = {TestValidateGroups.test1.class})
        private String name;
    
        @Email(message = "不是符合格式的邮箱")
        private String email;
    
        @Pattern(regexp = "0?(13|14|15|17|18|19)[0-9]{9}", message = "手机号码不符合格式")
        private String phone;
    
        @NotBlank(message = "说句话", groups = {TestValidateGroups.test2.class})
        private String word;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    调用这两个接口,参数对象都一样:

    在这里插入图片描述

    在这里插入图片描述

    可以看到参数对象都是一样的,但是提示是不一样的,说明校验规则是做了区分的。

    ❗注意,如果这个时候我在email属性上加了如下的规则

    @NotBlank(message = “邮箱不能为空”, groups = {TestValidateGroups.test1.class, TestValidateGroups.test2.class})
    @Email(message = “不是符合格式的邮箱”)
    private String email;

    因为**@Email没有指定分组,所以不管如何调用都不会校验是否是邮箱,@NotBlank因为加了指定分组所以才会校验是否为空。**

    出现这个问题,是因为在test1接口指定了TestValidateGroups.test1.class分组,如果在test1接口中将指定分组删掉:

    @RestController
    @RequestMapping("/validate")
    @Validated
    public class TestValidateWeb {
    
        @Autowired
        private TestValidateService tvs;
    
        @PostMapping("/test1")
        public String test1(@Validated @RequestBody TestValidateDTO dto) {
            return tvs.test1(dto);
        }
    
        @PostMapping("/test2")
        public String test2(@Validated(value = {TestValidateGroups.test2.class}) @RequestBody TestValidateDTO dto) {
            return tvs.test1(dto);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    这个时候也只会校验在参数对象中没有指定分组的属性。改变phone也是会校验的。

    自定义注解校验规则

    @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER,})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Constraint(validatedBy = TestAnnotationValidateImpl.class)
    @Repeatable(TestAnnotation.List.class)
    public @interface TestAnnotation {
    
        String message() default "字段不符合规范";
    
        Class[] groups() default {};
    
        Class[] payload() default {};
    
        @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER,})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        public @interface List {
            TestAnnotation[] value();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    这里出现的@Target注解指定的用途需要一致,个数一样,值一样,不然会提示错误。

    @Component
    public class TestAnnotationValidateImpl implements ConstraintValidator {
        @Override
        public void initialize(TestAnnotation constraintAnnotation) {
            ConstraintValidator.super.initialize(constraintAnnotation);
        }
    
        @Override
        public boolean isValid(TestValidateDTO testValidateDTO, ConstraintValidatorContext constraintValidatorContext) {
            if (testValidateDTO == null) {
                return true;
            }
            if (StringUtils.isBlank(testValidateDTO.getWord())) {
                return false;
            }
    //      返回false就会抛出message
            return !testValidateDTO.getWord().contains("c") && !testValidateDTO.getWord().contains("c") &&
                    !testValidateDTO.getWord().contains("cnm");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    @RestController
    @RequestMapping("/validate")
    @Validated
    public class TestValidateWeb {
    
        @Autowired
        private TestValidateService tvs;
    
        @PostMapping("/test1")
        public String test1(@Validated @RequestBody TestValidateDTO dto) {
            return tvs.test1(dto);
        }
    
        @PostMapping("/test2")
        public String test2(@Validated(value = {TestValidateGroups.test2.class}) @TestAnnotation(message = "cnm,别说脏话啊") @RequestBody TestValidateDTO dto) {
            return tvs.test1(dto);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在test2接口上加上TestAnnotation注释,因为我将TestAnnotation注解设置为可以用在参数上。

    在这里插入图片描述

    效果符合预期。

  • 相关阅读:
    Git合并固定分支的某一部分至当前分支
    3D打印喷嘴大小如何选择0.2-0.5mm喷嘴
    接口设计时的一些建议
    spring cloud+spring boot__基于AOP面向切面编程记录操作日志完整流程记录
    [附源码]计算机毕业设计springboot在线图书销售系统
    【WEEK15】 【DAY2】【DAY3】邮件任务【中文版】
    字节面经总结
    SpringBoot项目在Linux上启动、停止脚本
    行业落地分享:阿里云搜索RAG应用实践
    如何在JVS低代码表单配置中实现数据的高效管理?
  • 原文地址:https://blog.csdn.net/ZRL1996/article/details/126902877