"
 
 1 Einführung in JavaServer Faces
"
 
 2 Die Konzepte von JavaServer Faces
"
 
 3 Standard-JSF-Komponenten
"
 
 4 Advanced JSF
"
 
 5 Verwaltung von Ressourcen
"
 
 6 Die eigene JSF-Komponente
"
 
 7 Ajax und JSF
"
 
 8 JSF und HTML5
"
 
 9 JSF und CDI
"
 
 10 PrimeFaces -- JSF und mehr
"
 
 11 Faces-Flows
"
 
 12 MyGourmet Fullstack -- JSF, CDI und JPA mit CODI kombiniert
"
 
 13 JSF und Spring
"
 
 14 MyGourmet Fullstack Spring -- JSF, Spring, Orchestra und JPA kombiniert
"
 
 15 Tobago -- JSF und mehr
"
 
 16 Eine kurze Einführung in Maven
"
 
 17 Eclipse
"
 
 18 Autoren
"
 
 19 Änderungshistorie

10 PrimeFaces -- JSF und mehr

Komponenten sind ein essenzieller Bestandteil von JavaServer Faces und bilden einen zentralen Erweiterungspunkt. Der JSF-Standard definiert bereits eine ganze Reihe von Komponenten und Tags für die grundlegenden Anforderungen einer Webapplikation. Darüber hinausgehend sind im Laufe der letzten Jahre diverse Komponentenbibliotheken entstanden. Die meisten dieser Bibliotheken bieten neben einem erweiterten Angebot von Komponenten auch noch andere Konzepte, die das Entwickeln von JSF-Anwendungen teils erheblich vereinfachen. Eine der zurzeit populärsten und am aktivsten weiterentwickelten Komponentenbibliotheken ist PrimeFaces . In diesem Kapitel werden wir Ihnen zeigen, welche Funktionalitäten PrimeFaces in Version 3.5 über den JSF-Standard hinaus anbietet.
Nach einem kurzen Überblick in Abschnitt [Sektion:  PrimeFaces -- ein Überblick] gibt Abschnitt [Sektion:  Komponenten] einen Einblick in die Welt der PrimeFaces -Komponenten. In Abschnitt [Sektion:  Themes] zeigen wir Ihnen anschließend, wie Sie das Aussehen einer PrimeFaces -Applikation mit Themes anpassen. PrimeFaces bietet auch im Ajax-Bereich einige Erweiterungen gegenüber dem JSF-Standard - Abschnitt [Sektion:  PrimeFaces und Ajax] zeigt die Details. Abschließend werfen wir in Abschnitt [Sektion:  MyGourmet 18: PrimeFaces] noch einen Blick auf das Beispiel MyGourmet 18 .

10.1 PrimeFaces -- ein Überblick

PrimeFaces hat sich seit seiner Veröffentlichung im Jahr 2010 zu einer der populärsten Open-Source-Komponentenbibliotheken für JSF entwickelt. Der Kernbestandteil von PrimeFaces ist ein Set von momentan etwa 100 aufeinander abgestimmter Komponenten, deren Erscheinungsbild mit Themes an eigene Bedürfnisse angepasst werden kann. Die Palette der angebotenen Funktionalität geht weit über den JSF-Standard hinaus und reicht von diversen Eingabekomponenten über Komponenten zur Darstellung von Daten in Form von Listen, Bäumen oder Tabellen bis hin zu Komponenten für Diagramme oder Google-Maps . Als Zugabe gibt es unter anderem noch Erweiterungen im Bereich Ajax und die Unterstützung von Ajax-Push. Mit PrimeFaces Mobile existiert zusätzlich eine angepasste Variante, um die Entwicklung von Webapplikationen für mobile Endgeräte zu vereinfachen.
Neben der Funktionalität legen die Entwickler von PrimeFaces einen starken Fokus auf Themen wie Leichtgewichtigkeit und Performance - ein Unterfangen, das durchaus als gelungen bezeichnet werden kann. Die Integration von PrimeFaces in die eigene Webapplikation gestaltet sich daher äußerst einfach. Für die Basisversion muss lediglich eine einzige Jar-Datei in das Projekt eingebunden werden. Nur beim Einsatz von optionalen Features wie dem Export nach PDF oder Excel oder dem File-Upload sind weitere Abhängigkeiten notwendig. Details dazu entnehmen Sie bitte der Dokumentation von PrimeFaces .
Falls Sie in Ihrem Projekt Maven einsetzen, müssen Sie nur die in Listing Maven-Abhängigkeit für PrimeFaces gezeigte Abhängigkeit zur pom.xml hinzufügen. Andernfalls finden Sie die aktuellste Version von PrimeFaces unter .
<dependency>
  <groupId>org.primefaces</groupId>
  <artifactId>primefaces</artifactId>
  <version>3.5</version>
</dependency>
Damit Maven die Abhängigkeit auflösen kann, muss das PrimeFaces -Repository mit der URL http://repository.primefaces.org in der pom.xml eingetragen werden. Details dazu finden Sie im Quellcode zu MyGourmet 18 .
Ansonsten ist keine weitere Konfiguration notwendig - weder in der web.xml noch in der faces-config.xml . Hier zeigt sich deutlich der Fokus auf die Leichtgewichtigkeit in allen Belangen.

10.2 Komponenten

PrimeFaces bietet in Version 3.5 etwa 100 Komponenten für die unterschiedlichsten Anwendungsfälle an, die unter dem Namensraum http://primefaces.org/ui verfügbar sind. Die Vorstellung aller Komponenten würde den Rahmen des Buches sprengen, weshalb wir hier nur eine repräsentative Auswahl zeigen. Eine Übersicht aller verfügbaren Komponenten finden Sie unter der Adresse http://www.primefaces.org/showcase .
Listing PrimeFaces-Beispiel mit p:panel zeigt ein erstes Beispiel mit der Panel-Komponente von PrimeFaces , die über das Tag p:panel in die Seite eingebunden wird. Das Präfix p muss mit dem Namensraum http://primefaces.org/ui verknüpft sein, damit JSF die Tags der PrimeFaces -Komponenten auflösen kann. Im Beispiel bekommt das Panel über das Attribut header noch eine Überschrift und wird durch das Setzen von toggleable auf true im Browser ein- und ausblendbar gemacht. Vergessen Sie auch mit PrimeFaces nicht, h:head und h:body zu verwenden: Nur so ist gewährleistet, dass alle Stylesheets und Skripte in die Seite eingebunden werden.
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:p="http://primefaces.org/ui">
<h:head><title>Test</title></h:head>
<h:body>
  <p:panel header="Test" toggleable="true">
    <h:outputText value="Hallo, hier spricht PrimeFaces!"/>
  </p:panel>
