JHipster ist eine full-stack Entwicklungsplattform, um moderne Webanwendungen zu generieren, zu entwicklen und zu betreiben. Zu Beginn wurde nur AngularJS als Frontend und Spring Boot als Backendtechnologie unterstützt und es wurde via einer CLI bedient. Inzwischen kann eine komplette Anwendungen mit einer domänen spezifischen Sprache definiert und erzeugt werden. Durch das Konzept der Blueprints werden auch weitere Backends wie Micronaut, Quarkus oder NodeJS unterstützt. In diesem Artikel werden wir eine Anwendung auf Basis von Micronaut[6] erzeugen und auf Heroku deployen.

Was ist JHipster?

Ursprünglich war JHipster ein Yeoman [12] Generator um Webanwendungen schnell und einfach erstellen (scaffolding) zu können. Im Laufe der Zeit wurden weitere Funktionen hinzugefügt, sodass JHipster den kompletten Lebenszyklus einer Anwendung von Entwicklung, Testing über Deployment bis Monitoring unterstützt. Mit Version drei hielten Module Einzug, sodass generierte Anwendungen um neue Funktionen erweitert werden konnten. Seit Version fünf wurde das Modulsystem um sogenannte Blueprints erweitert [2]. Ein Blueprint kann nicht nur bestehende Anwendungen über definierte Erweiterungspunkte modifizieren, sondern auch komplette Teile austauschen oder ändern. Beispielsweise tauscht der Kotlin Blueprint den kompletten Javacode durch Kotlin aus. Durch Blueprints ist es nun auch möglich von der bisher festen Wahl von Spring Boot und Angular abzuweichen. In diesem Artikel werden wir daher eine Anwendung mit Micronaut entwickeln [6].

Installation

Um JHipster zu verwenden sollten folgende Tools installiert sein:

  • Java 11 (Java 8 wird weiterhin unterstützt)

  • Node 12

  • Git (optional)

  • Docker & Docker Compose (optional)

Die Installation erfolgt via NPM:

npm install -g generator-jhipster@6.10.1 generator-jhipster-micronaut@0.4.0

Nach der Installation kann die CLI mit dem Befehl jhipster (oder mhipster für Micronaut) ausgeführt werden (Abbildung 1).

mhipter-cli
Abbildung 1. MHipster CLI

JHipster Domain Language

Obwohl alle Funktionen von JHipster durch das Command-Line-Interface bedient werden können ist dies, inbesondere um Entitäten zu erstellen, nicht sonderlich komfortabel. Mit Hilfe der JDL[4] kann die komplette Konfiguration einer Anwendung und aller Entitäten sowie der Deploymentoptionen in einer Datei definiert werden.

JDL definiert für alle Optionen einen Standardwert, sodass es ausreicht die Abweichungen vom Standard explizit zu definieren. Die Konfiguration app.jdl verwendet alle Standardwerte und überschreibt nur den Anwendungsnamen und den Paketnamen. In diesem Fall würde zum Beispiel eine monolithsche Anwendung mit MySQL, JWT Authorisierung und Angular als Frontend erzeugt werden.

app.jdl
application {
  config {
    baseName hike
    packageName com.github.atomfrede.example.hike
  }
}

Beispielanwendung

In Folgenden betrachten wird eine fiktive Anwendung für einen Alpenverein, der eine Software bauen möchte, in der Mitglieder Wanderungen mit einer kurzen Beschreibung, einem Bild und weiteren Informationen hinterlegen können. Um den Zugriff einzuschränken sollen die Benutzer zentral verwaltet werden, daher wird als authenticationType oauth2 verwendet, sodass jeder OpenID Connect kompatibler Authorisierungsserver verwendet werden kann. Als Datenbank wird PostgreSQL verwendet.

app.jdl
application { (1)
  config {
    baseName hike
    applicationType monolith
    authenticationType oauth2
    packageName com.github.atomfrede.example.hike
    prodDatabaseType postgresql
    testFrameworks [protractor]
  }
  entities *
}

(2)
entity HikingLocation {
    name String required
    description String required
}

entity Hike {
    name String required
    date LocalDate required
    description TextBlob required
    photo ImageBlob required
    type Difficulty required
    length Integer required
}

