🔍 Bus Validate:轻量级 Java 验证框架
强大、灵活且易于使用的验证框架
Bus Validate 是一个轻量级、高性能的 Java 验证框架,旨在简化企业应用程序中的数据验证。它提供丰富的内置验证器,同时支持通过基于注解的配置自定义验证逻辑。
核心特性 :
基于注解 :使用 Java 注解进行声明式验证
可扩展 :易于创建自定义验证器
零依赖 :轻量级设计,最小依赖
类型安全 :编译时验证支持
嵌套验证 :支持验证复杂对象图
分组验证 :使用验证组验证不同场景
灵活的错误处理 :可自定义错误消息和代码
丰富的内置验证器 :20+ 开箱即用的验证注解
空安全处理 :整个框架中适当的空值处理
嵌套对象验证 :深度验证复杂对象结构
集合验证 :验证数组、集合和映射
条件验证 :基于不同场景的基于分组的验证
自定义验证器 :轻松创建自己的验证逻辑
消息模板 :灵活的错误消息格式,支持占位符
功能
好处
描述
延迟求值
低开销
仅在显式调用时验证
反射缓存
快速启动
缓存反射元数据以提高性能
最小依赖
小占用
仅依赖 bus-logger 和 Lombok
线程安全
并发使用
在多线程环境中安全使用
字符串验证 :邮箱、电话、URL、IP 地址、正则表达式、长度、大小
数字验证 :范围、倍数、正/负
类型验证 :NotNull、NotEmpty、NotBlank
集合验证 :使用 @Each 进行大小、元素验证
自定义逻辑 :条件、比较、等于、In/NotIn
区域支持 :中文字符、公民身份证、手机号码
<dependency >
<groupId >org.miaixz</groupId >
<artifactId >bus-validate</artifactId >
<version >8.x.x</version >
</dependency >
import lombok .Data ;
import org .miaixz .bus .validate .magic .annotation .*;
@ Data
public class User {
@ NotNull (errmsg = "用户 ID 不能为空" )
private Long id ;
@ NotBlank (errmsg = "用户名不能为空" )
@ Size (min = 3 , max = 20 , errmsg = "用户名长度必须在 3 到 20 个字符之间" )
private String username ;
@ Email (errmsg = "邮箱格式无效" )
private String email ;
@ Mobile (errmsg = "手机号码无效" )
private String phone ;
@ Chinese (errmsg = "姓名必须仅包含中文字符" )
private String realName ;
@ Date (errmsg = "日期格式无效" )
private String birthday ;
@ NotNull
@ Compare (field = "password" , errmsg = "密码不匹配" )
private String confirmPassword ;
private String password ;
}
import org .miaixz .bus .validate .Builder ;
import org .miaixz .bus .validate .Collector ;
public class UserService {
public void createUser (User user ) {
// 执行验证
Collector result = Builder .on (user ).access ();
// 检查验证是否通过
if (!result .isPass ()) {
// 处理验证错误
result .getResult ().forEach (error -> {
Criterion criterion = error .getCriterion ();
System .err .println ("验证失败:" + criterion .getErrmsg ());
System .err .println ("字段:" + criterion .getField ());
System .err .println ("值:" + criterion .getParam ("value" ));
});
throw new ValidationException ("用户验证失败" );
}
// 继续创建用户
saveUser (user );
}
}
注解
描述
示例
@NotNull
验证值不为 null
@NotNull(errmsg = "ID 不能为空")
@Null
验证值为 null
@Null(errmsg = "必须为 null")
@NotEmpty
验证值不为空(数组、集合、映射)
@NotEmpty(errmsg = "列表不能为空")
@NotBlank
验证字符串不为空(去除空格后长度 > 0)
@NotBlank(errmsg = "名称不能为空")
@Blank
验证字符串为空
@Blank(errmsg = "必须为空")
注解
描述
示例
@Email
验证邮箱格式
@Email(errmsg = "邮箱无效")
@Mobile
验证手机号码
@Mobile(errmsg = "手机无效")
@Phone
验证电话号码
@Phone(errmsg = "电话无效")
@Chinese
验证中文字符
@Chinese(errmsg = "必须为中文")
@English
验证英文字符
@English(errmsg = "必须为英文")
@URL
验证 URL 格式
@URL(errmsg = "URL 无效")
@IPAddress
验证 IP 地址
@IPAddress(errmsg = "IP 无效")
@CitizenId
验证中国公民身份证
@CitizenId(errmsg = "身份证无效")
注解
描述
示例
@Size
验证数组、集合、映射或字符串长度的大小
@Size(min = 1, max = 10)
@Length
验证字符串长度
@Length(min = 5, max = 100)
@Date
验证日期格式
@Date(format = "yyyy-MM-dd")
注解
描述
示例
@IntRange
验证整数范围
@IntRange(min = 0, max = 100)
@Multiple
验证值是否为指定数字的倍数
@Multiple(value = 5)
注解
描述
示例
@Compare
比较两个字段
@Compare(field = "password")
@Equals
检查值是否等于指定值
@Equals(value = "ACTIVE")
@In
检查值是否在指定值中
@In(values = {"A", "B", "C"})
@NotIn
检查值是否不在指定值中
@NotIn(values = {"X", "Y", "Z"})
@InEnum
检查值是否为有效枚举值
@InEnum(StatusEnum.class)
注解
描述
示例
@True
验证值为 true
@True(errmsg = "必须为 true")
@False
验证值为 false
@False(errmsg = "必须为 false")
注解
描述
示例
@Regex
使用正则表达式验证
@Regex(value = "^[A-Z]\\d{5}$")
@Each
验证集合中的每个元素
@Each @NotNull
@Valid
启用嵌套验证
@Valid(inside = true)
@Group
指定验证组
@Group({"create", "update"})
@ Data
public class Order {
@ NotNull
private Long id ;
@ Valid
@ NotNull
private User user ;
@ Valid
@ NotEmpty
private List <OrderItem > items ;
}
@ Data
public class OrderItem {
@ NotNull
private Long productId ;
@ IntRange (min = 1 , max = 100 )
private Integer quantity ;
@ NotNull
private BigDecimal price ;
}
// 验证
Collector result = Builder .on (order ).access ();
@ Data
public class Product {
@ NotNull (group = {"create" , "update" })
private Long id ;
@ NotBlank (group = "create" )
@ Size (min = 3 , max = 50 , group = {"create" , "update" })
private String name ;
@ Null (group = "create" )
@ NotNull (group = "update" )
private LocalDateTime updateTime ;
}
// 使用特定组验证
Context context = Context .newInstance ();
context .addGroups ("create" );
Collector result = Builder .on (product , context ).access ();
import org .miaixz .bus .validate .magic .Matcher ;
public class AgeValidator implements Matcher {
@ Override
public boolean on (Object value , Context context ) {
if (value == null ) {
return true ; // null 值被视为有效
}
int age = (Integer ) value ;
return age >= 18 && age <= 120 ;
}
}
import org .miaixz .bus .validate .Builder ;
import org .miaixz .bus .validate .magic .annotation .Complex ;
import java .lang .annotation .*;
@ Documented
@ Retention (RetentionPolicy .RUNTIME )
@ Target ({ElementType .ANNOTATION_TYPE , ElementType .METHOD , ElementType .PARAMETER , ElementType .FIELD })
@ Complex (value = "AgeValidator" , clazz = AgeValidator .class )
public @interface ValidAge {
String errcode () default ErrorCode ._PARAMETER_VALIDATE ;
String errmsg () default "年龄必须在 18 到 120 岁之间" ;
String [] group () default {};
String field () default Builder .DEFAULT_FIELD ;
}
public class Person {
@ ValidAge
private Integer age ;
}
public class BatchRequest {
@ Each @ NotNull
@ Each @ Size (min = 36 , max = 36 )
private List <String > userIds ;
@ Valid
private List <User > users ;
}
@ Data
public class RegistrationForm {
private String userType ; // "individual" 或 "company"
@ NotBlank
private String username ;
// 仅在 userType 为 "company" 时验证
@ NotBlank (errmsg = "公司名称必填" )
@ Reflect (condition = "userType == 'company'" )
private String companyName ;
}
// ✅ 推荐:清晰且具体
@ NotBlank (errmsg = "邮箱地址必填" )
@ Email (errmsg = "邮箱地址必须为有效格式(例如:user@example.com)" )
private String email ;
// ❌ 不推荐:模糊且无帮助
@ NotBlank (errmsg = "无效" )
private String email ;
// ✅ 推荐:全面验证
@ NotBlank
@ Size (min = 8 , max = 20 )
@ Regex (value = "^(?=.*[A-Za-z])(?=.*\\ d)[A-Za-z\\ d@$!%*#?&]+$" ,
errmsg = "密码必须包含字母和数字" )
private String password ;
public class User {
@ NotNull (group = {"create" })
@ Null (group = {"update" })
private Long id ;
@ NotBlank (group = {"create" , "update" })
private String username ;
}
// 大多数验证器默认跳过空值
// 显式使用 @NotNull 当空值无效时
@ NotNull
@ Size (min = 1 , max = 100 )
private String name ;
// 对于可选字段,避免使用 @NotNull
@ Email // 允许空,但如果非空则验证
private String optionalEmail ;
// 始终对嵌套对象使用 @Valid
@ Valid
@ NotNull
private Address address ;
@ Valid
@ NotEmpty
private List <Phone > phones ;
// 在错误消息中使用占位符
@ Size (min = 3 , max = 20 , errmsg = "用户名长度必须在 ${min} 到 ${max} 个字符之间" )
private String username ;
// 可用占位符:${field}、${value}、${min}、${max} 等
Collector result = Builder .on (user ).access ();
if (!result .isPass ()) {
Map <String , String > errors = new HashMap <>();
result .getResult ().forEach (error -> {
Criterion c = error .getCriterion ();
errors .put (c .getField (), c .getErrmsg ());
});
return ResponseEntity .badRequest ().body (errors );
}
// 是的,使用编程式验证
Context context = Context .newInstance ();
Collector result = Builder .on (value , new Annotation []{}, context ).access ();
// 使用消息代码并通过 MessageSource 解析
@ Email (errcode = "validation.email.invalid" )
private String email ;
// 在服务中
String message = messageSource .getMessage (
criterion .getErrcode (),
new Object []{criterion .getField ()},
LocaleContextHolder .getLocale ()
);
@ Valid (skip = {"internalField" , "tempField" })
private MyClass object ;
public void updateUser (@ Valid User user ) {
// 验证将自动触发
}
// 使用 @Each 进行元素级验证
@ Each @ NotNull
@ Each @ Size (min = 1 , max = 100 )
private List <String > items ;
// 对于非常大的集合,考虑批量验证
List <List <String >> batches = Lists .partition (items , 1000 );
for (List <String > batch : batches ) {
Builder .on (batch ).access ();
}
@ Valid (inside = false )
private User user ; // 仅验证用户本身,不验证嵌套字段
@ Data
public class Product {
@ NotBlank (group = {"create" , "update" })
private String name ;
@ Null (group = "create" )
@ NotNull (group = "update" )
private Long id ;
}
// 验证多个组
Context context = Context .newInstance ();
context .addGroups ("create" , "update" );
Builder .on (product , context ).access ();
Bus Validate 版本
JDK 版本
说明
8.x
17+
需要 Java 17 或更高版本
7.x
11+
支持 Java 11 及更高版本
注解
目标类型
空值处理
描述
@NotNull
所有
❌ 无效
值不能为 null
@Null
所有
✅ 有效
值必须为 null
@NotEmpty
数组、集合、映射、字符串
❌ 无效
值不能为空
@NotBlank
CharSequence
❌ 无效
去除空格后的长度必须 > 0
@Blank
CharSequence
✅ 有效
去除空格后的长度必须为 0
@Email
CharSequence
✅ 有效
必须为有效邮箱格式
@Mobile
CharSequence
✅ 有效
必须为有效手机号码
@Phone
CharSequence
✅ 有效
必须为有效电话号码
@Chinese
CharSequence
✅ 有效
必须包含中文字符
@English
CharSequence
✅ 有效
必须包含英文字符
@IPAddress
CharSequence
✅ 有效
必须为有效 IP 地址
@CitizenId
CharSequence
✅ 有效
必须为有效公民身份证
@Size
数组、集合、映射、CharSequence
✅ 有效
大小/长度必须在范围内
@Length
CharSequence
✅ 有效
长度必须在范围内
@Date
CharSequence
✅ 有效
必须匹配日期格式
@IntRange
数字、CharSequence
✅ 有效
必须在整数范围内
@Multiple
数字、CharSequence
✅ 有效
必须为值的倍数
@True
布尔
✅ 有效
必须为 true
@False
布尔
✅ 有效
必须为 false
@Compare
所有
✅ 有效
必须与其他字段比较
@Equals
所有
✅ 有效
必须等于指定值
@In
所有
✅ 有效
必须在指定值中
@NotIn
所有
✅ 有效
必须不在指定值中
@InEnum
CharSequence
✅ 有效
必须为有效枚举值
@Regex
CharSequence
✅ 有效
必须匹配正则表达式模式
@Each
数组、集合
-
验证每个元素
@Valid
所有
-
启用嵌套验证
@ Data
public class LoginForm {
@ NotBlank
@ Email
private String email ;
@ NotBlank
@ Size (min = 8 , max = 32 )
private String password ;
@ True (errmsg = "您必须接受条款和条件" )
private Boolean acceptTerms ;
}
@ Data
public class CreateOrderRequest {
@ NotNull
private Long userId ;
@ Valid
@ NotEmpty
private List <OrderItem > items ;
@ NotNull
@ Compare (field = "totalAmount" , errmsg = "支付金额必须与总计匹配" )
private BigDecimal paymentAmount ;
private BigDecimal totalAmount ;
}
@ Data
public class UserDataImport {
@ Each @ NotNull
@ Each @ CitizenId
private List <String > citizenIds ;
@ Each @ Date (format = "yyyy-MM-dd" )
private List <String > birthDates ;
@ Valid
private List <User > users ;
}