Über unsMediaKontaktImpressum
Sebastian Böhm & Tom Krauß 12. Januar 2015

Vaadin – Entwicklung von Rich-Client-Geschäftsanwendungen für den Browser

Der Trend zum Bau von Geschäftsanwendungen für den Browser hat sich durch die Anforderung, auch auf Smart-Phones und Tablets zu laufen, weiter verstärkt. Dabei sollte die entsprechende Technologie in der Lage sein, moderne Anforderungen wie Responsive Design zu unterstützen. Dies haben wir zum Anlass genommen, uns Vaadin, einen der Top-Player von Java-basierten Web Frameworks (Platz 3 in 2014 [1]), anzusehen.

Der Name Vaadin kommt aus dem Finnischen und bedeutet Rentierweibchen. Dieses kann man auch erkennen, wenn man das Logo }> um 90° im Uhrzeigersinn dreht. Vaadin basiert auf GWT und erlaubt die Erstellung moderner, Browser-unabhängiger Rich-Client-Oberflächen. Es bietet eine große Auswahl an Komponenten, Werkzeugen und Technologien, welche direkt und einfach verwendet werden können.

JSF vs. Vaadin

Man kann Vaadins Stärken am Besten in einem Vergleich mit einer klassischen Web-Technologie wie zum Beispiel Java Server Faces (JSF) demonstrieren. Im Folgenden wollen wir die Schritte zu einer minimalistischen Geschäftsanwendung einmal mit JSF und einmal mit Vaadin durchgehen. Unsere kleine Adressverwaltung soll dabei auf dem Modell aus Abb. 1 basieren und lediglich das Anlegen von Adressen unterstützen.

Unabhängig von der verwendeten Technologie erstellt man zunächst ein Web-Projekt und bindet alle benötigten Bibliotheken an. Die nächsten Schritte sind das Registrieren eines Servlets, das Mapping auf einen URL-Pfad und eventuelle zusätzliche Servlet-Einstellungen.

Die Logik in JSF-Anwendungen befindet sich hauptsächlich in Managed Beans. Für unsere Anwendung muss also eine Managed Bean, nennen wir sie PersonBean, angelegt werden, die eine Liste von gespeicherten Adressen und eine Methode zum Speichern einer neuen Adresse enthält. Für die Darstellung ist eine XHTML-Seite mit einem Formular und einer Tabelle für Adressen zu erstellen. Nach der Registrierung dieser Seite in der faces-config.xml über eine so genannte Navigation Rule ist die kleine JSF-Geschäftsanwendung fertig.

Wir haben mit geringem Aufwand eine einfache, aber funktionale Adressverwaltung erstellt. Die im Formular eingegebenen Werte werden über ein Binding in die PersonBean geschrieben und einer Liste hinzugefügt, in der sie zumindest für die Dauer einer Session gespeichert werden. Selbst für die Erstellung dieser Anwendungen muss man diverse Spezialthemen beherrschen (Facelets-Technologie, Managed Beans, Expression Language, …).

Die Ansprüche an ein zeitgemäßes User Interface erfüllt diese Anwendung jedoch bei Verwendung des JSF-Basis-Frameworks kaum. Layout und Dynamik von Anwendungen, die die User von Rich-Client-Anwendungen gewohnt sind (z.B. Spalten-Sortierung, Popup-Meldungen bei Validierungsfehlern oder asynchrone Datenübertragung) sind nicht vorhanden. Selbstverständlich kann man die Anwendung dahingehend erweitern. Allerdings ist dies mit viel Handarbeit verbunden und man muss sich diverser weiterer Technologien bedienen (z.B. CSS, Richfaces, JavaScript, jQuery, REST, JSON etc.).

Auch bei der Entwicklung unserer Anwendung mit Vaadin kommen wir um die ersten Schritte zum Anlegen eines Web-Projekts nicht herum. Bei der Verwendung von Eclipse als Entwicklungswerkzeug zusammen mit dem Vaadin-Plugin werden diese allerdings durch einen entsprechenden Assistenten vereinfacht.

Die eigentliche Entwicklung geschieht nun vollständig in Java. Den Startpunkt bildet eine Klasse, die von com.vaadin.ui.UI ableitet und dem VaadinServlet bekannt gemacht wird. Die Methode void init(VaadinRequest) wird beim Starten der Vaadin-Anwendung ausgeführt. Hier wird zunächst die Oberfläche aufgebaut: Das Eingabeformular, der “Speichern”-Button und die Adresstabelle werden in ein vertikales Layout gesteckt und dieses als Inhalt der Anwendung gesetzt:


