java中优雅的参数校验方法

2023-11-12

一、引子

要对方法的参数进行校验,最简单暴力的写法是这个样子:

    public static void utilA(String a,BigDecimal b){
        if (StringUtils.isEmpty(a)){
            System.out.println("a不可为空");
            return;
        }
        if (b == null){
            System.out.println("b不可为空");
            return;
        }
        if (b.compareTo(BigDecimal.ZERO) != 1){
            System.out.println("b的取值范围不正确");
            return;
        }
        System.out.println("do something");
    }

这样做从功能角度来说一点问题也没有。

但是从代码的长期维护性上来说,代码复用率低,校验规则一旦多起来很难维护,而且怎么看怎么显得笨拙,对于有一点追求的工程师来说,这么一大坨还是挺难接受的。

虽然有一些诸如 Preconditions(com.google) 的解决方案,但很难适应所有的场景,用起来也没到非常得心应有的地步。

二、如何优雅地校验参数,Spring官方推荐的,语义清晰的优雅的方法级别校验(入参校验、返回值校验)

2-1、“官方指导意见”
Spring官方在SpringBoot文档中,关于参数校验(Validation)给出的解决方案是这样的:

@Service
@Validated
public class MyBean {

    public Archive findByCodeAndAuthor(@Size(min = 8, max = 10) String code,
            Author author) {
        ...
    }

}



Spring Boot 官网文档 《37. Validation》

也就是说,使用 JSR-303 规范,直接利用注解进行参数校验。

(JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是 Hibernate Validator)

2-2、注解用法说明

2.2.1.注解简介

对于简单类型参数(非Bean),直接在参数前,使用注解添加约束规则。注解如下所示:

@AssertTrue / @AssertFalse 
验证适用字段:boolean
注解说明:验证值是否为true / false

@DecimalMax / @DecimalMin
验证适用字段:BigDecimal,BigInteger,String,byte,short,int,long
注解说明:验证值是否小于或者等于指定的小数值,要注意小数存在精度问题

@Digits
验证适用字段:BigDecimal,BigInteger,String,byte,short,int,long
注解说明:验证值的数字构成是否合法
属性说明:integer:指定整数部分的数字的位数。fraction: 指定小数部分的数字的位数。

@Future / @Past
验证适用字段:Date,Calendar
注解说明:验证值是否在当前时间之后 / 之前
属性说明:公共

@Max / @Min
验证适用字段:BigDecimal,BigInteger,String,byte,short,int,long
注解说明:验证值是否小于或者等于指定的整数值
属性说明:公共
注意事项:建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单提交的值为“”时无法转换为int

@NotNull / @Null
验证适用字段:引用数据类型
注解说明:验证值是否为非空 / 空
属性说明:公共

@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格. 
@NotEmpty 检查约束元素是否为Null或者是EMPTY.
@NotBlank 与 @NotEmpty 的区别:空格(" ")对于 NotEmpty 是合法的,而 NotBlank 会抛出校验异常

@Pattern
验证适用字段:String
注解说明:验证值是否配备正则表达式
属性说明:regexp:正则表达式flags: 指定Pattern.Flag 的数组,表示正则表达式的相关选项。

@Size
验证适用字段:String,Collection,Map,数组
注解说明:验证值是否满足长度要求
属性说明:max:指定最大长度,min:指定最小长度。

@Length(min=, max=):专门应用于String类型

@Valid
验证适用字段:递归的对关联对象进行校验
注解说明:如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验(是否进行递归验证)
属性说明:无

@Range(min=, max=) 被指定的元素必须在合适的范围内 

@CreditCardNumber信用卡验证 

@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。 

@URL(protocol=,host=, port=,regexp=, flags=)

2.2.2使用

1.引入依赖

 <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.1.5.Final</version>
        </dependency>


2.在对应字段上添加注解,方法被调用时,如果传入的实际参数与约束规则不符,会直接抛出 ConstraintViolationException ,表明参数校验失败。


import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;

/**
 * @Author: wangxia
 * @Date: 2021/10/20 16:30
 */
