首页 文章

JSF 2.0:验证2个InputSecret字段的相等性(确认密码)而不编写代码?

提问于
浏览
6

我正在使用JSF 2.0和Glassfish开发纯JavaEE6应用程序 . 我的JSF实现是Primefaces(除了Glassfish提供的Mojarra) .

我想验证JSF表单中2个密码字段的值是否相等 . 使用Seam,有一个整洁的组件 <s:validateEquality for="pw1"/> . 我想在没有Seam的情况下做同样的事情,只使用JSF(或者可能是JSF库的一个组件) . 到目前为止,我只看到了使用自定义验证器验证表单的示例 . 但我想比较这些字段而不编写Java代码或Javascript代码 . 那可能吗?

这与Seam一样:

...
<h:inputSecret id="passwort" value="#{personHome.instance.password}" 
    redisplay="true" required="true">
  <f:validateLength minimum="8"/>
  <a:support event="onblur" reRender="passwortField" bypassUpdates="true" ajaxSingle="true" />
</h:inputSecret>
...    
<h:inputSecret id="passwort2" required="true" redisplay="true">
  <!-- find the JSF2.0-equivalent to this tag: -->
  <s:validateEquality for="passwort"/>
  <a:support event="onblur" reRender="passwort2Field" bypassUpdates="true" ajaxSingle="true" />
</h:inputSecret>
...