protected void init(VaadinRequest request) {
  TextField firstNameField = new TextField("Vorname");
  // ...
  TextField streetField = new TextField("Straße");
  FormLayout formLayout = new FormLayout(firstNameField, lastNameField, streetField, zipcodeField, cityField);
  
  Button saveButton = new Button("Speichern", null);
  
  Table table = new Table();
  table.setColumnHeaders("Vorname", "Nachname", "Straße", "PLZ", "Stadt");
  
  setContent(new VerticalLayout(formLayout, saveButton, table));
}

Listing 1: Aufbau der Oberfläche

Für das einfache Binden der Personen- und Adress-Attribute auf die Formularfelder existiert die Klasse BeanFieldGroup, die Felder auf (bei Bedarf verschachtelte) Attributnamen abbildet:


personFieldGroup = new BeanFieldGroup<>(Person.class);
  
personFieldGroup.bind(firstNameField, "firstName");
// ...
personFieldGroup.bind(streetField, "address.street");
  
personFieldGroup.setItemDataSource(new Person());

Listing 2 - Binding der Formularfelder auf die Bean-Attribute

Ähnlich geht man bei einer Tabelle vor, die mit Hilfe eines BeanItemContainersgefüllt wird:


personContainer = new BeanItemContainer<>(Person.class);
personContainer.addNestedContainerBean("address");
  
table.setContainerDataSource(personContainer);
table.setVisibleColumns("firstName", "lastName", "address.street", "address.zipcode", "address.city");

Listing 3 - Binding der Tabellenspalten auf die Bean-Attribute

Die Aktion des Speichern-Buttons wird mit Hilfe eines ClickListeners implementiert, der das Model-Objekt Person aus der FieldGroup in den ItemContainer fügt:


Button saveButton = new Button("Speichern", new ClickListener() {
  
  @Override
  public void buttonClick(ClickEvent event) {
    personFieldGroup.commit();
    personContainer.addBean(personFieldGroup.getItemDataSource().getBean());
    personFieldGroup.setItemDataSource(new Person());
  }
  
});

Listing 4 - Zuweisung einer Aktion zum Speichern-Button

Mit diesem Code ist unsere kleine Geschäftsanwendung fertig und kann gestartet werden. Das Ergebnis kann sich sehen lassen (s. Abb. 3). Es ist nicht nur die gewünschte Funktionalität vorhanden, sondern auch ein einfaches Layout sowie einige Zusatz-Funktionen wie z.B. die Spaltensortierung. Auch werden beim Speichern einer neuen Adresse statt dem Laden der kompletten Seite nur die entsprechenden Daten zwischen Browser und Server getauscht, was eher einer Rich-Client-Anwendung gerecht wird.

Man beachte, dass wir weder für das Layouten noch für die Spaltensortierung oder die asynchrone Datenübertragung extra Aufwand betrieben haben. Vaadin macht also mehr, als man aus dem geschriebenen Java-Code schließen kann. Aber was passiert da unter der Haube?

Technik von Vaadin

Vaadin-Komponenten bestehen je aus zwei Teilen: aus der Repräsentation auf dem Server und einem entsprechenden GWT-Widget im Browser (GWT: Google Web Toolkit). Der Part auf dem Server dient dem Entwickler als Programmierschnittstelle. Hier werden die Komponenten über Setter-Methoden konfiguriert und zugewiesene Listener reagieren auf Events. Das GWT-Widget kümmert sich um die eigentliche Darstellung der Komponente und mit Hilfe von JavaScript um ihr dynamisches Verhalten. Abhängig von der implementierten Anordnung der Vaadin-Komponente – der Textfelder, der Tabellen, der vertikalen Layouts etc. – generiert Vaadin zur Laufzeit die Struktur der darzustellenden Seite. Die Komponenten werden dabei nicht in HTML kodiert, sondern über JavaScript direkt im Browser als DOM-Baum erzeugt. Über einen automatisch synchronisierenden Shared State werden die Eigenschaften der Komponenten von der Server- auf die Client-Komponente übertragen. Komplexere Änderungen oder Aktionen wie das Wechseln einer Seite oder Ereignisse (z.B. Klick auf einen Button) werden über Remote Procedure Calls (RPC) zwischen beiden Seiten getauscht.

Der Clou an der ganzen Sache ist, dass der Entwickler sich um die eigentliche Darstellung und die Kommunikation überhaupt nicht kümmern muss. Das notwendige Vorkompilieren der GWT-basierten Widgetsets, die alle dieses Schema implementieren, kann dabei über ein Maven- oder Ant-Build-Target oder über das Eclipse Plugin durchgeführt werden. Der Entwickler muss sich in der Regel nicht um die Technik, sondern kann sich um die fachlichen Dinge kümmern.

