Mehr Spaß im Web mit Wicket

Artikel als PDF herunterladen:
Download Mehr Spaß im Web mit Wicket

Apache WicketSchon viele Webframeworks kündigten mit vollmundigen Versprechen das Ende der Qualen beim Erstellen von Java-Webanwendungen an. Einfach und voller Freude sollte die Entwicklung von statten gehen. Der Projektpraxis ausgesetzt, wurde dieser Zahn jedoch oft schneller gezogen als einem lieb sein kann. Gegenwehr zwecklos? Apache Wicket, in Version 6 nun endgültig den Kinderschuhen entwachsen, verspricht erneut blendende Zeiten für Java-Webentwickler. Grund genug, sich das Framework einmal genauer anzusehen.

Wicket ist ein komponentenbasiertes Webframework, welches seit 2004 entwickelt wird. Inzwischen ist Wicket Apache Top-Level-Project und wurde im September 2012 in der Version 6 vorgestellt. Die auf der Webseite [1] des Projekts aufgeführten Intensionen und Key-Features lassen keinen Zweifel aufkommen – auch bei Wicket geht es wieder einmal um das „Höher, Schneller, Weiter“ der Java-Webentwicklung:

  • Proper mark-up/logic separation
  • POJO data model
  • A refreshing lack of XML
  • Makes developing web-apps simple and enjoyable again

Selbstverständlich fehlt auch das Versprechen nicht, mit Wicket die Menge des Boilerplate-Codes zu reduzieren. Auch das Erstellen von eigenen Komponenten soll besonders einfach sein. So langsam regt sich Misstrauen, kennt man Verkündigungen dieser Art doch auch von anderen Kandidaten der Vergangenheit. Ist Wicket wirklich anders? Dürfen wir glauben, was wir lesen? Werfen wir also einen Blick auf die Entwicklung einer Java-Webanwendung mit Apache Wicket.

Wicket by Example

Um den Versprechungen des Wicket-Teams auf den Zahn zu fühlen, erstellen wir am besten eine kleine Anwendung, um Wicket „Hallo“ zu sagen. Diese kann natürlich nicht den Anspruch erheben, ein reales Projekt abzubilden, aber sie ermöglicht einen guten Einstieg in die wichtigsten Features des Frameworks. In einem ersten Schritt soll die grundlegende Struktur einer Wicket-Anwendung erstellt und erläutert werden. Im zweiten Teil wird die Anwendung um ein Formular erweitert. Für die vorgestellten Beispiele werden lediglich die Wicket-Jars und ein Servlet-Container zum Testen benötigt. Bei Bedarf stehen auch Wicket-Plugins für alle namhaften IDEs zur Verfügung [2]. Beginnen wir nun mit unserer Anwendung.

Bauteile einer Wicket-AnwendungAbbildung 1: Bauteile einer Wicket-Anwendung

Ein Wicket-Projekt besteht mindestens aus einer Application-Class, einer Page samt Markup und einem Deployment-Descriptor in Form einer web.xml (siehe Abbildung 1). Wie greifen diese Bausteine ineinander und welche Aufgaben haben sie?

Kern-Klassen einer Wicket-Anwendung
Abbildung 2: Kern-Klassen einer Wicket-Anwendung

Die Application-Class dient als Startpunkt und zur Konfiguration der Anwendung. Sie zeichnet sich dadurch aus, dass sie von WebApplication erbt (siehe Abbildung 2). Durch diese Vererbung wird die Anwendung mit einer sinnvollen Standardkonfiguration versehen, die selbstverständlich angepasst werden kann (z.B. individuelle Fehlerseiten oder die maximale Fileupload-Größe). Die für das Deployment wichtige web.xml ist bei einer Wicket-Anwendung kurz und übersichtlich. Es muss lediglich ein Filter samt Filtermapping angegeben werden. Als Filter fungiert eine Wicket-Core-Klasse, die als Parameter den Namen der Application-Class unserer Anwendung übergeben bekommt (siehe Listing 1).

<web-app>
 …
 <filter>
  <filter-name>HelloWicketApplication</filter-name>
  <filter-class>
   org.apache.wicket.protocol.http.WicketFilter
  </filter-class>
  <init-param>
   <param-name>applicationClassName</param-name>
   <param-value>com.buschmais.HelloWicketApplication</param-value>
  </init-param>
 </filter>
 <filter-mapping>
  <filter-name>HelloWicketApplication</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