</h:body>
</html>
Abbildung p:panel im Browser zeigt die gerenderte Ausgabe des Beispiels aus Listing PrimeFaces-Beispiel mit p:panel . Die Panel-Komponente wird automatisch mit den Einstellungen vom aktuellen Theme dargestellt. Sie müssen dazu weder ein Stylesheet einbinden (das macht JSF automatisch) noch eine CSS-Klasse auf der Komponente setzen. Details zu Themes finden Sie in Abschnitt [Sektion:  Themes] .
Abbildung:p:panel im Browser
Sie können in einer Applikation und sogar innerhalb einer Seite Komponenten und Tags aus PrimeFaces beliebig mit jenen aus dem JSF-Standard kombinieren. In den meisten Fällen müssen Sie das sogar machen, da es für Tags wie h:form , h:outputText , h:head oder h:body keine Alternativen gibt. Probleme sind dadurch nicht zu erwarten, da sich PrimeFaces sehr strikt an den JSF-Standard hält. Für andere Standardkomponenten gibt es allerdings sehr wohl Alternativen, wie der nächste Abschnitt zeigt.

10.2.1 Erweiterte Standardkomponenten

PrimeFaces bietet für eine ganze Reihe von Komponenten aus dem JSF-Standard erweiterte Varianten an. Komponenten wie p:inputText , p:selectOneRadio , p:messages oder p:outputLabel verfügen über dieselbe Grundfunktionalität wie die gleichnamigen Standardkomponenten. In den meisten Fällen sind die erweiterten Komponentenklassen sogar von den JSF-Klassen abgeleitet. Die PrimeFaces -Komponenten sollten aber trotzdem bevorzugt zum Einsatz kommen, da sie Themes unterstützen und meist zusätzliche Funktionen bereitstellen.
Listing Beispiel mit erweiterten Standardkomponenten in PrimeFaces zeigt ein Beispiel mit erweiterten Standardkomponenten aus PrimeFaces . Im Vergleich zu bisherigen Beispielen mit Tags aus dem JSF-Standard hat sich bis auf das Präfix nicht viel geändert - selbst die Namen der Attribute bleiben gleich. Ein genauerer Blick auf das Tag p:inputText mit der ID birthday zeigt, dass Konverter und Validatoren aus JSF oder aus eigenen Tag-Bibliotheken problemlos weiterverwendet werden können. Ähnliches gilt für p:selectOneRadio : Die Definition der Auswahlmöglichkeiten wird wie gehabt mit f:selectItem oder f:selectItems erledigt.
<p:messages showDetail="true" showSummary="false"/>
<h:form id="form">
  <h:panelGrid id="baseData" columns="2">
    <p:outputLabel for="name" value="Name"/>
    <p:inputText id="name" value="#{bean.name}"/>
    <p:outputLabel for="birthday" value="Geburtstag"/>
    <p:inputText id="birthday" value="#{bean.birthday}">
      <f:convertDateTime pattern="dd.MM.yyyy"/>
      <mg:validateAge minAge="18"/>
    </p:inputText>
    <p:outputLabel for="gender" value="Geschlecht"/>
    <p:selectOneRadio id="gender" value="#{bean.gender}">
      <f:selectItems value="#{bean.genderItems}"/>
    </p:selectOneRadio>
  </h:panelGrid>
</h:form>
Abbildung Gerenderte Ausgabe zum Beispiel mit erweiterten Standardkomponenten zeigt die gerenderte Ausgabe des Beispiels aus Listing Beispiel mit erweiterten Standardkomponenten in PrimeFaces mit fehlerhaften Benutzereingaben. Hier sieht man deutlich den Unterschied zu Standard-JSF, da die Komponenten automatisch mit den Einstellungen vom aktuellen Theme dargestellt werden.
Abbildung:Gerenderte Ausgabe zum Beispiel mit erweiterten Standardkomponenten
In Abbildung Gerenderte Ausgabe zum Beispiel mit erweiterten Standardkomponenten lassen sich noch weitere Vorteile von PrimeFaces erkennen. Die beiden Komponenten mit fehlerhafter Benutzereingabe werden inklusive der zugeordneten Labels in roter Farbe dargestellt. Wenn Sie ganz genau hinsehen, werden Sie noch etwas entdecken: Die Fehlermeldung für die fehlende Auswahl des Geschlechts enthält automatisch den Wert der zugeordneten Label-Komponente. In Standard-JSF würde hier die Client-ID der Komponente stehen - außer das Attribut label ist explizit gesetzt. Gerade solche Details erleichtern die tägliche Entwicklungsarbeit oft enorm.

10.2.2 Auswahl einiger PrimeFaces-Komponenten

PrimeFaces stellt eine große Zahl von Komponenten zur Verfügung, deren Funktionalität weit über den JSF-Standard hinausgeht. Im Laufe dieses Abschnitts stellen wir eine zugegeben sehr kleine Auswahl dieser Komponenten vor.

10.2.2.1 AccordionPanel -- p:accordionPanel

Die AccordionPanel-Komponente mit dem Tag p:accordionPanel stellt mehrere auf- und zuklappbare Tabs untereinander dar. Ein Tab gruppiert beliebigen Inhalt und wird mit dem Tag p:tab definiert. Die einzelnen Tabs können mit einem Klick auf ihre Titelzeile auf- und zugeklappt werden, wobei im Standardfall maximal ein Tab aktiv ist. Klickt der Benutzer auf die Titelleiste eines geschlossenen Tabs, wird dieses aufgeklappt und das zuvor aktive zugeklappt. Abbildung p:accordionPanel im Browser zeigt ein Beispiel mit drei Tabs, von denen der erste aktiv ist und der dritte komplett deaktiviert wurde (mehr dazu später).
Abbildung:p:accordionPanel im Browser
Listing p:accordionPanel zeigt den Code zum Beispiel aus Abbildung p:accordionPanel im Browser . Innerhalb von p:accordionPanel wird jeder Tab in einem p:tab -Tag mit beliebigem Inhalt definiert. Der Titel wird im Attribut title oder alternativ in einem Facet mit dem Namen title angegeben. Der dritte Tab ist durch das Setzen des Attributs disabled auf true komplett deaktiviert und kann im Browser nicht aufgeklappt werden. Wenn Sie einen Tab dynamisch deaktivieren wollen, können Sie hier natürlich auch eine Value-Expression verwenden.
<p:accordionPanel>
  <p:tab title="Tab 1">
    Inhalt Tab 1
  </p:tab>
  <p:tab title="Tab 2">
    Inhalt Tab 2
  </p:tab>
  <p:tab title="Tab 3" disabled="true">
    Inhalt Tab 3
  </p:tab>
</p:accordionPanel>
Standardmäßig werden alle Tabs von p:accordionPanel gerendert und im Browser auf- und zugeklappt. Bei komplexeren Tabs kann das aber durchaus die Ladezeit der Seite verlängern. PrimeFaces bietet daher die Möglichkeit, Tabs dynamisch über Ajax nachzuladen. Dazu muss lediglich im Tag p:accordionPanel das Attribut dynamic auf true gesetzt werden. Initial inaktive Tabs werden dann erst beim ersten Aktivieren nachgeladen. Um einen Tab bei jedem Aktivieren neu zu laden - zum Beispiel wegen dynamischer Inhalte -, muss zusätzlich das Attribut cache auf false gesetzt werden.
p:accordionPanel erlaubt das Aufklappen mehrerer Tabs, wenn das Attribut multiple auf true gesetzt wird.

10.2.2.2 Calendar -- p:calendar

Eine Komponente zur komfortablen Auswahl eines Datums darf natürlich in keiner Komponentenbibliothek fehlen. PrimeFaces macht da keine Ausnahme und bietet zu diesem Zweck die Calendar-Komponente mit dem Tag p:calendar an. p:calendar hat zwei verschiedene Darstellungsmodi, die über das Attribut mode gesetzt werden. Im Modus inline wird die Komponente rein als Auswahlfeld für ein Datum ohne Texteingabemöglichkeit durch den Benutzer dargestellt. Im Modus popup wird die Komponente hingegen als Eingabefeld angezeigt. Das Auswahlfeld wird dann nur bei Bedarf als Pop-up eingeblendet. Abbildung p:calendar im Browser zeigt die gerenderte Ausgabe von p:calendar im Modus popup mit geöffnetem Auswahlfeld.
Abbildung:p:calendar im Browser
p:calendar verfügt über einige Attribute, um das Verhalten und die Darstellung der Komponente anzupassen. Im Modus popup lässt sich zum Beispiel über das Attribut showOn das Öffnen des Auswahlfeldes steuern: Mit button wird die Datumsauswahl über eine Schaltfläche neben dem Eingabefeld geöffnet, mit focus , wenn das Eingabefeld im Browser den Fokus erhält, und mit both in beiden Fällen.
Die Titelleiste des Datumsauswahlfeldes zeigt standardmäßig den ausgewählten Monat und das Jahr an. Alternativ kann an dieser Stelle auch ein Navigator mit Auswahlfeldern für den Monat und das Jahr eingeblendet werden. Der Navigator wird durch das Setzen des Attributs navigator auf true aktiviert.
Listing p:calendar zeigt das Tag für das Beispiel in Abbildung p:calendar im Browser im Modus popup mit Öffnen über eine Schaltfläche und aktiviertem Navigator. Im Attribut pattern wird außerdem noch das Datumsformat festgelegt.
<p:calendar value="#{bean.date}" mode="popup" navigator="true"
    showOn="button" pattern="dd.MM.yyyy"/>
Aus Sicht von JSF ist die Kalenderkomponente eine Eingabekomponente wie jede andere auch (die Klasse Calendar ist eine Subklasse von HtmlInputText ) und unterstützt beliebige Konverter und Validatoren für den Datentyp java.util.Date . Wenn die Komponente keinen expliziten Konverter findet, wird der Wert intern konvertiert.
PrimeFaces liefert standardmäßig nur eine Lokalisierung für Englisch aus. Wenn Sie den Kalender wie in Abbildung p:calendar im Browser mit deutschen Texten (und Montag als ersten Tag) haben wollen, müssen Sie noch ein kurzes Stück JavaScript in Ihre Seite einbinden. Den entsprechenden Code für eine ganze Reihe von Sprachen finden Sie im PrimeFaces -Wiki http://code.google.com/p/primefaces/wiki/PrimeFacesLocales: .

10.2.2.3 DataTable -- p:dataTable

Ein weiterer Klassiker für Komponentenbibliotheken im JSF-Umfeld ist eine leistungsfähige Komponente zur tabellarischen Darstellung dynamischer Daten. Nachdem die DataTable-Komponente aus dem JSF-Standard Pagination nur halbherzig unterstützt und Features wie Sortierung oder Filterung komplett fehlen, besteht in diesem Bereich enormes Verbesserungspotenzial. In PrimeFaces gibt es dazu die DataTable-Komponente mit dem Tag p:dataTable , die all diese Features (und noch viel mehr) mitbringt.
Abbildung p:dataTable im Browser zeigt die gerenderte Ausgabe von p:dataTable mit aktivierter Pagination und Sortierung für eine Liste von Personen. Wie Sie sehen, wird auch p:dataTable gemäß dem aktuellen Theme dargestellt.
Abbildung:p:dataTable im Browser
Die grundlegende Funktionsweise von p:dataTable entspricht jener der DataTable-Komponente aus dem JSF-Standard (wie in Abschnitt Sektion:  DataTable-Komponente beschrieben). Analog zu h:dataTable verfügt auch p:dataTable über die Attribute value und var . In unserem Beispiel referenziert value eine Liste von Instanzen der Klasse Person mit den Eigenschaften name und email . Beim Einsatz von p:dataTable werden die Spalten der Tabelle mit dem Tag p:column definiert. Listing p:dataTable mit Pagination und Sortierung zeigt das XHTML-Fragment für die Tabelle aus Abbildung p:dataTable im Browser .
<p:dataTable var="person" value="#{bean.persons}"
    paginator="true" rows="5">
  <p:column headerText="Name" sortBy="#{person.name}">
    <h:outputText value="#{person.name}"/>
  </p:column>
  <p:column headerText="E-Mail" sortBy="#{person.email}">
    <h:outputText value="#{person.email}"/>
  </p:column>
</p:dataTable>
Das Hinzufügen eines Paginators für die seitenweise Darstellung großer Datenmengen ist mit p:dataTable äußerst einfach. Dazu muss nur das Attribut paginator auf den Wert true gesetzt werden. Die Anzahl der Zeilen pro Seite wird dann im Attribut rows definiert. PrimeFaces rendert standardmäßig einen Paginator mit Schaltflächen für bestimmte Seiten im Umfeld der aktuellen Seite und zur Navigation auf die erste, letzte, vorherige und nächste Seite. Das Umschalten zwischen den einzelnen Seiten erfolgt automatisch mittels Ajax.
Fall Sie den Paginator nicht wie in Abbildung p:dataTable im Browser am Anfang und am Ende der Tabelle haben wollen, müssen Sie lediglich das Attribut paginatorPosition auf den Wert top oder bottom setzen (der Standardwert ist both ).
Das Sortieren der Daten nach den Werten in einzelnen Spalten ist ähnlich einfach. Für jede Spalte kann im Attribut sortBy von p:column eine Eigenschaft der dargestellten Objekte als Sortierkriterium angegeben werden. In unserem Beispiel sind das die Eigenschaften name für die Spalte mit den Namen und email für die Spalte mit den Mailadressen. Intern benutzt die Komponente zum Vergleich zweier Werte einfach einen Java-Comparator. Sobald sortBy angegeben ist, rendert PrimeFaces ein Icon zum Sortieren der Daten, basierend auf den Werten der Spalte. Die Sortierung der Daten über einen Klick auf das Icon erfolgt ebenfalls mittels Ajax.
p:dataTable bietet noch eine Vielzahl weiterer Features wie das Filtern der Daten, die Selektion von Zeilen, das Verschieben von Spalten oder das Verändern der Spaltenbreite. Aus Platzgründen müssen wir für weitere Details allerdings auf die Dokumentation von PrimeFaces verweisen.

10.2.2.4 Menu -- p:menu

PrimeFaces stellt eine ganze Reihe von Komponenten für die verschiedensten Menüs zur Verfügung. Wir erläutern stellvertretend die Menu-Komponente mit dem Tag p:menu - die restlichen Menükomponenten funktionieren sehr ähnlich. Abbildung p:menu im Browser zeigt die gerenderte Ausgabe eines mit p:menu definierten Menüs mit diversen Menüeinträgen.
Abbildung:p:menu im Browser
Die Einträge eines Menüs werden in PrimeFaces mit dem Tag p:menuitem zu einer Menükomponente hinzugefügt. Dabei unterstützt p:menuitem Einträge mit unterschiedlichem Navigationsverhalten:
Mit dem Tag p:submenu können zusätzlich mehrere Einträge gruppiert werden. Listing p:menu mit verschiedenen Menüeinträgen zeigt das XHTML-Fragment für das Menü aus Abbildung p:menu im Browser mit vier unterschiedlichen Typen von Einträgen.
<p:menu>
  <p:menuitem value="Anbieter" outcome="providerList"/>
  <p:menuitem value="Kunden" action="#{bean.goToCustomers}"
      ajax="false"/>
  <p:menuitem value="Aktualisieren" action="#{bean.update}"
      update="form"/>
  <p:submenu label="Extern">
    <p:menuitem value="JSF@Work" url="http://jsfatwork.irian.at"
        target="_blank"/>
  </p:submenu>
</p:menu>
Das Aufbauen eines Menüs mit den beiden Tags p:menuitem und p:submenu funktioniert für andere Menükomponenten wie p:menubar , p:menuButton oder p:tabMenu exakt gleich.

10.2.2.5 PanelGrid -- p:panelGrid

Die PanelGrid-Komponente mit dem Tag p:panelGrid bietet eine einfache Möglichkeit, andere Komponenten in Form einer Tabelle anzuordnen. p:panelGrid lässt sich auf die gleiche Art und Weise wie h:panelGrid aus dem JSF-Standard verwenden (Details dazu finden Sie in Abschnitt Sektion:  Panel-Komponenten ). Die PrimeFaces -Alternative verwendet für die Darstellung allerdings automatisch die Einstellungen vom aktuellen Theme.
Der größte Pluspunkt von p:panelGrid ist die Unterstützung von Tabellenzellen, die sich über mehrere Zeilen oder Spalten erstrecken. Dazu müssen die Zeilen allerdings mit dem Tag p:row und die Spalten mit p:column definiert werden. Abbildung p:panelGrid im Browser zeigt die gerenderte Ausgabe einer mit p:panelGrid definierten Tabelle.
Abbildung:p:panelGrid im Browser
In Listing p:panelGrid finden Sie das XHTML-Fragment für die Tabelle aus Abbildung p:panelGrid im Browser . Die Zeilen und Spalten der Tabelle sind explizit mit den Tags p:row und p:column definiert - auch im Header-Facet von p:panelGrid . Damit sich eine Zelle innerhalb einer Zeile über mehrere Spalten erstreckt, muss im Tag p:column das Attribut colspan entsprechend gesetzt werden. Die Anzahl der Spalten sollte natürlich in jeder Zeile gleich sein. Analog erstreckt sich eine Zelle über mehrere Zeilen, wenn das Attribut rowspan entsprechend gesetzt wird.
<p:panelGrid>
  <f:facet name="header">
    <p:row>
      <p:column>Überschrift 1</p:column>
      <p:column colspan="2">Überschrift 2</p:column>
    </p:row>
  </f:facet>
  <p:row>
    <p:column rowspan="2">Zelle 1</p:column>
    <p:column colspan="2">Zelle 2</p:column>
  </p:row>
  <p:row>
    <p:column>Zelle 3</p:column>
    <p:column>Zelle 4</p:column>
  </p:row>
</p:panelGrid>

10.2.2.6 Rating -- p:rating

