TWRestMindmap mit React, Patternfly, RESTEasy, Swagger-UI, Quarkus, Panache, ORM, JPA, Hibernate, Docker und PostgreSQL DB verwenden. Um nicht JUnit 5 zu vergessen.
Wir bauen nun mit Quarkus eine React Anwendung die Titel und das Datum von Mindmaps anzeigt und per REST bedient werden kann. Die GUI im Browser sieht dann so aus:
Aufteilung in einem Projekt nach Frontend und Backend. Das Backend läuft ua. in einem Docker mit einer PostreSQL Datenbank. Das Backend wird mit Maven und Java zusammengebaut und das Frontend verwendet NPM und Node.js bzw. JavaScript.
Das ganze Projekt kann von GitLab heruntergeladen werden. Hier beschreibe ich einige wichtige Dinge zu den verwendeten Technologien angefangen beim Backend bis zum Frontend.
Automatischer JUnit-Test
Fangen wir an mit JUnit Test, also TDD. Das geht mit Quarkus ganz gut, es werden automatisch beim speichern alle JUnit-Tests ausgeführt und im Browser das Ergebnis mit Log anzgezeigt. Das alles läuft, wenn das Projekt im mvn quakus:dev Modus läuft, hier z.B. die Ansicht der GUI, die im Browser über diese URL aufgerufen werden kann:
http://localhost:8080/q/dev/io.quarkus.quarkus-vertx-http/tests
Folgende Einträge sind in der pom.xml für das Testen mind. nötig:
1 2 3 4 5 6 7 8 9 10 |
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-junit5</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <scope>test</scope> </dependency> |
Ok, alles GRÜN.
Datenbank in Docker Container
Dann ein paar Worte zur verwendeten Datenbank. In diesem Beispiel verwenden wir in einem Docker Container eine PostgreSQL DB. Wir brauchen dazu nur diese beiden Einträge in der /src/main/resources/application.properties Datei:
1 2 |
quarkus.datasource.db-kind=postgresql quarkus.hibernate-orm.database.generation=drop-and-create |
In einer /src/main/resources/import.sql Datei, wird die Erstladung der DB eingetragen, wir nehmen mal vier Mindmaps:
1 2 3 4 |
INSERT INTO mindmap(id, name, erstellung) VALUES (nextval('hibernate_sequence'), 'Reverse Proxy', '2021-11-08T20:48:09.999796'); INSERT INTO mindmap(id, name, erstellung) VALUES (nextval('hibernate_sequence'), '2. Mindmap', '2021-10-08T20:48:09.999796'); INSERT INTO mindmap(id, name, erstellung) VALUES (nextval('hibernate_sequence'), '6 Best Point to Protecting your Crypto', '2021-01-08T20:48:09.999796'); INSERT INTO mindmap(id, name, erstellung) VALUES (nextval('hibernate_sequence'), 'Letzte 4. Mindmap Beschreibung Titel', '2020-08-08T |
Und da wir auch Hibernate mit Panache verwenden brauchen wir für jedes BE eine @Entity Annotation und die Klasse muss von PanacheEntity erben. Die Mindmap.java Klasse:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package de.wenzlaff.mindmap.be; import java.time.LocalDateTime; import javax.persistence.Cacheable; import javax.persistence.Column; import javax.persistence.Entity; import io.quarkus.hibernate.reactive.panache.PanacheEntity; /** * BE einer Mindmap * * @author Thomas Wenzlaff */ @Entity @Cacheable public class Mindmap extends PanacheEntity { @Column(length = 120, unique = true) public String name; /** * Zeitpunkt der Erstellung der Mindmap. */ @Column() public LocalDateTime erstellung; } |
In der pom.xml muss noch
1 2 3 4 |
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-hibernate-reactive-panache</artifactId> </dependency> |
ergänzt werden. Das ist schon alles, um eine DB in einem Docker-Container laufen zu lassen.
REST und Swagger
Da wir auch einen REST-Service anbieten wollen, auf den das Frontend zugreifft, erstellen wir eine MindmapResource.java Klasse mit @Path(„/mindmaps“) und
@ApplicationScoped Annotationen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
package de.wenzlaff.mindmap; import java.net.URI; import java.time.LocalDateTime; import java.util.List; import javax.enterprise.context.ApplicationScoped; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.core.Response; import org.jboss.logging.Logger; import de.wenzlaff.mindmap.be.Mindmap; import io.quarkus.hibernate.reactive.panache.Panache; import io.quarkus.panache.common.Sort; import io.smallrye.mutiny.Uni; /** * http://localhost:8080/q/swagger-ui/ * * @author Thomas Wenzlaff */ @Path("/mindmaps") @ApplicationScoped public class MindmapResource { private static final Logger LOG = Logger.getLogger(MindmapResource.class); @GET public Uni<List<Mindmap>> get() { return Mindmap.listAll(Sort.by("name")); } /** * Liefert die Anzahl der Mindmaps. * * @return Anzahl der Mindmaps. */ @Path("/anzahl") @GET public Uni<Long> count() { return Mindmap.count(); } @GET @Path("/{id}") public Uni<Mindmap> getSingle(Long id) { return Mindmap.findById(id); } @POST public Uni<Response> create(Mindmap mindmap) { LOG.info("Erzeuge Mindmap"); mindmap.erstellung = LocalDateTime.now(); return Panache.<Mindmap>withTransaction(mindmap::persist).onItem().transform(inserted -> Response.created(URI.create("/mindmaps/" + inserted.id)).build()); } } |
Der REST-Service ist dann über eine Swagger-UI mit dieser URL http://localhost:8080/q/swagger-ui/ aufrufbar:
Und hier mal ein Service ausgeführt, es werden die vier Mindmaps sortiert nach Namen mit Mindmap.listAll(Sort.by(„name“)); als Json geliefert:
Auch gibt es einige Infos über RESTEasy über die URL http://localhost:8080/q/dev/io.quarkus.quarkus-resteasy-reactive/scores z.B.
OpenApi
Die OpenApi kann auch über die Swagger-UI abgefragt werden:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
--- openapi: 3.0.3 info: title: de.wenzlaff.twrestmindmap API version: 1.0.0-SNAPSHOT paths: /info: get: tags: - Version Resource responses: "200": description: OK content: text/plain: schema: type: string /mindmaps: get: tags: - Mindmap Resource responses: "200": description: OK content: application/json: schema: type: array items: $ref: '#/components/schemas/Mindmap' post: tags: - Mindmap Resource requestBody: content: application/json: schema: $ref: '#/components/schemas/Mindmap' responses: "200": description: OK content: application/json: {} /mindmaps/anzahl: get: tags: - Mindmap Resource responses: "200": description: OK content: application/json: schema: format: int64 type: integer /mindmaps/{id}: get: tags: - Mindmap Resource parameters: - name: id in: path required: true schema: format: int64 type: integer responses: "200": description: OK content: application/json: schema: $ref: '#/components/schemas/Mindmap' components: schemas: Mindmap: type: object properties: id: format: int64 type: integer name: type: string erstellung: format: date-time type: string |
Start Backend
Nachdem der Docker Desktop gestartet wurde kann die pom.xml aus dem TWRestMindmap Verzeichnis mit mvn quarkus:dev gestartet werden. Dann kann das Backend schon über die Swagger-Ui oder auch über ein einfaches curl abgefragt werden. Z.B. curl ‚http://localhost:8080/mindmaps‘ | jq liefert:
Oder auch nur den Namen der 1.Mindmap mit
curl ‚http://localhost:8080/mindmaps‘ | jq ‚.[1].name
Struktur Frontend und Backend
Das Frontend ist in dem Verzeichnis src/main/webapp in dem TWRestMindmap Projekt zu finden:
React Frontend
Die React Componente ist in der mindmaps.js Datei zu finden:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import React from 'react' const Mindmaps = ({ mindmaps }) => { return ( <div> <center><h1>Mindmaps</h1></center> <table class="pf-c-table pf-m-grid-md" role="grid" id="table-basic"> <caption>{mindmaps.length} von kleinhirn.eu</caption> <thead> <tr role="row"> <th role="columnheader" scope="col">Erstellung</th> <th role="columnheader" scope="col">Titel</th> </tr> </thead> {mindmaps.map((mindmap) => ( <tbody role="rowgroup"> <tr role="row"> <td role="cell" data-label="">{mindmap.erstellung}</td> <td role="cell" data-label="">{mindmap.name}</td> </tr> </tbody> ))} </table> </div> ) }; export default Mindmaps |
und die ganze Application in der App.js Datei:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import React, {Component} from 'react'; import Mindmaps from './components/mindmaps' class App extends Component { state = { mindmaps: [] } componentDidMount() { fetch('/mindmaps') .then(res => res.json()) .then((data) => { this.setState({ mindmaps: data }) }) .catch(console.log) } render () { return ( <Mindmaps mindmaps={this.state.mindmaps} /> ); } } export default App; |
Starten des React Frontend
In einer neue Konsole in dem /TWRestMindmap/src/main/webapp Verzeichnis die React Gui starten mit: npm start und schon öffnet sich im Browser die http://localhost:3000/ wo die Gui läuft und alle Mindmaps wie ganz oben angezeigt wird.
Evl. ist ein einmaliges installieren der React und Patternfly Abhängigkeiten nötig:
1 2 3 |
# im /TWRestMindmap/src/main/webapp einmal die beiden Befehler ausführen: npx create-react-app . npm install @patternfly/patternfly --save |
Am schnellsten einfach das ganze Projekt mit einem
git clone https://gitlab.com/IT-Berater/twrestmindmap.git
holen und die oben genannten Schritte nachverfolgen. Fehlt was? … Gern Merge Repuest https://gitlab.com/IT-Berater/twrestmindmap/-/merge_requests oder EMail …