Teil 1: Going Vaadin 10

Backend meets Frontend Reloaded: Basics schaffen für Projekte mit Vaadin 10

Sven Ruppert

© Shutterstock / HelenField & bkf (modifiziert)

Vaadin 10 ist nun schon einige Zeit verfügbar und immer mehr Projekte beginnen mit dieser Version oder mit der entsprechenden Migration auf die neue Version. In diesem Tutorial werden wir uns mit Vaadin 10 beschäftigen und den Fokus dabei auf langlebige Projekte legen.

Die Projektgrundlage

Beginnen wollen wir mit der Projektgrundlage. Aufgrund der neuen Releasezyklen von Oracle werden wir uns hier auch immer mit dem gerade aktuellen JDK auseinandersetzen. Das hat für lange laufende Projekte auf der einen Seite seinen Reiz, auf der anderen Seite sollte die Struktur auch darauf ausgelegt sein. Ich werde an dieser Stelle nur kurz auf diese Thematik eingehen und verweise an dieser Stelle auf meine andere Artikelserie hier auf JAXenter, die sich eingehender mit dieser Thematik beschäftigt.

Der Projektbeginn

Zum Zeitpunkt, da dieser Artikel geschrieben wurde, war JDK 10 noch aktuell, die Veröffentlichung von JDK 11 stand kurz bevor. Durch die neue Release-Kadenz von Java wird es solche Wechsel nun öfter geben, daher geht es nun zunächst einmal darum, wie die Auswirkungen eines JDK-Wechsels zu handhaben sind.

Das Projekt selbst wird mittels Maven verwaltet. Hierzu wird die grundlegende Struktur angelegt und wir beginnen in der pom.xml mit der notwendigen Definition zur Verwendung des JDK 10. Als aller erstes stellen wir sicher, dass auf keinen Fall eine Version in einem Maven Repository abgelegt wird. Stattdessen wird als Ziel ein lokales Verzeichnis angegeben.

    
  
  
    
      localhost
      file://${basedir}/target/repo/
    
    
      localhost
      file://${basedir}/target/snapshot-repo/
    
   

Wir werden zu Beginn keine Vaadin Add-ons verwenden, demnach kann die nachfolgende Definition in der pom.xml zu Beginn auch entfallen, was die Ausführung des Befehls mvn clean install beschleunigt.

    
   
    
      vaadin-addons
      http://maven.vaadin.com/vaadin-addons
      
    
   

Um nun die grundlegenden Versionsdefinitionen der Vaadin-Plattform zu verwenden, wird die Vaadin 10 BOM (Bill of Materials) importiert.


    
      
      
        com.vaadin
        vaadin-bom
        ${vaadin.version}
        pom
        import
      
    
   

Kommen wir zu den Properties. Um das JDK auch in der Sprachversion 10 verwenden zu können, setzen wir noch die nachfolgenden Konstanten, die für das Maven-Compiler-Plug-in notwendig sind.

    10
    10
    10

Den Zeichensatz setzen wir zudem auf UTF-8.

UTF-8
    UTF-8

Dazu kommen noch die Versionen für die Vaadin-Platform und den verwendeten Servlet-Container.

10.0.9
    1.2.5

Was nun noch fehlt, sind die Abhängigkeiten selbst. An dieser Stelle zunächst einmal die minimal notwendigen, um mit Java eine Vaadin-10-Anwendung zu schreiben.


    
      com.vaadin
      vaadin
    

    
      com.vaadin
      vaadin-lumo-theme
    

Zu guter letzt kommt als Servlet-Container bzw. Ablaufumgebung Apache Meecrowave zum Einsatz. Wer dazu ein wenig mehr lesen möchte, der kann hier auf JAXenter den Artikel Anwendungsbau mit Apache Meecrowave als Startpunkt verwenden.


    
      org.apache.meecrowave
      meecrowave-core
      ${meecrowave.version}
      compile
    

