SpringBoot参数校验的最佳实战教程

作者:范闲 时间:2023-11-28 21:13:47 

目录
  • 前言

  • hibernate-validator基本使用

    • 引入依赖

    • 编写需要验证对象

    • 验证对象属性是否符合要求

    • 验证规则

      • 空/非空验证

      • bool

      • 时间

      • 数学

      • 字符串

    • 模板正则

    • SpringBoot整合hibernate-validator

      • 引入依赖

        • 配置hibernate-validator验证器对象

          • 借助SpringMVC统一异常处理处理参数校验结果

            • 使用参数校验

              • 分组校验

                • 啥叫分组校验?

            • 总结

              前言

              我们这里使用hibernate-validator作为对象参数验证器,所以在正式介绍SpringBoot参数验证之前,需要先简单了解一下hibernate-validator的使用。

              hibernate-validator基本使用

              引入依赖


              <dependency>
                 <groupId>org.hibernate</groupId>
                 <artifactId>hibernate-validator</artifactId>
                 <version>6.0.17.Final</version>
              </dependency>
              <dependency>
                 <groupId>javax.validation</groupId>
                 <artifactId>validation-api</artifactId>
              </dependency>

              编写需要验证对象

              验证要求 person对象的用户名不能为空,年龄在1-150岁之间。


              @Data
              public class Person {

              @NotBlank(message = "username must not be null")
                 private String username;

              @Min(value = 1, message = "age must be >= 1")
                 @Max(value = 150, message = "age must be < 150")
                 private Integer age;
              }

              验证对象属性是否符合要求


                 /**
                  * 对象验证器
                  */
                 public Validator validator() {
                     ValidatorFactory validatorFactory =
                             Validation
                                     .byProvider(HibernateValidator.class)
                                     .configure()
                                     // 验证属性时,如果有一个验证不通过就返回,不需要验证所有属性
                                     .addProperty("hibernate.validator.fail_fast", "true")
                                     .buildValidatorFactory();
                     return validatorFactory.getValidator();
                 }

              @Test
                 public void test() throws Exception {
                     Person person = new Person();
                     Set<ConstraintViolation<Person>> validate = validator().validate(person);
                     validate.forEach(errorParam -> {
                         System.out.println(errorParam.getMessage());
                     });
                 }
              1. 我们只需要验证的对象实例即可完成对象验证,如果验证成功,那么返回一个空的集合,如果验证失败,会返回具体的验证失败的属性信息。

              2. 我们输出验证失败的错误信息如下:


              username must not be null

              验证规则

              validator提供了大量的验证注解供我们使用,主要以下几类:

              SpringBoot参数校验的最佳实战教程

              空/非空验证

              1. @Null 元素必须为空

              2. @NotNull 元素不能为空,空字符串""是非空

              以下所有验证规则都在元素非空的时候才会进行验证,如果传入的元素为空,验证都会通过。

              bool

              1. @AssertTrue 元素必须为true

              2. @AssertFalse 元素必须为false

              时间

              1. @Future 元素必须是未来的某个时间。

              2. @FutureOrPresent 元素必须是未来或者现在的某个时间。

              3. @Past 元素必须是过去的某个时间。

              4. @PastOrPresent 元素必须是过去或者现在的某个时间。

              数学

              数字类型可以是BigDecimal、BigInteger、CharSequence 、byte 、 short 、 int 、 long以及它们各自的包装器类型

              1. @Digits 元素必须是该数字类型下可以被接受的数值范围内。

              2. @Negative 元素必须是负数

              3. @NegativeOrZero  元素必须小于等于0

              4. @Positive 元素必须大于0

              5. @PositiveOrZero 元素必须大于等于0

              6. @Max,@Min 元素的大小必须符合指定大小

              字符串

              1. @Email 邮箱格式验证

              2. @NotBlack 验证字符串非空,空字符串""也属于空

              3. @Pattern 字符串正则验证

              模板正则

              validator提供了字符串模板正则的注解,这里提供一份常用的正则表达式,大家可以直接作为常量工具类放到项目里使用


              public interface ValidatorPattern {

              /**
                  * 正则表达式:验证用户名
                  * 1.长度在5-17
                  * 2.由大写小写字母构成
                  */
                 String REGEX_USERNAME = "^[a-zA-Z]\w{5,17}$";

              /**
                  * 正则表达式:验证密码
                  * 密码只能为 6 - 12位数字,字母及常用符号组成。
                  */
                 String REGEX_PASSWORD = "^(?=.*[a-zA-Z])(?=.*[0-9])[A-Za-z0-9._~!@#$^&*]{6,12}$";

              /**
                  * 正则表达式:验证手机号
                  */
                 String REGEX_MOBILE = "^[1][34578]\d{9}$";

              /**
                  * 正则表达式:验证邮箱
                  */
                 String REGEX_EMAIL = "^.+@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\.)+[a-zA-Z]{2,}$";

              /**
                  * 正则表达式:验证汉字
                  */
                 String REGEX_CHINESE = "^[\u4e00-\u9fa5],*$";

              /**
                  * 正则表达式:验证身份证
                  */
                 String REGEX_ID_CARD = "(^\d{18}$)|(^\d{15}$)";

              /**
                  * 正则表达式:验证URL
                  */
                 String REGEX_URL = "http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?";

              /**
                  * 正则表达式:验证IP地址
                  */
                 String REGEX_IP_ADDR = "(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)";

              /**
                  * 车牌号正则
                  */
                 String LICENSE_NO = "^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z][A-Z][A-Z0-9]{4,5}[A-Z0-9挂学警港澳]$";

              /**
                  * 姓名校验
                  * 1~15位
                  * 姓名支持空格和中文的点
                  */
                 String NAME = "[\u4e00-\u9fa5\u00b7\sA-Za-z]{1,15}$";

              /**
                  * 表情正则
                  */
                 String EMOJI = "[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]";

              /**
                  * 数字正则
                  */
                 String NUMBER = "^[0-9]*$";

              /**
                  * n位的数字
                  */
                 String N_NUMS = "^\d{n}$";

              }

              SpringBoot整合hibernate-validator

              引入依赖

              这个不再赘述,直接拷贝上文的依赖信息

              配置hibernate-validator验证器对象

              在配置类中加入hibernate-validator验证器对象


                 @Bean
                 @Primary
                 public Validator validator() {
                     ValidatorFactory validatorFactory =
                             Validation
                                     .byProvider(HibernateValidator.class)
                                     .configure()
                                     .addProperty("hibernate.validator.fail_fast", "true")
                                     .buildValidatorFactory();
                     return validatorFactory.getValidator();
                 }

              借助SpringMVC统一异常处理处理参数校验结果

              配置好后,Spring会自动帮助我们进行参数验证,如果参数验证不通过,会抛出BindException异常,我们刚刚手动验证时的Set<ConstraintViolation<Person>>通过该异常获取。

              我们这可以通过借助SpringMVC统一异常处理的能力处理这个异常


              @Slf4j
              @RestControllerAdvice
              public class BaseExceptionHandler {
                 /**
                  * spring validation 自动校验的参数异常
                  *
                  * @param e BindException
                  * @return R<Void>
                  */
                 @ResponseStatus(org.springframework.http.HttpStatus.PAYMENT_REQUIRED)
                 @ExceptionHandler(BindException.class)
                 public R<Void> handler(BindException e) {
                     String defaultMsg = e.getBindingResult().getAllErrors()
                             .stream()
                             .map(ObjectError::getDefaultMessage)
                             .collect(Collectors.joining(":"));
                     log.warn(defaultMsg);
                     return R.of(IRespCode.PARAMETERS_ANOMALIES.getCode(), e.getMessage());
                 }
              }

              使用参数校验

              我们只需要在校验参数的方法传参上标注@Valid或者@Validated都行


                 @PostMapping("register")
                 public R<Void> register(@Valid @RequestBody Person person) {
                     // todo
                     return R.ok();
                 }

              分组校验

              那么@Valid和@Validated有什么区别呢?

              Validated比Valid多了一个属性,这个属性用于分组校验使用


              public @interface Valid {
              }
              public @interface Validated {
                 Class<?>[] value() default {};
              }

              啥叫分组校验?

              就是一个实体类中的属性,在不同的方法传参中,方法的对属性的要求不同。

              比如说,Person类中有三个属性,一个是用户名称,一个是邮箱,一个是年龄。

              在注册用户接口中,用户名称,邮箱和年龄都不能为空,但是在更改用户的信息接口中,用户的年龄和邮箱都可以为空,但是用户名称不能为空。

              这时候,我们就可以按照对属性校验的要求进行分组。

              新建一个RegisterGroup分组,该分组只是一个空的接口,仅仅用于标记该校验要求


              public interface RegisterGroup {
              }

              对校验要求进行分组


              @Data
              public class Person {

              @NotBlank(message = "username must not be null")
                 private String username;

              @Min(value = 1, message = "age must be >= 1")
                 @Max(value = 150, message = "age must be < 150")
                 @NotNull(message = "age must not be null", groups = RegisterGroup.class)
                 private Integer age;

              @Email(message = "email format error")
                 @NotBlank(message = "email must not be null",groups = RegisterGroup.class)
                 private String email;
              }

              方法调用时,加入分组要求


                 @PostMapping("register")
                 public R<Void> register(@Validated(value = RegisterGroup.class) @RequestBody Person person) {
                     // todo
                     return R.ok();
                 }

              这种方式其实不推荐使用,我在标题的时候,也已经标记为“过时”,因为,我们完全可以为这两个不同的接口创建两个不同的实体类,而不是使用分组对校验要求进行隔离,因为实际生产环境中,分组可能有非常多个,这会为我们的程序的可读性埋下隐患,后期开发人员难以维护,而且对于自动生成API文档也不友好。大家对于分组只需要了解即可,不建议在项目开发中使用。

              来源:https://juejin.cn/post/6999607085998538759

              标签:springboot,参数,校验
              0
              投稿

              猜你喜欢

            • Java关于桶排序的知识点总结

              2023-12-06 03:18:04
            • 基于C#实现屏幕取色器

              2023-02-16 04:17:53
            • Android编程之TextView的字符过滤功能分析

              2023-05-19 20:23:36
            • 关于Controller层和Service层的类报错问题及解决方案

              2023-09-28 15:12:23
            • SpringBoot整合Xxl-Job的完整步骤记录

              2021-08-08 20:47:16
            • Java之 TreeSet的详细使用说明

              2021-08-22 14:52:22
            • Android开发之拖动条和评分组件用法分析

              2022-01-15 02:55:18
            • DataGridView控件显示行号的正确代码及分析

              2022-07-26 22:05:50
            • java 使用异常的好处总结

              2023-11-29 13:35:49
            • Java 8 中的 10 个特性总结及详解

              2023-07-21 00:06:51
            • Java线程通信中关于生产者与消费者案例分析

              2022-01-18 10:49:25
            • tomcat部署java web项目遇到的问题及解决方法

              2023-08-04 23:44:27
            • Java设计模式编程中的工厂方法模式和抽象工厂模式

              2023-03-19 05:50:48
            • C#实现Base64编码与解码及规则

              2023-09-17 13:06:19
            • C++链表节点的添加和删除介绍

              2023-08-23 02:32:09
            • java的IO流详细解读

              2022-01-24 20:18:40
            • JVM之参数分配(全面讲解)

              2023-11-09 08:19:10
            • Maven插件的安装及使用

              2022-04-05 04:38:30
            • Struts2源码分析之ParametersInterceptor拦截器

              2023-11-05 00:41:37
            • Java编程中ArrayList源码分析

              2023-05-20 00:05:25
            • asp之家 软件编程 m.aspxhome.com