20.01.2013

Java Server Faces - JSFs

In diesem Artikel wird kurz beschrieben, wie eine JSF-Seite aufgebaut ist und wie sie verwendet werden kann. Dies wird an dem "bekannten" Beispiel eines Einkaufswagens (Shopping-Cart) erklärt. Dieser Artikel ist keine Einführung in die JSF-Programmierung. Er soll vielmehr zeigen, wie die grundlegende Funktionsweise von JSF-Seiten ist. In den folgenden Artikeln zum Thema Java EE6 Web-Client werden andere Technologien vorgestellt, um Web-Oberflächen und Web-Clients zu erstellen.

Die fertige Anwendung, die in diesem Artikel erstellt wird, sieht im Browser folgendermaßen aus:

Auf der linken Seite lassen sich in dem Textfeld Artikelbezeichnungen eintragen und über die ComboBox wird eine Menge von 1 bis 5 ausgewählt. Mit dem Button Hinzufügen wird der Artikel in den Warenkorb gelegt und in einer Liste oberhalb angezeigt. Mit dem Button Warenkorb leeren werden alle Artikel aus dem Warenkorb entfernt und die Liste wird nicht mehr angezeigt.

Die folgende Abbildung zeigt den Ablauf einer Anfrage an den Web-Container und die Antwort an den Client.

Man sieht, dass ein Request vom Browser, in dem der Web-Client läuft, an den Web-Container, in dem das Faces-Servlet läuft, gestellt wird. Das Faces-Servlet dient in diesem Kontext als Controller und arbeitet die Business-Logik ab. Dann wird das Erstellen der Antwort an die JSF-Seite weitergeleitet. Die View, die der Web-Container an den Browser als Response zurückgeliefert, wird also durch das Verarbeiter der JSF-Seite erstellt. Wichtig ist, dass beim Übergang vom Faces-Servlet zur JSF-Seite, der JSF-Lifecycle durchlaufen wird. Das Ergebnis ist eine fertige HTML-Seite, die an den Browser gesendet werden kann. (Anmerkung: Die Darstellung ist sehr vereinfacht. Der JSF-Lifecycle wäre einen eigenen Artikel wert.)

Der zugehörige Java-Quellcode sieht folgendermaßen aus:

package org.hameister.shoppingcarts;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

/**
 *
 * @author hameister
 */
@Named
@SessionScoped
public class CartJSF implements Serializable {
    private List<String> items = new ArrayList<String>();
    
    private String item;
    private String quantity;
    
    public String getItem() {
        return item;
    }

    public void setItem(String item) {
        this.item = item;
    }

    public String getQuantity() {
        return quantity;
    }

    public void setQuantity(String quantity) {
        this.quantity = quantity;
    }
    
    public String add() {
        System.out.println(quantity + " × " + item);
        
        
        items.add(quantity + " × " + item);
        
        item = null;
        quantity = "1";
        
        return "jsf-page";
    }

    public List<String> getItems() {
        return items;
    }
    
    public void reset() {
        items.clear();
    }
}

Was bei dieser Klasse sofort auffällt ist, dass sie sehr einfach und übersichtlich ist. (im Vergleich zu der JSP- oder auch Servlet-Lösung). Über die Annotation @Named wird mittels Dependency Injection dafür gesorgt, dass die Klasse von der JSF-Seite aus erreichbar ist. Und die Annotation @SessionScoped ist dafür zuständig, dass für jede neue Session ein neues Objekt der Klasse erstellt wird.

Die folgende XML-Datei enthält die JSF-Seite.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:c="http://java.sun.com/jsp/jstl/core">
    <h:head>
        <title>Shopping Cart</title>
    </h:head>
    <h:body>

        <h:form>
            <c:choose>
                <c:when test="${not empty cartJSF.items}">
                    <h2>Artikel im Warenkorb:</h2>
                </c:when>
            </c:choose>
            <h:dataTable value="#{cartJSF.items}" var="item">
                <h:column>
                    ˙ #{item}
                </h:column>
            </h:dataTable>
            <br/>
            <strong>Artikel zum Warenkorb hinzufügen:</strong><br/>
            <h:inputText value="#{cartJSF.item}"/>
            <h:selectOneListbox size="1" value="#{cartJSF.quantity}">
                <f:selectItem itemLabel="1" itemValue="1" />
                <f:selectItem itemLabel="2" itemValue="2" />
                <f:selectItem itemLabel="3" itemValue="3" />
                <f:selectItem itemLabel="4" itemValue="4" />
                <f:selectItem itemLabel="5" itemValue="5" />
            </h:selectOneListbox>
            <h:commandButton value="Hinzufügen" action="#{cartJSF.add()}"/><br/>
            <h:commandButton value="Warenkorb leeren" action="#{cartJSF.reset()}"/>
        </h:form>
    </h:body>
</html>

In der JSF-Seite werden ausschließlich XML-Elemente aus verschiedenen JSF-Tag-Bibliotheken verwendet. Es ist also kein Java-Code enthalten. Um den Zugriff auf die Bean CartJSF zu ermöglichen, wird eine Expression Language (EL) verwendet. Dadurch, dass in der Klasse CartJSF, die Annotation @Named verwendet wurde, ist dieser Zugriff auf diese Weise möglich.

Zum Aufbau der JSF-Seite läßt sich erstmal folgendes sagen:

  • Die JSF-Seite besteht aus einem <form>-Element, in das alle weiteren Komponenten eingebettet sind.
  • Mit den Elementen <c:choose> und <c:when> wird dafür gesorgt, dass der Text Artikel im Warenkorb: nur dann angezeigt wird, wenn sich Artikel im Warenkorb befinden.
  • Die Komponente <h:dataTable> dient der tabellarischen Darstellung von Daten. In dem Beispiel wird nur eine Spalte verwendet. Ein ausführlicheres Beispiel ist in dem Artikel zum Thema EJBs und TimerService zu finden.
  • Das Eingabefeld ist mit einem <h:inputText>-Element umgesetzt und greift direkt über die getter und setter auf die Variable item im Bean zu.
  • Mit dem Element <h:selectOneListbox> wird die ComboBox erstellt. Mit dem Attribut size wird dafür gesorgt, dass nur eine Zeile angezeigt wird und über das Attribut value wird die Verbindung zum Bean hergestellt.
  • Die Buttons werden über das Element <commandButton> erstellt. Diesmal enthält das Attribut value den Button-Text und das Attribut action ruft beim Klick auf den Button die entsprechende Methode in der Bean auf.

Weitere Informationen

Weitere Informationen zu Web-Clients findet man in den folgenden Artikeln:

  1. Einleitung - Teil 1
  2. Servlets - Teil 2
  3. JSP-Seiten - Teil 3
  4. JSP-Seiten mit JSTL - Teil 4
  5. JSF-Seiten - Teil 5
  6. JSF-Seiten mit Ajax - Teil 6
  7. JSF-Templates - Teil 7