Tutorial: World Wide Wicket - JAXenter

Tutorial: World Wide Wicket

Verlassen wir kurz Herrn K. und rekapitulieren die bisher gewonnenen Erkenntnisse.

Wicket-Komponenten bestehen aus nichts anderem als Java-Klassen und zugehörigen HTML-Templates (und evtl. zusätzlichen CSS und/oder JavaScript-Dateien). Die HTML-Templates müssen sich im gleichen Package wie die Java-Klassen befinden und den gleichen Bezeichner tragen. Komponenten können ineinander geschachtelt werden (mit der Methode add()und der Vergabe einer ID). Die Java-Komponentenhierarchie spiegelt sich in der Tag-Hierarchie des HTML-Templates wider. Die Zuordnung von Java-Komponenten zu HTML-Tags erfolgt über das Attribut wicket:id. Natürlich müssen nur diejenigen HTML-Tags eine ID erhalten, die auch tatsächlich mit einer Java-Komponente verknüpft werden sollen.

Herr K. ist mittlerweile auf das erste Problem gestoßen. Er ist ein hervorragender Entwickler aber leider auch ein lausiger Designer. Zum Glück befindet sich in seinem Bekanntenkreis Herr D., ein erfolgreicher Webdesigner. Herr K. skizziert kurz seine Vorstellung auf einem Blatt Papier und schickt den Entwurf an Herrn D.. Kurz darauf erhält er ein fertiges HTML-Template inkl. CSS-Styling, das er nun als Grundlage für die weitere Entwicklung verwendet.

Der nächste Schritt für Herrn K. besteht nun darin, die fachlichen Domänenobjekte für seine Videothek zu definieren. (Die Klasse Customer ist exemplarisch in Listing 4 dargestellt).

Listing 4
public class Customer implements Serializable {
  private String name;
  private Adress adress;
  private String email;
  private CustomerType type;

  public Customer(){
  }

public Customer(String name, String email, CustomerType type, Adress adress) {  
    this.email = email;
    this.name = name;
    this.adress = adress;
    this.type = type;
  }  
/*
Getter und Setter
*/
}

Alle Domänenklassen sind einfache Pojos und für Herrn K. selbsterklärend. Die einzige Besonderheit: jede Domänenklasse implementiert das Serializable-Interface. Warum das notwendig ist, wird im Kasten Wicket und Serialisierung genauer erläutert.

Wicket und Serialisierung

Wicket serialisiert eine Page sowie deren Komponenten nach jedem Request per Default in den so genannten DiskPageStore auf die Festplatte und stellt so eine Lösung für das Back-Button-Problem im Browser bereit. Das bedeutet aber auch, dass wirklich jede Domänenklasse der Webanwendung zwingend das Serializable-Interface implementieren und serialisierbar sein sollte. Ist dies nicht möglich, kann das Problem umgangen werden, indem beispielsweise ein LoadableDetachableModel verwendet wird [7]. Über das LoadableDetachableModel wird Objekt detached (also z. B. das Objekt selbst auf null gesetzt und nur eine ID gespeichert), bevor der Komponentenbaum serialisiert wird. Beim nächsten Request kann das Objekt erneut geladen werden (z. B. aus der Datenbank anhand der gespeicherten ID).

Herr K. möchte die kundenspezifischen Informationen in einer Session speichern. Zunächst sollte der aktuell angemeldete Benutzer über die Session zugreifbar sein. Weiterhin ist es sinnvoll, eine Liste an bereits ausgewählten Filmen über die Session zugreifbar zu machen.

Diese Informationen scheinen für den Anfang zu genügen und Herr K. implementiert die Klasse VideoSession in Listing 5.

Listing 5
public class VideoSession extends WebSession{
  public VideoSession(Request request) {
    super(request);
  }

  private Customer customer;
  private List selectedMovies;

  public Customer getCustomer() {
    return customer;
  }
  public void setCustomer(Customer customer) {
    this.customer = customer;
  }
  public List getSelectedMovies() {
    return selectedMovies;
  }
  public void setSelectedMovies(List selectedMovies) {
    this.selectedMovies = selectedMovies;
  }