Nun sind die notwendigen Abhängigkeiten definiert und wir können mit der Programmierung beginnen.

Web-App mit Vaadin 10 – der Einstieg

Als erstes erzeugen wir uns eine Klasse mit einer main-Methode, um den initialen Einstiegspunkt zu definieren. In unserem Fall bekommt die Klasse den Namen BasicTestUIRunner. Sie dient lediglich dazu, Meecrowave zu starten und ein paar Parameter zu setzen. In diesem Fall zum Beispiel, das http2 aktiviert wird und der Port 8080 verwendet werden soll.

public class BasicTestUIRunner {
  private BasicTestUIRunner() {
  }

  public static void main(String[] args) {
    new Meecrowave(new Meecrowave.Builder() {
      {
//        randomHttpPort();
        setHttpPort(8080);
        setTomcatScanning(true);
        setTomcatAutoSetup(true);
        setHttp2(true);
      }
    })
        .bake()
        .await();
  }
}

Der grafische Einstiegspunkt

In Vaadin 8 ist es noch notwendig gewesen, ein Servlet zu definieren, das den logischen Einstiegspunkt darstellte. Das hat sich mit Vaadin 10 geändert. Das Servlet ist optional, da eine Implementierung standardmäßig mitgeliefert wird, die in den meisten Fällen mehr als ausreichend ist. Bei dem Start des Servlet-Containers registriert sich das Servlet selbständig und übernimmt die initialen Schritte.

Basierend darauf kann die Definition der ersten grafischen Elemente erfolgen. Hierfür erzeugen wir eine Klasse VaadinApp extends Composite<Div>. Diese soll uns als logischer Einstieg in die App dienen. Anhand der Definition kann man erkennen, dass es sich hier schon um eine Klasse mit Vaadin-spezifischen Elementen handelt. In diesem Fall um ein Composite. Bei einem Composite handelt es sich um einen Wrapper, der die darin enthaltenen grafischen Elemente in der Zielseite enthält, ohne Teil des DOM-Baumes zu sein. Ok, hört sich erst einmal kompliziert an. Allerdings kann man sich das nun so vorstellen, dass hier ein Rahmen für die hinzuzufügenden Elemente geschaffen wird. In diesem Fall handelt es sich um ein Basiselement vom Typ Div. In dieses Div werden wir nun unsere eigenen Elemente hineinlegen.

Die Klasse bekommt noch die Annotation @Route(""). Hiermit wird die Komposition in der Klasse VaadinApp mit der logischen URL / verknüpft. Damit stehen initial alle notwendigen Informationen zum Starten der Vaadin-Anwendung zur Verfügung. Das Servlet wird initialisiert und ein Request auf die Root-Ebene der Anwendung wird mit dem Inhalt der in der Klasse VaadinApp gesetzten grafischen Elemente bedient.

@Route("")
public class VaadinApp extends Composite<Div> {
  public VaadinApp() {
    getContent().add(new LoginView());
  }
}

Und am Anfang steht der Log-in

Der erste Use Case, der in diesem Beispiel implementiert wird, ist der Anmeldeprozess.

Die Funktion ist schnell erklärt: Der Benutzer soll bei dem ersten Besuch auf diese Anmeldeseite weitergeleitet werden. Dort wird die Angabe von Username und Passwort gefordert. Bei Bedarf kann der User noch die Checkbox Remember me aktivieren. Sind die Eingaben getätigt, werden diese durch die Verwendung des Login-Buttons zum Server gesendet, dort verifiziert und (wenn es sich um eine gültige Kombination handelt) den Zugriff auf die restliche Applikation ermöglichen. Der Cancel-Button bricht diesen Vorgang ab. Auf jeden Fall werden die beiden Eingabefelder bei der Verwendung von einem der beiden Buttons geleert.

Aufbau und Aktivierung der LoginView