</web-app>

Listing 1: web.xml mit Wicket-Filterdefinition und Application-Class Parameter

Für die Darstellung der Inhalte sieht Wicket so genannte Pages vor. Diese bestehen aus einer von WebPage abgeleiteten Klasse und einer HTML-Datei. Die Klasse dient als Controller, enthält also die Seitenlogik. In der HTML-Datei werden Layout und Styling der Seite festgelegt. Die Verknüpfung zwischen Controller und Markup erfolgt implizit durch Convention-over-Configuration. Dieser unter anderem aus Ruby-on-Rails bekannte Ansatz ermöglicht den Wegfall expliziter Konfigurationen, wenn sich der Entwickler an festgelegte Vereinbarungen hält. Im Falle von Wicket heißt dies: Die HTML-Datei liegt im selben Verzeichnis wie die Class-Datei und trägt bis auf das Dateikürzel den gleichen Namen. Die Zuordnung erfolgt dann durch Wicket. Die Startseite einer Wicket-Anwendung heißt „HomePage“. Diese Page muss der Application-Class bekannt gegeben werden, damit sie beim Aufruf der Webanwendung ausgeliefert werden kann. Nun ist ein einfacher Anwendungsrahmen erstellt und wir können uns auf die Inhalte der Anwendung konzentrieren.

Model, View, Controller strikt getrennt

Die Trennung von Model, View und Controller nach dem gleichnamigen Entwurfsmuster ist ein Ziel, welches viele Frameworks anstreben. Der Entwickler wird allerdings in den seltensten Fällen dazu gezwungen, diese Dreiteilung auch wirklich vorzunehmen. Und ohne das nötige Wissen und einer guten Portion Selbstbeherrschung der beteiligten Personen wird schnell eine Aufweichung des angedachten MVC-Patterns eintreten. Der Grund dafür, liegt nicht ausschließlich beim bequemen Entwickler. Die eingesetzten Frameworks räumen in dieser Hinsicht schlicht zu viele Freiheiten ein. Ein Framework, welches den Anspruch erhebt, das MVC-Pattern umzusetzen, sollte auch nur so viel Freiheit einräumen, wie benötigt wird. Anderenfalls wird entweder aus Bequemlichkeit oder Unwissen an dem eigentlichen Muster vorbeigearbeitet.

Also los, strikte MVC-Trennung à la Wicket: Starten wir mit dem View. Dieser wird in separaten Dateien mittels XHTML definiert. Durch die Verwendung eines separaten Namespaces können nicht nur HTML-Tags und -Attribute im Markup genutzt werden, sondern auch eine Handvoll Wicket-Elemente. Das Aussehen und die Position einer Komponente werden mithilfe von CSS bzw. HTML festgelegt. Durch die Angabe einer so genannten „Wicket-ID“ können die Komponenten des Views vom Controller zugeordnet werden (siehe Listing 2).

<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org">
 <head>…</head>
 <body>
  Hallo <span wicket:id="name" style="font-weight:bold;">
  Framework</span>!
</body>
</html>

Listing 2: Beispiel Homepage.html Hello-World-Markup

Durch diese einfache Markierung der Komponenten bleibt dem Entwickler nichts anderes übrig als die Logik da zu definieren, wo sie hingehört – in die Controller-Klasse. Im Markup gibt es dafür keine Gelegenheit. Neben der sauberen Trennung von Code und Layout bietet dieses Vorgehen noch weitere Vorteile: die Markup-Dateien sind valides XHTML und können von Browsern interpretiert werden. Der View kann dadurch jederzeit so betrachtet werden, wie er später auch von der Webanwendung ausgeliefert wird. Außerdem entfällt das Erlernen vieler, zum Teil komplizierter, Template-Tags wie es bei Java Server Faces (JSF) beispielsweise der Fall ist.

In der Controller-Klasse (Page), die zwingend zu einer Markup-Datei gehört, werden die entsprechenden Komponenten initialisiert und konfiguriert. Dabei muss jeder Komponente eine verwendete Wicket-ID zugewiesen werden (siehe Listing 3). Es darf aber umgekehrt auch keine ungenutzte Wicket-ID im Markup stehen. Durch das Hinzufügen des Labels wird der Inhalt des span-Tags während der Ausführung durch den Wert „Wicket“ ersetzt. Das restliche Markup bleibt unverändert.