  public static VideoSession get(){
    return (VideoSession) Session.get();
  }

}

Die Klasse VideoSession erweitert die Klasse WebSession des Wicket-Frameworks. WebSession ist eine Abstraktion für die aus der Servlet-Spezifikation bekannte HttpSession. Vorteil der Verwendung von Websession gegenüber der direkten Verwendung von HttpSession ist die Typsicherheit der in der Session verfügbaren Objekte. Anstatt eines Zugriffs der Art Customer customer = (Customer) httpSession.getAttribute(„customer“) kann Herr K. direkt und ohne zu Casten auf den Kunden zugreifen über Customer customer = VideoSession.get().getCustomer().

Damit für jeden Benutzer eine neue Session erzeugt wird, überschreibt Herr K. einfach die Methode newSession(Request request, Response response) in der Klasse VideoStoreApplication und liefert als Rückgabewert eine neue Instanz von VideoSession.

Da Herr K. ein von Natur aus gutgläubiger Mensch ist, verzichtet er zunächst auf die Implementierung eines Login-Mechanismus für seine Videothek. Stattdessen soll der Benutzer direkt auf der ersten Seite die Möglichkeit bekommen, seinen Namen, E-Mail-Adresse, Rechnungsadresse sowie seinen Kundentyp (privat oder business) zu hinterlegen.

Models auf der Titelseite

Herr K. beginnt gut gelaunt mit der Erweiterung der bereits vorhandenen Klasse HomePage. Zur Umsetzung von Formularen für Eingabefelder bietet Wicket entsprechende Komponenten wie beispielsweise TextField für <input type=“text“/>, RadioChoice für <input type=“radio“/> oder Form für das <form/>-Element selbst.

Herr K. erstellt zunächst die für die Eingabe der Benutzerdaten passende Html-Form (in Auszügen in Listing 6) und anschließend die korrespondierenden Wicket-Komponenten (Listing 7). Die Komponenten werden später im Artikel noch genauer betrachtet.

Listing 6

[…]

Listing 7
  final Customer customer = createEmptyCustomer();
  Form form = new Form("customerForm", new CompoundPropertyModel(customer));
  final TextField nameField = new TextField("name");
  final TextField emailField = new TextField("email");
final RadioChoice customerTypeChoice = new RadioChoice("type", Arrays.asList(CustomerType.values()),
    new EnumChoiceRenderer());  
   final TextField streetField = new TextField("adress.street");
  final TextField zipField = new TextField("adress.zip");
  final TextField cityField = new TextField("adress.city");
  final TextField houseNumberField = new TextField(
    "adress.houseNumber");
  form.add(nameField);
  form.add(emailField);
[..]

Zunächst jedoch macht sich Herr K. mit einem weiteren wichtigen Konzept des Wicket-Frameworks, den Modellen, vertraut. Ein Wicket-Modell kann als Wrapper-Objekt betrachtet werden, das die Zugriffe auf die domänenspezifischen Klassen kapselt.

Modelle ermöglichen einer Wicket-Komponente den Zugriff auf das zugrunde liegende Domänenobjekt (wie beispielsweise einen Customer) über entsprechende Zugriffsmethoden (getObject ()/setObject()). Ein einfaches Beispiel für die Verwendung von Modellen ist in folgendem Codefragment dargestellt:

Model model = new Model(customer.getName());
Label label = new Label("labelId", model);

Das Label würde jetzt automatisch den im Model hinterlegten Namen des Kunden anzeigen. Die Verwendung von Models hat gegenüber der direkten Verwendung von fachlich motivierten Klassen einige Vorteile. Modelle abstrahieren von der zugrundeliegenden Datenquelle, was deren problemlosen Austausch zu einem späteren Zeitpunkt ermöglicht. Wicket bietet verschiedene Modellimplementierungen, die beispielsweise ein automatisches Binding an bestimmte Attribute einer Domänenklasse (PropertyModel) oder auch das Laden von Daten über ein Backend-System (LoadableDetachableModel) ermöglichen.

Name:
Email:
Kommentare

Schreibe einen Kommentar

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