7 回答

  • 2

    Seam3 Faces module将支持"Cross-field form validation"即将发布的Alpha3版本 . 这是最小的代码解决方案的最佳选择,请参阅blog了解howto .

    或者,我通过使用f:attribute标记将另一个表单字段的clientId传递给自定义验证器,然后使用传递给自定义验证器的UIComponent通过id访问另一个字段来以编程方式完成此操作 .

    这是facelet文件:

    <h:outputLabel value="Enter your email address" rendered="#{!cc.attrs.registration.subRegistration}" />
    <h:inputText label="Email" id="textEmail1" value="#{cc.attrs.registration.email}" rendered="#{!cc.attrs.registration.subRegistration}" required="true" maxlength="128" size="35"></h:inputText>
    <h:message for="textEmail1" rendered="#{!cc.attrs.registration.subRegistration}"></h:message>
    
    <h:outputLabel value="Re-enter your email address confirmation:" rendered="#{!cc.attrs.registration.subRegistration and cc.attrs.duplicateEmailRequired}" />
    <h:inputText label="Email repeat" id="textEmail2" rendered="#{!cc.attrs.registration.subRegistration and cc.attrs.duplicateEmailRequired}" maxlength="64" size="35">
        <f:validator validatorId="duplicateFieldValidator" />
        <f:attribute name="field1Id" value="#{component.parent.parent.clientId}:textEmail1" />
    </h:inputText>
    <h:message for="textEmail2" rendered="#{!cc.attrs.registration.subRegistration and cc.attrs.duplicateEmailRequired}"></h:message>
    

    这是验证器类:

    package ca.triumf.mis.trevents.jsf.validator;
    
    import javax.faces.application.FacesMessage;
    import javax.faces.component.UIComponent;
    import javax.faces.component.UIInput;
    import javax.faces.context.FacesContext;
    import javax.faces.validator.FacesValidator;
    import javax.faces.validator.Validator;
    import javax.faces.validator.ValidatorException;
    
    @FacesValidator(value="duplicateFieldValidator")
    public class DuplicateFieldValidator implements Validator {
    
    @Override
    public void validate(FacesContext context, UIComponent component, Object value)
            throws ValidatorException {
        // Obtain the client ID of the first field from f:attribute.
        System.out.println(component.getFamily());
        String field1Id = (String) component.getAttributes().get("field1Id");
    
        // Find the actual JSF component for the client ID.
        UIInput textInput = (UIInput) context.getViewRoot().findComponent(field1Id);
        if (textInput == null)
            throw new IllegalArgumentException(String.format("Unable to find component with id %s",field1Id));
        // Get its value, the entered text of the first field.
        String field1 = (String) textInput.getValue();
    
        // Cast the value of the entered text of the second field back to String.
        String confirm = (String) value;
    
        // Check if the first text is actually entered and compare it with second text.
        if (field1 != null && field1.length() != 0 && !field1.equals(confirm)) {
            throw new ValidatorException(new FacesMessage("E-mail addresses are not equal."));
        }
    }
    }
    
  • 6

    我必须使用两种答案的混合才能成功 .

    我使用ifischers短解决方案,但我的bean密码字段为空 .

    所以我使用Brian Leathem的行来从上下文中获取UIInput:

    public void passwordValidator(FacesContext context, UIComponent toValidate, Object value) {
    
        UIInput passwordField = (UIInput) context.getViewRoot().findComponent("registerForm:password");
        if (passwordField == null)
            throw new IllegalArgumentException(String.format("Unable to find component."));
        String password = (String) passwordField.getValue();
        String confirmPassword = (String) value;
        if (!confirmPassword.equals(password)) {
            FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Passwords do not match!", "Passwords do not match!");
            throw new ValidatorException(message);
        }
    }
    
  • 6

    你可以用这种非常简单的方式使用Primefaces标签:

    <p:password id="password" value="#{bean.password}" match="repeated_password" />
    
    <p:password id="repeated_password" value="#{bean.password}" />
    
  • 3

    Edited :在阅读之前,请考虑一下这个解决方案是否完美,答案是从2012年7月开始,所以请不要因为你不喜欢它而投票给我 . 世界发生了变化,现在我们有更好的组件和解决方案 .

    没有解决方案,我被迫以丑陋的方式进行验证(不推荐) . 至少它有效,直到我找到更好的解决方案 .

    在返回操作的方法中,我检查两个值,如果值不同,我在上下文中添加错误消息并返回null到导航处理程序 .

    package com.jsf.beans.user;
    
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.RequestScoped;
    import javax.faces.component.html.HtmlInputSecret;
    
    import org.apache.commons.lang.StringUtils;
    
    import com.pichler.jsf.beans.base.JsfViewBean;
    
     @ManagedBean(name = "changePassword")
     @RequestScoped
     public class ChangePassword extends JsfViewBean {
    private HtmlInputSecret inputSecret1, inputSecret2;
    
    /**
     * @return the inputSecret1
     */
    public HtmlInputSecret getInputSecret1() {
        return inputSecret1;
    }
    
    /**
     * @param inputSecret1
     *            the inputSecret1 to set
     */
    public void setInputSecret1(HtmlInputSecret inputSecret1) {
        this.inputSecret1 = inputSecret1;
    }
    
    /**
     * @return the inputSecret2
     */
    public HtmlInputSecret getInputSecret2() {
        return inputSecret2;
    }
    
    /**
     * @param inputSecret2
     *            the inputSecret2 to set
     */
    public void setInputSecret2(HtmlInputSecret inputSecret2) {
        this.inputSecret2 = inputSecret2;
    }
    
    private String password1, password2;
    
    public String alterar() {
        if (!StringUtils.equals(password1, password2)) {
            addErrorMessage(inputSecret1.getClientId(),
                    "As senhas não coincidem");
            addErrorMessage(inputSecret2.getClientId(),
                    "As senhas não coincidem");
            return null;
        }
        return null;
    }
    
    /**
     * @return the password1
     */
    public String getPassword1() {
        return password1;
    }
    
    /**
     * @param password1
     *            the password1 to set
     */
    public void setPassword1(String password1) {
        this.password1 = password1;
    }
    
    /**
     * @return the password2
     */
    public String getPassword2() {
        return password2;
    }
    
    /**
     * @param password2
     *            the password2 to set
     */
    public void setPassword2(String password2) {
        this.password2 = password2;
    }
    

    }

    • JsfViewBean只是一个具有一些常用方法的类,如“addMessages” .
  • -1

    如果您正在使用JSF实用程序库OmniFaces,则可以使用<o:validateEqual> . 它还允许设置自定义消息 . showcase有一个实例,演示了验证密码确认的常用用法 . 在调用验证器之前,甚至不需要ajax来更新模型(如your own approach那样) .

    这是最低必要代码:

    <h:inputSecret id="password" value="#{personHome.person.password}" />
    <h:message for="password" />
    
    <h:inputSecret id="password2" />
    <h:message for="password2" />
    
    <o:validateEqual components="password password2" 
        message="Passwords do not match!" showMessageFor="password2" />
    

    不需要Java代码 .

  • 3

    您可以使用Apache MyFaces ExtVal轻松完成 .

  • 0

    这是我最终做到这一点的方式,我喜欢它因为它简短而容易 . 唯一的问题是它不是真的可以重复使用,但因为我只需要在一个案例中使用它,我宁愿保存一些LOC并以这种方式执行 . 我认为的片段:

    <h:inputSecret id="password" value="#{personHome.person.password}">
      <f:ajax event="blur" render="passwordError" />
    </h:inputSecret> 
    <h:message for="password" errorClass="invalid" id="passwordError" />
    
    <h:inputSecret id="password2" validator="#{personHome.validateSamePassword}">
      <f:ajax event="blur" render="password2Error" />
    </h:inputSecret> 
    <h:message for="password2" errorClass="invalid" id="password2Error" />
    

    我的支持 beans (只是重要部分):

    @Named @ConversationScoped
    public class PersonHome {
      private Person person;
    
      public Person getPerson() {
        if (person == null) return new Person();
        else return person;
      }
    
      public void validateSamePassword(context:FacesContext, toValidate:UIComponent, value:Object) {
        String confirmPassword = (String)value;
        if (!confirmPassword.equals(person.getPassword()) {
          FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Passwords do not match!", "Passwords do not match!")
          throw new Validatorexception(message);
        }
      }
    

相关问题