Mit p:rating können Bewertungen in Form von anklickbaren Sternen abgegeben werden. Der Wert der Rating-Komponente entspricht der Anzahl der ausgewählten Sterne. Die Komponente kann sowohl für die Eingabe als auch rein für die Ausgabe einer Bewertung dienen. Abbildung p:rating im Browser zeigt die gerenderte Ausgabe von zwei Rating-Komponenten: einmal ohne und einmal mit Icon zum Zurücksetzen des Werts auf 0.
Abbildung:p:rating im Browser
Listing Beispiele zu p:rating zeigt einige Beispiele für das Tag p:rating . Die Anzahl der auswählbaren Sterne wird im Attribut stars angegeben (der Standardwert ist 5). Das Icon zum Zurücksetzen des Werts wird standardmäßig gerendert, wenn nicht das Attribut cancel explizit auf false gesetzt wird. Mit dem Setzen des Attributs readonly auf true kann die Komponente zur reinen Ausgabekomponente umfunktioniert werden.
<p:rating value="#{bean.value}" cancel="false" stars="5"/>
<p:rating value="#{bean.value}" stars="5"/>
<p:rating value="#{bean.value}" readonly="true" stars="5"/>

10.2.2.7 Slider -- p:slider

Die Slider-Komponente mit dem Tag p:slider stellt einen Schieberegler für Zahlenwerte zur Verfügung, ist selbst aber keine Eingabekomponente. p:slider muss daher immer mit einer Eingabekomponente wie p:inputText oder h:inputHidden verbunden werden. Abbildung p:slider im Browser zeigt zwei mögliche Einsatzszenarien: einmal in Kombination mit einem Eingabefeld und einmal in Kombination mit einer reinen Textausgabe des aktuellen Werts.
Abbildung:p:slider im Browser
Die ID der verbundenen Eingabekomponente wird im Attribut for von p:slider eingetragen. Jede Betätigung des Schiebereglers aktualisiert dann den Wert des Eingabefelds im Browser. Umgekehrt funktioniert das natürlich auch: Der Schieberegler wird jedes Mal angepasst, wenn der Benutzer den Wert im Eingabefeld ändert.
Listing p:slider mit Eingabefeld zeigt ein Beispiel für die Kombination von p:slider und p:inputText . Im Tag p:slider definieren dabei die Attribute min-Value und max-Value den minimalen und maximalen Wert des Schiebereglers. Der Regler lässt sich zwischen diesen beiden Werten in Schritten bewegen, die durch das Attribut step bestimmt sind. In unserem Beispiel ergibt das die möglichen Werte -5, -4, ..., 5.
<p:inputText id="value" value="#{bean.value}"/>
<p:slider for="value" minValue="-5" maxValue="5" step="1"/>
Wenn Sie die direkte Eingabe des Werts durch den Benutzer verhindern wollen, können Sie p:slider mit h:inputHidden verbinden. In diesem Fall kann der aktuelle Wert des Schiebereglers als Text ausgegeben werden. Dazu muss lediglich die ID einer Ausgabekomponente wie h:outputText im Attribut display eingetragen werden. Listing p:slider mit Textausgabe zeigt ein entsprechendes Beispiel.
<h:inputHidden id="value" value="#{bean.value}"/>
<h:outputText value="Wert: "/>
<h:outputText id="out" value="#{bean.value}"/>
<p:slider for="value" display="out"
    minValue="0" maxValue="100"/>

10.2.2.8 Spinner -- p:spinner

Die Spinner-Komponente mit dem Tag p:spinner ist eine Eingabekomponente für Zahlen mit zwei Schaltflächen zum Erhöhen und Reduzieren des Zahlenwerts. Abbildung p:spinner im Browser zeigt die gerenderte Ausgabe eines Beispiels.
Abbildung:p:spinner im Browser
In Listing p:spinner finden Sie ein Beispiel für das Tag p:spinner . Das Attribut stepFactor definiert den Betrag, der addiert beziehungsweise subtrahiert wird. Mit den Attributen min und max lassen sich eine untere und obere Grenze für den Zahlenwert definieren.
<p:spinner value="#{bean.value}"
    stepFactor="2" min="1" max="20"/>

10.3 Themes

Das visuelle Erscheinungsbild einer PrimeFaces -Applikation lässt sich mit sogenannten Themes sehr einfach ändern. Ein Theme definiert das Aussehen einer Anwendung und bestimmt unter anderem das Farbschema oder die verwendeten Zeichensätze. PrimeFaces bietet in der aktuellen Version über 30 verschiedene Themes mit etlichen Farbkombinationen für die unterschiedlichsten Geschmäcker an. Eine Übersicht aller verfügbaren Themes finden Sie unter http://www.primefaces.org/themes.html . Abbildung Ausgewählte PrimeFaces-Themes zeigt einen kleinen Vorgeschmack.
Abbildung:Ausgewählte PrimeFaces-Themes
PrimeFaces benutzt standardmäßig das Theme mit dem Namen Aristo . Alle weiteren Themes sind nicht im Standardumfang enthalten und müssen als Jar-Datei in die Applikation eingebunden werden. Die einzelnen Themes stehen als Download auf der PrimeFaces -Seite und als Maven-Abhängigkeit im PrimeFaces -Repository zur Verfügung. Listing Maven-Abhängigkeit für PrimeFaces-Theme zeigt zum Beispiel die Abhängigkeit für das Theme Afterdark .
<dependency>
  <groupId>org.primefaces.themes</groupId>
  <artifactId>afterdark</artifactId>
  <version>1.0.9</version>
</dependency>
Das aktuell von PrimeFaces verwendete Theme wird über den Kontextparameter primefaces.THEME in der web.xml definiert. Als Wert des Parameters kommt der kleingeschriebene Theme-Name zum Einsatz. Mit dem Kontextparameter in Listing Kontextparameter für PrimeFaces-Theme wird zum Beispiel das Theme Afterdark aktiviert.
<context-param>
  <param-name>primefaces.THEME</param-name>
  <param-value>afterdark</param-value>
</context-param>
PrimeFaces unterstützt auch das dynamische Umschalten zwischen Themes zur Laufzeit. Dazu muss lediglich im Kontextparameter primefaces.THEME eine Value-Expression angegeben werden, die den Theme-Name als String zurückliefert. Listing Dynamischer Kontextparameter für PrimeFaces-Theme zeigt ein Beispiel, in dem die Eigenschaft theme der Bean preferences referenziert wird. In Listing CDI-Bean für PrimeFaces-Theme finden Sie die dazu passende CDI-Bean.
<context-param>
  <param-name>primefaces.THEME</param-name>
  <param-value>#{preferences.theme}</param-value>
