09.03.2012

Tapestry - Dynamische Formulare mit java.util.Map

Vielen Entwicklern wird es eventuell ähnlich gegangen sein, wie es mir gegangen ist. Irgendwo in der Anwendung findet sich ein Zugriff auf die Datenbank mit Hilfe eines JdbcTemplates und die Ergebnisse werden durch eine Liste von Maps repräsentiert.


Die Anzeige mag noch einfach sein, dort kann einfach eine Grid Komponente genutzt werden. Die Bearbeitung eines einzelnen Datensatzes ist spätestens dann nicht mehr!
Aus diesem Grund möchte ich die Arbeit mit einer Map innerhalb eines Formulars vorstellen. Demonstriert wird dies mit Hilfe eines einfachen Tapestry Projektes, welches mittels Maven verwaltet wird. Das Grundgerüst des Projektes entspricht dem Standard Tapestry Projekt. Der generelle Projekt-Aufbau kann in der Dokumentation nachgelesen werden.


Im wesentlichen besteht das Projekt aus einer einzelnen Seite, einer Service-Implementierung unddem Anwendungsmodul, in dem der Service registriert wird. Das folgende Klassendiagramm veranschaulicht die Beziehungen unter den Klassen.


Wie bereits beschrieben, besteht das Projekt aus dem Service inkl. seiner Implementierung (DataService und DataServiceMock), dem Anwendungsmodul für die Registrierung der Services (AppModule) und der eigentlichen Visualisierung inkl. Controller (Index.tml und Index).

Zusätzlich finden sich noch weitere Konfigurationsdateien (log4j.xml) und Maven-Build-Files (build.properties und pom.xml) in dem Projekt, auf diese werde ich an dieser Stelle nicht näher eingehen.

Gestartet wird die Anwendung über das Jetty-Plugin, welches in der pom.xml definiert ist.


Damit kann das Projekt nach dem Auschecken direkt gestartet werden, es ist keine weitere Konfiguration mehr notwendig.

Die Anwendung an sich ist so einfach gehalten, dass der eigentliche Sinn des Beispiels nicht untergeht. Das folgende Sequenzdiagramm beschreibt den Ablauf des einfachen Workflows.



Der Nutzer ruft also die Seite auf, wählt die ID der zu bearbeitenden Zeile, führt die Bearbeitung der Werte durch und die Zeile wird mit dem Submit des Formulars in der Session aktualisiert. Um zu verstehen, wie das Formular dynamisch aufgebaut und gefüllt wird, werden die einzelnen Schritte sukzessive betrachtet.

1. Auswahl der ID der zu bearbeitenden Zeile

Die vorhandenen IDs werden direkt aus dem DataService geholt. Die Implementierung hält die Werte nach der Initialisierung der Klasse innerhalb der Session vor.


Innerhalb der Seite Index wird der Dienst mit Hilfe der @Inject Annotation durch Tapestry injiziert. Dort wird dann auf die Liste der vorhandenen IDs zurückgegriffen.


Die Liste der IDs wird wiederum im Template zur Visualisierung der Select Komponente genutzt.


Die Komponente ist natürlich in das gesamtheitliche Template eingebettet und liegt innerhalb eines Formulars, welches durch den Nutzer abgeschickt werden kann. Für den Nutzer bietet sich also beim ersten Betrachten der Seite das folgende Bild:


Nach dem Wählen der ID zur Bearbeitung einer einzelnen Spalte wird das Formular abgesendet und mit dem zweiten Schritt und dem eigentlichen dynamischen Aufbau des Formulars begonnen.

2. Laden der zu bearbeitenden Zeile und Aufbau des Formulars


Nach der Auswahl der ID wird die Zeile durch die Seite geladen und der dynamische Aufbau des Formulars kann beginnen. Die durch den Nutzer gewählte Zeile wird dabei in der Variablen currentRow in der Session vorgehalten. Die Verknüpfung zum Template wird durch die @Property Annotation erreicht, welche einen direkten Zugriff auf die Variable ohne Getter und Setter ermöglicht.




Für die Visualisierung der Felder wird über die Einträge der aktuellen Zeile iteriert. Jeder Eintrag innerhalb der Map bekommt ein eigenes Eingabefeld, welches dem Nutzer zur Bearbeitung zur Verfügung steht.




Das Iterieren wird mit Hilfe der Loop Komponente durchgeführt. Diese bietet die Möglichkeit über eine Menge von Objekte zu iterieren und diese dann mit Hilfe von weiteren Komponenten zu verarbeiten. Das aktuelle Objekt wird hierbei innerhalb der Index Seite gespeichert.


Für die spätere Verarbeitung der einzelnen Felder ist dies ein wesentlicher Punkt. Dieses Attribut wird bei der Aktualisierung der Werte noch eine weitere Rolle spielen. Damit der State des Forms wieder hergestellt werden kann, wird dem Formular ein sogenannter ValueEncoder mitgegeben. Ist für Tapestry nicht ersichtlich, wie die im Formular gespeicherten Werte in eine eindeutige String-Darstellung und zurück gewandelt werden können, muss ein solcher ValueEncoder definiert werden. Für einfache Datentypen sind bereits ValueEncoder definiert und müssen somit nicht erneut erstellt werden.


Im zweiten Teile des Templates ist zu sehen, dass für jeden Eintrag innerhalb der Map ein TextField generiert wird. Der einzige Unterschied zur Standardnutzung ist an dieser Stelle der Zugriff auf die Daten, die durch das TextField verwaltet werden. Zu sehen ist, dass nicht direkt auf die Rendervariable der Schleife zurückgegriffen wird, sondern auf ein Attribut der Seite an sich.


Das entsprechende Feld, bzw. die Zugriffsmethoden, sind in der Index Seite definiert und greifen dort direkt auf den Eintrag in der Map zurück.


Damit werden die vom Nutzer erfassten Werte direkt in der Map bzw. dem Eintrag in der Map gespeichert. Für den Nutzer stellt sich die Bearbeitung der Zeile wie ein normales Formular dar:


Somit steht der Verarbeitung bzw. Bearbeitung von Einträgen innerhalb einer Map nichts mehr im Wege. Die Daten können leicht aus dem Formular übertragen und in die Map überführt werden. Denkbar ist auch eine andere Verwertung der Daten, da diese nicht zwingend an die Map gebunden sind.

Der gesamte Code ist wie immer im Repository zu finden.

1 Kommentar:

  1. Eine nette, kurze Anleitung zur Erstellung dynamischer Formulare. Sehr detailliert und ausführlich mit den Bildern beschrieben.

    AntwortenLöschen