使用 Hibernate Validator (JSR 303) 进行跨领域验证
Hibernate Validator 4.x 中是否有跨字段验证的实现(或第三方实现)?如果不是,那么实现跨域验证器的最简洁方法是什么?
例如,如何使用 API 来验证两个 bean 属性是否相等(例如验证密码字段与密码验证字段是否匹配)。
在注释中,我期望类似的内容:
public class MyBean {
@Size(min=6, max=50)
private String pass;
@Equals(property="pass")
private String passVerify;
}
Is there an implementation of (or third-party implementation for) cross field validation in Hibernate Validator 4.x? If not, what is the cleanest way to implement a cross field validator?
As an example, how can you use the API to validate two bean properties are equal (such as validating a password field matches the password verify field).
In annotations, I'd expect something like:
public class MyBean {
@Size(min=6, max=50)
private String pass;
@Equals(property="pass")
private String passVerify;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
每个字段约束应该由不同的验证器注释来处理,或者换句话说,不建议让一个字段的验证注释与其他字段进行检查;跨领域验证应该在类级别进行。此外,JSR-303 第 2.2 节 是首选方式表达同一类型的多个验证是通过注释列表。这允许为每个匹配指定错误消息。
例如,验证一个常见的表单:
注释:
验证器:
Each field constraint should be handled by a distinct validator annotation, or in other words it's not suggested practice to have one field's validation annotation checking against other fields; cross-field validation should be done at the class level. Additionally, the JSR-303 Section 2.2 preferred way to express multiple validations of the same type is via a list of annotations. This allows the error message to be specified per match.
For example, validating a common form:
The Annotation:
The Validator:
我建议你另一个可能的解决方案。也许不太优雅,但更容易!
isValid()
和isPassExpiryAfterDateOfJoining()
方法由验证器自动调用。ConstraintViolation
中报告的属性路径将从方法名称中提取:valid
和passExpiryAfterDateOfJoining
。I suggest you another possible solution. Perhaps less elegant, but easier!
The
isValid()
andisPassExpiryAfterDateOfJoining()
methods are invoked automatically by the validator. The property paths reported in theConstraintViolation
s will be extracted from the method names:valid
andpassExpiryAfterDateOfJoining
.我很惊讶这不是开箱即用的。无论如何,这是一个可能的解决方案。
我创建了一个类级别验证器,而不是原始问题中描述的字段级别。
以下是注释代码:
以及验证器本身:
请注意,我已使用 MVEL 来检查正在验证的对象的属性。这可以替换为标准反射 API,或者如果您正在验证的是特定类,则可以替换为访问器方法本身。
然后可以在 bean 上使用 @Matches 注释,如下所示:
作为免责声明,我在最后 5 分钟内写了此内容,因此我可能还没有解决所有错误。如果出现任何问题,我会更新答案。
I'm surprised this isn't available out of the box. Anyway, here is a possible solution.
I've created a class level validator, not the field level as described in the original question.
Here is the annotation code:
And the validator itself:
Note that I've used MVEL to inspect the properties of the object being validated. This could be replaced with the standard reflection APIs or if it is a specific class you are validating, the accessor methods themselves.
The @Matches annotation can then be used used on a bean as follows:
As a disclaimer, I wrote this in the last 5 minutes, so I probably haven't ironed out all the bugs yet. I'll update the answer if anything goes wrong.
对于 Hibernate Validator 4.1.0.Final,我建议使用 @ScriptAssert。摘自其 JavaDoc:
注意:评估是由 Java VM 中运行的脚本“引擎”执行的,因此是在 Java“服务器端”上执行的,而不是在“客户端”上执行,如中所述一些评论。
示例:
或者使用更短的别名和空安全:
或者使用 Java 7+ 空安全
Objects.equals()
:尽管如此,自定义类级别验证器 @Matches 没有任何问题< /em> 解决方案。
With Hibernate Validator 4.1.0.Final I recommend using @ScriptAssert. Exceprt from its JavaDoc:
Note: the evaluation is being performed by a scripting "engine" running in the Java VM, therefore on Java "server side", not on "client side" as stated in some comments.
Example:
or with shorter alias and null-safe:
or with Java 7+ null-safe
Objects.equals()
:Nevertheless, there is nothing wrong with a custom class level validator @Matches solution.
可以通过创建自定义约束来完成跨字段验证。
示例:- 比较用户实例的密码和确认密码字段。
CompareStrings
StringComparisonMode
CompareStringsValidator
ConstraintValidatorHelper
用户
测试
输出
消息:- [密码,确认密码]必须相等。
通过使用CompareStrings验证约束,我们还可以比较两个以上的属性,并且可以混合四种字符串比较方法中的任何一种。
ColorChoice
测试
输出
消息:- 请选择三种不同的颜色。
同样,我们可以有 CompareNumbers、CompareDates 等跨领域验证约束。
PS 我还没有在生产环境下测试过这段代码(尽管我在开发环境下测试过),所以将此代码视为 Milestone Release。如果您发现错误,请写一个好的评论。 :)
Cross fields validations can be done by creating custom constraints.
Example:- Compare password and confirmPassword fields of User instance.
CompareStrings
StringComparisonMode
CompareStringsValidator
ConstraintValidatorHelper
User
Test
Output
Message:- [Password, ConfirmPassword] must be equal.
By using the CompareStrings validation constraint, we can also compare more than two properties and we can mix any of four string comparison methods.
ColorChoice
Test
Output
Message:- Please choose three different colors.
Similarly, we can have CompareNumbers, CompareDates, etc cross-fields validation constraints.
P.S. I have not tested this code under production environment (though I tested it under dev environment), so consider this code as Milestone Release. If you find a bug, please write a nice comment. :)
如果您使用 Spring 框架,那么您可以使用 Spring 表达式语言 (SpEL)。我编写了一个小型库,提供基于 SpEL 的 JSR-303 验证器 – 它使跨领域验证变得轻而易举!看看 https://github.com/jirutka/validator-spring。
这将验证密码字段的长度和相等性。
您还可以轻松修改此设置,以仅在两者都不为空时验证密码字段。
If you’re using the Spring Framework then you can use the Spring Expression Language (SpEL) for that. I’ve wrote a small library that provides JSR-303 validator based on SpEL – it makes cross-field validations a breeze! Take a look at https://github.com/jirutka/validator-spring.
This will validate length and equality of the password fields.
You can also easily modify this to validate the password fields only when not both empty.
我尝试过 Alberthoven 的示例(hibernate-validator 4.0.2.GA),并且得到一个 ValidationException:“带注释的方法必须遵循 JavaBeans 命名约定。 match() 也没有。”在我将该方法从“match”重命名为“isValid”后,它就可以工作了。
I have tried Alberthoven's example (hibernate-validator 4.0.2.GA) and i get an ValidationException: „Annotated methods must follow the JavaBeans naming convention. match() does not.“ too. After I renamed the method from „match“ to "isValid" it works.
我喜欢 Jakub Jirutka 使用 Spring 表达式语言 的想法。如果您不想添加另一个库/依赖项(假设您已经使用 Spring),这里是他的想法的简化实现。
约束:
验证器:
像这样应用:
I like the idea from Jakub Jirutka to use Spring Expression Language. If you don't want to add another library/dependency (assuming that you already use Spring), here is a simplified implementation of his idea.
The constraint:
The validator:
Apply like this:
我对 Nicko 的解决方案做了一个小改动,这样就不需要使用 Apache Commons BeanUtils 库,并将其替换为 Spring 中已有的解决方案,对于那些使用它的人来说,我可以更简单:
I made a small adaptation in Nicko's solution so that it is not necessary to use the Apache Commons BeanUtils library and replace it with the solution already available in spring, for those using it as I can be simpler:
我没有对第一个答案发表评论的声誉,但想补充一点,我已经为获胜答案添加了单元测试,并有以下观察结果:
I don't have the reputation for commenting on the first answer but wanted to add that I have added unit tests for the winning answer and have the following observations:
非常好的解决方案布拉德豪斯。有没有一种方法可以将@Matches注释应用于多个字段?
编辑:
这是我为回答这个问题而提出的解决方案,我修改了约束以接受数组而不是单个值:
注释的代码:
以及实现:
Very nice solution bradhouse. Is there any way to apply the @Matches annotation to more than one field?
EDIT:
Here's the solution I came up with to answer this question, I modified the Constraint to accept an array instead of a single value:
The code for the annotation:
And the implementation:
您需要显式调用它。在上面的示例中,bradhouse 为您提供了编写自定义约束的所有步骤。
将此代码添加到您的调用者类中。
在上面的情况下它将是
You need to call it explicitly. In the example above, bradhouse has given you all the steps to write a custom constraint.
Add this code in your caller class.
in the above case it would be
为什么不尝试 Oval:http://oval.sourceforge.net/
我看起来它支持 OGNL,所以也许你可以通过更自然的方式做到这一点
Why not try Oval: http://oval.sourceforge.net/
I looks like it supports OGNL so maybe you could do it by a more natural
你们太棒了。真是令人惊奇的想法。我最喜欢Alberthoven和McGin,所以我决定将这两个想法结合起来。并开发一些通用解决方案来满足所有情况。这是我提出的解决方案。
You guys are awesome. Really amazing ideas. I like Alberthoven's and McGin's most, so I decided to combine both ideas. And develop some generic solution to cater all cases. Here is my proposed solution.
与问题相关的解决方案:
如何访问注释属性中描述了
以及如何使用它...?像这样:
Solution realated with question:
How to access a field which is described in annotation property
And how to use it...? Like this: