JSF-Applikationen mit Ajax4JSF aufwerten

Wolfgang Klaus

Bestehende JavaServer Faces-Komponenten um Ajax-Funktionalität zu erweitern, das geht mittlerweile recht einfach. Und das, ohne sich in eine Ajax-Bibliothek einzuarbeiten, Umwege über Servlets zu machen oder sonstige, nicht auf den JSF-Lifecycle abgestimmte Techniken zu benutzen.

JavaServer Faces gewinnen in der Webentwicklung immer mehr an Bedeutung. Allerdings wurde die Spezifikation dafür zu einem Zeitpunkt manifestiert, als es Ajax zwar schon lange gab, es jedoch nur Insidern ein Begriff war bzw. das Schlagwort dafür noch nicht erfunden war. Deshalb verwundert es nicht, dass in Suns JSF 1.1-Referenzimplementierung keine Ajax-fähigen Komponenten enthalten sind.

Dank des offenen JSF-Modells gibt es aber mittlerweile fertige Ajax-fähige JSF-Komponenten von unterschiedlichen Herstellern. Auch bei der freien JSF-Implementierung MyFaces gibt es dazu erste Ansätze. Diese sind aber noch in der „Sandbox“ zu finden und noch nicht offiziell freigegeben. Wie bei MyFaces sind dies oft aber nur einzelne Komponenten (Tabelle, Tree, Menü), die für den eigentlichen Anwendungsfall nicht immer passen. Es wäre doch schön, bestehende Komponenten ohne großen Aufwand um eine Ajax-Funktionalität zu erweitern. Genau in diesem Bereich gibt es mit Ajax4JSF ein Open-Source-Projekt, das hierfür eine hervorragende Lösung bietet.

Der Vorteil von Ajax4JSF gegenüber anderen Frameworks besteht darin, dass es vollkommen in den Lifecycle von JSF eingebunden ist und zudem nicht nur Zugriff auf Managed Beans gewährt, sondern auch den Vorteil der ValueChange Listener sowie der serverseitigen Validatoren und Konverter ausnutzt. Damit benötigen bestehende Anwendungen keine umfangreichen Änderungen an der Basis mehr.

Installation

Die Installation stellt sich nach dem Herunterladen der Binary Packages von der Projektseite recht einfach dar. Die beiden im Archiv enthalten .jar-Dateien werden am besten in das Verzeichnis WEB-INF/lib der Webapplikation kopiert. Um Ajax4JSF nun zu aktivieren, muss ein Filter in der Datei web.xml konfiguriert werden. Dabei ist darauf zu achten, dass dieser Filter vor allen anderen deklarierten Filtern kommt.

Listing 1
--------------------------------
Ajax4Jsf Filterajax4jsforg.ajax4jsf.Filterajax4jsfFaces-ServletREQUESTFORWARDINCLUDE
Wie funktioniert das Ganze?

Ajax4JSF enthält Komponenten, die dazu dienen, bestehende JSF-Komponenten um Ajax-Funktionalität zu erweitern bzw. JSF-Komponenten zu ersetzen, ohne umfangreichen JavaScript-Code zu schreiben. Um dieses Prinzip zu verdeutlichen, wird dies an einem typischen Ajax-Beispiel gezeigt: dem partiellen Update einer HTML-Seite.

Alle hier gezeigten Beispiele sind auch von hier erhältlich. Zur Installation der Beispiele ist es ausreichend, die Datei ajax4jsf.war in das webapps-Verzeichnis zu kopieren. Von der darin enthaltenen index.html kann bequem zu den einzelnen Beispielen navigiert werden. Um die Ajax4JSF-Komponenten zu benutzen, muss folgende Namespace-Deklaration in die JSF-Seiten hinzugefügt werden:


Eine der wichtigsten Komponenten ist <aj4:support>. Diese Komponente erweitert bestehende Komponenten um die Ajax-Funktionalität. Ein normales Eingabefeld wird damit folgendermaßen um Ajax-Support erweitert:

Die Komponente <aj4:support> wird einfach als Kindelement von <h:inputText> verwendet. Das Attribut event gibt an, wann eine Ajax-Aktion ausgeführt werden soll. Gemeint sind hier die entsprechenden Javascript-Events. Hier bedeutet „onkeyup“, dass bei jedem Tastendruck ein Request an den Server gesendet werden soll. Mit dem Attribut reRender werden die IDs der Elemente angegeben, die nach der Antwort vom Server über DOM-Manipulation neu ausgegeben werden sollen. Voraussetzung ist allerdings, dass den zu ändernden Komponenten auch IDs über das Attribut id zugewiesen wurden. Sollen mehrere Elemente neu ausgegeben werden, so können diese durch Kommata getrennt angegeben werden. In unserem Fall soll das Element mit der ID „repeater“ neu ausgegeben werden. „repeater“ könnte folgendermaßen definiert sein.

