2010-05-25 12 views
5

Sto sviluppando un'applicazione JavaEE6 pura con JSF 2.0 e Glassfish. La mia implementazione JSF è Primefaces (accanto a Mojarra fornita da Glassfish).JSF 2.0: convalida l'uguaglianza di 2 campi InputSecret (conferma password) senza scrivere Codice?

Voglio verificare se i valori di 2 campi password in un modulo JSF sono uguali. Con Seam, c'è il componente pulito <s:validateEquality for="pw1"/>. Voglio fare lo stesso senza Seam, usando solo JSF (o forse un componente di una libreria JSF). Fino ad ora ho visto solo esempi che convalidano il modulo con un validatore personalizzato. Ma vorrei confrontare i campi senza scrivere codice Java o codice Javascript. È possibile?

Questo come si presenta con 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> 
... 
+0

quindi ... se non c'è soluzione 'senza' codice, qual è la soluzione più pulita 'con' codice? – ifischer

risposta

3

Questo è il modo in cui ho finalmente fatto, che mi piace perché è breve e facile. L'unico problema è che non è veramente riutilizzabile, ma come ho bisogno di questo in un caso, piuttosto salvo alcuni LOC e lo faccio in questo modo. Snippet dal mio punto di vista:

<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" /> 

mio Backing Bean (solo la parte importante):

@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); 
    } 
    } 
6

Il Seam3 Faces module sosterrà "la forma incrociata campo convalida" nella sua versione alpha3 imminente. Questa è la soluzione migliore per una soluzione di codice minimale, vedi questo blog per un howto.

In alternativa, l'ho fatto a livello di programmazione utilizzando il tag f: attribute per passare l'ID client di un altro campo modulo a un validatore personalizzato, quindi utilizzando l'UIComponent passato nel validatore personalizzato per accedere all'altro archiviato dall'ID.

Ecco il file 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> 

Ecco la classe di convalida:

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.")); 
    } 
} 
} 
3

ho dovuto usare una miscela di entrambe le risposte per avere successo.

Ho usato ifischers soluzione breve ma il mio campo password del bean era nullo.

quindi ho usato le linee da Brian Leathem per ottenere l'UIInput dal contesto:

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); 
    } 
} 
0

si può fare facilmente con Apache MyFaces ExtVal.

-1

A cura: Prima di leggere, per favore, considerare che questa soluzione funziona perfettamente, e la risposta è da luglio 2012, quindi per favore non verso il basso mi ha votare solo perché non ti piaceva. Il mondo è cambiato e ora abbiamo componenti e soluzioni migliori.

Senza soluzione, sono stato costretto a fare la convalida in modo brutto (non consigliato). Almeno funziona finché non ho trovato una soluzione migliore.

Nel metodo che restituisce l'azione, controllo entrambi i valori, in caso di valori diversi, aggiungo messaggi di errore sul contesto e restituisco null al gestore di navigazione.

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 è solo una classe che ha alcuni metodi comuni, come "addMessages".

4

È possibile utilizzare tag primefaces in questo modo molto semplice:

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

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

Se stai usando JSF libreria di utilità OmniFaces, allora si potrebbe utilizzare <o:validateEqual>. Permette anche di impostare un messaggio personalizzato. Lo showcase ha un esempio dal vivo che dimostra l'utilizzo comune della convalida della conferma della password. Non hai nemmeno bisogno di ajax per aggiornare il modello prima di invocare il validatore (come fa your own approach).

Ecco il codice necessario minima:

<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" /> 

codice No Java necessario.