# JSF/Facelets - Fehlermeldung ausgeben



## berndt (15. Jun 2007)

Hallo!

Ich habe nur eine kleine Frage, deren Lösung sich mir gerade nicht erschliesen will.

Und war habe ich ein simples Eingabeformular. Man gibt eine Antwort ein, klickt auf den Submit-Button, die Methode *mybean.antwortsenden* liest die getter-Variable von *getAntworttext()* aus, ermittelt was drin steht, und wenn die Antwort ok ist, soll weitergeleitet werden indem der String "weiter" zurückgeliefert wird. 

Meine Frage nun, wie schaffe ich es, dass wenn die eingegebene Antwort falsch war, dieselbe Seite neu geladen wird und ein selbst definierter Fehlermeldungstext unter dem Eingabefeld erscheint? Habs bisher so gemacht das wenn die Antwort falsch ist, der String "fehler" zurückgeliefert worden ist. 


```
<h:inputText id="antwort" value="#{mybean.anworttext}"/> 

<h:message for="antwort"  /> 

<h:commandButton value="Antwort senden" action="#{mybean.antwortsenden}"/>
```


```
<navigation-rule>
        <description>
            Startseite
        </description>
        <from-view-id>/start.xhtml</from-view-id>
        <navigation-case>
            <description>
                von Startseite zu Ergebnisseite
            </description>
            <from-outcome>weiter</from-outcome>
            <to-view-id>/ergebnis.xhtml</to-view-id>
        </navigation-case>
        <navigation-case>
            <description>
                Fehlerhafte Antwort
            </description>
            <from-outcome>fehler</from-outcome>
            <to-view-id>/start.xhtml</to-view-id>
        </navigation-case>
    </navigation-rule>
```


----------



## WeirdAl (15. Jun 2007)

Hi,
dazu gibts die Validatoren. Hier mal als Beispiel einen Validator der die Eingabe eines Nutzernamens bei dem registrieren prüft (nach dem submit in einer form):


```
<h:outputText value="Username:" /> 
					<h:inputText id="userName" value="#{registerBean.userName}" 
						validator="#{registerBean.validateUserName}" required="true">
					</h:inputText>
```

Und hier der Validator in dem Bean:




```
public void validateUserName(FacesContext context,
			 UIComponent componentToValidate,
			 Object value) 
			 throws ValidatorException {
				
		// Object value ist der String im InputText


		// prüfe ob User vorhanden ist wenn ja dann gebe eine Fehlermeldung aus:
			FacesMessage message = new FacesMessage(User existiert bereits"));
			throw new ValidatorException(message);
				
	}
```

Diese faceMessage erscheint dann im Bereich <h:messages> oder <h:message for...>. Ich hoffe das hilft dir weiter


Cu
Alex


----------



## berndt (16. Jun 2007)

Vielen Dank für die Antwort Alex. 

So wie es aussieht funktioniert es mit dem Validator nicht. Ich muss die Überprüfung in "mybean.antwortsenden" erledigen, da ich dort noch auf die getter einiger anderer Input-Felder zugreifen muss. Habe ich leider vergessen zu erwähnen.
Von einer Validator-Methode aus, kann ich leider nicht auf die getter der anderen Variablen zugreifen, da diese noch nicht gesetzt worden sind.

Stell dir einfach vor, es sind 2 Eingabefelder vorhanden. Beide müssen in einer Methode (antwortsenden) miteinander verglichen werden und je nach Ergebnis wird dann entweder "weiter" zurückgesendet, oder aber eine Fehlermeldung welche dann angezeigt werden soll.

Eine Idee wie ich das lösen kann?


----------



## WeirdAl (16. Jun 2007)

Hi,
nee das geht schon in einem Validator. Stell Dir vor neben dem UserName hast Du noch eine Emailadresse. Du musst nun überprüfen, ob Username UND Emailadresse vorhanden sind. Dazu bindest Du Dir zb. die Emailadresse auf UIInput BeanInput im Bean. 

Hier mal ein Snippet als Beispiel, wo ich Username und Passwort bei meinem Login überprüfe:


```
private UIInput loginInput;
	private UIInput pwInput;
	
	public AuthenticBean() {
	}
	
	/**
	 * checks if user exists
	 * if not throw a Message
	 */
	public void validateLogin(FacesContext context,
							 UIComponent componentToValidate,
							 Object value) 
							 throws ValidatorException {
		
		String login2check = loginInput.getLocalValue().toString();
		String pw2check = value.toString();
		
			
			switch (UserRegistry.isUserReg(login2check, pw2check)) {
			// no user found
			case -1:{
				FacesMessage message = new FacesMessage(this.getMessageBundle().
														getString("AuthenticBean.noUserFound"));
				throw new ValidatorException(message);
				}
			// pw wrong
//login wrong
...
			default:
				break;
			}
	}
```


----------



## berndt (16. Jun 2007)

Hättest du mir noch den dazugehörigen JSF-Code? Bekomme das leider nicht so ganz hin. 

Vielen Dank!


----------



## WeirdAl (16. Jun 2007)

Sischa Sischa 

Hier der JSF Teil: 

```
...
		
	    	<h:form id="loginForm">	
				<h:panelGrid styleClass="panelGrid" id="loginPanelGrid" columns="2" >
					<h:outputText id="loginText" value="Login:" />
					<h:inputText id="userLogin" size="8" binding="#{authenticBean.loginInput}" required="true"/>
					<h:outputText id="pwText" value="Pass:" />
					<h:inputSecret id="PW" required="true" size="8" 
						binding="#{authenticBean.pwInput}" validator="#{authenticBean.validateLogin}" />
					<h:commandButton id="loginButton" action="#{authenticBean.login}" 
						value="#{webContentBundle['button.login']}"/>
				</h:panelGrid>
			</h:form>
	...
```


----------



## berndt (17. Jun 2007)

Nach einigen Anpassungen hat es nun wunderbar geklappt. Vielen Dank für die Hilfe Alex.

Kannst du mir vielleicht noch erklären was genau da nun passiert ist? Ich vermute mal das während der Validierung mittels der Befehle


```
String login2check = loginInput.getLocalValue().toString(); 
String pw2check = value.toString();
```

die UI-Elemente aus dem Komponentenbaum ausgelesen worden sind, da zu diesem Zeitpunkt die Variablen der Bean noch nicht gesetzt werden.


----------



## WeirdAl (17. Jun 2007)

Hi,
jo mit UIInput kannst Du auf das gebundene Inputfeld im Komponentenbaum direkt zugreifen. Dies geht für jedes JSF-Element im Komponentenbaum. Da zu dem Zeitpunkt der Validierung die Werte in der Bean noch nicht gesetzt wurden (wie Du bereits selbst gesagt hast) musst Du über den Komponentenbaum auf die Felder/Properties, die nicht das value-Objekt sind, zugreifen. Wieso man jetzt genau mit getLocalValue an das Objekt kommt kann ich Dir nicht 100%ig sagen, da ich mir die API dazu nicht angsehen habe  (ich habs blind aus einem Buch übernommen)

Cu
Alex


----------



## berndt (17. Jun 2007)

Danke! Und wieso wird hier Bindung benutzt, anstatt einfach "value"?


```
<h:inputText id="userLogin" size="8" binding="#{authenticBean.loginInput}" required="true"/>
```


----------



## WeirdAl (17. Jun 2007)

Weil value vom Typ String und binding vom Typ UIComponent ist.  Hier  in der Komponentenliste findest Du eine Übersicht der Unterklassen von UIComponent. (Die Liste ist zwar von der 1.1 Api, aber da dürfte sich in 1.2 nichts geändert haben)

Edit: Ah ich glaub jetzt weiss ich was Du meinst: Ich habe hier kein value genutzt, da ich die Logindaten nur prüfe und nicht weiterverarbeite. Daher hole ich mir die Werte von login und pw via binding und brauche kein String Login, pw. (Das spart mir auch getter/setter von den zwei Strings).
Wobei ich der Lesbarkeit halber mittlerweile nur noch dort Bindings nutze, wo ich sie zum validieren oder selektieren, zb von Tabellenreihen, benötige. 