enum Difficulty {
  EASZ,
  MEDIUM,
  HARD,
  ULTRA
}


relationship OneToOne { (3)
  Hike{startLocation(name)} to HikingLocation,
  Hike{destination(name)} to HikingLocation
}

paginate Hike with pagination (4)
paginate HikingLocation with pagination
1 Die Konfiguration der Anwendung überschreibt den Namen, die Authetifizierungsmethode, Datenbank und zusätliche Testframeworks
2 Entitäten mit Validierungsregeln
3 Relationen zwischen Entitäten
4 Paginierung kann für jede Entität separat definiert werden

Eine vollständige Liste aller Optionen und Funktionen der JHipster Domain Language kann online nachgelesen werden [4]. Neben dem Online Tool JDL Studio existieren Plugins für Eclipse und Visual Studio Code, sodass ein komfortables Erstellen und Editieren (Syntaxhervorhebung, Validierung und Vervollständigung) einer JDL möglich ist.

In folgendem werden wir das definierte Model verwenden um eine komplette Webanwendung zu erzeugen.

Anwendung erzeugen

Durch Ausführen des Befehls mhipster import-jdl app.jdl wird der Generierungsprozess angestoßen. Es werden eine Menge Dateien sowohl für das Backend als auch das Frontend erzeugt. Wenn der Prozess erfolgreich beendet wurde kann die Anwendung gestarted werden.

Hierzu muss zuerst der Authentifizierungsserver gestartet werden. JHipster unterstützt Keycloak [8] und Okta [9] out of box, es kann aber jeder OpenId Connect Provider verwendet werden. JHipster stellt für alle benötigten externen Komponenten wie z.B. Datenbanken oder Monitoringsystem passende Docker Compose Skripte [7] für die lokale Entwicklung bereit, sodass durch Eingabe von docker-compose -f src/main/docker/keycloak.yml up -d eine mit Benutzern, Realms und Anwendungen konfigurierte Keycloak Instanz gestartet wird.

Sobald Keycloak hochgefahren ist kann die Anwendung mit Maven (./mvnw) gestartet werden. Die laufende Anwendung ist unter localhost:8080 erreichbar Abbildung 2.

mhipster-start
Abbildung 2. Generierte Anwendung

Die Anwendung läuft im dev Modus. Daher werden die Daten in einer lokalen H2 Datenbank gespeichert, das Frontend ist nicht optimiert und durch Verwendung des Micronaut Maven Plugins wird Hot Reloading des Backends unterstützt. In Kombination mit einem lokalen Webpack Server (npm start) sind Änderungen fast sofort im Browser sicht- und testbar [10].

Ein Klick auf Account > Sign in leitet weiter zu Keycloak. Mit den Zugangsdaten admin/admin ist eine Anmeldung als Administrator möglich.

Unter Administration finden sich verschiedene Verwaltungsoberflächen um Metriken einzusehen, den Healthstatus und Konfigurationsparameter der Anwendung einzusehen und die Log Level zu ändern Abbildung 3.

mhipster-metrics
Abbildung 3. Anwendungsmetriken

Unter Entities können Orte und Wanderungen angelegt werden Abbildung 4. Die vorhandenen Daten werden durch einen speziellen Liquibase Context durch Faker.js erzeugt. Um die Fakedaten nicht zu generieren muss die Konfiguration in src/main/resources/application-dev.yml angepasst werden und der faker Context entfernt werden application-dev.yml.

Da wir Protractor als zusätzliches Testframework konfiguriert haben werden sowohl für die Anwendung (Login, Administration) als auch für jede Entität End-2-End Tests generiert. Durch npm run e2e können diese gestartet werden, die Anwendung sollte dabei natürlich weiterhin laufen.

application-dev.yml
liquibase:
  datasources:
    default:
      async: true
      change-log: classpath:config/liquibase/master.xml
      contexts: dev, faker (1)
1 faker entfernen um keine Demodaten zu erzeugen
mhipster-entities
Abbildung 4. Entitäten

Angular, React oder Vue?

Falls man React bevorzugt kann dies durch hinzufügen der Option clientFramework react erreichen app.jdl.

app.jdl
application {
  config {
    baseName hike
    applicationType monolith
    authenticationType oauth2
    clientFramework react
    packageName com.github.atomfrede.example.hike
    prodDatabaseType postgresql
    testFrameworks [protractor]
  }
  entities *
}

