Dienstag, 22. Mai 2012


Artikel

September 2006 | Artikel

JavaServer Faces: Integrationsstrategien für AJAX

(Link zum Artikel: http://www.entwickler.de/php//001169)

AJAX zeigt Gesicht

Text: von Matthias Weßendorf
  • Teilen
  • kommentieren
  • empfehlen
  • Bookmark and Share
Der AJAX-Ansatz verspricht die Entwicklung moderner Webanwendungen, die den Rich Clients einer "echten" Desktop-Umgebung in nichts nachstehen. Die JavaServer-Faces-Technik verspricht durch die Bereitstellung serverseitiger GUI-Komponenten die Vereinfachung der Programmierung von Java-Weban-wendungen. Doch wie sieht es mit einer Kombination beider Techniken aus?
Teil 1   Teil 2   Teil 3   

Zu den absoluten Hype-Themen des letzten Jahres gehört mit 100%iger Sicherheit Web 2.0 und die damit verbundene AJAX-Technik. Innerhalb der Java-Community wird AJAX häufig mit dem Thema JavaServer Faces (JSF) in Verbindung gebracht. Die diesjährige JavaOne Conference bestätigte diesen Trend deutlich. Mit JavaServer Faces steht ein durch den Java Community Process (JCP) geschaffener Standard für Java-Webanwendungen bereit (JavaServer Faces 1.0/1.1 und JavaServer Faces 1.2), der in die Java EE Version 5 integriert ist. Eine der wesentlichen Haupteigenschaften von JSF ist das integrierte Komponenten-Framework (Informationen zu JSF). Neben der Bereitstellung von standardisierten User-Interface-Komponenten ermöglicht es die Programmierung eigener wieder verwendbarer Komponenten für Java-Webanwendungen. Dieser Artikel stellt drei Strategien für die Implementierung von AJAX-basierten JSF-Komponenten vor, wobei primär die Integration im Vordergrund steht. Als durchgängiges Beispiel wird im Artikel ein Eingabefeld herangezogen, das eine automatische Vervollständigung von Benutzereingaben ermöglicht, indem es asynchron Daten vom Webserver lädt. Ein bekanntes Beispiel für eine solche Komponente ist Google Suggest. Die im Artikel verwendeten JavaScript-Bibliotheken stammen von Thomas Fuchs und werden bereits in verschiedenen Web-Frameworks, wie z.B. Ruby on Rails, eingesetzt.

Warum AJAX-basierte JSF-Komponenten?
Gerade die Programmierung AJAX-basierter Webanwendungen benötigt eine Menge verschiedener Ressourcen (JavaScript- und CSS-Dateien), die durch den Webentwickler eingebunden und mit entsprechenden HTML-Tag-Attributen (z.B. onclick) kombiniert werden. Diese Arbeitsschritte sind nicht sonderlich schwer, jedoch schleichen sich gerade bei solchen Tätigkeiten gerne kleine Fehler ein. Soll ein AJAX-Element mehrfach in einer Webanwendung verwendet werden, muss der Webentwickler gewisse Arbeitsschritte öfter tätigen. Idealerweise sollte der Web-entwickler bzw. Page Author bei der Benutzung einer AJAX-Komponente keine zusätzlichen Schritte tätigen, außer dass er die Komponente über einen speziellen Tag in die Seite einbindet.
Rollenspiele
Die JSF-Spezifikation beschreibt ein detailliertes Rollenkonzept, wobei innerhalb dieses Artikels die Rollen des Component Writer und des Page Author im Vordergrund stehen. Die Arbeit des Component Writer soll den Page Author entlasten, sodass er sich statt der Einbindung von Ressourcen intensiver seiner eigentlichen Tätigkeit, der Erstellung ansprechender Weboberflächen, widmen kann.

  1. Listing 1
  2. -----------------------------------------------------------------------
  3. <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
  4. <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
  5. <html>
  6. <head>
  7. <title>einfache Integration von AJAX und JavaServer Faces</title>
  8. <script src="./res/prototype.js" type="text/javascript"></script>
  9. <script src="./res/scriptaculous.js" type="text/javascript"></script>
  10. <style type="text/css" media="screen">
  11. .ajax {
  12. position:absolute; width:250px; background-color:white;
  13. border:1px solid #888; margin:0px; padding:0px;
  14. }
  15. .ajax li.selected {
  16. background-color: #bff;
  17. }
  18. .ajax ul {
  19. list-style-type:none;margin:0px;padding:0px;
  20. }
  21. </style>
  22. </head>
  23. <body>
  24. <f:view>
  25. <h:form id="form">
  26. <h:panelGrid columns="2">
  27. <h:outputText value="Eingabe"/>
  28. <h:inputText id="eingabe" value="#{ajaxbacking.eingabe}"/>
  29. <h:commandButton value="Senden"/>
  30. </h:panelGrid>
  31. </h:form>
  32. <h:outputText
  33. escape="false"
  34. value="Wert: <b>#{ajaxbacking.eingabe}</b>"
  35. rendered="#{!empty ajaxbacking.eingabe}"/>
  36. </f:view>
  37. <div id="results" class="ajax"></div>
  38. <script>
  39. try {
  40. new Ajax.Autocompleter('form:eingabe', 'results', 'ajax/suggest');
  41. } catch(e) {
  42. alert(e.message)
  43. }
  44. </script>
  45. </body>
  46. </html>
First Contact
Die erste Strategie eines AJAX-basierten JSF-Eingabefeldes ist auch zugleich die einfachste. Sie verwendet lediglich standardisierte JSF-Komponenten. Listing 1 zeigt den Quelltext der JSP. Im <head/>-Element bindet der Page Author zwei JavaScript-Dateien ein, die die Logik für das Absenden des AJAX-Requests enthalten. Ebenfalls definiert er verschiedene CSS-Klassen, um die grafische Darstellung des Eingabefeldes aufzupeppen (Abb. 1).

Innerhalb des Formulars befindet sich ein Texteingabefeld (<h:inputText/>), das für die automatische Vervollständigung benutzt wird. Das bedeutet, dass der aktuelle Eingabewert an einen Webserver gesendet wird, der in dessen Abhängigkeit ein Ergebnis an die JSP zusendet (Abb. 2).

Dafür muss der Page Author einiges an Tipparbeit leisten. Zunächst wird ein leeres <div>-Element benötigt, das auf eine CSS-Klasse verweist. Das eigentliche Absenden des AJAX-Requests wird über die JavaScript-Anweisung new Ajax.Autocompleter(...) realisiert. Als Parameter werden die IDs des Eingabefeldes und des <div>-Elements sowie ein URL übergeben. Die JavaScript-Klasse Autocompleter verwendet die ID des Eingabefeldes, um den aktuellen Eingabewert zu identifizieren. Die ID des <div>-Elements wird benötigt, weil das empfangene Ergebnis diesem <div>-Element angefügt wird. An den übergebenen URL wird letztendlich der AJAX-Request gesendet.

IDs von JSF-Komponenten
Für JSF-Neulinge sieht die übergebene ID des Eingabefeldes (form:eingabe) wahrscheinlich wunderlich aus. Bei JSF ist es jedoch notwendig, dass alle Komponenten-IDs innerhalb der Seite eindeutig sind. Somit wäre es also nicht möglich, zwei Formulare auf einer Seite zu haben, die beide ein Eingabefeld mit der ID eingabe haben. Um dieses Problem zu lösen, bietet JSF ein NamingContainer-Interface an, das die Formular-Komponente implementiert. Dadurch entsteht eine Client-ID wie beispielsweise form:eingabe oder form2:eingabe. Der aufmerksame Leser hat sicherlich bereits bemerkt, dass dies Probleme bei der Wiederverwendung von "legacy" JavaScript-Code bereitet, der beispielsweise die Methode getElementById() verwendet. Für dieses Problem bietet Apache MyFaces mit seinem forceId-Attribut eine Lösung an. Eine weitere Lösung ist der Einsatz der Apache-Trinidad-Formular-Komponenten, die das oben beschriebene Interface nicht implementiert. Das Trinidad-Projekt enthält die von Oracle gespendeten ADF-Faces-Komponenten und befindet sich gerade innerhalb des Apache Incubators. In JSF 1.2 ist ein Trinidad-ähnlicher Ansatz enthalten.

  1. Listing 2
  2. package net.wessendorf.jm.servlet.ajax.backend;
  3. import java.io.IOException;
  4. import java.util.*;
  5. import javax.servlet.ServletException;
  6. import javax.servlet.http.*;
  7. import net.wessendorf.jm.helper.LookupUserHelper;
  8. public class AjaxBackendServlet extends HttpServlet {
  9. protected void doGet(HttpServletRequest request, HttpServletResponse response)
  10. throws ServletException, IOException {
  11. List users = LookupUserHelper.getInstance()
  12. .lookupUsers(request.getParameter("form:eingabe"));
  13. StringBuffer sb = new StringBuffer();
  14. sb.append("<ul>");
  15. for (Iterator it = users.iterator(); it.hasNext();) {
  16. sb.append("<li>"+it.next()+"</li>");
  17. }
  18. sb.append("</ul>");
  19. response.setCharacterEncoding("UTF-8");
  20. response.getWriter().write(sb.toString());
  21. }
  22. ...
  23. }

Teil 1   Teil 2   Teil 3   

Kommentare