Tutorial: JSF 2.0 Beispielanwendung

Wie schon erwähnt, erscheinen bald die ersten Releases von JSF 2.0. Entsprechend wird nun eine kleine Beispielanwendung erstellt, um einen ersten Eindruck zu bekommen. Technologie:

  • JSF 2.0: Mojarra in Version 2.0.0-b16
  • Tomcat 6
  • Maven
  • Eclipse

Voraussetzung:

Vorbereitung:

  1. In Eclipse ein dynamische Webprojekt erstellen
  2. Tomcat 6 als Server in Eclipse einrichten
  3. Dem Projekt "Maven Nature" hinzufügen. Zur Zeit ist das Projekt ein reines Webprojekt ohne Maven Eigenschaften. Durch Rechte-Maustaste auf das Projekt und dann Maven > Enable Dependency Management wird Maven-Funktionalität für das Projekt hinzugefügt
  4. Maven erwartet eine andere Ordner-Struktur als in dem WTP-Webprojekt. Als erstes muss der Source-Ordner angepasst werden. Hierfür müssen mind. folgender Ordner erstellt werden: src/main/java. Diesen muss man in Eclipse dann auch als Source-Ordner konfigurieren (Java Build Path)
  5. Der WebContent-Ordner wird von Maven mit der WTP-Integration genutzt. Hier ist keine Veränderung/Anpassung notwendig
  6. Die existierende pom.xml muss entsprechende Einträge erweitert werden. Für JSF 2 könnte das wie folgt aussehen:

    <project xmlns="http://maven.apache.org/POM/4.0.0"; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4\_0\_0.xsd"> 4.0.0 jsf2test jsf2test 0.0.1-SNAPSHOT

    2.0.0-b16 4.4 1.2 2.5 1.2.14 maven2-repository.dev.java.net Java.net Repository for Maven http://download.java.net/maven/2/ default jsf2test maven-compiler-plugin 1.5 1.5 org.mortbay.jetty maven-jetty-plugin 6.1.15 com.sun.faces jsf-api ${version.jsf2}
    <dependency>
    	<groupId>com.sun.faces</groupId>
    	<artifactId>jsf-impl</artifactId>
    	<version>${version.jsf2}</version>
    </dependency>
    
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>${version.jstl}</version>
    </dependency>
    
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>${version.servlet}</version>
    </dependency>
    
    <!-- Misc -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${version.junit}</version>
      <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>${version.log4j}</version>
    </dependency>
  7. Die Bibliotheken, welche Maven bereitstellt, müssen beim Deploy in WEB/lib kopiert werden. Die Nutzung der Maven Dependencies geschieht durch folgende Einstellung: In den Eigenschaften des Projekts muss unter Java EE Module Dependencies die Maven Dependencies ausgewählt werden.
  8. Web.xml für JSF anpassen. Z.B. wie folgt:

    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; xmlns="http://java.sun.com/xml/ns/javaee"; xmlns:web="http://java.sun.com/xml/ns/javaee/web-app\_2\_5.xsd"; xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app\_2\_5.xsd"; id="WebApp_ID" version="2.5"> dynWebTest

    Faces Servlet javax.faces.webapp.FacesServlet 1 Faces Servlet \*.xhtml javax.faces.PROJECT\_STAGE Development index.html index.xhtml

Nun steht das Grundgerüst bereit, um endlich mit JSF 2.0 anzufangen. Für diejenigen, die mit JSF 1.x schon gearbeitet haben, werden wohl die faces-config.xml vermissen. Korrekt. Ist gewollt. Ist nämlich die erste Verbesserung von JSF 2.0! Die faces-config.xml kann immer noch verwendet werden, aber vieles ist durch Annotations möglich und die Navigation ist einfacher/verständlicher geworden. Später mehr dazu.

Vielleicht noch ein paar Worte zur Beispielanwendung: Die Beispielanwendung beinhaltet eine Seite, mit einem Input-Feld und zwei Select-Boxen. Man stelle sich folgendes Szenario vor: Man möchte ein Registrierungs-Formular erstellen, in dem der Nutzer überprüfen kann, ob der Username noch vorhanden ist. Zusätzlich soll er das Land auswählen können, in dem er lebt.

Controller: Der Controller ist das ManagedBean, welches in den XHTML-Seiten verwendet wird und alle Anfragen verarbeitet.