public class TestPerson {

    @NotEmpty(message = "用户名不能为空")
    private String username;

    @Min(value = 0,message = "年龄不能小于0岁")
    @Max(value =150,message = "年龄不能大于150岁")
    private int age;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}


3..对于Bean类型的参数,在Bean内部的各个字段上面追加约束注解,然后在方法的参数前面添加 @Validated或@Valid注解即可。示例:

@RequestMapping("/")
@RestController
public class TestValidatController {

    @PostMapping("/testValid")
    public String testValid(@Validated @RequestBody TestPerson testPerson){
        return "测试成功";
    }

}

4.优雅捕获异常,这一步可以省略,但是请求时会直接返回,400的异常提示,不太优雅。

@ControllerAdvice
@ResponseBody 
public class MethodArgumentNotValidHandel {


    @ExceptionHandler(value=MethodArgumentNotValidException.class)
    public JSONObject MethodArgumentNotValidHandler(HttpServletRequest request,
                                                    MethodArgumentNotValidException exception) throws Exception
    {
        JSONObject result=new JSONObject();
        result.put("code","fail");
        JSONObject errorMsg=new JSONObject();
        for (FieldError error : exception.getBindingResult().getFieldErrors()) {
            errorMsg.put(error.getField(),error.getDefaultMessage());
        }
        result.put("msg",errorMsg);
        return result;
    }

}

添加优雅捕获的异常提示:

未添加优雅捕获的异常提示:

本章内容到此就结束啦,检验原理简介

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java中优雅的参数校验方法 的相关文章