Die Elemente, die für diesen Use Case benötigt werden, werden in der Klasse mit dem Namen LoginView definiert. Um nun die LoginView zu verwenden, erzeugen wir eine Instanz in der Klasse VaadinApp und fügen diese dann dem Objektbaum hinzu. Mit der Methode getContent() erhält man die Instanz der Komponente, die durch das Composite bereitgestellt wird. Dieser Instanz fügt man dann die gewünschten Elemente hinzu. In unserem Fall die Instanz der LoginView.

Route("")
public class VaadinApp extends Composite<Div> {
  public VaadinApp() {
    getContent().add(new LoginView());
  }
}

Natürlich kann man auch alle Elemente, die wir nun in der Klasse LoginView definieren, gleich der Instanz der Klasse VaadinApp hinzufügen. Allerdings sollte man schon bei Beginn der Implementierung die wesentlichen Blöcke voneinander trennen. Benötigt werden zwei Texteingabe-Felder, wobei eines davon für die Eingabe von Passwörtern verwendet wird. Eine Checkbox für die Remember Me-Funktion und zwei Buttons. Die Anzahl der Elemente ist demnach sehr überschaubar. Allerdings ist im Mock zu sehen, das die Elemente untereinander ausgerichtet sind und sich dabei in der Mitte der zur Verfügung stehenden Fläche innerhalb des Browsers befinden. Alles zusammen ergibt dies schon eine gewisse Komplexität.

Version 01 – die Elemente

Beginnen wir nun, die benötigten Elemente erst einmal zu erzeugen. Um einen Überblick über die verfügbaren Komponenten zu erhalten, kann man sich unter https://vaadin.com/components/browse eine Liste aller verfügbaren Elemente ansehen. Dort sind ebenfalls zu jeder Komponente kleine Beispiele als Demo zusammen mit dem dazugehörigen Quelltexten. Zusammen gibt es einen guten Einstieg.

Wenn man nun einfach alle Elemente in der Klasse LoginView definiert, ergibt sich das nachfolgende Ergebnis:

public class LoginViewOO extends Composite<VerticalLayout> {

  private final TextField     username   = new TextField();
  private final PasswordField password   = new PasswordField();
  private final Checkbox      rememberMe = new Checkbox();
  private final Button        btnLogin   = new Button();
  private final Button        btnCancel  = new Button();

  public LoginViewOO() {
    getContent().add(username, password, rememberMe, btnLogin, btnCancel);
  }
}

Als nächstes gruppieren wir die beiden Eingabefelder und ordnen diese nebeneinander an. Dazu werden einfach beide Eingabefelder in einem HorizontalLayout zusammengefasst.

 public LoginViewOO() {
    HorizontalLayout input = new HorizontalLayout(username, password);
    getContent().add(input, rememberMe, btnLogin, btnCancel);
  }

Ebenso wird mit den beiden Buttons verfahren.

public LoginViewOO() {
    HorizontalLayout input = new HorizontalLayout(username, password);
    getContent().add(input, rememberMe, btnLogin, btnCancel);
  }

Um nun alle Elemente in der Mitte des verfügbaren Fläche zu positionieren, werden alle Elemente in ein gemeinsames Element gruppiert. Auch hier kommt wieder ein VerticalLayout zum Einsatz. Innerhalb dieser Komponente werden alle Elemente horizontal in der Mitte positioniert.

  public LoginViewOO() {
    HorizontalLayout input = new HorizontalLayout(username, password);
    HorizontalLayout buttons = new HorizontalLayout(btnLogin, btnCancel);
    VerticalLayout group = new VerticalLayout(input, rememberMe, buttons);
    group.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);
    getContent().add(group);
  }

Als nächstes werden die Elemente untereinander bündig an der linken Seite ausgerichtet. Dazu wird das VerticalLayout so konfiguriert, dass die enthaltenen Elemente horizontal alle am Beginn der VerticalLayout-Instanz ausgerichtet werden. Das VerticalLayout selbst soll nicht über die gesamte Breite des verfügbaren Platzes gehen. Das wird erreicht, indem die Größe auf undefiniert gesetzt wird. Somit wird die Größe anhand der enthaltenen Elemente berechnet.

