Ich nehme derzeit an einer Akademie zum Java Fullstack Software Engineer teil. In den kommenden Wochen möchte ich hier meine Mitschrift, so gut es geht, aufzeichnen und mitteilen. Hier ist das, was ich vom ersten Tag in Block 8 gelernt und behalten habe:
Swagger

Zwei Ansätze: Code first vs. Contract first
Bei Code First wird der Service Code genutzt um daraus die Beschreibung zu erstellen.
Bei Contract first wird zuerst die wsdl-Datei erstellt und danach wird der Code und der Client erstellt.
*.wsdl (Web Service Despription Language) - alte XML -Description, die besagt, wie man auf den Service zugreifft
Wir benutzen heutzutage JAXRS (Java Restful Services) und damit json, also OpenAPI bzw. Swagger
Wir öffnen das Beispielprojekt kap0104swagger und schauen uns die pom.xml an:

Folgendes benutzen wir für Swagger:
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency><dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
Wir müssen Swagger freischalten, bevor wir es starten können.

Die Konfiguration findet nicht in application.properties statt (obwohl es dort ginge), sondern in einer Konfigurationsklasse:

Das @Bean ist neben der spring.xml und der Annotation an Klassen die dritte Möglichkeit sich in Spring zu registrieren. Es wird das Objekt (nicht die Klasse) des Docket an Spring übergeben.
Das Docket erzeugt den Contract (der definiert wie Server und Client zu programmieren sind). Die Contract-Datei sieht dann nachher so aus (gebaut aus den Annotationen des Codes):

Sobald die App gestartet ist, können wir auf die Doku zugreifen über z.B.: http://localhost:8099/v2/api-docs

Exkurs: Beim Starten gab es (nur bei einigen Kursteilnehmern) das Problem, dass die main Methode in der Startklasse app.java nicht gefunden worden sei (was Schwachsinn ist). Wir fanden den Workaround, dass wir den Inhalt kopierten und in eine app2.java pasteten. Dann funktionierte es. Es ist nicht erklärbar, da der selbe Code bei anderen auf Anhieb funktionierte. IntelliJ ist manchmal etwas buggy.
Der Zugriff auf die UI geht über: http://localhost:8099/swagger-ui.html


Execute:

So sieht der Hello-Controller aus:

Wir öffnen das Kreiservice Projekt von gestern.
Wir fügen in der Pom.xml die Dependencies ein und ändern die Springframework Version auf die 2.5.4

Wir erstellen das Package Configuration und pasten dort die SwaggerConfig Datei:

Jetzt können wir auf Swagger zugreifen:



Beim "Contract-First" Ansatz kopieren wir den Code von den API-Docs:

Und fügen ihn ein in https://editor.swagger.io (oder in den Client, den man von dort herunter laden kann):

Wir können daraus einen Server und einen Client erstellen:

Datenbanken - Web-Rest-JPA
Wir öffnen das BeispielProjekt kap0102-web-rest-jpa. Es wurde wie folgt erstellt:

Dependencies:
Dependecy: <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency><dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency>
</dependencies>
Die Model/Entity Klasse ist eine JPA-Klasse und geht in Richtung Datenbank:

Config/LoadDatabase:

Dem CommandLineRuner übergeben wir Argumente. Wir simmulieren so etwas wie eine Shell und geben die Argumente. Insbesondere das Repository. Save bedeutet: Wenn der Datensatz neu ist: Insert, wenn er vorhanden ist: update.
Das EmployeRepository ist ein Interface, welches von JPA-Interface erbt. Spring baut die Instanz dafür:

Hier die Zusammenhänge zwischen LoadDataBase, dem Employee und dem Interface:

Die List-Objekte "findbyName" und "FindByRole" könnten auch anders heißen. Aber so helfen sie uns ihre Aufgaben direkt abzulesen.
JPARepository erbt von crud-api. Dort findet sich die Methode save.
Wir brauchen die CRUD-Befehle nicht mehr, weil Spring das für uns macht. Wir schreiben nur das das Interface, den Rest macht Spring.
Also in diesem Beispiel erstellt Spring eine Query (select e FROM Employee e where e.role = :role) und liefert das Ergebnis in die Liste findByRole.

Oder wir geben das SQL-Script vor:

Hier das komplette Interface:
public interface EmployeeRepository extends JpaRepository<Employee, Long> { //public Employee findById(Long id); // @Query(value = "SELECT e FROM Employee e where e.role = :role") public List<Employee> findByRole(String role); // -> findByRole -> Properties -> Employee -> setRole(),setRole() public List<Employee> findByName(String name); @Query(value = "SELECT e FROM Employee e") List<Employee> findAllEmployee(); }
Hier der Unterschied zwischen Entity und Repository:

Die Konfiguration der Datenbank wurde bisher in der persistence.xml durchgeführt.
Wir machen das aber hier anders. Wir benutzen die application.properties und übergeben die Parameter als url und console:

Wir starten den Server und gehen mit einem Browser auf localhost:8099/h2-console:


In die JDBC URL kommt der Eintrag aus dem Log: jdbc:h2:mem:acb83f31-e7cb-474f-a02d-b0ae2e68b7c7
Wir kommen dann auf die SQL-Konsole:

Damit der Eintrag in der JDBC URL einfacher wird, wir tragen folgendes in die application.properties:
spring.datasource.url=jdbc:h2:mem:testdb


Wir kommen auch mit dem Befehl curl an die Daten:

Hier die Liste der curl-Befehle für dieses Beispiel:
Spring RESTful services - https://spring.io/guides/tutorials/rest/ - https://github.com/spring-guides/tut-restnetstat -anp tcp
READ:
curl -v localhost:8080/employees
curl -v localhost:8080/employees/1
curl -v localhost:8080/employees/99CREATE:
Unix / Linux:
curl -v -X POST localhost:8080/employees -H 'Content-type:application/json' -d '{"name": "Samwise Gamgee", "role": "gardener"}'
curl -v -X POST localhost:8080/employees -H 'Content-type:application/json' -d '{"id":3,"name":"Samwise Gamgee","role":"gardener"}'
Windows:
curl -X POST localhost:8080/employees -H "Content-type:application/json" -d "{'name': 'Samwise Gamgee', 'role': 'gardener'}"
curl -X POST localhost:8080/employees -H "Content-type:application/json" -d "{"id":3,"name":"Samwise Gamgee","role":"gardener"}"
UPDATE:
curl -X PUT localhost:8080/employees/3 -H 'Content-type:application/json' -d '{"name": "Samwise Gamgee", "role": "ring bearer"}'
curl -X PUT localhost:8080/employees/3 -H "Content-type:application/json" -d "{"name": "Samwise Gamgee", "role": "ring bearer"}"
DELETE:
curl -X DELETE localhost:8080/employees/3
curl localhost:8080/employees/3
Could not find employee 3
Wir laden jetzt Samwise Gamgee hoch:

Transaction Rollback
Wir öffnen das Projekt 0105-jaxrs-jpa-jta
Wenn wir die app starten sehen wir im Browser folgendes:


Wenn eine der beiden addAmount-Methoden eine Exception wirft, wird alles, was in der @Transactional-Methode sendMoney steht zurückgerudert:

Disclaimer
Alles was ich mitschrieb und verstanden habe ist ohne Gewähr. Die Bilder stammen teilweise aus dem Internet und wir haben keine Urheberansprüche darauf.
Besten Dank an unseren sehr empfehlenswerten
Trainer: Hans-Joachim Blanke blanke@4point.de

In den nächsten Tagen und Wochen geht’s weiter, so: stay tuned!
Gruß, Achim Mertens