Konvertierung & Validierung

Neben dem Binding der Felder auf Bean-Attribute ist auch die Konvertierung und Validierung für eine reibungslose Datenverarbeitung wichtig. Für die Konvertierung der meisten einfachen Datentypen wie zum Beispiel Integer, Date oder BigDecimal bringt Vaadin bereits entsprechende Konverter-Klassen mit. Für alle anderen Fälle kann man seine eigenen Konverter erstellen, indem man das Interface

com.vaadin.data.util.converter.Converter

implementiert. Die Konverter können einfach den Eingabefeldern per Setter-Methoden zugewiesen werden:


TextField numberField = new TextField();
numberField.setConverter(new StringToIntegerConverter());
Integer integer = (Integer) numberField.getConvertedValue();

Listing 5: Zuweisung der Konverter

Mit der Validierung verhält es sich ähnlich. Auch hier bietet Vaadin diverse vorgefertigte Validatoren für verschiedene Typen an (z.B. RegexValidator, IntegerRangeValidator), aber man kann mit Hilfe des Interfaces com.vaadin.data.Validator auch eigene anlegen. Besonders interessant ist der BeanValidator, welcher anhand von JSR-303-Annotationen validiert. Wurde zum Beispiel ein Eingabefeld mit diesem Validator einem Bean-Attribut mit der Annotation @Size(min = 5) zugeordnet, so muss der Benutzer mindestens 5 Zeichen für einen validen Wert eingeben.

Sowohl für die Konvertierung als auch für die Validierung bietet Vaadin die entsprechende Infrastruktur. Der Entwickler setzt lediglich den gewünschten Konverter bzw. Validator ein und Vaadin kümmert sich um den eigentlichen Aufruf, um ein geeignetes Exception-Handling und natürlich um die Darstellung von eventuellen Validierungsfehlern.

Auswahl an Bedienkomponenten

Vaadin kommt mit einer großen Auswahl an Standard- und komplexeren Komponenten, wie TreeTables, umfangreich anpassbaren Tabellen oder Charts (diese allerdings nur als kommerzielles Add-on). Sogar eine komplette Kalender-Komponente ist vorhanden. Interessanterweise fehlen allerdings einige Standardkomponenten, die man von anderen UI-Frameworks gewohnt ist wie beispielsweise ein ToggleButton oder ein Button mit Kontextmenü. Einige dieser Komponenten sind zwar als Add-ons verfügbar, aber mit einigen kleineren Problemen behaftet.

Nicht einfach ist die Verwendung der vorgefertigten Layouts. Für gut gelayoutete Oberflächen muss man unter Umständen das CustomLayout verwenden, das die Positionierung von UI-Elementen mit CSS-Mitteln erlaubt. Seit Version 7.3 ist es hier zudem möglich, Responsive Layouts zu erstellen d.h. Layouts, die sich abhängig von der Größe des Browserfensters verändern.

Speziell für die Entwicklung von Mobile Apps steht das (ebenfalls kommerzielle) Vaadin Touchkit zur Verfügung, welches speziell für Smartphones optimierte Komponenten bietet. Auch ist es möglich, mobile Anwendungen so zu programmieren, dass sie im Falle eines Verbindungsabbruchs oder bei hohen Latenzzeiten immer noch gut funktionieren. Gesten werden allerdings bewusst nicht unterstützt, da sie trotz des sehr hohen Aufwands bei der Implementierung keinen großen Mehrwert in Geschäftsanwendungen haben.

Werkzeuge

Wer schon einmal in Swing programmiert hat, weiß, dass das Zusammenbauen von Oberflächen recht unübersichtlich werden kann. Man hat zahlreiche Eingabefelder, die mehrstufig in diversen Containern zusammengefasst sind oder muss die Komponenten auf einem Panel positionieren und verliert dabei im Code den Überblick.

Mit der Installation des Eclipse Vaadin Plugins bekommt man aber einen graphischen Editor für Oberflächen, den Visual Designer. Hier kann man, wie mit anderen graphischen Editoren auch, Komponenten aus einer Liste auf die bearbeitete Oberfläche ziehen, kann ihre Eigenschaften ändern und sieht in einem Baum die Struktur der Oberfläche.