protected void onInitialize() {
  //Label mit ID "name" und Wert "Wicket"
  add(new Label("name", "Wicket");
}

Listing 3: Beispiel Homepage.java Hello-World-Page

Um das MVC-Pattern vollständig umzusetzen, braucht es neben View und Controller auch noch Model-Objekte. Jede Komponente, die zur Darstellung von Daten dient, bezieht diese Daten aus einem Objekt, welches das Interface IModel implementiert (siehe Abbildung 3). Die Wicket-Entwickler haben bereits ein paar sinnvolle Model-Klassen erstellt. Für unser Beispielprojekt nehmen wir die einfache Implementierung „Model“ diese ist generisch und kann den Modelwert im Konstruktor entgegennehmen.

Wicket MVC
Abbildung 3: Wicket MVC

protected void onInitialize() {
  Model model = new Model("Wicket");
  //Label mit dem Modelwert
  add(new Label("name", model);
}

Listing 4: Beispiel „Hello World“ mit Model-Objekt

In Listing 3 war scheinbar kein Model nötig, um den Wert „Wicket“ an das Label zu übergeben, bei einem Blick in die Klasse Label sieht man jedoch, dass das Model in diesem speziellen Fall vom Konstruktor selbst erzeugt wird. Da ein Label-Wert vom Nutzer nicht geändert werden kann, ist der Zugriff auf das Model aus dem Controller heraus meist nicht erforderlich. Und schon sind wir mit unserer kleinen Beispielanwendung fertig: „Hallo Wicket“! Hauchen wir der Anwendung nun also etwas Leben ein, indem wir sie durch ein Formular erweitern.

Eigene Komponenten mit Wicket

Da die Entwicklung von eigenen Komponenten unter Wicket ja kinderleicht sein soll, werden wir eine einfache Formular-Komponente zur Eingabe eines Namens erstellen. Diese wollen wir anschließend in die bestehende Seite integrieren. In der Vererbungshierarchie (siehe Abbildung 4) ist zu sehen, dass ein Page-Objekt auch eine Komponente ist. Die Vorgehensweise beim Erstellen eigener Komponenten ähnelt daher stark dem Erzeugen einer Page-Klasse.

Vererbungshierarchie Wicket-Komponenten
Abbildung 4: Vererbungshierarchie Wicket-Komponenten

Für unsere Komponente werden wir ein Panel mit einem Formular erstellen. Das Form-Objekt enthält ein Eingabefeld und einen Button zum Absenden des Formulars. Der Komponentenbaum, der erzeugt werden muss, ist in Abbildung 5 dargestellt. Java-seitig wird nun noch eine Klasse benötigt, die von Panel erbt (siehe Listing 5). Dem Panel werden die Wicket-ID und ein Model übergeben. Das Model wird mit dem Textfeld verknüpft und speichert somit den Wert aus dem Textfeld. Da unsere Komponenten hierarchisch angeordnet sind, erstellen wir ein Form-Objekt auf Grundlage einer anonymen, inneren Klasse und fügen diesem das Textfeld und den Button hinzu. Da der Modelwert bei einer Änderung durch den Nutzer automatisch aktualisiert wird, übernehmen alle Komponenten, die mit diesem Model arbeiten, den geänderten Wert. Vor dem Aktualisieren der Modeldaten werden diese konvertiert und validiert. Tritt dabei ein Fehler auf, werden die Daten nicht übernommen und die Ausgangsseite wird angezeigt. Ein einfacher Controller für das Formular-Panel wäre damit fertig.

Komponentenbaum des FormularpanelAbbildung 5: Komponentenbaum des Formularpanel

public class SingleValueFormPanel extends Panel {

  private IModel strModel;

  public SingleValueFormPanel(String id, IModel model) {
    super(id);
    this.strModel = model;
  }

  @Override
  protected void onInitialize() {
    add(new Form("form"){
  
      protected void onInitialize() {
        add(new TextField("textField", strModel));
        add(new Button("okButton"));
      }

    });
  }
}

Listing 5: Java-Code für das Formular-Panel

In der Markup-Datei werden nicht nur die spezifischen Schnipsel angelegt, die zur Darstellung der Adresse benötigt werden, denn Markup-Dateien in Wicket bestehen immer aus validem XHTML. Daher muss das HTML-Grundgerüst beibehalten werden. Der eigentliche Code für das Panel wird mit dem Tag <wicket:panel> umschlossen und somit für Wicket gekennzeichnet (siehe Listing 6). Wenn eine Seite mit diesem Panel gerendert wird, fügt Wicket die Teile innerhalb der wicket:panel-Tags an der entsprechenden Stelle im Page-Markup ein. Nun kann die Panel-Klasse wie die vorgefertigten Komponenten mit der add-Methode zum Komponentenbaum hinzugefügt werden.

<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org">
 <head></head>
 <body>
  <wicket:panel>
   <form method="POST" wicket:id="form">
    <input type="text" size="20" wicket:id="textField"/> 
    <input type="submit" value="OK" wicket:id="okButton"/>
   </form>
  </wicket:panel>
 </body>
</html>

Listing 6: HTML-Datei für das Formular-Panel

Sollte die Komponente eigene Javascript- oder Style-Dateien benötigen, können diese in dem Tag <wicket:head> eingeschlossen werden. Bei der Verwendung der Komponente wird der Inhalt von <wicket:head> automatisch in den Header der Webseite eingefügt.

Einfach, effizient, aber schlecht dokumentiert!

Nun haben wir eine kleine Wicket-Anwendung erstellt und können überprüfen, ob die gemachten „Versprechen“ gehalten oder ob wir Entwickler (wieder einmal) enttäuscht wurden. Natürlich treten in diesem Beispielprojekt nicht die gleichen Probleme und Herausforderungen auf, wie sie im Projektalltag üblich sind. Es zeigt sich jedoch, dass Wicket dabei helfen kann, einige Probleme zu verhindern. Gerade der Zwang zur strikten Umsetzung des MVC-Patterns und der sinnvolle Einsatz von Konventionen führen zu klar strukturierten Projekten, in die man sich schnell einarbeiten kann. Ebenfalls hilfreich für die Entwicklung dürfte die konsequente Trennung zwischen Markup und Logik sein. Jeder am Projekt Beteiligte kann sich so auf seine Domäne konzentrieren. Während der Webdesigner die HTML-Vorlagen im Blick hat, fokussiert sich die Arbeit des Entwicklers auf die Umsetzung der Anwendungslogik. Anders als bei JSF müssen Designvorlagen mit Wicket nur noch minimal ergänzt werden. Dies hilft vor allem bei nachträglichen Designänderungen.

Auch in Sachen Effizienz kann Wicket punkten. Wie gezeigt, kann eine einfache Anwendung innerhalb kürzester Zeit erstellt werden. Dies gelingt vor allem auf Grund der vielen Standardeinstellungen, mit denen Wicket ausgeliefert wird. Bei Bedarf können weite Teile des Anwendungsverhaltens individuell angepasst werden.

Doch es gibt auch Schattenseiten, mit denen Wicket zu kämpfen hat. Wie bei vielen Open-Source-Projekten ist die Dokumentation des Frameworks mangelhaft. Das betrifft sowohl die Codedokumentation als auch die Onlinehilfe [3]. Für Wicket-Einsteiger ist es daher ratsam, ein Buch über das Framework bei der Hand zu haben. Auch wenn die Lernkurve bei Wicket sehr steil ist, sorgt die schlechte Dokumentation an manchen Stellen für Frust. Zum Glück sind wenigstens die Fehlermeldungen aussagekräftig und tragen zur schnellen Behebung von Fehlern bei. Insgesamt macht das Wicket-Framework jedoch einen sehr ausgereiften und durchdachten Eindruck. Aber macht das Programmieren von Webanwendungen mit Wicket wirklich mehr Spaß? Mir schon.

Quellen:

[1] http://wicket.apache.org/
[2] http://wicket.apache.org/​learn/ides.html
[3] https://cwiki.apache.org/WICKET/​new-user-guide.html

Diesen Artikel können Sie auch als PDF herunterladen:
Download Mehr Spaß im Web mit Wicket

Kommentare sind abgeschaltet.