Die Verwendung von Vue.js ist momenta noch komplizierter, da Vue.js ebenfalls ein Blueprint ist und die Kompatibilität nicht notwendigerweise gegeben ist. Daher wird Vue.js mit JHipster 7 in den Hauptgenerator integriert. Wenn man dennoch Micronaut und Vue.js kombinieren möchte kann das auch schon heute tun. Zuerst muss der Vue.js Blueprint durch npm install -g generator-jhipster-vuejs installiert werden. Die JDL muss dann unter Angabe aller Blueprints mit der jhipster CLI importiert werden [lst-multiple-blueprints].

jhipster import-jdl app.jdl --blueprints micronaut,vuejs

Auf geht’s in die Cloud

Bisher wurde die Anwendung im dev Profil ausgeführt, welches für die Entwicklung optimiert ist. Eine Anwendung im dev Profil zu deployen ist allerdings keine gute Idee, da z.B. das Logging sehr ausführlich ist und Javascript Resourcen nicht optimiert sind. Dadurch sind die Ladezeiten für die Benutzer unnötig hoch. Entsprechend sieht auch der Lighthouse Abbildung 5 Report schlecht aus. Es werden insgesamt knapp 3,3 MB Javascript ausgeliefert.

mhipster-dev-lighthouse
Abbildung 5. Lighthouse Report (dev Profil)

Um die Anwendung für Produktion zu bauen muss der Build mit dem entsprechenden Profil gestartet werden:

./mvwn verify -Pprod

JHipster unterstützt verschiedene Cloud Provider (Azure, GCP). In diesem Beispiel verwenden wir Heroku [11], um unsere Anwendung in der Cloud zu betreiben. Heroku ist eine Platform as a service, sodass das Verwalten der eigentlichen Infrastruktur nahezu nicht nötig ist. Dadurch ist die Verwendung sehr einfach.

JHipster provisioniert alle benötigten Addons in Abhängigkeit der gewählten Konfiguration. Es werden nur kostenfreie Optionen gewählt und die sog. Free Dynos verwendet. Hierdurch ist die Performance eingeschränkt, kann aber sehr schnell seine Anwendung in die Cloud bringen, um diese z.B. testen zu können.

Um den Heroku Subgenerator verwenden zu können muss zunächst die Heroku CLI installiert und konfiguriert sein. Obwohl JHipster keine kostenpflichtigen Addons provisioniert, muss der verwendete Heroku Account durch das hinzufügen einer Kreditkarte zunächst verifiziert werden. Sind alle Vorbereitungen abgeschlossen kann durch den Befehl mhipster heroku die Konfiguration gestartet werden. Der Generator erfordert die Eingabe von weiteren Parametern:

  1. Name to deploy as

    Name der Anwendung. Kann in der Regel auf dem Standardwert belassen werden.

  2. On which region do you want to deploy ?

    Hier sollte eu ausgewählt werden.

  3. Which type of deployment do you want ?

    Während das Deployment via Git in der Regel schneller ist muss dafür der Source Code auf einen Heroku Server geladen werden. Das ist nicht in jedem Fall möglich, daher kann auch nur das fertige JAR hochgeladen werden. Wir verwenden Git.

  4. Which Java version would you like to use to build and run your app ?

    Falls es keinen Grund gibt eine andere Version zu verwenden kann hier der Standardwert (11) verwendet werden.

  5. You are using OAuth 2.0. Do you want to use Okta as your identity provider it yourself?

    Da wir uns nicht um den Betrieb eines separaten Keycloak Servers kümmern möchten wählen, wir hier die Option Okta (Yes, provision the Okta add-on) automatisch zu konfigurieren.

  6. Login (valid email) for the JHipster Admin user

    Dies ist der Login für den Administrator und muss eine valide E-Mail-Adresse sein. Zum Beispiel max@jhipster.tech

  7. Initial password for the JHipster Admin user

    Das initiale (!) Password für den Administrator. Es muss den Richtlinien von Okta genügen und nach dem ersten Login geändert werden.

