
本文探讨了在J*a Bean Validation中,当字段为`null`时,如何聚合多个约束(如`@NotNull`、`@Length`、`@Pattern`)的错误信息及其参数。通过创建自定义复合注解并结合`@ReportAsSingleViolation`和`@OverridesAttribute`,可以实现当一个字段不满足多个条件时,生成一条包含所有相关验证详情的统一错误消息,显著提升用户体验和错误提示的清晰度。
在J*a应用程序开发中,数据验证是确保数据完整性和用户体验的关键环节。Bean Validation(JSR 380)提供了一种标准化的方式来声明和验证J*a对象上的约束。然而,在处理复杂验证场景,特别是当一个字段需要满足多个条件且其中一个条件是@NotNull时,默认的错误信息行为可能无法满足预期。
考虑一个username字段,它有以下约束:
其初始定义可能如下:
立即学习“J*a免费学习笔记(深入)”;
public class User {
@NotNull
@Length(min = 4, max = 64)
@Pattern(regexp = "[A-Za-z0-9]+")
String username;
// ... getters and setters
}当username字段为null时,Bean Validation通常只会报告@NotNull的错误,例如“must not be null”。这是因为@Length和@Pattern等大多数约束注解默认将null视为有效输入,只有当值不为null时才进行实际的长度或模式匹配验证。因此,当字段为null时,其他约束根本不会被触发,也就不会生成相应的错误信息。
一种直观的尝试是直接在@NotNull注解的消息模板中组合所有约束的消息占位符:
public class User {
@NotNull(message = """
{jakarta.validation.constraints.NotNull.message}
AND {org.hibernate.validator.constraints.Length.message}
AND {jakarta.validation.constraints.Pattern.message}""")
@Length(min = 4, max = 64)
@Pattern(regexp = "[A-Za-z0-9]+")
String username;
// ...
}然而,这种方法存在一个问题:虽然消息模板被成功组合,但{min}、{max}和{regexp}等占位符的值不会被正确解析。这是因为这些占位符是@Length和@Pattern注解自身的属性,而不是@NotNull注解的属性。当@NotNull生成消息时,它无法访问其他注解的属性值。最终的错误信息会包含未解析的占位符,例如:“must not be null AND length must be between {min} and {max} AND must match "{regexp}"”。
为了实现当字段为null时,也能统一报告所有相关约束的错误信息,并正确解析其参数,我们可以创建一个自定义的复合约束注解。
创建一个新的注解,例如@ValidUsername,并将其标记为@Constraint。在这个注解上,我们将叠加所有需要聚合的约束,并使用@ReportAsSingleViolation来确保所有违规被报告为单一错误。
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import org.hibernate.validator.constraints.Length;
import jakarta.validation.ReportAsSingleViolation;
import j*a.lang.annotation.Documented;
import j*a.lang.annotation.Retention;
import j*a.lang.annotation.Target;
import static j*a.lang.annotation.ElementType.FIELD;
import static j*a.lang.annotation.RetentionPolicy.RUNTIME;
@Documented
@Constraint(validatedBy = {}) // 无需特定的验证器,它将委托给内部约束
@NotNull
@Length(min = 4, max = 64)
@Pattern(regexp = "[A-Za-z0-9]+")
@ReportAsSingleViolation // 将所有内部约束的违规报告为单一违规
@Target({ FIELD })
@Retention(RUNTIME)
public @interface ValidUsername {
String message() default """
{jakarta.validation.constraints.Not
Null.message}
AND {org.hibernate.validator.constraints.Length.message}
AND {jakarta.validation.constraints.Pattern.message}""";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}关键点解释:
Codeium
一个免费的AI代码自动完成和搜索工具
345
查看详情
即使有了自定义复合约束,{min}、{max}、{regexp}等占位符仍然无法直接从内部约束中获取值。为了解决这个问题,我们可以使用@OverridesAttribute注解,将内部约束的属性“暴露”到我们的自定义注解中。
在@ValidUsername注解中添加以下属性:
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import org.hibernate.validator.constraints.Length;
import jakarta.validation.ReportAsSingleViolation;
import jakarta.validation.OverridesAttribute; // 导入此注解
import j*a.lang.annotation.Documented;
import j*a.lang.annotation.Retention;
import j*a.lang.annotation.Target;
import static j*a.lang.annotation.ElementType.FIELD;
import static j*a.lang.annotation.RetentionPolicy.RUNTIME;
@Documented
@Constraint(validatedBy = {})
@NotNull
@Length(min = 4, max = 64)
@Pattern(regexp = "[A-Za-z0-9]+")
@ReportAsSingleViolation
@Target({ FIELD })
@Retention(RUNTIME)
public @interface ValidUsername {
String message() default """
{jakarta.validation.constraints.NotNull.message}
AND {org.hibernate.validator.constraints.Length.message}
AND {jakarta.validation.constraints.Pattern.message}""";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
// 使用 @OverridesAttribute 将内部约束的属性暴露出来
@OverridesAttribute(constraint = Length.class, name = "min")
int min() default 4; // 默认值应与 @Length 保持一致
@OverridesAttribute(constraint = Length.class, name = "max")
int max() default 64; // 默认值应与 @Length 保持一致
@OverridesAttribute(constraint = Pattern.class, name = "regexp")
String regexp() default "[A-Za-z0-9]+"; // 默认值应与 @Pattern 保持一致
}@OverridesAttribute解释:
现在,只需将username字段上的所有单独注解替换为我们新创建的@ValidUsername注解:
public class User {
@ValidUsername
String username;
// ... getters and setters
}当username字段为null时,验证器将触发@ValidUsername。由于它内部包含了@NotNull,并且使用了@ReportAsSingleViolation,它会尝试聚合所有内部约束的消息。通过@OverridesAttribute,消息模板中的{min}、{max}和{regexp}占位符将能够正确地从@ValidUsername注解中获取其值,从而生成一条包含所有详细信息的统一错误消息,例如:
"must not be null AND length must be between 4 and 64 characters AND must match "[A-Za-z0-9]+"."
通过创建自定义复合约束并结合@ReportAsSingleViolation和@OverridesAttribute,我们可以有效地解决Bean Validation中多约束错误信息聚合和参数解析的问题。这种方法具有以下优点:
注意事项:
这种技术提供了一种强大而灵活的方式来定制Bean Validation的行为,特别适用于需要提供详细且聚合的验证反馈的场景。
以上就是J*a Bean Validation:自定义复合约束实现多条件错误信息聚合的详细内容,更多请关注其它相关文章!
# 应与
# 网站代码优化重构
# 长沙网站建设策略
# 平度市网站推广营销
# 滴滴打车的seo
# hotlist推广红人营销
# 营销推广怎样收费
# 福州一般seo介绍
# 郁南seo推广服务
# 阜阳响应型网站建设价格
# 网站优化优化设计工具
# 三大
# 多条
# java
# 默认值
# 死锁
# 多个
# 错误信息
# 自定义
# java应用程序
# 本地化
# 多语言
# ai
# 正则表达式
# js
相关文章:
学习通网页版官方登录 超星学习通电脑端入口指南
特斯拉自动驾驶房车计划曝光 原型车将于2027年亮相
PHP文件上传至S3:策略、考量与避免本地存储的挑战
千牛数据看板网页版_千牛数据看板网页版访问方法
优化 Jest 模拟:强制未实现函数抛出错误以提升测试效率
html怎么在cmd下运行php文件_cmd运行html中php文件方法【教程】
Windows电脑怎么截图最方便_系统自带截图工具的5种神仙用法【技巧】
QQ邮箱官网登录入口 QQ邮箱网页版邮箱快速登录
PHP基于会话的用户类型页面访问控制指南
cad如何更改注释性对象的比例_cad注释性比例调整方法
C#使用XPath查询节点时出错? 常见语法错误与调试技巧
AI抖音网页版免费视频入口 AI抖音网页端最新视频实时观看
UE5.7引擎表现爆炸优化无敌!5090跑4K稳定60FPS
在J*a中如何使用Stream.map转换元素_Stream映射操作解析
win11 arm版怎么安装 M1/M2 Mac虚拟机安装ARM win11的方法
单12V-2×6实现为RTX 5090供电750W!甚至都没敢跑分
Python类型检查:优化关联可选属性的Mypy推断策略
荒野行动PC版怎么注册_荒野行动PC版账号注册详细流程图文教程
小红书怎么解除第三方平台绑定_小红书多平台登录解绑方法介绍
Windows10怎么开启夜间模式 Windows10系统设置调整色温与亮度缓解夜间用眼疲劳【教程】
J*aScript中高效管理与清空动态列表:避免循环陷阱
顺丰国际快递查询 国际件官方查询入口
在哪找SublimeJ远程工具_SFTP插件配置教程
“在文档元素之后找到了标记”是什么错误? 检查并修复XML中多个根元素的3个方法
将HTML动态表格多行数据保存到Google Sheet的教程
PHP教程:将数据库查询结果动态展示到HTML Textarea的最佳实践
在python-socketio事件处理器中安全访问Flask应用上下文
Go语言中Map存储的结构体如何调用指针方法:深入解析与实践
Composer如何解决json扩展缺失的错误
Win11怎么合并任务栏图标 Win11开启任务栏合并减少图标占空间【方法】
C++的std::forward_list怎么用_C++ STL中单向链表容器的特点与应用
Log4j Console Appender性能瓶颈与高并发优化策略
Golang如何安装Swagger工具_GoSwagger文档生成环境
微博网页版怎么开启两步验证_微博网页版账号安全两步验证设置方法
wps文字怎么插入目录并自动更新_wps文字如何插入目录并自动更新方法
vivo云服务网页版登录 怎么登录vivo云服务网页版
PHP字符串中复杂变量插值的最佳实践与语法解析
夸克浏览器桌面版同步不了书签怎么处理 夸克浏览器跨设备同步异常解决方案
邮编格式怎么匹配地址_根据邮编格式快速匹配详细地址的技巧
如何创建独立于主系统的J*a运行环境_隔离式环境搭建策略
PDO预处理语句中冒号的正确处理:区分SQL函数格式与命名占位符
聚水潭ERP登录页面入口 聚水潭ERP官网登录界面
苹果手机如何防止被恶意App追踪
漫蛙2正版漫画站 漫蛙2网页版快速访问入口
浏览器打开即用 美图秀秀网页版入口
PHP:根据嵌套关联数组项值动态添加新键值对
晋江读书网页版在线登录 晋江读书电脑版官网
微信语音通话掉线如何解决 微信语音通话稳定优化方法
Bilibili动漫最新防封地址发布-Bilibili动漫2025年最稳正版入口推荐
win11如何加载ICC颜色配置文件 Win11校色文件安装与显示器色彩管理【指南】
*请认真填写需求信息,我们会在24小时内与您取得联系。