随机推荐

  • Structural Time Series modeling in TensorFlow Probability

    在邯郸学步后 想要深入用好Tensorflow中的STS model 还是要静下心来 好好阅读点材料 f t f 1
  • 分页插件pagehelper配置和 使用;

    先看结论 在看代码是实现 代码就这么多 现在来看配置 配置 1 pom xml加入这个依赖 com github pagehelper pagehelper 3 7 5 com github jsqlparser jsqlparser 0
  • 关于HashMap扩容造成死循环的介绍

    一 造成死循环的原因 HashMap扩容导致死循环的主要原因在于扩容后链表中的节点在新的hash桶使用头插法插入 新的hash桶会倒置原hash桶中的单链表 那么在多个线程同时扩容的情况下就可能导致产生一个存在闭环的单链表 从而导致死循环
  • 虚幻4学习笔记(10)蓝图接口、拾取物品-射线检测

    虚幻4学习笔记 蓝图接口 拾取物品 射线检测 骨架网格体和静态网格体的区别 骨架网格体设置碰撞 B站UP谌嘉诚课程 https www bilibili com video BV164411Y732 蓝图接口 添加 内容浏览器 右键 蓝图
  • 多模态简介

    1 多模态定义 多模式深度学习是一个机器学习子领域 旨在训练人工智能模型来处理和发现不同类型数据 模式 之间的关系 通常是图像 视频 音频和文本 通过结合不同的模态 深度学习模型可以更普遍地理解其环境 因为某些线索仅存在于某些模态中 想象一
  • VMware Tools安装(实现物理机与虚拟机文件互拷)

    1 开启虚拟机 2 点击VMware菜单上的虚拟机 弹出的菜单中点击安装VMware Tools 3 点击DVD 出现右边如图 4 复制VMware Tools压缩文件到opt文件夹 复制时可能出现下图描述 5 解决方法 1 打开终端 输入
  • 你了解System.out.println()的真正含义吗?

    在Java编程中 我们常常用 System out println 来输出字符串 也许我们都已经猜到println 是方法名 但System是什么 out又是什么呢 其实System是java lang里面的一个类 如下图 而out就是Sy
  • IDEA中/** 内容 */注释的快捷键

    在 IDEA 中 你可以使用快捷键 来快速生成 内容 注释 要使用此快捷键 请在你想要添加注释的代码行上按 Ctrl Windows 系统 或 Command Mac 系统 如果你想要撤销注释 可以再次按一次快捷键即可 注意 你必须在代码行
  • 设计模式学习笔记(七)之模板方法模式(Template Method)

    设计模式学习笔记 七 之模板方法模式 Template Method 最近实习工作稍微没有那么忙了 继续抽些晚上时间学习一下设计模式 以下是看设计模式书的学习笔记 关于模式定义之类的内容是在自己理解之后进行摘录的 希望对大家有用 代码下载链
  • SpringBoot获取微信公众号(小程序)access_token 使用Redis存储

    文章目录 前言 一 导入依赖 二 编写配置 1 personal yaml配置文件 2 WeChatBean实体类 3 编写RestTemplateConfig 4 开启定时任务 三 实现生成和存储access token 1 基本介绍 2
  • 路飞IT全学科实战项目5年黑金卡

    正在代理路飞IT全学科实战项目5年黑金卡 文末有联系方式 包含Python开发 Linux云计算 前端开发 Golang开发 AI 数据分析 网络安全 技术生涯 C语言 JAVA开发 测试 PHP 视频讲解 项目源码内容非常详细 开通黑金卡
  • 浅入深谈:如何更好地理解面向对象编程与面向过程编程的本质区别?

    今天 我们以一个例子 如打扫房间 来说明面向过程和面向对象在程序流程上的不同之处 在菜鸟分析看来 面向过程就是将编程当成是做一件事 要按步骤完成 每一步就是一个过程 比如菜鸟分析要打扫房间这件事 需要先取扫帚 然后仔仔细细打扫每一处 最后将
  • springboot理论知识汇总(图文解析)

    MVC HTTP请求处理流程 参数绑定 不同注解修饰的参数都有支持的方法参数处理器 例如 RequestParam对应的是RequestParamMethodArgumentResolver 在请求处理流程中的调用目标方法环节 会使用对应的
  • 语义分割混淆矩阵、 mIoU、mPA计算

    一 操作 import cv2 img gray cv2 imread nezha jpg cv2 IMREAD GRAYSCALE for i in range 22 dst cv2 applyColorMap img gray i cv
  • Scratch基础-积木讲解-必学(2000字)

    上次那篇文章有小伙伴跟Rocky丶说教程看不大懂 那我今天来给大家分享自己对scratch中每一个积木的认识 运用 后半部分Rocky丶可能没时间更新了 因为要上课 作业做不完 而且初三任务较重 我让我的好朋友PLTS帮我慢慢补咯 希望CS
  • vs2010环境下提示找不到d3dx9.h

    无法打开d3dx9 h 我们知道d3dx9 h是在DirectX SDK中的 我们只是需要下载下来就可以了 下载地址为 http www microsoft com en us download details aspx id 6812 如
  • 如何在 Luminar 4 中​使用AI天空更换工具?

    如何在 Luminar 4 中使用AI天空更换工具 如果照片缺少引人入胜的天空 AI天空更换工具可以轻松替换它 该工具设计用于平坦或暴风雨的天空 但通常可以通过改进滑块进行调整以适用于大多数天空 AI天空更换工具利用人工智能的力量自动分析图
  • 【JavaScript】(一)类型转换

    JS支持自动类型转换 其功能非常强大 首先看一段代码 结果如下 由此可见执行减法运算的时候 自动执行算术运算 但是执行加法运算的时候 默认将 作为连接符 它的转换规律如下 对于减号运算符 因为字符串不支持减法运算 所以系统自动将字符串转换成
  • Loongnix单机部署Ceph(LoongArch架构、Ceph N版、手动部署MON、OSD、MGR、Dashboard服务)

    基础环境信息 CPU 龙芯3C5000L 2 内存 128G 硬盘 系统盘 一块512G的NVME的SSD 数据盘 三块16T的HDD 操作系统版本 Loongnix 8 4 Ceph版本 Ceph 14 2 21 Nautilus Cep
  • java中优雅的参数校验方法

    一 引子 要对方法的参数进行校验 最简单暴力的写法是这个样子 public static void utilA String a BigDecimal b if StringUtils isEmpty a System out printl