Das Ergebnis, das der Visual Editor generiert, ist eine gewöhnliche Java-Klasse, die die modellierte Oberfläche enthält. Die vom Editor angelegten Felder und Methoden sind mit der Annotation @AutoGenerated markiert und sollten vom Entwickler nicht angefasst werden. In der generierten Klasse gibt es Platzhalter für individuellen Code, die mit einem entsprechenden Kommentar gekennzeichnet sind. Diese Struktur ermöglicht es, eine Oberfläche zu modellieren, Anpassungen im Code vorzunehmen und die Oberfläche anschließend im Visual Designer erneut zu öffnen und zu bearbeiten, ohne dass dieser den geschriebenen Code verändert oder gar entfernt.


public class ZipcodeAndCityEditor extends CustomComponent {
  
  @AutoGenerated
  private AbsoluteLayout mainLayout;
  @AutoGenerated
  private Label zipcodeAndCityLabel;
  // ...
    
  /**
   * The constructor should first build the main layout, set the
   * composition root and then do any custom initialization.
   *
   * The constructor will not be automatically regenerated by the
   * visual editor.
   */
  public ZipcodeAndCityEditor() {
    buildMainLayout();
    setCompositionRoot(mainLayout);
  
    // TODO add user code here
  }
  
  @AutoGenerated
  private AbsoluteLayout buildMainLayout() {
    // common part: create layout
    mainLayout = new AbsoluteLayout();
      
    // ...

Listing 6: Generierter Code aus dem Visual Designer

Wenn die Oberfläche dann endlich steht, möchte sie natürlich noch getestet werden. Diejenigen, die schon einmal versucht haben, eine Web-GUI automatisiert zu testen, wissen, dass dies sehr mühsam und zeitaufwendig sein kann. Dabei verbringt man meistens mehr Zeit mit technischen Schwierigkeiten, als mit den eigentlichen fachlichen Tests. Mit dem (kostenpflichtigen) Vaadin Pro-Tool TestBench bekommt man ein Werkzeug an die Hand, das einem hilft, die technischen Hürden zu meistern. Es basiert auf dem Web-Testframework Selenium und bietet ableitbare Testklassen und Methoden zum Selektieren und Interagieren mit Vaadin-Komponenten.

Tests mit TestBench werden als einfache JUnit-Tests erstellt und erben von der Klasse

com.vaadin.testbench.TestBenchTestCase

(Listing 7). Initial wird ein Driver für den Browser gesetzt, auf dem der Test ausgeführt werden soll (Zeile 19ff.). Dieser muss am Ende natürlich auch beendet werden (Zeile 24ff.). Beim eigentlichen Test wird zunächst die URL der Vaadin-Anwendung aufgerufen (Zeile 31), anschließend können über die Methode $(Class) Vaadin-Komponenten aus der Oberfläche selektiert werden. Die Selektion erinnert ein wenig an die Funktionsweise von jQuery. Man gibt der Methode den gewünschten Komponententyp (Vaadin-Komponenten-Klassenname + “Element”) und erhält eine Liste der existierenden Elemente, die man weiter z.B. über den Titel einschränken kann. Schließlich können die Elemente auf ihre Eigenschaften geprüft, neue Eigenschaften gesetzt oder Aktion ausgeführt werden (Zeile 32ff.).


public class VaadinBusinessApplicationUITest extends TestBenchTestCase {
  
  @Before
  public void setUp() throws Exception {
    setDriver(new FirefoxDriver());
  }
                      
  @After
  public void tearDown() throws Exception {
    getDriver().quit();
  }
  
  @Test
  public void testAddingAddress() throws Exception {
    getDriver().get("http://localhost:8080/vaadin-business-application");
    assertTrue($(TextFieldElement.class).caption("Vorname").exists());
    $(TextFieldElement.class).caption("Vorname").first().setValue("Hans");
    $(ButtonElement.class).caption("Speichern").first().click();
    assertEquals("Hans", $(TableElement.class).first().getCell(0, 0).getText());
  }
  
}

Listing 7: Automatisierter Test mit TestBench

Den Code zum Selektieren einer Komponente kann man sich auch generieren lassen. Man startet die Vaadin-Anwendung mit dem Parameter ?debug und erhält ein kleines Panel in der rechten unteren Ecke des Browserfensters mit allerlei Entwickler-Informationen (z.B. Kommunikationslog, Versionsinformationen, Komponentenhierarchie etc.). Außerdem bietet das Debug-Fenster eben auch die Möglichkeit, sich mit einem Klick den Selektionscode für TestBench-Tests ausgeben zu lassen (s. Abb. 6).

Layout und Look&Feel

Vaadin bringt bereits ein paar recht ansehnliche Themes mit (z.B. Reindeer, s. Abb. 3), die man per @Theme(String)-Annotation an der UI-Klasse setzen kann. Selbstverständlich kann man diese anpassen oder auch eigene Themes erstellen. Themes werden in Vaadin unter Verwendung von SASS (Syntactically Awesome Style Sheet) erstellt. Dabei erstellt man die für Themes benötigte Ordnerstruktur und definiert eine Datei styles.scss, die die benötigten Basisdefinitionen über einen Mixin Mechanismus referenziert und erlaubt, vorhandene CSS-Klassen umzudefinieren und neue zu erstellen.

Die CSS-Basisklassen der Standard-Komponenten kann man leicht im Book of Vaadin, dem offiziellen Manual, finden. Dort sind auch alle Konfigurationsmöglichkeiten des neu in Version 7.3 eingeführten Valo-Themes beschrieben. Valo erlaubt nicht nur die Definition eigener, neuer Komponenten-CSS-Klassen, sondern bietet auch die Möglichkeit, über diverse SCSS-Variablen das komplette Layout zu definieren. Zum Beispiel kann über die Variable $background-color der Hintergrund der Vaadin-Anwendung und über die Variable $v-border-radius die Rundung der Ecken bei Vaadin-Komponenten mit Rahmen gesetzt werden.

Des Weiteren können vorgefertigte Komponenten-Styles im Code gesetzt werden. Diese sind in der Klasse com.vaadin.ui.themes.ValoTheme gesammelt. Man kann beispielsweise über

lastNameField.addStyleName(ValoTheme.TEXTFIELD_ALIGN_CENTER)

den Text im Textfeld zentrieren lassen. Die Konstanten beginnen stets mit dem Namen der Komponente, für die sie gedacht sind, somit kann man sich schnell einen Überblick verschaffen, was für eine Komponente möglich ist.

Um die Mächtigkeit des Valo-Themes zu demonstrieren, haben die Vaadin-Entwickler einige Konfigurationen zusammengestellt, die die Vaadin-Anwendung unter anderem mit einer Metro- oder Facebook-ähnlichen Oberfläche rendern lassen (s.[2]).

Mit den Theme-Mechanismen kann man also relativ einfach seine Vaadin-Anwendung an die Wünsche des Kunden anpassen um zum Beispiel einen Corporate Look & Feel zu erzeugen. Allerdings kommt man mit dem Layouting schnell an die Grenzen, wenn man von dem Standard-Aussehen zu stark abweichen möchte z.B. abgerundete Ecken bei Komponenten ohne Rahmen.

Fazit

Überzeugt hat uns an Vaadin, wie schnell man produktiv ist und eine erste einfache Geschäftsanwendung gebaut hat. Gerade für Entwickler, die neu in die Welt der Web-Entwicklung einsteigen, fällt der Einstieg leicht. Dabei gibt es für viele Fragestellungen der Anwendungsentwicklung im Bereich von Geschäftsanwendungen wie Validierung, Konvertierung, Ablaufsteuerung, Skinning oder Browser-spezifische Themen wie die Unterstützung des Zurück-Buttons eine Lösung. Fragen, die bei der ersten Verwendung auftreten, lassen sich schnell durch die umfangreiche Dokumentation oder über Konsultation des Vaadin Forums klären.

Sobald Anwendungen komplexer werden und selbst die zahlreichen verfügbaren Add-ons nicht ausreichen, muss man allerdings sehr tief in Vaadin und GWT einsteigen, um spezielle Lösungen zu erarbeiten oder komplexere Probleme zu debuggen.

Vaadin eignet sich gut für die Erstellung von Geschäftsanwendungen, die aus technischen Gründen als Web-Anwendung ausgelegt werden, aber von der Funktionalität eher Rich-Clients sein sollen. Da Vaadin sehr gut einige Unwägbarkeiten der Web-Entwicklung vom Anwendungsentwickler fernhält, können sich die Entwickler auf die vielzitierte Fachlichkeit konzentrieren. Zur Implementierung von Endbenutzer Web-Anwendungen wie beispielsweise Shop-Systemen oder einem Social Network wird man jedoch sicher alternative Frameworks einsetzen.

Autoren

Tom Krauß

Tom Krauß ist seit 1994 Partner bei GEBIT und leitet dort den Bereich Internet-/Java-Technologien. Er ist für Design und Architektur Java/JavaEE-basierter Businessanwendungen verantwortlich.
>> Weiterlesen

Sebastian Böhm

Sebastian Böhm ist Diplom-Ingenieur der Informationstechnik und sein Hauptinteresse gilt Web-Technologien und der Verwendung von Techniken zur Minimierung der Kosten und der Komplexität in der Software-Entwicklug wie...
>> Weiterlesen
botMessage_toctoc_comments_9210