Die Abfrage, ob die pom.xml überschrieben werden soll, kann mit ja beantwortet werden. Der Build- und Deploymentprozess kann einige Zeit dauern. Sobald der erfolgreich abgeschlossen wurde kann die Anwendung durch den Befehl heroku open im Browser geöffnet werden. Man kann sich nun mit den zuvor vergebenen Zugangsdaten anmelden und wird aufgefordert ein neues Password zu vergeben und eine Sicherheitsfrage auszuwählen. Danach sollte man wieder auf die Startseite der JHipster Anwendung geleitet werden Abbildung 6. Durch die Optimierung des Frontends sind die Ergebnisse des Lighthouse Reports sehr gut Abbildung 7. Es werden nur noch knapp 280 kB Javascript übertragen, wobei der größte Teil davon durch Angular verbraucht wird. JHipster legt Wert auf gute und sichere Standardkonfiguration, sodass auch ein Test auf übliche Security Header in der Bestnote A Abbildung 8 resultiert.

mhipster-heroku-login
Abbildung 6. Nach der Anmeldung mit Okta
mhipster-lighthouse
Abbildung 7. Lighthouse Report
mhipster-securityheaders
Abbildung 8. Security Headers

Ausblick auf JHipster 7

Das mit Version 5 eingeführte Konzept von Blueprints wurde mit der aktuellen Version 6 weiter verfeinert und führte zu einem regen Interesse von weiteren Communities und Firmen. Inzwischen gibt es neben Micronaut Implementierungen für Quarkus, NodeJS und .Net. Es werden noch nicht alle Optionen des Hauptgenerators unterstützt aber die meist benutzten Optionen werden von allen Blueprints unterstützt.

Mit der kommenden Version 7 hält Vue.js Einzug in den Hauptgenerator, sodass hier die Integration und Kompatibilität zu unterschiedlichen Optionen besser gewährleistet werden kann. Um es den Benutzern einfacher zu ermöglichen das Design des Frontends zu verändern werden mindestens die Administrationsoberflächen in ein separates Projekt ausgelagert und nicht mehr Teil des generierten Codes sein. Das sog. JHipster Control Center funktioniert dabei ähnlich wie der Spring Boot Admin [13], wird aber z.B. auch mit Quarkus oder Micronautanwendungen funktionieren. Protractor als End-2-End Testingframework wird durch das modernere Cypress ersetzt. Cypress Tests sind einfacher zu warten und Cypress arbeitet besser mit Vue.js und React zusammen.

Seit Sommer 2020 ist das Prettier Plugin for Java [14] im Beta Status und im Einsatz. JHipster 7 wird dann auch Java Code mit Prettier formatieren, sodass keine unterschiedlichen Tools für Frontend- und Backendcode mehr benötigt werden.

Fazit

Mit Hilfe von JHipster konnte das Grundgerüst einer produktionsreifen Webanwendung aufgesetzt werden. Die Datenstruktur und die Bedienung der Anwendung konnten mit der erzeugten Oberfläche direkt getestet werden. Der sichere Betrieb der Anwendung ist durch sinnvolle Standardkonfigurationen sichergestellt. Der Workflow mit Maven/Gradle und Webpack ermöglicht es schnell neue Funktionen zu entwicklen und in Produktion zu bringen.

Natürlich ist die erzeugte UI nicht ausreichend um von Endnutzern gerne verwendet zu werden. Um weiterhin JHipster aktualisieren zu können sollte der generierte Code nach Möglichkeit nicht verändert werden. Hier bietet sich die Verwendung des sog. Side-by-Side Ansatzes [15] [16] an. Dadurch kann der generierte Code um Funktionen erweitert werden, ohne dass generierte Code verändert werden muss.

Über den Autor

author Frederik Hahne arbeitet als Software Entwickler bei der WPS Management GmbH in Paderborn an der offenen B2B Integrationsplattform wescale (wescale.com). Er ist Organisator der JUG Paderborn und hat in Paderborn die lokale Devoxx4Kids Gruppe ins Leben gerufen. Seit 2015 ist er Mitglied des Java Hipster Core Teams und hat hier neben dem Gradle Support in letzter Zeit vorallem am Neo4j, Micronaut und Heroku Support gearbeitet. Er twittert unter @atomfrede und Blogged gelegentlich auf https://atomfrede.gitlab.io/.

Quellen