Spieglein, Spieglein an der Wand

Schöneres JSF mit PrettyFaces

Christian Kaltepoth

JavaServer Faces war in der Vergangenheit oft Kritik ausgesetzt. Eines der Hauptargumente der Kritiker sind die häufigen POST-Requests für selbst einfachste Navigation innerhalb der Applikation. Darunter leidet vor allem die Benutzerfreundlichkeit, da beispielsweise das Setzen von Lesezeichen unmöglich wird. Besser wäre sicherlich die Verwendung von menschenlesbaren URLs in Verbindung mit einfachen HTML-Links. Mit PrettyFaces lässt sich dies in JSF-Applikation umsetzen.

JavaServer Faces gehört heute zu den am weitesten verbreiteten Frameworks für die Entwicklung moderner Webanwendungen. Trotz seiner Popularität und der großen Anzahl von Komponentenbibliotheken stoßen Entwickler jedoch immer wieder auf dieselben Probleme. Einige dieser Schwierigkeiten rühren daher, dass die meisten Anfragen einer JSF-Applikation an den Server POST-Requests sind. Für Seiten, die das Ergebnis eines POST-Requests sind, lassen sich beispielsweise keine Lesezeichen setzten, da der Browser beim Aufruf des Lesezeichens lediglich einen GET-Request sendet. Ein weiteres Problem sind die so genannten Form-Resubmission-Dialoge. Betätigt der Benutzer den ZURÜCK-Button des Browsers, wird er von einem Dialog vor den potenziellen Konsequenzen gewarnt (Abb. 1). Und diese Warnung ist nicht unbegründet: Viele Applikationen führen die durch den vorherigen Request angestoßene Aktion einfach noch einmal aus. Im schlechtesten Fall hat man die Bestellung im Onlineshop damit ein zweites Mal aufgegeben.

Abb. 1: Der Form-Resubmission-Dialog von Firefox

Besonders bei der reinen Navigation innerhalb der Applikation stören die Postbacks enorm. Eine Alternative wäre die konsequente Verwendung von einfachen HTML-Links in Verbindung mit RESTful URLs. Leider unterstützt JSF dieses Vorgehen nur sehr eingeschränkt. Zwar hat sich die Lage durch die Einführung von <f:viewParam> in JSF 2.0 verbessert, jedoch vermisst man hier immer noch mehr Flexibilität. Genau an dieser Stelle setzt PrettyFaces an. Es erlaubt die Erstellung von einfachen menschenlesbaren URLs und integriert sich nahtlos in das Navigationskonzept von JSF. Zusätzlich bietet PrettyFaces eine Reihe von häufig benötigten Features, wie beispielsweise Page Actions und eine eigene Rewrite Engine.

Um im Folgenden praxisnahe Anwendungsfälle beschreiben zu können, wird die Verwendung von PrettyFaces am Beispiel eines Onlineshops vorgestellt. Das Datenmodell ist absichtlich sehr einfach gehalten. Der Shop bietet Bücher an, die eindeutig durch ihre ISBN-Nummer identifiziert werden und einer oder mehreren Kategorien zugeordnet sind. Unsere Applikation verwendet JSF 2.0 in Verbindung mit CDI. Es sei jedoch angemerkt, dass PrettyFaces genauso gut in anderen Umgebungen funktioniert, beispielsweise mit JSF 1.x und Spring.

Installation

Zur Einbindung ins Projekt werden neben dem PrettyFaces-Archiv noch Apache-Commons-Bibliotheken benötigt. Verwendet man Apache Maven, muss lediglich das entsprechende Maven-Artefakt in die pom.xml eingetragen werden. Alle benötigten Abhängigkeiten werden dann automatisch dem Projekt hinzugefügt. Bei der Verwendung von JSF 2.0 in einem Servlet-3.0-Container ist die Konfiguration durch das Hinzufügen des PrettyFaces-Archivs bereits vollständig abgeschlossen. Der benötigte Servlet-Filter wird in diesem Fall automatisch vom Container eingebunden. In allen anderen Fällen muss er manuell in die web.xml eingetragen werden (Listing 1).

Pretty Filtercom.ocpsoft.pretty.PrettyFilterPretty Filter/*REQUESTFORWARDERROR

Listing 1: web.xml

Mapping

Als Einstieg in den Shop dient die Startseite mit einer Liste aller Buchkategorien. Das für diese Seite zuständige Bean ist in Listing 2 zu sehen. Die CDI-Annotationen @Named und @RequestScoped legen den Namen und den Scope für das Bean fest. Mit der PrettyFaces-Annotation @URLMapping wird ein URL-Mapping erzeugt. Das pattern-Attribut gibt dabei den gewünschten URL an, und viewId verweist auf die darzustellende JSF-View. Das Mapping verbirgt die eigentliche JSF-Seite hinter einem nahezu beliebigen URL, der nicht dem durch das FacesServlet vorgegebenen Format entsprechen muss (/faces/* bzw. *.jsf). Darüber hinaus wird für jedes URL-Mapping eine eindeutige ID benötigt.

@Named("homeBean")
@RequestScoped
@URLMapping(id="home", pattern="/home", viewId="/faces/home.xhtml")
public class HomeBean {

  @Inject
  private CategoryDao categoryDao;

  private List categories;
  
  @URLAction
  public void initView() {
    categories = categoryDao.getCategories();
  }

  /* Getter + Setter */
}

Listing 2: HomeBean.java

Page Actions

Bevor die Seite gerendert werden kann, benötigen wir die darzustellenden Kategorien. Diese Liste wird in der Methode initView() aus der Datenbank geladen und in der Bean gespeichert. Die Annotation @URLAction weist PrettyFaces an, die Methode bei jedem Zugriff auf das URL-Mapping aufzurufen. Der Aufruf einer Page Action findet standardmäßig in der RestoreView-Phase statt. Mithilfe des phaseId-Attributs kann jedoch auch jede andere Phase des JSF Lifecycle verwendet werden. Anzumerken ist an dieser Stelle, dass die Methode bei jedem Request an den konfigurierten URL aufgerufen wird. Das schließt vor allem auch JSF Postbacks mit ein. Sollte das nicht gewünscht sein, so lässt sich das Standardverhalten durch Setzen des onPostback-Attributs auf false abschalten. Das kann vor allem dann Sinn machen, wenn die Bean den View Scope verwendet und sein Status somit bis zum Postback erhalten bleibt. Mit dieser Bean ist nun alles für die View vorbereitet. Listing 3 zeigt die zugehörige XHTML-Seite, die alle Kategorien in Tabellenform anzeigt.


  NameBeschreibung

Listing 3: home.xhtml

Path-Parameter

Im nächsten Schritt werden wir eine Seite erstellen, die alle Bücher einer bestimmten Kategorie anzeigt. Im Gegensatz zur Startseite ist diese Seite von einem Parameter abhängig. Damit die Seite eigenständig funktionieren kann, muss die Kategorie Bestandteil des URL sein. Optimal wäre sicherlich ein URL wie /category/Java. Glücklicherweise lässt sich eine solche Anforderung mit PrettyFaces leicht erfüllen.

Geschrieben von
Christian Kaltepoth
Kommentare

Schreibe einen Kommentar

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