注解式参数校验@Valid,拒绝if-else炼狱

前言

在软件开发中,与客户进行数据的交互是比较频繁的数据采集方式,而为了确保数据的正确落库,数据校验的部分必不可少。参数校验具体指的是对输入数据的大小、类型、正则匹配等对数据本身属性的校验,这一块的校验通常是在前端进行第一轮校验,确保参数具备一定逻辑正确性才将其打包至后端处理,而为了进一步增强安全性,也同样需要在后端板块进行二次校验。而对于此类校验,最常见也是最臃肿的处理方案就是if-else炼狱,如果说参数个数较少,那么无可厚非,但如果包含了七八个参数,那么这就很拉跨了,下面介绍一种基于注解的校验方案,进一步优化校验参数代码的可读性。


效果演示

本例子基于通过在实体类映射接收请求参数的MVC接口,对实体类中需要对属性进行如下验证:

  • name - 用户姓名,不能为空;
  • age - 年龄,大于0小于20;
  • phone - 手机号,满足手机号格式;

实体类代码

less 复制代码
 @Data
 public class TestPojo {
   @NotBlank(message = "不满足时抛出的自定义异常回馈信息")
   private String name;
   
   @Min(value = 0, message = "不满足时抛出的自定义异常回馈信息")
   @Max(value = 20, message = "不满足时抛出的自定义异常回馈信息")
   private Integer age;
   
   @Pattern(regexp = "^((13[0-9])|(15[^4])|(18[0-9])|(17[0-9])|(147))\d{8}$", message = "不满足时抛出的自定义异常回馈信息")
   private String phone;
 }

业务接口

less 复制代码
@PostMapping("/test")
public ResultVO test(@Valid @RequestBody TestPojo testPojo) {
     // 直接写业务代码,无需编写if-else校验....
    
     return ResultVO.ok("响应数据");
 }

结果VO类

kotlin 复制代码
@Data
public class ResultVO<T> implements Serializable {
    private int code;
    private boolean success;
    private T data;
    private String msg;
​
    private ResultVO(int code, T data, String msg) {
        this.code = code;
        this.data = data;
        this.msg = msg;
        this.success = code == 200;
    }
​
    public static <T> ResultVO<T> ok(T data) {
        return new ResultVO<>(200, data, null);
    }
​
    public static <T> ResultVO<T> error(String msg) {
        return new ResultVO<>(500, null, msg);
    }
}

全局异常处理类

java 复制代码
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    /*  
     *  这里的BindException不是自定义的,是该参数校验框架自带的
     *  当设置的参数规则不满足,就会抛出该类型的异常,并且把不满足的哪个校验参数自定义的异常信息封装到该对象中
     */
    @ExceptionHandler(BindException.class)  
    public ResultVO handleError(BindException e) {
        BindingResult bindingResult = e.getBindingResult();
        return R.error(bindingResult.getFieldError().getDefaultMessage());
    }
}

通过以上代码,就可以实现对接收的请求数据的参数校验,并且当校验失败就会抛出指定异常被异常处理类进行捕捉处理,返回自定义的不满足参数所对应的自定义提示信息


快速使用

引入依赖

xml 复制代码
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-validation</artifactId>
 </dependency>

编写校验实体类

其实这一块和上方"结果VO类"的演示中可以了解到使用的方式,咱主要要知道它有哪些常用的校验注解可以使用就好

常用注解 作用解释
@NotNull 值不能为null
@NotEmpty 字符串、集合或数组的值不能为空,即长度大于0
@NotBlank 字符串的值不能为空白,即不能只包含空格
@Size 字符串、集合或数组的大小是否在指定范围内
@Min 数值的最小值
@Max 数值的最大值
@DecimalMin 数值的最小值,可以包含小数
@DecimalMax 数值的最大值,可以包含小数
@Pattern 字符串是否匹配指定的正则表达式

还有许多有关的校验可以自行查询,这里不作过多赘述

校验失败异常捕获处理

java 复制代码
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    /*  
     *  这里的BindException不是自定义的,是该参数校验框架自带的
     *  当设置的参数规则不满足,就会抛出该类型的异常,并且把不满足的哪个校验参数自定义的异常信息封装到该对象中
     */
    @ExceptionHandler(BindException.class)  
    public ResultVO handleError(BindException e) {
        BindingResult bindingResult = e.getBindingResult();
        String 自定义的不满足参数校验结果信息 = bindingResult.getFieldError().getDefaultMessage();
    }
}

启用校验

其实就是在接收实体类上加一个@Valid注解就可以启用实体类中校验逻辑

less 复制代码
@PostMapping("/test")
public void test(@Valid @RequestBody TestPojo testPojo) {
     // 直接写业务代码,无需编写if-else校验....
 }

也许会有疑惑,一个实体类我不一定要用来校验数据呀,这样子设置后会不会以后用这个实体类都要进行参数校验了?并不会,不想校验就不要加@Valid注解就完事了嘛


总结

通过以上的方案,我们可以较为简洁实现简单的参数校验,为shi山的削减贡献了一份力量,当然,我们会发现通过这种方案,我们能够校验的方式实际上是比较单薄的,往往我们需要针对项目业务需求对参数进行一些自定义的校验逻辑,那么这点可以参考我写的另一篇文章:基于 AOP + 自定义注解 的校验业务讲解,希望本文对大家有所帮助。

相关推荐
程序员爱钓鱼4 分钟前
Go语言实战案例-实现简易定时提醒程序
后端·google·go
迦蓝叶4 分钟前
JAiRouter 配置文件重构纪实 ——基于单一职责原则的模块化拆分与内聚性提升
java·网关·ai·重构·openai·prometheus·单一职责原则
ST.J7 分钟前
系统架构思考20241204
java·笔记·系统架构
TDengine (老段)26 分钟前
TDengine 时间函数 TIMETRUNCATE 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
堕落年代27 分钟前
Spring Boot HTTP状态码详解
spring boot·后端·http
Victor35632 分钟前
Redis(49)Redis哨兵如何实现故障检测和转移?
后端
Victor35635 分钟前
Redis(48)Redis哨兵的优点和缺点是什么?
后端
IT_陈寒1 小时前
Python异步编程的7个致命误区:90%开发者踩过的坑及高效解决方案
前端·人工智能·后端
绝无仅有1 小时前
三方系统callback回调MySQL 报错排查与解决:mysql context cancel
后端·面试·github
绝无仅有1 小时前
项目三方合同提交失败的MySQL 错误排查与解决:`context deadline exceeded`
后端·面试·github