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

我们这里使用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());
        });
    }
复制代码

我们只需要验证的对象实例即可完成对象验证,如果验证成功,那么返回一个空的集合,如果验证失败,会返回具体的验证失败的属性信息。
我们输出验证失败的错误信息如下:

username must not be null
复制代码
验证规则
validator提供了大量的验证注解供我们使用,主要以下几类:

空/非空验证

@Null 元素必须为空
@NotNull 元素不能为空,空字符串""是非空

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

@AssertTrue 元素必须为true
@AssertFalse 元素必须为false

时间

@Future 元素必须是未来的某个时间。
@FutureOrPresent 元素必须是未来或者现在的某个时间。
@Past 元素必须是过去的某个时间。
@PastOrPresent 元素必须是过去或者现在的某个时间。

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

@Digits 元素必须是该数字类型下可以被接受的数值范围内。
@Negative 元素必须是负数
@NegativeOrZero  元素必须小于等于0
@Positive 元素必须大于0
@PositiveOrZero 元素必须大于等于0
@Max,@Min 元素的大小必须符合指定大小

字符串

@Email 邮箱格式验证
@NotBlack 验证字符串非空,空字符串""也属于空
@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
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

(0)

相关推荐

  • 详解SpringBoot中的参数校验(项目实战)

    Java后端发工作中经常会对前端传递过来的参数做一些校验,在业务中还要抛出异常或者不断的返回异常时的校验信息,充满了if-else这种校验代码,在代码中相当冗长.例如说,用户注册时,会校验手机格式的正确性,用户名的长度等等.虽说前端也可以做参数校验,但是为了保证我们API接口的可靠性,以保证最终数据入库的正确性,后端进行参数校验不可忽视. Hibernate Validator 提供了一种统一方便的方式,让我们快速的实现参数校验. Hibernate Validator 使用注解,实现声明式校验

  • SpringBoot中自定义注解实现参数非空校验的示例

    前言 由于刚写项目不久,在写 web 后台接口时,经常会对前端传入的参数进行一些规则校验,如果入参较少还好,一旦需要校验的参数比较多,那么使用 if 校验会带来大量的重复性工作,并且代码看起来会非常冗余,所以我首先想到能否通过一些手段改进这点,让 Controller 层减少参数校验的冗余代码,提升代码的可阅读性. 经过阅读他人的代码,发现使用 annotation 注解是一个比较方便的手段,SpringBoot 自带的 @RequestParam 注解只会校验请求中该参数是否存在,但是该参数是

  • SpringBoot如何优雅的处理校验参数的方法

    前言 做web开发有一点很烦人就是要校验参数,基本上每个接口都要对参数进行校验,比如一些格式校验 非空校验都是必不可少的.如果参数比较少的话还是容易 处理的一但参数比较多了的话代码中就会出现大量的IF ELSE就比如下面这样: 这个例子只是校验了一下空参数.如果需要验证邮箱格式和手机号格式校验的话代码会更多,所以介绍一下validator通过注解的方式进行校验参数. 什么是Validator Bean Validation是Java定义的一套基于注解的数据校验规范,目前已经从JSR 303的1.

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

    我们这里使用hibernate-validator作为对象参数验证器,所以在正式介绍SpringBoot参数验证之前,需要先简单了解一下hibernate-validator的使用. hibernate-validator基本使用 引入依赖 <dependency>     <groupId>org.hibernate</groupId>     <artifactId>hibernate-validator</artifactId>     &

  • SpringBoot参数校验与国际化使用教程

    一.参数校验 springboot 使用校验框架validation校验方法的入参 SpringBoot的Web组件内部集成了hibernate-validator,所以我们这里并不需要额外的为验证再导入其他的包. 1.bean 中添加标签 标签需要加在属性上,@NotEmpty标签String的参数不能为空 @Data public class DemoDto { @NotEmpty(message = "名称不能为空") private String name; @Length(m

  • java开发SpringBoot参数校验过程示例教程

    目录 为什么需要参数校验 SpringBoot中集成参数校验 第一步,引入依赖 第二步,定义要参数校验的实体类 常见的约束注解如下: 第三步,定义校验类进行测试 第四步,体验效果 自定义参数校验 第一步,创建自定义注解 第二步,自定义校验逻辑 第三步,在字段上增加注解 第四步,体验效果 分组校验 第一步:定义分组接口 第二步,在模型中给参数分配分组 第三步,给需要参数校验的方法指定分组 第四步,体验效果 小结 大家好,我是飘渺. 前几天写了一篇SpringBoot如何统一后端返回格式?老鸟们都是

  • SpringBoot参数校验的方法总结

    一.前言 在上一篇MyBatis-plus 初体验 中已经简单实现了 MyBatis-Plus 数据库查询.我们知道 CURD 离不开前后端的数据交互,因此参数校验是必不可少的.这篇主要讲一下 SpringBoot 参数校验. 在 Web 开发中经常需要对前端传过来的参数进行校验,例如格式校验.非空校验等,基本上每个接口都需要进行校验.如果使用常规的 IF ELSE 进行校验,随着参数越来越多,校验逻辑的冗余度也越来越高,导致维护性变差.在 Java 中定义了一套基于注解的数据校验规范 Bean

  • 超详细讲解SpringBoot参数校验实例

    目录 使用传统方式的弊端 引入依赖 注解说明 一.对实体类进行校验 1.entity 2.controller 3.编写全局统一异常处理 二.针对单个参数进行校验 三.分组校验 1.entity 2.controller 四.自定义分组校验 1.entity 2.CustomSequenceProvider 3.controller 五.自定义校验 1.定义校验注解 2.实现注解 六.嵌套校验 七.快速失败 注意事项 总结 使用传统方式的弊端 public String addUser(User

  • SpringBoot参数校验Validator框架详解

    目录 SpringBoot 如何进行参数校验 1.集成Validator校验框架 1.1. 引入依赖包 1.2. 定义要参数校验的实体类 1.3. 定义校验类进行测试 1.4. 测试结果1 1.5. 问题 1.6. 将参数异常加入全局异常 1.7. 测试结果2 2. 自定义注解 2.1. 第一步,创建自定义注解 2.2. 第二步,自定义校验逻辑 2.3. 第三步,在字段上增加注解 2.4. 第四步,体验效果 3. 分组校验 3.1. 第一步,定义分组接口 3.2. 第二步,在模型中给参数分配分组

  • SpringBoot参数校验之@Valid的使用详解

    目录 简介 依赖 代码 测试 测试1:缺少字段 测试2:不缺少字段 测试3:缺少字段,后端获取BindResult 简介 说明 本文用示例说明SpringBoot的@Valid的用法. 依赖 <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> </dependency> 代码 Contr

  • SpringBoot参数校验之@Validated的使用详解

    目录 简介 依赖 用法1:不分组 代码 测试 用法2:分组 代码 测试 简介 说明 本文用示例说明SpringBoot的@Validated的用法. 依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> 它里边依赖了hibernat

  • SpringBoot各种参数校验的实例教程

    目录 简单使用 引入依赖 requestBody参数校验 requestParam/PathVariable参数校验 统一异常处理 进阶使用 分组校验 嵌套校验 集合校验 自定义校验 编程式校验 快速失败(Fail Fast) @Valid和@Validated区别 实现原理 requestBody参数校验实现原理 方法级别的参数校验实现原理 总结 简单使用 Java API规范(JSR303)定义了Bean校验的标准validation-api,但没有提供实现.hibernate valida

随机推荐