2012-08-09 13 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

相關問題