Dieser Block soll dann aber horizontal in der Mitte platziert werden. Hierfür wird wieder ein HorizontalLayout verwendet. Die Ausrichtung der Elemente innerhalb des Layouts erfolgt in diesem Layout mittig.

  public LoginViewOO() {
    HorizontalLayout input   = new HorizontalLayout(username, password);
    HorizontalLayout buttons = new HorizontalLayout(btnLogin, btnCancel);
    VerticalLayout   groupV  = new VerticalLayout(input, rememberMe, buttons);
    groupV.setDefaultHorizontalComponentAlignment(Alignment.START);
    groupV.setSizeUndefined();


    HorizontalLayout content = getContent();
    content.setDefaultVerticalComponentAlignment(Alignment.CENTER);
    content.setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER);
    content.setSizeFull();
    content.add(groupV);
  }

Nun muss dieser Block, den wir gerade ausgerichtet haben, wieder vertikal in die Mitte verlegt werden. Es stellt sich die Frage, warum das nicht schon geschehen ist. Um hier eine Antwort zu erhalten lohnt es sich, mittels Chrome einmal einen Blick auf die Seite zu werfen und in dem Zusammenhang die Entwicklertools zu verwenden.

Wie man unschwer erkennen kann, ist das umschließende Div nicht auf die gesamte zur Verfügung stehende Fläche ausgebreitet. Das lässt sich leicht ändern und ist in einer Anwendung oftmals eine solide Grundeinstellung. Hierzu wird in der Klasse VaadinApp die Instanz der Klasse Div aus dem Composite geholt und dessen Größe auf maximal gesetzt.

  public VaadinApp() {
    Div content = getContent();
    content.setSizeFull();
    content.add(new LoginViewOO());
  }

Fertig sind wir mit dem grundsätzlichen Aufbau der Anmelde-Maske. Nun fehlen noch die Feinheiten der einzelnen Elemente und die Funktionen. Eine Kleinigkeit allerdings möchte ich noch der Klasse VaadinApp hinzufügen: @Theme(value = Lumo.class, variant = Lumo.DARK). Hiermit wird das Theme angegeben, in diesem Fall das Standard-Theme, und zusätzlich ein Attribut, das angibt, welche Variante aktiviert werden soll. Und da derzeit dunkle Varianten überall anzutreffen sind, probieren wir es hier ebenfalls aus.

@Route("")
@Theme(value = Lumo.class, variant = Lumo.DARK)
public class VaadinApp extends Composite<Div> implements HasLogger {
  public VaadinApp() {
    Div content = getContent();
    content.setSizeFull();
    content.add(new LoginViewOO());
  }
}

Fazit

Wir haben in diesem Artikel den Grundstein für ein Vaadin-10-Projekt gelegt. Hierbei haben wir in Maven alle notwendigen Abhängigkeiten definiert, als JDK ist das OpenJDK in Version 10 zum Einsatz gekommen. In Apache Meecrowave läuft dann alles zusammen.

In den nächsten Teilen werden wir uns mit weiteren Dingen beschäftigen, wie zum Beispiel Mehrsprachlichkeit, Aufbau von Komplexen UI-Modulen, Einbindung von Kernfunktionen aus den Bereichen Security, TDD und vieles mehr.

Das Beispiel zu diesem Teil ist auf GitHub zu finden. Wer Fragen und Anmerkungen hat, meldet sich am besten per Twitter an @SvenRuppert oder direkt per E-Mail an mich

Happy Coding!

Geschrieben von
Sven Ruppert
Sven Ruppert
Sven Ruppert arbeitet seit 1996 mit Java und ist Developer Advocate bei Vaadin. In seiner Freizeit spricht er auf internationalen und nationalen Konferenzen, schreibt für IT-Magazine und für Tech-Portale. Twitter: @SvenRuppert
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu: