Java参数校验神器:ValidParam 一行代码搞定判空
·
Java 参数验证工具实战:ValidParam 一个方法消灭 80% 的 if-else 判空
选题说明:每个 Java 方法开头都有一堆
if (param == null)if (str.isEmpty())if (list.size() == 0)的参数校验代码,既冗余又容易遗漏。ValidParam用统一判空语义覆盖 null/空串/空集合/空数组/空 Map 等全场景,配合required系列方法一行搞定多参数校验,让方法入口的防御代码从 10 行缩减到 1 行。
一、先看痛点:每个方法开头的"防御性编程"
public void createUser(String name, String phone, List<String> roles) {
// 参数校验 —— 每个方法都要写一遍
if (name == null || name.isEmpty() || "null".equals(name)) {
throw new IllegalArgumentException("name不能为空");
}
if (phone == null || phone.isEmpty()) {
throw new IllegalArgumentException("phone不能为空");
}
if (roles == null || roles.isEmpty()) {
throw new IllegalArgumentException("roles不能为空");
}
// 真正的业务逻辑从这里才开始...
}
问题:
- 判空逻辑不统一:有的用
== null,有的用"".equals(),有的用StringUtils.isBlank() - 代码冗长:3 个参数就要写 9 行校验代码
- 容易遗漏:新人入职可能只校验部分参数
- 集合/数组/Map 各有一套判空写法,记不住
ValidParam 的设计目标:统一判空语义,一行校验多参数,覆盖所有数据类型。
环境准备:
<!-- Spring Boot 2.x (javax) -->
<dependency>
<groupId>com.gitee.apanlh</groupId>
<artifactId>pan-common</artifactId>
<version>2.0.6</version>
</dependency>
<!-- Spring Boot 3.x (jakarta) -->
<dependency>
<groupId>com.gitee.apanlh</groupId>
<artifactId>pan-common</artifactId>
<version>3.0.6</version>
</dependency>
二、核心 API 速览
ValidParam 的方法按功能分为 5 类:
| 分类 | 核心方法 | 说明 |
|---|---|---|
| 必填校验 | required(String...) |
多参数一行校验 |
| 空值判断 | isEmpty() / isNotEmpty() |
全类型重载(字符串/集合/数组/Map) |
| null 判断 | isNull() / isNotNull() |
支持单对象和多对象 |
| 类型判断 | isNumber() / isLetter() |
数字、字母、大小写判断 |
| 特殊检测 | isContainsFullWidth() |
全角字符检测(防用户输入全角符号) |
三、必填校验:required 系列
3.1 required:最常用的一行校验
// 校验多个字符串参数,任一为 null 或空则返回 false
boolean valid = ValidParam.required("name", "age", "phone"); // true
// 实际使用 —— 方法入口一行搞定
public void createUser(String name, String phone, String email) {
if (!ValidParam.required(name, phone, email)) {
throw new IllegalArgumentException("必填参数不能为空");
}
// 业务逻辑...
}
对比手写判空:
// 手写:3 个参数 9 行
if (name == null || name.isEmpty() || "null".equals(name)) return false;
if (phone == null || phone.isEmpty() || "null".equals(phone)) return false;
if (email == null || email.isEmpty() || "null".equals(email)) return false;
// ValidParam:1 行
if (!ValidParam.required(name, phone, email)) return false;
3.2 requiredContainsSpace:额外检查空格
// 除了判空,还检查是否包含空格(含全角空格)
boolean valid = ValidParam.requiredContainsSpace("hello", "world"); // true
boolean invalid = ValidParam.requiredContainsSpace("hello world"); // false — 包含空格
boolean invalid2 = ValidParam.requiredContainsSpace("hello world"); // false — 全角空格
3.3 requiredMapByValue:Map 值校验
Map<String, String> map = new HashMap<>();
map.put("name", "张三");
map.put("age", "25");
// 校验 Map 中所有 value 非 null(字符串 value 还需非空)
boolean valid = ValidParam.requiredMapByValue(map); // true
map.put("empty", "");
boolean invalid = ValidParam.requiredMapByValue(map); // false — 存在空值
3.4 requiredBean:对象属性校验
User user = new User();
user.setName("张三");
user.setAge(25);
// 校验对象所有字段值均非 null
boolean valid = ValidParam.requiredBean(user); // true
User emptyUser = new User();
boolean invalid = ValidParam.requiredBean(emptyUser); // false — 所有属性为 null
注意:
requiredBean仅检查直接声明的字段(含私有),不递归校验嵌套对象。
四、空值判断:isEmpty / isNotEmpty
4.1 统一判空语义
isEmpty 覆盖所有数据类型,返回值含义一致:null 或无内容返回 true:
// ========== 字符串 ==========
ValidParam.isEmpty(null); // true
ValidParam.isEmpty(""); // true
ValidParam.isEmpty("null"); // true — 字符串 "null" 也视为空
ValidParam.isEmpty(" "); // false — 空格不算空(用 isBlank 判断)
ValidParam.isEmpty("hello"); // false
// ========== 集合 ==========
ValidParam.isEmpty((List<?>) null); // true
ValidParam.isEmpty(Collections.emptyList()); // true
ValidParam.isEmpty(List.of("a")); // false
// ========== 数组 ==========
ValidParam.isEmpty((int[]) null); // true
ValidParam.isEmpty(new int[0]); // true
ValidParam.isEmpty(new int[]{1, 2}); // false
// ========== Map ==========
ValidParam.isEmpty((Map<?, ?>) null); // true
ValidParam.isEmpty(Collections.emptyMap()); // true
ValidParam.isEmpty(Map.of("k", "v")); // false
// ========== Set ==========
ValidParam.isEmpty((Set<?>) null); // true
ValidParam.isEmpty(Collections.emptySet()); // true
4.2 isNotEmpty:反向判断
ValidParam.isNotEmpty("hello"); // true
ValidParam.isNotEmpty(List.of("a")); // true
ValidParam.isNotEmpty(""); // false
4.3 支持的基本类型数组
// byte/short/int/long/float/double/boolean/char 数组均有重载
ValidParam.isEmpty(new byte[]{1, 2}); // false
ValidParam.isEmpty(new int[0]); // true
ValidParam.isEmpty((long[]) null); // true
ValidParam.isEmpty(new double[]{0.0}); // false
五、null 判断:isNull / isNotNull
5.1 单对象判断
ValidParam.isNull(null); // true
ValidParam.isNull("hello"); // false
ValidParam.isNotNull("hello"); // true
ValidParam.isNotNull(null); // false
5.2 多对象判断(全部为/全部非)
// 全部为 null 才返回 true
ValidParam.isNull(null, null, null); // true
ValidParam.isNull(null, "a", null); // false — 不全是 null
// 全部非 null 才返回 true
ValidParam.isNotNull("a", "b", "c"); // true
ValidParam.isNotNull("a", null, "c"); // false — 有 null
六、对象属性判空:isEmptyBean
// 对象为 null 或所有属性值均为空
ValidParam.isEmptyBean(null); // true
ValidParam.isEmptyBean(new User()); // true — 所有属性默认 null
ValidParam.isEmptyBean(User.of("张三")); // false — name 有值
七、类型与字符判断
7.1 数字判断
// isNumber:严格判断,每个字符必须是 '0'-'9'
ValidParam.isNumber("12345"); // true
ValidParam.isNumber("-123"); // false — 不允许负号
ValidParam.isNumber("12.3"); // false — 不允许小数点
ValidParam.isNumber(""); // false
// isNumeric:允许首位负号,其余必须为数字(不支持小数点)
ValidParam.isNumeric("12345"); // true
ValidParam.isNumeric("-123"); // true — 允许负号
ValidParam.isNumeric("12.3"); // false — 不支持小数点
ValidParam.isNumeric("+123"); // false — 不允许正号
7.2 字母判断
// 单个字符判断
ValidParam.isLetter('A'); // true
ValidParam.isLetter('z'); // true
ValidParam.isLetter('0'); // false
ValidParam.isUpperCaseLetter('A'); // true
ValidParam.isUpperCaseLetter('a'); // false
ValidParam.isLowerCaseLetter('a'); // true
ValidParam.isLowerCaseLetter('A'); // false
八、空格与全角字符检测
8.1 空格检测
// 检测半角空格和全角空格(' ')
ValidParam.isContainsSpace("hello world"); // true — 半角空格
ValidParam.isContainsSpace("hello world"); // true — 全角空格
ValidParam.isContainsSpace("hello"); // false
ValidParam.isContainsSpace(' '); // true
ValidParam.isContainsSpace(' '); // true — 全角空格
8.2 全角字符检测
全角字符是中文输入法下的"胖"字符,如 A(全角 A)、1(全角 1)、,(全角逗号)。用户误输入全角字符是常见的 Bug 来源(如全角数字导致 JSON 解析失败)。
// 检测全角字母、全角数字、全角标点、全角空格
ValidParam.isContainsFullWidth("hello"); // true — 全角字母
ValidParam.isContainsFullWidth("123"); // true — 全角数字
ValidParam.isContainsFullWidth(",。!"); // true — 全角标点
ValidParam.isContainsFullWidth("hello world"); // true — 全角空格
ValidParam.isContainsFullWidth("hello"); // false — 纯半角
实战场景:用户输入清洗
@PostMapping("/user")
public ResultVO<?> createUser(@RequestBody UserDTO dto) {
// 检测用户输入是否包含全角字符
if (ValidParam.isContainsFullWidth(dto.getName())) {
return ResultVO.fail(400, "姓名中包含全角字符,请检查输入法");
}
if (ValidParam.isContainsFullWidth(dto.getPhone())) {
return ResultVO.fail(400, "手机号中包含全角数字,请切换半角输入法");
}
// 业务逻辑...
}
九、实战场景
9.1 Controller 参数校验
@PostMapping("/user")
public ResultVO<?> createUser(@RequestBody Map<String, Object> params) {
String name = (String) params.get("name");
String phone = (String) params.get("phone");
String email = (String) params.get("email");
// 一行校验所有必填参数
if (!ValidParam.required(name, phone, email)) {
return ResultVO.fail(400, "name、phone、email 均为必填项");
}
// 手机号格式校验(配合正则工具)
if (!ValidParam.isNumber(phone) || phone.length() != 11) {
return ResultVO.fail(400, "手机号格式不正确");
}
userService.create(name, phone, email);
return ResultVO.suc();
}
9.2 Service 层业务校验
@Service
public class OrderService {
public Order createOrder(String userId, String productId, int quantity) {
// 参数校验
if (!ValidParam.required(userId, productId)) {
throw new BizException("userId和productId不能为空");
}
if (quantity <= 0) {
throw new BizException("数量必须大于0");
}
// 业务逻辑...
return orderRepository.save(new Order(userId, productId, quantity));
}
}
9.3 Map 参数校验(适配老接口)
// 老系统通过 Map 传参,需要校验所有必填字段
@PostMapping("/legacy/api")
public ResultVO<?> legacyApi(@RequestBody Map<String, String> params) {
if (!ValidParam.requiredMapByValue(params)) {
return ResultVO.fail(400, "所有参数均为必填");
}
// 业务逻辑...
}
9.4 全角字符清洗
// 在保存前检测并提示用户修正
public ResultVO<?> saveArticle(String title, String content) {
if (ValidParam.isContainsFullWidth(title)) {
return ResultVO.fail(400, "标题中包含全角字符,请检查输入法");
}
if (ValidParam.isContainsFullWidth(content)) {
return ResultVO.fail(400, "正文中包含全角字符,请检查输入法");
}
articleService.save(title, content);
return ResultVO.suc();
}
十、与 JSR 303(@NotNull/@NotBlank)的配合
ValidParam 和 JSR 303 注解验证是互补关系,不是替代关系:
| 维度 | JSR 303 注解 | ValidParam |
|---|---|---|
| 使用方式 | 声明式(注解标记字段) | 编程式(方法内调用) |
| 触发时机 | Spring MVC 参数绑定阶段 | 业务逻辑执行阶段 |
| 适用场景 | DTO/VO 字段校验 | Map 参数、动态参数、嵌套校验 |
| 灵活性 | 固定规则 | 可动态组合条件 |
推荐组合使用:
// DTO 字段用 JSR 303
public class UserDTO {
@NotBlank(message = "姓名不能为空")
private String name;
@NotBlank(message = "手机号不能为空")
private String phone;
}
// 业务层用 ValidParam
@Service
public class UserService {
public void processUser(Map<String, String> params) {
// Map 参数无法用 JSR 303,用 ValidParam 校验
if (!ValidParam.requiredMapByValue(params)) {
throw new BizException("参数不完整");
}
// 业务逻辑...
}
}
十一、API 速查表
必填校验
| 方法 | 说明 |
|---|---|
required(String... params) |
所有字符串非 null 且非空 |
requiredContainsSpace(String... params) |
所有字符串非空且不含空格 |
requiredMapByValue(Map<K,V>) |
Map 所有 value 非 null |
requiredBean(T obj) |
对象所有字段非 null |
空值判断
| 方法 | 支持类型 |
|---|---|
isEmpty() / isNotEmpty() |
String, CharSequence, byte[], short[], int[], long[], float[], double[], boolean[], char[], T[], Collection, Map, Set |
isEmptyBean(T obj) |
任意 JavaBean |
null 判断
| 方法 | 说明 |
|---|---|
isNull(T) / isNotNull(T) |
单对象 null 判断 |
isNull(T...) / isNotNull(T...) |
多对象全部为/全部非 null |
类型判断
| 方法 | 说明 |
|---|---|
isNumber(String) |
全为数字(不允许负号、小数点) |
isNumeric(String) |
数值格式(允许首位负号) |
isNumber(char) / isLetter(char) |
单字符判断 |
isUpperCaseLetter(char) / isLowerCaseLetter(char) |
大小写判断 |
特殊检测
| 方法 | 说明 |
|---|---|
isContainsSpace(String) |
含半角或全角空格 |
isContainsFullWidth(String) |
含全角字母/数字/标点/空格 |
十二、注意事项
| 问题 | 说明 |
|---|---|
| isEmpty(String) 对 “null” 返回 true | 字符串 "null" 被视为空,与 StringUtils.isEmpty 行为一致 |
| isNumber vs isNumeric | isNumber 更严格(只允许 0-9),isNumeric 允许首位负号 |
| requiredBean 不递归 | 仅检查直接字段,嵌套对象不递归校验 |
| 全角字符范围 | 全角字母 65281-65374、全角空格 、全角符号 65509 |
| 线程安全 | 所有方法均为静态无状态方法,天然线程安全 |
十三、总结
| 维度 | 手写 if-else | ValidParam |
|---|---|---|
| 代码量 | 3 个参数 9 行 | 1 行 required() |
| 类型覆盖 | 每种类型一套写法 | 统一 isEmpty() 重载 |
| 特殊检测 | 自己写正则 | isContainsFullWidth() 一行 |
| 可读性 | 散落的 if 判断 | 语义明确的方法名 |
| 维护成本 | 每个方法重复 | 统一工具类 |
源码地址:pan-common
如果这篇文章对你有帮助,欢迎点赞、收藏、关注,后续将持续更新 Java 工具类实战系列。
更多推荐
所有评论(0)