</context-param>
@Named @SessionScoped
public class Preferences implements Serializable {
  public String getTheme() {
    return "afterdark";
  }
}
Wenn Sie trotz der großen Auswahl kein passendes Theme für Ihre Applikation finden, können Sie mit relativ geringem Aufwand ein eigenes erstellen.

10.3.1 Benutzerdefinierte Themes erstellen

Das Erstellen eigener Themes gestaltet sich mit PrimeFaces relativ einfach. Sie können dazu das Online-Tool jQuery ThemeRollerThemeRoller ist unter http://jqueryui.com/themeroller/ verfügbar.: verwenden. ThemeRoller ist ein einfach zu bedienender Editor mit eingebauter Vorschau für jQuery UI -Themes, die sich auch für den Einsatz in eignen. Abbildung JQuery-ThemeRoller zeigt den ThemeRoller in Aktion.
Abbildung:JQuery-ThemeRoller
ThemeRoller stellt im Tab Gallery eine ganze Reihe vorgefertigter Themes als Grundlage für eigene Entwürfe zur Verfügung. Einige der dort aufgelisteten Themes finden sich auch in PrimeFaces wieder. Nachdem Sie das Theme gemäß Ihren Wünschen gestaltet haben, müssen Sie es über einen Klick auf die Schaltfläche als Zip-Datei downloaden. In der daraufhin angezeigten Downloadseite können Sie das Auswahlfeld Toggle all deselektieren und im Eingabefeld Theme Folder Name den Namen des Theme-Verzeichnisses in der Zip-Datei angeben.
In der von ThemeRoller erzeugten Zip-Datei finden Sie im Verzeichnis css das Verzeichnis mit dem auf der Downloadseite angegebenen Namen. Dort liegt zum einen die für uns relevante CSS-Datei in einer lesbaren Variante mit der Endung custom.css und in einer optimierten Variante mit der Endung custom.min.css und zum anderen das Verzeichnis images mit Bildern und Icons. Aus diesen Daten erstellen wir jetzt das Theme mit dem Namen mygourmet .
PrimeFaces lädt die Daten zu einem Theme als JSF-Ressourcen (Details zur Ressourcenverwaltung finden Sie in Kapitel Kapitel:  Verwaltung von Ressourcen ). Per Konvention liegt jedes Theme in einer eigenen Bibliothek, deren Name aus dem Präfix primefaces- und dem Theme-Namen zusammengesetzt wird - für unser Beispiel ist das primefaces-mygourmet .
Im ersten Schritt legen wir daher das Verzeichnis der Bibliothek primefaces-mygourmet unter /resources im Wurzelverzeichnis der Webapplikation oder unter /META-INF/resources in einer Jar-Dateien an. Dorthin kopieren wir im nächsten Schritt die CSS-Datei mit der Endung custom.css und das Verzeichnis images aus der von ThemeRoller erstellten Zip-Datei. Die CSS-Datei muss unbedingt auf theme.css umbenannt werden, damit PrimeFaces die Ressource auflösen kann.
Im letzten Schritt müssen in der CSS-Datei theme.css noch alle URL-Referenzen für Bilder auf Value-Expressions umgebaut werden. Damit wird sichergestellt, dass die Bilder von JSF als Ressourcen geladen werden. Die Referenz url(images/icons.png) muss zum Beispiel folgendermaßen geändert werden:
url("#{resource['primefaces-mygourmet:images/icons.png']}")
Wie Sie sehen, ist es ohne Probleme möglich, in einer CSS-Datei, die von JSF als Ressource geladen wird, Value-Expressions zu verwenden. Im Beispiel von oben wird damit die Ressource images/icons.png aus der Bibliothek primefaces-mygourmet referenziert. Diese Art der Referenzierung haben wir bereits in Abschnitt Sektion:  Ressourcen im Einsatz vorgestellt.
Das Theme ist damit fertig und einsatzbereit. Sie müssen nur den Kontextparameter primefaces.THEME auf den Wert mygourmet setzen.

10.4 PrimeFaces und Ajax

PrimeFaces verfügt über eine sehr leistungsfähige Integration von Ajax, die auf der standardisierten Ajax-Integration von JSF 2 basiert. Die in Kapitel Kapitel:  Ajax und JSF vorgestellten Grundprinzipien gelten somit auch beim Einsatz von PrimeFaces . Wie nicht anders zu erwarten, bietet PrimeFaces allerdings auch im Ajax-Bereich einige über den JSF-Standard hinausgehende Features an. Details dazu finden Sie in Abschnitt [Sektion:  Erweiterungen im Vergleich zu Standard-JSF] .
Bei zahlreichen PrimeFaces -Komponenten ist das Ajax-Verhalten bereits eingebaut. Dazu zählen neben Komponenten wie p:dataTable und p:accordionPanel auch Komponenten mit spezifischer Ajax-Funktionalität wie p:ajaxStatus und p:poll . In Abschnitt [Sektion:  Ajax-Komponenten] finden Sie einige dieser Ajax-Komponenten. Eine Reihe von Komponenten verfügt außerdem über spezielle Attribute, um direkt Ajax-Anfragen zum Aktualisieren der Seite auszulösen oder um auf Ajax-Anfragen zu reagieren. Abschnitt [Sektion:  Komponenten mit Ajax-Unterstützung] gibt dazu einen kurzen Überblick.

10.4.1 Erweiterungen im Vergleich zu Standard-JSF

Das Pendant zu f:ajax in PrimeFaces ist p:ajax . Die Handhabung von f:ajax und p:ajax sind bis auf ein paar kleine Abweichungen identisch. Der größte Unterschied zwischen den beiden Tags ist die Benennung der Attribute: execute und render von f:ajax werden zu process und update in p:ajax .
Das Beispiel in Listing f:ajax versus p:ajax demonstriert den gemeinsamen Einsatz von f:ajax und p:ajax anhand zweier Eingabekomponenten mit Ajax-Verhalten. Bei beiden Komponenten löst das Ereignis onChange eine Ajax-Anfrage aus, um das Textfeld mit der ID out neu zu rendern. Im ersten Fall wurde das Ajax-Verhalten allerdings mit f:ajax und im zweiten Fall mit p:ajax zur Komponente hinzugefügt - das Resultat bleibt gleich.
<p:inputText value="#{bean.first}">
  <f:ajax event="change" execute="@this" render="out"/>
</p:inputText>
<p:inputText value="#{bean.last}">
  <p:ajax event="change" process="@this" update="out"/>
</p:inputText>
<h:outputText id="out" value="#{bean.first} #{bean.last}"/>
Bei Ajax-Anfragen benachrichtigt PrimeFaces standardmäßig eventuell vorhandene Ajax-Status-Komponenten mit dem Tag p:ajaxStatus . Ist das nicht gewünscht, muss in p:ajax lediglich das Attribut global auf den Wert false gesetzt werden. Details zu p:ajaxStatus finden Sie in Abschnitt [Sektion:  Ajax-Komponenten] .
Per Definition werden in JSF bei jeder Ajax-Anfrage die Daten des gesamten Formulars an den Server geschickt. Das gilt zum Beispiel auch dann, wenn von 100 Eingabekomponenten nur eine einzige im partiellen Lebenszyklus ausgeführt wird. Standardmäßig zeigt PrimeFaces dasselbe Verhalten, bietet aber die Möglichkeit, hier einzugreifen. Wird in p:ajax das Attribut partialSubmit auf true gesetzt, werden nur die Daten der für die Ajax-Anfrage relevanten Komponenten an den Server geschickt. Dieses Verhalten lässt sich auch global aktivieren, indem in der web.xml der Kontextparameter primefaces.SUBMIT auf den Wert partial gesetzt wird.

10.4.2 Ajax-Komponenten

In diesem Abschnitt stellen wir die Ajax-Komponenten p:ajaxStatus und p:poll vor.

10.4.2.1 AjaxStatus -- p:ajaxStatus

Die AjaxStatus-Komponente mit dem Tag p:ajaxStatus ermöglicht das Einblenden von Statusmeldungen (oder komplexeren Komponenten) für verschiedene Ereignisse während einer Ajax-Anfrage in PrimeFaces . Die Komponente unterstützt ein Facet für jedes mögliche Ereignis (eine vollständige Liste finden Sie in der Dokumentation zu PrimeFaces ). Tritt das entsprechende Ereignis ein, wird der Inhalt des Facets mit dem gleichen Namen eingeblendet.
Im Beispiel in Listing p:ajaxStatus wird beim Start einer Ajax-Anfrage (Ereignis start ) der Text Loading eingeblendet. Nach dem Beenden der Ajax-Anfrage (Ereignis complete ) wird ein leerer Text angezeigt.
<p:ajaxStatus>
  <f:facet name="start">
    <h:outputText value="Loading"/>
  </f:facet>
  <f:facet name="complete">
    <h:outputText value=""/>
  </f:facet>
</p:ajaxStatus>

10.4.2.2 Poll -- p:poll

Die Poll-Komponente mit dem Tag p:poll erlaubt das periodische Senden von Ajax-Anfragen. Das Intervall zwischen zwei Anfragen wird dabei im Attribut interval als Sekundenwert angegeben. Die restlichen Attribute zum Steuern der Ajax-Anfrage wie etwa process , update oder global sind identisch zu p:ajax .
Listing p:poll zeigt ein Beispiel für p:poll , in dem alle fünf Sekunden eine Ajax-Anfrage gesendet wird.
<p:poll interval="5" process="@none" update="time"
    listener="#{bean.touch}" global="false"/>
<h:outputText id="time" value="#{bean.timeStamp}"/>
Während der Abarbeitung dieser Anfrage am Server wird zuerst die im Attribut listener referenzierte Listener-Methode aufgerufen. Listing Listener-Methode für p:poll zeigt die Details der Methode. Anschließend rendert JSF die Komponente mit der ID time neu und aktualisiert die Ausgabe am Client. Nachdem global auf false gesetzt ist, bleibt die Benachrichtigung einer eventuell vorhandenen Ajax-Status-Komponente aus.
private Date timestamp = new Date();

public void touch() {
  timestamp = new Date();
}

10.4.3 Komponenten mit Ajax-Unterstützung

Bei einigen Komponenten wie p:commandButton oder p:commandLink sind die Attribute von p:ajax bereits integriert. p:commandButton und p:commandLink senden sogar standardmäßig Ajax-Anfragen, wenn nicht explizit das Attribut ajax auf false gesetzt wird.
Listing Ajax-Anfrage mit p:commandLink zeigt ein Beispiel mit p:commandLink . Ein Klick auf diesen Link löst ohne spezielle Vorkehrungen automatisch eine Ajax-Anfrage aus. Durch die Angaben in den Attributen process und update werden serverseitig die Komponenten mit den IDs first und last ausgeführt und die Komponente mit der ID out wird neu gerendert.
<p:inputText id="first" value="#{bean.first}"/>
<p:inputText id="last" value="#{bean.last}"/>
<p:commandLink value="Aktualisieren"
    process="first last" update="out"/>
<h:outputText id="out" value="#{bean.first} #{bean.last}"/>
Für Inhalte, die bei jeder Ajax-Anfrage aktualisiert werden müssen, bietet sich die OutputPanel-Komponente mit dem Tag p:outputPanel an. Die Komponente wird inklusive aller Kindkomponenten automatisch bei jeder Ajax-Anfrage neu gerendert, wenn das Attribut autoUpdate auf true gesetzt wird.

10.5 MyGourmet 18: PrimeFaces

Das Beispiel MyGourmet 18 basiert auf dem Vorgängerbeispiel MyGourmet 17 und bietet auch denselben Funktionsumfang. Allerdings haben wir in MyGourmet 18 die komplette Anwendung auf PrimeFaces umgestellt. Das Ziel der Migration war eine Anwendung, die in Funktionalität und Aussehen MyGourmet 17 sehr ähnlich ist, die aber das volle Potenzial von PrimeFaces zur Verfügung hat.
Die Umstellung von MyGourmet 17 auf PrimeFaces erfolgt in mehreren Schritten, die in den folgenden Abschnitten näher erklärt werden. Zuerst widmet sich Abschnitt [Sektion:  Integration von PrimeFaces] der Integration von PrimeFaces . Anschließend zeigt Abschnitt [Sektion:  Umstellung auf PrimeFaces-Komponenten] in groben Zügen die Umstellung der einzelnen Seiten. Zu guter Letzt finden Sie in Abschnitt [Sektion:  Benutzerdefiniertes Theme] noch Hinweise zum benutzerdefinierten Theme für MyGourmet .

10.5.1 Integration von PrimeFaces

Die Integration von PrimeFaces in MyGourmet gestaltet sich äußerst einfach und umfasst das Eintragen der entsprechenden Abhängigkeit und des dazu notwendigen Repositories in die pom.xml . Details dazu finden Sie in Abschnitt [Sektion:  PrimeFaces -- ein Überblick] und im Code des Beispiels.
Wie in Abschnitt [Sektion:  Auswahl einiger PrimeFaces-Komponenten] beim Tag p:calendar bereits erwähnt, liefert PrimeFaces standardmäßig nur eine Lokalisierung für Englisch aus. Das Hinzufügen weiterer Sprachen ist allerdings kein Problem - ein kurzes Stück JavaScript aus dem PrimeFaces -Wiki http://code.google.com/p/primefaces/wiki/PrimeFacesLocales: genügt.
Da MyGourmet auch auf Deutsch funktionieren soll, haben wir den dazu notwendigen Code in der Ressource primeFacesLoc.js in der Bibliothek scripts abgelegt und im Template template.xhtml mit dem Tag h:outputScript eingebunden. Damit ist der Code in allen Seiten verfügbar und der Umstellung der einzelnen Seiten auf PrimeFaces -Komponenten steht nichts mehr im Weg.

10.5.2 Umstellung auf PrimeFaces-Komponenten

Die Umstellung der einzelnen Seiten der Anwendung gestaltet sich relativ unspektakulär. Im ersten Schritt haben wir wie in Abschnitt [Sektion:  Erweiterte Standardkomponenten] beschrieben alle Standardkomponenten - soweit vorhanden - mit erweiterten Alternativen aus PrimeFaces ersetzt. Bei vielen Komponenten wie outputLabel oder inputText genügt es, dazu das Präfix von h auf p zu ändern - vorausgesetzt p ist korrekt mit dem Namensraum http://primefaces.org/ui verknüpft.
Manche Komponenten verlangen nach zusätzlichen Anpassungen. p:commandButton und p:commandLink senden zum Beispiel standardmäßig Ajax-Anfragen. Wenn dieses Verhalten nicht gewünscht ist, muss explizit das Attribut ajax auf false gesetzt werden. Im Ajax-Fall kann dafür aber auf f:ajax oder p:ajax verzichtet werden, da die Tags bereits die entsprechenden Attribute mitbringen (siehe Abschnitt [Sektion:  Komponenten mit Ajax-Unterstützung] ).
Die Umstellung von h:dataTable beziehungsweise mc:dataTable auf p:dataTable benötigt geringfügig mehr Aufwand. Dafür bietet p:dataTable aber auch einige zusätzliche Features, wie Listing MyGourmet 18: p:dataTable in customerList.xhtml anhand eines Ausschnitts aus der Seite customerList.xhtml zeigt. Details zu p:dataTable finden Sie in Abschnitt [Sektion:  Auswahl einiger PrimeFaces-Komponenten] .
<p:dataTable value="#{customerListBean.customerList}" var="cust"
    paginator="true" rows="10" paginatorPosition="bottom"
    emptyMessage="#{msgs.customers_empty}">
  <p:column headerText="#{msgs.name}" sortBy="#{cust.fullName}">
    <p:commandLink value="#{cust.fullName}" ajax="false"
        action="#{customerBean.showCustomer(cust.id)}"/>
  </p:column>
  <p:column headerText="#{msgs.email}" sortBy="#{cust.email}">
    <h:outputText value="#{cust.email}"/>
  </p:column>
  <p:column>
    <p:commandLink value="#{msgs.delete}" update="@form"
        action="#{customerListBean.deleteCustomer(cust)}"/>
  </p:column>
</p:dataTable>
Ansonsten haben wir noch an einigen Stellen Standard- oder Kompositkomponenten mit PrimeFaces -Komponenten ersetzt. In showProvider.xhtml finden Sie zum Beispiel p:rating , in editProvider.xhtml p:spinner und in editCustomer.xhtml p:calendar . Im Template customerTemplate.xhtml wird statt der Kompositkomponente mc:ajaxStatus die flexiblere Alternative p:ajaxStatus verwendet.
In der linken Seitenleiste leftSideBar.xhtml gibt es ebenfalls einige Änderungen. Anstatt der ersten Kompositkomponente mc:panelBox mit den h:link -Tags zur Navigation kommt p:menu zum Einsatz. Die einzelnen Einträge des Menüs werden mit p:menuitem hinzugefügt, wobei das Ziel der Navigation im Attribut outcome definiert wird. So ist gewährleistet, dass die Navigation weiter über GET-Anfragen läuft. Das zweite mc:panelBox -Tag muss p:panel weichen. Listing MyGourmet 18: leftSideBar.xhtml zeigt den relevanten Inhalt der Seitenleiste (ohne lokalisierte Labels).
<p:menu>
  <p:submenu label="Menü">
    <p:menuitem outcome="providerList" value="Anbieterliste"/>
    <p:menuitem outcome="customerList" value="Kundenliste"/>
  </p:submenu>
</p:menu>
<p:panel header="Neuigkeiten">
  <p>MyGourmet - jetzt mit Facelets und Templating</p>
</p:panel>
Damit sich p:menu harmonisch in die Seitenleiste einfügt, muss das Styling noch etwas angepasst werden. PrimeFaces definiert dazu für jede Komponente eine ganze Reihe von CSS-Selektoren (eine Übersicht für jede Komponente finden Sie in der Dokumentation). Die gerenderte Ausgabe der Menükomponente kann unter anderem über die CSS-Klasse .ui-menu angepasst werden. Listing MyGourmet 18: Styling für p:menu zeigt zum Beispiel eine CSS-Regel, um das Menü innerhalb eines Elements mit der ID left_sidebar (die ID der Seitenleiste) anzupassen. Alle notwendigen Anpassungen finden Sie in mygourmet.css .
#left_sidebar .ui-menu {
  width: 134px;
  padding: 2px;
  margin-bottom: 5px;
}

10.5.3 Benutzerdefiniertes Theme

Als letzten Schritt haben wir mit ThemeRoller ein benutzerdefiniertes Theme für MyGourmet erstellt und in die Anwendung integriert. Alles Wissenswerte zu diesem Thema inklusive einer kurzen Anleitung finden Sie in Abschnitt [Sektion:  Themes] .