Ohne eine Zeile JavaScript-Code haben wir nun eine Anwendung, die Ajax nutzt, um Teile der HTML-Seite zu aktualisieren. Zugegeben, dies ist ein einfaches Beispiel, doch es verdeutlicht sehr gut die Möglichkeiten, die sich mit Ajax4JSF für bereits bestehende JSF-Applikationen ergeben. Sinnvoller, als den eingegebenen Text direkt wieder auszugeben, wäre es jetzt, vom Server die Eingaben sofort überprüfen zu lassen, um den Benutzer während der Erfassung auf eventuelle Fehler hinzuweisen. Da clientseitige Validatoren in JSF noch relativ selten sind, wäre es doch schön, ein solches Verhalten per Ajax zu emulieren, um falsche Eingaben sofort entdecken zu können.

Auch Validatoren können mitbenutzt werden

Bei jedem Tastendruck im Eingabefeld wird ein Ajax Request an den Server gesendet. Dabei wird der normale JSF Lifecycle auf dem Server durchlaufen. Das Ergebnis ist auf Serverseite eine HTML-Seite. Ajax4JSF trennt allerdings die Elemente aus der Seite heraus, die im reRender-Attribut angegeben wurden. Diese werden in XML eingepackt und als Antwort zurückgeschickt. Es wird also nicht die ganze Seite komplett neu übertragen, um auch den bekannten Vorteil von Ajax auszunutzen.

Dadurch, dass der komplette JSF Lifecycle durchlaufen wird, werden alle JSF-Validatoren ebenfalls abgearbeitet. Die entsprechenden Fehlermeldungen oder Warnungen der Validatoren können nun über Ajax4JSF wieder ausgegeben werden. Unser voriges Beispiel muss eigentlich nur um einen Validator erweitert werden. Angenommen, es sollen in dem Eingabefeld mindestens drei und maximal fünf Zeichen eingegeben werden dürfen. Dafür sind nun zwei Erweiterungen notwendig: Zuerst muss der Validator zum Eingabefeld hinzugefügt werden.

Als Nächstes muss noch die Fehlermeldung des Validators ausgegeben werden. Fehlermeldungen und Warnungen werden mit dem JSF-Tag <h:message> bzw. <H:messages> ausgegeben. Um diese Meldungen über Ajax auszugeben, wird die Ajax4JSF-Komponente verwendet. Mit dieser Komponente ist es möglich, alle darin enthaltenen Kindelemente über einen Ajax Request aktualisieren zu lassen. Das Ganze sieht dann so aus.

 

Das Attribut ajaxRendered=“true“ gibt an, dass der Inhalt des Panels bei jedem Ajax Request neu ausgegeben wird, ohne dass die ID bei einem reRender-Attribut explizit angegeben wurde.

Dass die Validatoren sowie der komplette JSF Lifecycle weiterhin funktionieren, ist an folgendem Verhalten erkennbar. Die eingegebenen Daten werden erst in der zweiten Zeile ausgegeben, wenn mindestens drei Zeichen eingegeben wurden. Bei mehr als fünf eingegebenen Zeichen wird die Ausgabe nicht mehr aktualisiert, da auf dem Server kein Update des Wertes erfolgt.

Ajax4JSF und MyFaces
————————————-
Bei der Verwendung von Ajax4JSF mit MyFaces muss Folgendes beachtet werden. In MyFaces wird, im Gegensatz zu der Sun RI-Implementierung, das <f:view>-Tag in der RENDER_RESPONSE-Phase nicht angesprochen, deshalb ist es für Ajax4JSF nicht möglich, die Kontrolle zu erlangen und eine eigene Response zu erzeugen. Um dieses Problem zu vermeiden, ist es notwendig, den Bereich, der Ajax4JSF-Komponenten enthält, mit dem Tag <a4j:region selfRendered=“true“/> zu umschließen. Alternativ kann auch die Komponente <a4j:page> direkt hinter <f:view> verwendet werden, um die ganze Seite Ajax-fähig zu machen. Bei <a4j:page> ist zu beachten, dass dann in der JSP-Seite keine eigenen <html>-, <head>- und <body>-Tags mehr notwendig sind, da diese von <a4j:page> erzeugt werden. Eine JSP-Seite für MyFaces ist im Quellcode zu diesem Artikel enthalten.
Darf es auch etwas mehr sein?

An folgendem weiteren Beispiel wird deutlich, wie einfach und doch sinnvoll Anwendungen mit Ajax-Funktionalität aufgewertet werden können. Es sollen aus einer Tabelle von Namen über einen Link die Details zu deren Adresse angezeigt werden (Abb. 1). In der Detailmaske können Änderungen vorgenommen werden, die über Ajax gespeichert werden, wenn die Tabelle neu ausgegeben wird.

Abb. 1: Beispielmaske

Die Anzeige der Tabelle erfolgt über die Standardkomponente <h:datatable>. Die Aktualisierung des Detailformulars erfolgt nach einem Klick auf den Link DETAILS. Hinter diesem Link verbirgt sich die Komponente <a4j:commandLink>, die eine Erweiterung der Standardkomponente <h:commandLink> darstellt.

