Validation über ManagedBeans

Bitte aktiviere JavaScript!
Hallo,

ich möchte aus einem Formular zum "Profil bearbeiten" die eingegebene Mail überprüfen. Standardmäßig steht die des angemeldeten Nutzers bereits im entsprechenden InputField. Beim Speichern soll u.a. dieses Feld auf 3 Sachen geprüft werden:

1. Ist die Mail noch die gleiche wie in der DB hinterlegt (keine Änderung)?
2. Ist die geänderte Mail noch nicht vergeben (Das Attribut ist kein Primärschlüssel, sollte trotzdem unique sein)
3. Sollte die Mail bereits vergeben sein, soll eine message ausgegeben werden, welche den Nutzer informiert.

So sieht das Feld im Formular aus:

HTML:
<b:column medium-screen="4">
                    <b:inputText id="mail" required="true"
                                 validatorMessage="Deine E-Mail-Adresse ist nicht gültig. Bitte gib Deine E-Mail-Adresse erneut ein!"
                                 requiredMessage="Deine E-Mail-Adresse ist nicht gültig. Bitte gib Deine E-Mail-Adresse erneut ein!"
                                 label="E-Mail" placeholder="[email protected]" value="#{profilManagedBean.mail}">
                        <f:validateRegex pattern="[\w\.-]*[a-zA-Z0-9_]@[\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]"/>
                        <f:ajax event="blur" execute="mail" render="m_mail"/>
                    </b:inputText>
                    <b:messages id="m_mail" for="mail"/>
                </b:column>
So die Bean-Methode, welche über den Speichern-Button in dem "action"-Attribut übergeben wird:

Java:
public String update() {
        if (!nutzer.getPasswort().equals(tempPassword) && tempPassword != null && !tempPassword.isEmpty()) {
            nutzer.setPasswort(tempPassword);
        }
        if (mail.equals(nutzer.getMail())) {
            nutzer.addBezirk(dao.findBezirkByID(bezirkID));
            updateSprachen();
            updateFreizeitaktivitaeten();
            dao.merge(nutzer);
            refreshNutzer();
            return "home";

        } else if(validateMail(mail)){
            nutzer.addBezirk(dao.findBezirkByID(bezirkID));
            updateSprachen();
            updateFreizeitaktivitaeten();
            nutzer.setMail(mail);
            dao.merge(nutzer);
            refreshNutzer();
            return "home";
        }
            else {
            FacesContext.getCurrentInstance().addMessage("formProfil:mail", new FacesMessage(
                    "Diese Mail wird bereits verwendet!"));
            return "profil";
        }
    }

Das Problem ist in meinen Augen, dass ich bei der "update"-Methode immer einen String, also eine .xhtml-Seite zurückgeben muss und daher die Seite wahrscheinlich sogar nach Ausgabe der richtigen Fehlermeldung neu geladen wird. Diesen benötige ich aber, um nach erfolgreichem Speichern automatisch auf die Homepage zu gelangen.

Wie kann ich das umgehen?

Eine Alternative wäre keine Seite zurückzugeben, und damit auf die automatische Weiterleitung zu verzichten, oder?
 
Ich habe jetzt versucht, das so umzusetzen, leider funktioniert auch das nicht.

Hier ist der Aufruf in der .xhtml:

HTML:
<b:inputText id="mail" required="true"
                                 requiredMessage="Bitte geben Sie Ihre E-Mail-Adresse an!"
                                 label="E-Mail" placeholder="[email protected]" value="#{registrierenManagedBean.nutzer.mail}">
                        <f:validator validatorId="mailValidatorRegistrieren"/>
                        <b:messages for="mail"/>
                    </b:inputText>
So sieht der Validator aus:

Java:
@FacesValidator("mailValidatorRegistrieren")
public class MailValidatorRegistrieren implements Validator {

    @EJB
    private DAO dao;
    private String mail;
    private static final Pattern EMAIL_PATTERN =
            Pattern.compile("^[A-Z0-9._%+-][email protected][A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);

    @Override
    public void validate(FacesContext facesContext, UIComponent uiComponent, Object o) throws ValidatorException {
        mail = (String)o;
        boolean matchesPattern = EMAIL_PATTERN.matcher(mail).find();

        if(!matchesPattern)
        {
            throw new ValidatorException((new FacesMessage("Ungültige E-Mail-Adresse","Bitte erneut eingeben!")));
        }

        if(mail.isEmpty()) {
            return;
        } else if(validateNutzer(mail)){
            throw new ValidatorException(new FacesMessage("Die E-Mail-Adresse ist bereits vergeben!"));
        } else{
            return;
        }

    }

    private boolean validateNutzer(String mail) {
        try {
            Nutzer n = dao.findNutzerByMail(mail);
            return n.getMail().equals(mail);
        } catch (NullPointerException e) {
            return false;
        }
    }
}
Und so die "findNutzerByMail"Methode in der DAO:

Java:
public Nutzer findNutzerByMail(String mail) {
        try {
            return em.createNamedQuery("findNutzerByMail", Nutzer.class)
                    .setParameter("mail", mail)
                    .getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }
Das Problem ist, dass er nun trotz bereits existierender Mail in der DB einen Eintrag mit der gleichen Mail hinzufügt, dann aber direkt eine NonUniqueResultException wirft, da er ja nun 2 Einträge findet. Ich frage mich, wie das sein kann, denn eigentlich kommt die Validierung im JSF-Lebenszyklus doch vor der Invoke-Application-Phase und er müsste somit nach der Validierung abbrechen.

Sieht jemand den Fehler?
 
Gleiches Problem, habe es nur erst mal auf die Registrieren-Seite verschoben. Allerdings funktioniert das nicht wie ich es mir vorstelle und ich weiß absolut nicht wieso..
 
Zuletzt bearbeitet:
Deine private validateNutzer Methode sieht falsch aus. Zum einen ist bei der Benennung völlig unklar, was denn der boolsche Rückgabewert überhaupt aussagen soll. Eigentlich willst du doch nur prüfen, ob es einen solchen Benutzer mit der übergebenen Mail-Adresse gibt?! Dann nenn die Methode doch auch so ... also etwa doesUserExistsWithMail(String mail) Darin braucht es nur eine Überprüfung à la return dao.findNutzerByMail(mail) != null
Die NullPointerException zu fangen und in diesem Fall einfach false zurückzugeben ist gefährlich. Bist du dir sicher, dass die EJB Injection deines DAO überhaupt funktioniert? Wenn nein, dann gibt die Methode ebenfalls false zurück. (Und keine Ahnung, ob das mit den neuesten Versionen mittlerweile geht, aber noch vor einiger Zeit war EJB Injection in JSF Validatoren technsich nicht möglich.)
Wenn du damit noch nicht weiterkommst, dann versuch doch bitte ein MCVE zu erstellen, die geposteten Code-Schnipsel zeigen das Problem möglicherweise gar nicht. Außerdem ist es mitunter wichtig zu wissen welche exakte Plattform du verwendest (welche JSF Version und welche Implementierung, welche EJB Version usw...)
 
Bist du dir sicher, dass die EJB Injection deines DAO überhaupt funktioniert? Wenn nein, dann gibt die Methode ebenfalls false zurück.
...und das würde nebenbei bemerkt auch das beschriebene Verhalten erklären. Aber nur geraten, ich hab nix getestet.
 
Passende Stellenanzeigen aus deiner Region:

Oben