2012-08-09 14 views
13

我正在使用HibernateValidator指定的this answer中指定的表单中的两个字段“password”和“confirmPassword”进行验证。以下是约束描述符(验证器接口)。使用HibernateValidator进行交叉字段验证不会显示错误消息

package constraintdescriptor; 

import constraintvalidator.FieldMatchValidator; 
import javax.validation.Constraint; 
import javax.validation.Payload; 
import java.lang.annotation.Documented; 
import static java.lang.annotation.ElementType.ANNOTATION_TYPE; 
import static java.lang.annotation.ElementType.TYPE; 
import java.lang.annotation.Retention; 
import static java.lang.annotation.RetentionPolicy.RUNTIME; 
import java.lang.annotation.Target; 

@Target({TYPE, ANNOTATION_TYPE}) 
@Retention(RUNTIME) 
@Constraint(validatedBy = FieldMatchValidator.class) 
@Documented 
public @interface FieldMatch 
{ 
    String message() default "{constraintdescriptor.fieldmatch}"; 
    Class<?>[] groups() default {}; 
    Class<? extends Payload>[] payload() default {}; 

    /** 
    * @return The first field 
    */ 
    String first(); 

    /** 
    * @return The second field 
    */ 
    String second(); 

    /** 
    * Defines several <code>@FieldMatch</code> annotations on the same element 
    * 
    * @see FieldMatch 
    */ 
    @Target({TYPE, ANNOTATION_TYPE}) 
    @Retention(RUNTIME) 
    @Documented 
    public @interface List{ 
     FieldMatch[] value(); 
    } 
} 

以下是约束验证(实现类)。


package constraintvalidator; 

import constraintdescriptor.FieldMatch; 
import javax.validation.ConstraintValidator; 
import javax.validation.ConstraintValidatorContext; 
import org.apache.commons.beanutils.BeanUtils; 

public final class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object> 
{ 
    private String firstFieldName; 
    private String secondFieldName; 

    public void initialize(final FieldMatch constraintAnnotation) { 
     firstFieldName = constraintAnnotation.first(); 
     secondFieldName = constraintAnnotation.second(); 
     //System.out.println("firstFieldName = "+firstFieldName+" secondFieldName = "+secondFieldName); 
    } 

    public boolean isValid(final Object value, final ConstraintValidatorContext cvc) { 
     try { 
      final Object firstObj = BeanUtils.getProperty(value, firstFieldName); 
      final Object secondObj = BeanUtils.getProperty(value, secondFieldName); 
      //System.out.println("firstObj = "+firstObj+" secondObj = "+secondObj); 
      return firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj); 
     } 
     catch (final Exception e) { 
      System.out.println(e.toString()); 
     } 
     return true; 
    } 
} 

以下是被映射与JSP页(与<form:form></form:form>标签指定commandName="tempBean")验证豆。

package validatorbeans; 

import constraintdescriptor.FieldMatch; 
import javax.validation.constraints.Size; 
import org.hibernate.validator.constraints.NotEmpty; 

@FieldMatch.List({ 
    @FieldMatch(first = "password", second = "confirmPassword", message = "The password fields must match", groups={TempBean.ValidationGroup.class}) 
}) 

public final class TempBean 
{   
    @NotEmpty(groups={ValidationGroup.class}, message="Might not be left blank.") 
    private String password; 
    @NotEmpty(groups={ValidationGroup.class}, message="Might not be left blank.") 
    private String confirmPassword; 

    public interface ValidationGroup {}; 

    //Getters and setters     
} 

UPDATE

这一切都正常工作,并验证预期。剩下的一件事就是在之内显示TempBean类以上的指定错误消息,即只有一个问题:如何在发生验证违规时在JSP页面上显示错误消息?

(在两个领域中TempBean类作品passwordconfirmPassword的注释@NotEmpty并显示违规行为,事情是不是发生@FieldMatch指定的消息)。

我使用基于this question验证组this blog规定和它运作良好,导致显示错误信息没有中断(因为它看起来是)。


在JSP页面上,这两个字段指定如下。

<form:form id="mainForm" name="mainForm" method="post" action="Temp.htm" commandName="tempBean"> 

    <form:password path="password"/> 
    <font style="color: red"><form:errors path="password"/></font><br/> 

    <form:password path="confirmPassword"/> 
    <font style="color: red"><form:errors path="confirmPassword"/></font><br/> 