Die namentliche Verwandtschaft zum JSF CommandLink ist natürlich gewollt, um die Funktion dieser Komponente auszudrücken. Im Unterschied zur JSF-Komponente wird jedoch kein normaler Seiten-Request durch den Browser generiert, sondern ein Ajax Request an den Server gesendet. Welche Methode auf dem Server aufgerufen werden soll, ist wiederum über das Attribut action anzugeben. Der Index der aktuellen Zeile innerhalb der Tabelle wird als Parameter zum Request hinzugefügt und an den Server übermittelt. Der Parameter wird über eine weitere Komponente von Ajax4JSF, <a4j:actionparam>, angegeben.

Mithilfe der <a4j:actioparam>-Komponente wird ein zusätzlicher Parameter dem Request mit übergeben. Der Wert ist über das Attribut assignTo einem Feld im Managed Bean zugewiesen. In der aktuellen Version von Ajax4JSF funktioniert das aber nur für die primitiven Datentypen. Die Methode zeigeDetails, die über das Attribut action angegeben wurde, wird auf dem Server aufgerufen. Da dieses Beispiel sehr vereinfacht wurde, passiert nichts weiter, als dass der Wert der Variablen mit detaild ausgegeben wird. Welche Teile der Seite nach erfolgreichem Response neu ausgegeben werden sollen, ist wiederum über das bekannte Attribut reRender angegeben.

Die Tabelle ist über das binding-Attribut mit einem Feld vom Typ javax.faces.component.html.HtmlDataTable im Managed Bean verbunden. Über die Methode setRowIndex(int index) wird die Zeile in der Tabelle ausgewählt, die mit dem Parameter index der Variablen detailId zugewiesen wurde. Danach wird mit der Methode getRowData() das komplette Adressobjekt dieser Zeile von der Tabelle zurückgegeben. Durch das vereinfachte Beispiel ist die eindeutige ID des Adressobjektes gleichzusetzen mit der Position innerhalb der Liste, welche die Adressobjekte enthält. Die Ausgabe der Details erfolgt in diesem Beispiel in einem <h:panelGrid>.

Listing 2
---------------------------------------

Wie in Listing 2 zu sehen ist, kommt zum Aktualisieren der Daten auf dem Server und in der Tabelle eine weitere Komponente von Ajax4JSF zum Einsatz: <a4j:commandButton>. Diese Komponente gibt einen Button auf der HTML-Seite aus. Der Unterschied zur normalen JSF-Komponente <h:commandButton> besteht wiederum darin, dass ein Ajax Request zum Server gesendet wird. Über das Attribut action wird die Methode genannt, welche auf dem Server ausgeführt werden soll. Nach dem Ausführen dieser Methode soll die Tabelle neu ausgegeben werden, was wieder mit dem Attribut reRender angegeben wird.

Natürlich ist es schön, wenn auf Anhieb alles so einfach funktioniert, jedoch kann es immer mal wieder Probleme mit einer Komponente oder einer bestimmten Konstellation geben. Auch hier bietet Ajax4JSF Unterstützung an. Durch Hinzufügen der Komponente <a4j:log> in der JSF-Seite kann auf Bedarf ein Debug-Fenster geöffnet werden. Über das Attribut level kann der Log-Level bestimmt werden. Zusätzlich kann über das Attribut hotkey eine Taste definiert werden, die zusammen mit STRG und SHIFT gedrückt werden muss, um das Debug-Fenster anzuzeigen. Im Debug-Fenster kann nun der Ablauf des Ajax Request genau beobachtet werden. Unter anderem wird auch die Response vom Server ausgegeben, was sehr hilfreich ist, um Problemen auf die Spur zu kommen.

Fazit

Die aktuell vorliegenden Version 1.0.3 stellt eine gute Basis für die Erweiterung von JSF um eine Ajax-Funktionalität zur Verfügung. Dem Entwickler wird es sehr leicht gemacht, bestehende oder neue Seiten um Features zu erweitern, wie sie nur von Desktopapplikationen her bekannt sind. Dadurch entstehen natürlich auch ganz neue Lösungsansätze für Webapplikationen, wenn die Bindung an das Seitenparadigma aufgehoben ist. Leider konnten in diesem Artikel nicht alle Komponenten vorgestellt werden, die das Projekt sonst noch zu bieten hat. Aber was damit alles möglich ist und was zukünftig von dem Projekt noch zu erwarten ist, wird durch das Subprojekt G4JSF deutlich, welches eine Integrationsbibliothek für das Google Web Toolkit und JSF darstellt.

Wolfgang Klaus arbeitet als Softwareentwickler bei einem Maschinenbauunternehmen. Er ist zuständig für die Entwicklung von Webapplikationen für das Intranet auf Basis von JSF, Spring und Hibernate.
Geschrieben von
Wolfgang Klaus
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.