Cu
Alex


----------



## berndt (17. Jun 2007)

Ich hab in einem Buch gelesen das man für Bindings eigene Backing Beans benutzen und es vermeiden soll diese mit Managed Beans zu vermischen.

Also hätte dein Code auch funktioniert wenn man statt bindings einfach nur normale values mit setter und getter benutzt hätte?


----------



## WeirdAl (18. Jun 2007)

Hi,
Normal "sollte" man für eine View eine Bean benutzen. Es würde nicht mit values gehen, da man nur mit den Bindings an die zu prüfenden Werte kommt, da sie ja noch nicht in der Bean "eingetragen" wurden.




> Ich hab in einem Buch gelesen das man für Bindings eigene Backing Beans benutzen und es vermeiden soll diese mit Managed Beans zu vermischen.


Welches Buch war denn das? 
Managed Beans sind "nur" Instanzen von Backing Beans und wenn man z.B. Bindings und Strings nebst gettern/settern splittet, würde man somit nur zwei Managed Beans für eine View erstellen. (Link dazu)

Cu
Alex


----------



## Bluevelvet64 (27. Dez 2007)

Hallo


habe ein ähnliches Problem und habe mich an Deiner Lösung orientiert.

Aber ich bekomme nur folgende fehlermedlung :

27.12.2007 22:26:39 com.sun.faces.lifecycle.LifecycleImpl phase
WARNUNG: executePhase(RENDER_RESPONSE 6,com.sun.faces.context.FacesContextImpl@147a87e) threw exception
javax.faces.FacesException: org.apache.jasper.JasperException: An exception occurred processing JSP page /pages/login/login.jsp at line 13

10:     <DIV class="loginbox">
11:         <DIV class="textueber">Privatkunden</DIV>
12:         <DIV class="textbox">Name</div>
13:         <DIV class="inputbox"><h:inputText binding="#{Login.priv_name}"/></div>
14:         <DIV class="textbox">Passwort</div>
15:         <DIV class="inputbox"><h:inputSecret binding="#{Login.priv_pass}" /></div>
16:         <DIV class="buttonbox"><h:commandButton id="login_priv" actionListener="#{Login.check_login}" value="Anmelden"/></div>

Login ist in der faces-config  mit Bean.LoginBean verbunden.

Den Quellcode aus der JSP siehst Du ja in der fehlermeldung.  Hier ist der Code aus der bean

public class LoginBean
{
    private UIInput priv_name;
    private UIInput priv_pass;

    public void check_priv(FacesContext context, UIComponent input, Object value) throws ValidatorException
    {
      ... ...
    }

    public void check_login(ActionEvent event)
    {        

        if(...)
        {    
          .....
        }

    }

}

Ich vermute das die Komponente priv_name nicht gefunden wird weil das Objekt private ist. ( Auch netBeans zeigt mir über die Erweiterung das Objekt priv_name nicht an).  Wenn ich das ganze über value binde, und eine getter und setter methode einbaue ( für eine String komponente ) funktioniert es. ( getter und setter sind ja public ) Ebenso wird die check_priv Methode nicht gefunden. Der ActionListener den ich auch in der bean verwende wird gefunden. Beide die Validator und die AcktionListener methode sind public. Warum finde ich zwar den ActionListener aber nicht den Validator. Und warum wird das UIInput Element nicht gefunden, wohl aber eine getter methode.

Leider geben auch die Bücher die ich verwende, hier keine richtige Auskunft.

Danke für eine Auskunft.


----------



## Gast (5. Feb 2008)

Hallo

ich glaube du müsstest Dich an die Namens-Konventionen halten. 

priv_name und priv_pass und check_login folgen nicht ganz dieser Konvention. Die Setter und Getter könnten die Ursache des Problems sein ... Besser wäre  

privName und privPass und checkLogin 

bin aber nicht sicher ob Deine Fehler dann verschwinden.

Gruss
C


----------

