Spring Boot + DATA JPA + HATEOAS

Spring Boot bietet die Möglichkeit auf sehr einfachem Wege standalone Anwendungen zu schreiben, die keinerlei Applicationserver als Laufzeitumgebung benötigen. Als Erweiterungen existieren eine ganze Reihe von Möglichkeiten, darunter die Einbindung von JPA und Rest (unter Anwendung von HATEOAS). Dieser Beitrag fast das Projekt-Setup kurz zusammen und stellt die technischen Möglichkeiten vor Rest-Schnittstellen mittels Spring Data auf einfachem Wege bereitzustellen.

Aller Anfang ist leicht. Die Entwickler von Spring unterstützen neue Projekte in der Initialisierung neuer Projekte über ein Webangebot über das Basis-Projekte mit den gewünschten Features generiert werden können: https://start.spring.io/ .

Das pom.xml eines so erstellten Projektes könnte wie folgt aussehen:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.M3</version>
        <relativePath/>
    </parent>

    <dependencies>
        <!--JPA Support-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--Support für die Veröffentlichung unserer Repositories als REST-Schnittstelle-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <!--Laufzeitumgebung-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jersey</artifactId>
        </dependency>
        <!--Testing-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--Basis-Support für Webanwendungen-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--integrierte Datenbank-->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>@RepositoryRestResource
            <scope>runtime</scope>
        </dependency>
    </dependencies>

Gestartet wird das Projekt über eine klassische Main-Methode und beinhaltet neben unserer Anwendung auch einen entsprechenden WebServer und Datenbank. Die Konfiguration für diese Komponenten erfolgt in einer einzelnen Properties Datei (src/main/resources/application.properties) in der wir zum Beispiel wie im folgenden zu sehen die (standardmäßige) In-Memory H2 Datenbank auf eine File-basierte umstellen und JPA anweisen die benötigten Tabellen zu generieren.

application.properties

spring.jpa.hibernate.ddl-auto = create
spring.jpa.generate-ddl = true
spring.datasource.url=jdbc:h2:file:~/spring;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=test
spring.datasource.password=test
spring.datasource.driverClassName=org.h2.Driver

Start, per main(…)

Der Start übernimmt wie angesprochen eine simple main-Methode, die lediglich Spring dazu veranlasst die benötigten Container zu initialisieren. Darüber hinaus scannt dieser Prozess alle unterliegenden Packages nach Spring Komponenten und registriert z.B. unsere Rest-Resources und aktualisiert auf Basis unserer JPA-Entitäten die Datenbank.

SpringDemoApplication.java

@SpringBootApplication
public class SpringbootDemoApplication {

  public static void main(String[] args) {
    SpringApplication.run(SpringbootDemoApplication.class, args);
  }
}

Rest, ganz einfach

Spring bietet uns die Möglichkeit in vielen Situationen auf das implementieren einer separaten Rest-Resource-Klasse zu verzichten. Dank der Annotation „@RepositoryRestResource“ ist Spring in der Lage auf Basis seines CRUD-Basis Repositories alle Operationen direkt als Rest-Resource zur Verfügung zu stellen. Um dies zu realisieren reicht es ein entsprechendes Interface bereit zu stellen und das generische CrudRepository zu erweitern:

MessageRepository

@RepositoryRestResource(path = "msg", collectionResourceRel = "msg")
public interface MessageRepository extends CrudRepository<Message, Integer> {

}

Request: http://localhost:8080/msg

{
    "_embedded": {
        "msg": [
            {
                "date": "1970-01-01T00:00:00.000+0000",
                "message": "Hello World",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/msg/1"
                    },
                    "message": {
                        "href": "http://localhost:8080/msg/1"
                    },
                    "user": {
                        "href": "http://localhost:8080/msg/1/user"
                    }
                }
            }]
    }
}

Dank unseres Projekt-Setups verwendet Spring per default ein HAL-Format um unsere Entität aus zu liefern (s. Blog Beitrag HATEOAS + HAL). Damit entfällt das lästige manuelle Handling Umwandeln von Referenzen auf andere Entitäten. Stattdessen fügt Spring entsprechende Links in die Response eins, über dessen URL der Client die referenzierten Daten bei Bedarf abholen kann.

Vom Suchen und Finden

Neben den einfachen Get-Anfragen die automatisch für uns generriert werden bietet Spring auch eine halbautomische Erzeugung von Query-Methoden an. So erübrigt sich das manuelle Schreiben von Methoden die lediglich simple Queries an die Datenbank übermitteln wenn wir uns auf die reine Definition solcher zusätzlichen Methoden im Resource-Interface stützen. Dies geschieht wahlweise durch eine Namens-Konvention oder durch die explizite Angabe einer JPQL-Query über Annotationen

  @RestResource(path = "searchMessage", rel = "searchMessage")
  List<Message> findByMessageIgnoreCaseContaining(@Param("msg") String message);
}

ermöglicht GET-Anfragen ala:

http://localhost:8080/msg/search/searchMessage?msg=Blank

Post it

Die automatische Erzeugung von Rest-Schnittstellen beschränkt sich dabei aber nicht nur auf GET-Anfragen. Auch das Speicher und Löschen von Objekten wird unterstützt. Sehr charmant dabei ist die erneute Verwendung von HAL um Referenzen zwischen unseren Entitäten vom Client aus fest zu legen.

Post Request

{
    "user": "http://localhost:8080/usr/2",
    "message": "Hello Blank",
    "date": 0
}

Dies führt nicht nur zu einer simplen Speicherung unseres Objektes sondern Spring fügt ganz automatisch, auf Basis der User-URL, die benötigte JPA-Referenz hinzu.

JAX-RS bietet uns eine sehr einfache, standatisierte Möglichkeit Rest-Schnittstellen bereit zu stellen. Dabei existieren jedoch sehr viel sich wiederholende Implemetierungen, welche die Entwicklungszeit erhöhen. Hier liefert Spring ( /Spring Data) eine extrem mächtige Möglichkeit unnötigen Ballast bei CRUD-Operationen aus der Anwendung fern zu halten.

Live? In Farbe? Auf Github !

Advertisements

Über Dominik Mathmann
Dominik Mathmann arbeitet als Berater, Entwickler und Trainer bei der GEDOPLAN GmbH. Auf Basis seiner langjährigen Erfahrung in der Implementierung von Java-EE-Anwendungen leitet er Seminare, hält Vorträge und unterstützt Kunden bei der Konzeption und Realisierung von Webanwendungen vom Backend bis zum Frontend. Sein derzeitiger Schwerpunkt liegt dabei auf der Entwicklung von JSF-Anwendungen. Er sieht die stärker werdende Position von JavaScript-Frameworks jedoch positiv und beschäftigt sich darüber hinaus mit Webframeworks wie AngularJS.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: