2016-04-29 46 views
2

我想用JSF 2.3實現f:validateWholeBean。 我試圖實現與Mojarra 2.3.0-m05這個例子和Tomcat 8:f:validateWholeBean in JSF 2.3

<h:form> 
    <h:panelGroup> 
     <h:inputSecret id="passwd" value="#{bean.dataList['passwd']}"> 
      <f:ajax event="blur" render="passwdvalidator" /> 
     </h:inputSecret> 
     <h:message id="passwdvalidator" for="passwd" /> 
    </h:panelGroup> 

    <h:panelGroup>Confirm Password</h:panelGroup> 
    <h:panelGroup> 
     <h:inputSecret id="confurmpasswd" value="#{bean.dataList['passwd']}"> 
      <f:ajax event="blur" render="confurmpasswdvalidator" /> 
     </h:inputSecret> 
     <h:message id="confurmpasswdvalidator" for="confurmpasswd" /> 
    </h:panelGroup> 
    <h:commandButton action="#{bean.submit}"> 
     <f:ajax render="@form" execute="@form"></f:ajax> 
    </h:commandButton>       

    <f:validateWholeBean value="#{contactBean}" validationGroups="validateBean.ContactGroup" /> 
</h:form> 

自定義驗證

@Named 
@ViewScoped 
public class NewAccountValidator implements Validator, Serializable 
{ 
    @Override 
    public void validate(FacesContext fc, UIComponent uic, Object o) throws ValidatorException 
    { 
     // not used 
    } 

    public void validatePasswords(FacesContext context, UIComponent component, Object value) 
    { 
     String l; 
     String s = value.toString().trim(); 

     if (s != null) 
     { 
      // compare passwords 
     } 
     else 
     { 
      throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_INFO, 
       s.isEmpty() ? " This field cannot be empty!" : " '" + s + "' is not a number!", null)); 
     } 
    } 
} 

什麼是實現與f:validateWholeBean和定製JSF驗證解決方案的正確方法?

回答

4

您不應執行「標準」驗證程序,而是執行ConstraintValidator

你可以找到Arjan Tijms Weblog一個例子:

<h:form> 
    <h:inputText value="#{indexBean.foo}"> 
     <f:validateBean validationGroups="javax.validation.groups.Default,java.util.RandomAccess"/> 
    </h:inputText> 
    <h:inputText value="#{indexBean.bar}"> 
     <f:validateBean validationGroups="javax.validation.groups.Default,java.util.RandomAccess"/> 
    </h:inputText> 

    <f:validateWholeBean value="#{indexBean}" validationGroups="java.util.RandomAccess"/> 

    <h:commandButton value="submit"/> 
</h:form> 

與支持bean:

@Named 
@RequestScoped 
@ValidIndexBean(groups = java.util.RandomAccess.class) 
public class IndexBean implements ConstraintValidator<ValidIndexBean, IndexBean> { 

    @Constraint(validatedBy = IndexBean.class) 
    @Documented 
    @Target(TYPE) 
    @Retention(RUNTIME) 
    public @interface ValidIndexBean { 
     String message() default "Invalid Bean"; 
     Class<?>[] groups() default {}; 
     Class<? extends Payload>[] payload() default {}; 
    } 

    @Inject // @EJB 
    private PersistenceService service; 

    @NotNull 
    private String foo; 

    @NotNull 
    private String bar; 

    @Override 
    public void initialize(ValidIndexBean constraintAnnotation) { 
     // 
    } 

    @Override 
    public boolean isValid(IndexBean other, ConstraintValidatorContext context) { 
     // return other.getFoo().equals(other.getBar()); 

     return service.query("select count(p) from Person p where p.foo like ?1 and p.bar like ?2", other.getFoo(), other.getBar()) == 0; 
    } 

    ... 
} 

答案評論:

  • 這是一個常見的bean,所以是的,它可以是@ViewScoped。
  • 然後您應該創建多個驗證程序:使單個驗證程序執行多個邏輯是不好的做法。

無關:

,我可以從你貼,你是誤會了用「經典」的驗證,使之成爲一個ManagedBean(CDI加味)的代碼中看到的,但這 JSF驗證器/轉換器的「普通」使用。

我想你是不使用驗證程序,而是使用驗證方法代替。

「經典」 驗證應該像(見here):

@FacesValidator("usernameValidator") 
public class UsernameValidator implements Validator, Serializable 
{ 
    @Override 
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException 
    { 
     // you should use THIS method to validate a single Component's Value 

     if(query("select count(*) from user where username = '?'", String.valueOf(value)) > 0) 
     { 
      throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "invalid username")); 
     } 
    } 
} 

,應該像使用:

<h:inputText value="#{someBean.username}" validator="usernameValidator" /> 

這樣:

  1. 「經典」 的面孔校驗用於驗證一個組件的值
  2. 他們不應該是@ManagedBean或@Named
  3. 他們應該通過名稱引用(validator="usernameValidator"不使用EL表達式validator="#{usernameValidator}"

然而,這是驗證器的最佳實踐/轉換器要「專業」:他們應該執行一個驗證邏輯。

如果需要驗證組件的值,即一個日期,那一定非空大於01/01/1970,你需要專門的驗證。

+0

謝謝你的例子。但我需要在驗證器中執行SQL查詢。你能告訴我一個快速的例子,我可以在哪部分代碼中進行查詢? –

+0

所有的檢查都應該在* isValid *方法中完成,包括數據庫訪問。請參閱更新。 –

+0

我還有一些問題:我可以使用'ViewScoped'還是強制使用'RequestScoped'?另外如果我有一個需要將幾個SQL查詢放入一個驗證器的情況呢?進入「經典」解決方案,我只是添加了額外的Java方法。請參閱 –