</form:form> 
+1

验证未执行的原因是因为这个问题中的语句“*所有内容都在同一个包'package validatorbeans;'*”中。 HibernateValidator需要**公共定义**用于约束描述符(注释)*和约束验证器(实现类)*,并且我将它们都声明在同一个包中,因此缺省修饰符** no修饰符**应用于它们两者(因为它不可能在同一个包中声明多于一个类或接口为* public *)。 – Tiny 2012-08-10 03:35:20

+0

但有一个问题仍然存在。它仍然不显示[this]所指定的错误消息(http://stackoverflow.com/questions/1972933/cross-field-validation-with-hibernate-validator-jsr-303#comment8918149_2155576)评论。即使验证执行正确,是否有人知道它不显示错误消息的原因? – Tiny 2012-08-10 03:37:38

+0

好吧,我想你应该发布你的解决方案,关于包私人验证器作为答案。至于错误消息,它可能是一个问题,在这个问题中没有指定form:errors声明。 – 2012-08-10 09:14:16

回答

19

你可以试试你的isValid方法是这样吗? (这肯定是为我工作在现场的项目):

public boolean isValid(final Object value, final ConstraintValidatorContext cvc){ 
    boolean toReturn = false; 

    try{ 
     final Object firstObj = BeanUtils.getProperty(value, firstFieldName); 
     final Object secondObj = BeanUtils.getProperty(value, secondFieldName); 

     //System.out.println("firstObj = "+firstObj+" secondObj = "+secondObj); 

     toReturn = firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj); 
    } 
    catch (final Exception e){ 
     System.out.println(e.toString()); 
    } 
    //If the validation failed 
    if(!toReturn) { 
     cvc.disableDefaultConstraintViolation(); 
     //In the initialiaze method you get the errorMessage: constraintAnnotation.message(); 
     cvc.buildConstraintViolationWithTemplate(errorMessage).addNode(firstFieldName).addConstraintViolation(); 
    } 
    return toReturn; 
} 

我也看到你实现ConstraintValidator接口与对象,从字面上。它应该是您从表单中获得的支持对象:

tempBean //您在commandName中实际指定的那个对象。

所以,你应该执行这样的:

implements ConstraintValidator<FieldMatch, TempBean> 

这可能不是这里的问题,但作为未来的参考,这是应该的。

UPDATE

里面你FieldMatch接口/注释有两种方法:第一,第二,再添加一个名为的errorMessage例如:

Class<? extends Payload>[] payload() default {}; 

/** 
* @return The first field 
*/ 
String first(); 

/** 
* @return The second field 
*/ 
String second(); 

/** 
    @return the Error Message 
*/ 
String errorMessage 

目光从验证类,你的方法里面 - 你在那里得到第一和第二个字段名称,所以只需添加errorMessage,例如像这样:

private String firstFieldName; 
    private String secondFieldName; 
    //get the error message name 
    private String errorMessagename; 
public void initialize(final FieldMatch constraintAnnotation) 
{ 
    firstFieldName = constraintAnnotation.first(); 
    secondFieldName = constraintAnnotation.second(); 
    errorMessageNAme = constraintAnnotation.errorMessage(); 

    //System.out.println("firstFieldName = "+firstFieldName+" secondFieldName = "+secondFieldName); 
} 

在isValida里面得到它,就像你为第一个和第二个域名所做的一样,并使用它。

+0

试过,它的工作,先生!提供赏金需要从现在开始几个小时,如果系统允许,我会在稍后给予答案。请说一个额外的东西,在这个方法**本身**'cvc.buildConstraintViolationWithTemplate(“两个字段的密码必须匹配。”)。addNode(password).addConstraintViolation();',我已经指定了错误信息。有没有办法获取'@ FieldMatch.List({})'中指定的消息?不管有没有办法这样做。这是次要的事情。对我而言,根据你的答案知道它是有效的。非常感谢 – Tiny 2012-08-19 13:05:10

+0

@Tiny检查我的更新答案。 – Eugene 2012-08-19 13:26:20

+0

现在我的整个应用程序都运行良好。非常感谢,先生! – Tiny 2012-08-20 08:48:39

相关问题