@ManagedBean(name = "fc") @RequestScoped public class FrontController { private Person person;

private String country;

private String continent;

private Map<String, String\[\]> countries;

@ManagedProperty(value = &quot;#{authService}&quot;)
private AuthService authService;


public void isUsernameValid() {
	
	if(authService.isUsernameValid(person.getUsername())) {
		
		output = &quot;Username ist nocht nicht vorhanden&quot;;
	} else {
		output = &quot;Username ist schon vorhanden. Bitte einen anderen auswählen&quot;;
	}
}

    public String\[\] getCountries() {
	// deliver the countries to the actual continent
	return countries.get(continent);
}
   /\* further get/set-Methods \*/

}

Durch die Annotations wird JSF mitgeteilt, dass es sich bei der Klasse um ein managed bean mit dem Namen fc handelt (@ManagedBean) und die jeweils immer nur für ein Request gültig ist (@RequestScoped, weitere Scops sind vorhanden). Früher hat man diese Einstellungen in faces-config.xml durchgeführt. Neu ist auch @ManagedProperty. Mittels dieser Annotation wird die Dependency Injection Funktionalität von JSF 2.0 verwendet. In FrontController#authService wird nun das passende Objekt mit dem managed bean namen "authService" injiziert. Hier sei anzumerken, dass JSF kein field access durchführt, sondern die getter/setter-Methoden verwendet um Properties zu setzen.

Die Domain-Klasse Person ist ein einfaches Bean bzw. POJO, und repräsentiert die einzugebenden Daten in dem Formular.

Zu dem Controller und Model Teil gehört noch die Präsentation und diese wird mittels Facelets durchgeführt. In JSF 2.0 ist Facelets die primäre Technologie zur Beschreibung des Views. Man kann natürlich JSP nutzen, wenn man den Sprung nicht durchführen möchte. Aber die Vorteile liegen eher bei Facelets!

<h:head>

JSF Demo

Register

<h:inputText id=&quot;name&quot; value=&quot;#{fc.person.username}&quot;>
</h:inputText>
<h:commandButton value=&quot;Check username&quot; action=&quot;#{fc.isUsernameValid}&quot;>
	<f:ajax execute=&quot;name&quot; render=&quot;outIsUserValid&quot; />
</h:commandButton>
<h:outputText id=&quot;outIsUserValid&quot; value=&quot;#{fc.output}&quot; />

</h:form>

<h:form> <h:selectOneMenu value="#{fc.continent}"> <f:selectItems value="#{fc.continents}" /> <f:ajax render="countrylist" /> </h:selectOneMenu> <h:selectOneMenu value="#{fc.country}" id="countrylist"> <f:selectItems value="#{fc.countries}" /> </h:selectOneMenu> </h:form> </h:body>

Mittels Facelets ist die Beschreibung der Views reiner XML/XHTML. In dem ersten Formular ist das Input-Feld, in dem der Nutzer überprüfen kann, ob sein Username schon vergeben ist. Die Überprüfung wird mittels Ajax durchgeführt. Hierfür ist der neue <f:ajax>-Tag zuständig. Beim betätigen des Buttons wird ein Ajax-Request verschickt, dieser beinhaltet die Werte aus den Felder in dem execute-Attribute. In unserem Fall aus dem Feld mit der ID name. Die Antwort wird, wie in dem render-Attribute definiert, in ID outIsUserValid eingefügt. Auf dem Server wird zur Verarbeitung die Methode FrontController.isUsernameValid() aufgerufen. Während des Aufrus ist FrontController#person mit den aktuellen Werten (hier: username) gesetzt.

In dem zweiten Formular gibt es zwei Select-Boxen. In dem einen kann ein Kontinent ausgewählt werden. Resultierend dazu, wird in der zweiten eine Liste von Ländern angezeigt. Diese Länder-Liste wird durch Ajax ermittelt. In der ersten Liste ist wieder ein <f:ajax>-Tag zu finden. Bei dem 1. Beispiel wurde der Request verschickt, wenn der Nutzer den Button drückt. D.h. in der Javascript-Welt, beim Click-Event, wird der Request verschickt. Das <f:ajax>-Tag wählt immer das passende Event aus, abhängig von der Komponente, in dem es verwendet wird. Bei Listen horcht es auf ein OnChange-Event. Natürlich kann man ein anderes Event festlegen, dafür gibt es das event-Attribut. D.h. also, sobald in der ersten Liste die Auswahl verändert wird, wird die zweite Liste aktualisiert (durch render="countrylist"). Auf dem Server wird FrontController.getCountries() aufgerufen. In dem Kontext ist FrontController#continent belegt, da der Nutzer eine Auswahl in der 1.Liste durchgeführt hat. FrontController.getCountries() liefert nun nur ein Array von Ländern zurück. Die korrekte Verschachtelung in HTML-Elemente (option-Tag) übernimmt JSF!

Fazit:

  • Mittels JSF 2.0 hat man weniger Konfigurationsaufwand
  • Durch den Einsatz von Facelets macht das Erstellen der HTML-Seiten wieder Spass. Hier kann man die vorhandenen HTML-Templates fast unverändert übernehmen...
  • Unproblematischer Javascript/Ajax-Einsatz, ohne es wirklich zu merken!
  • DI ohne Spring!

Also der erste Eindruck hat überzeugt. Wenn man JSF-Fan war, wird man JSF-Fan weiter bleiben. Wenn nicht, könnte man es jetzt bestimmt werden ;-)

comment

Comments

arrow_back

Previous

Spec 2.0: JSF 2 Überblick

Next

Commons-IO: DirectoryWalker
arrow_forward