Spring mit RESTful Webservice (Tutortial)

Die REST-API des Webservice der Fahrerverwaltung

Dieser Beitrag ist Teil einer (Tutorial-) Serie über die Einführung in das Spring Framework und beschreibt die Erstellung eines RESTful Webservices mit dem Spring Framework MVC.

Die Struktur des Projektes

Dieses Beispiel baut auf dem vorherigen Beispiel Spring mit einer Webanwendung mit JPA und Validierung in der Version 2.x auf. Die verwendeten Frameworks und Werkzeuge sind hier beschrieben. In diesem Beispiel werden die folgenden Technologien des Spring Frameworks vorgestellt:

  • Das Definieren eines XML-Schemas mit JAXB.
  • Das Serialisieren von Entitäten durch JAXB nach XML und JSON.
  • Das Erstellen eines RESTful Webservices.
  • Das Testen eines RESTful Webservices mit dem Kommando curl.

In der folgenden Bildergalerie sind die benötigten Bibliotheken für jedes Eclipse Projekt dargestellt.

Die Literaturempfehlungen für dieses Beispiel

Die Erweiterungen des Projektes test-spring-jpa

An diesem Projekt müssen wir nur eine leichte Veränderungen an den Entitäten vornehmen, damit sie später in andere Repräsentationen (z. B. XML oder JSON) konvertiert bzw. serialisiert werden können.

  • In Zeile 35 wird die Entität des Fahrers als ein Wurzelelement für eine XML-Repräsentation gekennzeichnet.

  • Von folgender Erweiterung in Zeile 55 wurde abgesehen. Die XML-Form eines Fahrers dient hauptsächlich zur Übertragung von Daten, da ist es manchmal nötig auch unvollständige Konstrukte, z. B. für eine Suche, übertragen zu können. Nebenbei können sich solche Details ändern und dann müssen alle externe Partner entsprechend unterrichtet werden.

  • In Zeile 18 wird die Entität des Autos als ein Wurzelelement für eine XML-Repräsentation gekennzeichnet.

Die Definition des XML-Schemas erfolgt am Package durch eine package-info.java.

Als nächstes wird der Service der Fahrerverwaltung um das Löschen des Fahrers erweitert.

Die Fahrerverwaltung als RESTful Webservice

Aufbauend auf der existierenden Fahrerverwaltung werden zwei REST-Schnittstellen (URI mit HTTP-Methode) mit Operationen auf einen bestimmten Fahrer und auf alle Fahrer definiert.

Weitere Informationen siehe im Beitrag RESTful Webservices.

Schnittstelle zu einem bestimmten Fahrer
URI /drivers/{Id des Fahrers}
POST
GET Liefere den Fahrer mit der angegebenen Id.
PUT Aktualisiere den Fahrer mit der angegebenen Id.
Falls der Fahrer nicht existiert, wird er unter der angegeben Id angelegt.
DELETE Lösche den Fahrer mit der angegebenen Id.
HEAD
Schnittstelle zur Fahrerverwaltung
URI /drivers
POST Erzeuge einen neuen Fahrer und liefere die Id des Fahrers im HTTP-Attribut Location zurück.
GET Liste alle Fahrer der Fahrerverwaltung auf.
PUT
DELETE
HEAD Liefere die Header-Informationen eines GET.

Die Erweiterungen des Projektes test-spring-web

Hier muss das Mapping für das Servlet geändert werden.

  • In Zeile 40 wird das konkrete Mapping von /drivers/edit auf /drivers/* geändert.

Die REST-Schnittstelle zum Fahrer

Für die REST-Schnittstelle des Fahrers wird ein neuer Controller erzeugt.

  • In Zeile 24 wird die URI der Schnittstelle definiert (Siehe auch den Beitrag Ressourcen und ihre Repraesentationen). Damit wird aus der URI http://localhost:8080/test-spring-web/drivers/0 die Id des Fahrers mit 0 extrahiert und durch die Definition ( @PathVariable) in Zeile 37 im Parameter id der Methode übergeben.
  • In Zeile 37 wird definiert, für welche HTTP-Methode diese Methode zuständig ist.
  • In Zeile 38 wird angegeben, dass das Ergebnis dieser Methode der Fahrer in den Body der HTTP-Response zu mappen ist. Dabei wird die Content Negotiation berücksichtigt.

Die Implementierung kann direkt mit dem Kommando curl getestet werden.

Die folgenden Parameter kann das Kommando verarbeiten:

  • -X <Methode>
    Mit diesem Parameter wird die HTTP Methode ( GET, HEAD, PUT, DELETE, POST, etc.) festgelegt.
  • -i
    Zeigt die komplette HTTP Response mit allen Attributen an.
  • -I
    Zeigt nur die Informationen über das empfangende Dokument an.
  • -H <Attribut>
    Mit dieser Option wird ein HTTP-Header-Attribut definiert, falls mehrere Attribute benötigt werden, muss dieser Parameter für jedes Attribut angegeben werden.
  • -d <Daten> oder -d <Name>=<Value> oder -d @<Dateiname>
    Die Daten des HTTP Request oder ein Parameter mit Wert. Falls der Parameter -X nicht angegeben ist, wird die Methode POST mit den MIME-Typ application/x-www-form-urlencoded verwendet. Startet das Argument mit einem @, so wird eine Datei mit den Daten erwartet.

Nun wird mit dem folgendem Kommando der erste Test des Webservices durchgeführt. Dazu wird mit der HTTP-Methode GET und der URL http://localhost:8080/test-spring-web/drivers/0 der Webservice für die Abfrage eines Fahrers durchgeführt. Dieser liefert den HTTP-Statuscode 200 OK mit dem Fahrer im XML-Format zurück.

Im folgendem Kommando wird das HTTP-Header-Attribut Accept auf den MIME-Type application/json gesetzt. In diesem Fall wird der Fahrer im JSON-Format geliefert. Dazu muss aber die Jackson Bibliothek ( org.codehaus) im Klassenpfad sein.

Das nächste Kommando fragt den Fahrer mit dem MIME-Typ eines Bildes ab. Dieses kann der Webservice natürlich nicht liefern, daher sendet er den HTTP-Statuscode 406 Not Acceptable und im Inhalt eine entsprechende Fehlermeldung des Applicationservers in HTML-Format zurück.

Das nächste Kommando fragt einen nicht-existierenden Fahrer ab.

Huch! Dieser Aufruf liefert den HTTP-Statuscode 200 OK statt den erwartete HTTP-Statuscode 404 Not Found zurück. Warum! Ein Hinweis liefert das HTTP-Attribut Content-Length: 0. Der Service der Fahrerverwaltung liefert null zurück, wenn kein Fahrer gefunden wird und genau das hat der Webservice zurückgeliefert.

Um einen richtigen HTTP-Statuscode 404 Not Found zurückzuliefern, wird der Controller entsprechend geändert. Dazu wird die Klasse ResponseEntity verwendet. Dieser Klasse kann ein HTTP-Statuscode und ggf. HTTP-Attribute mitgegeben werden.

Nun wird die Abfrage auf einen nicht-existierenden Fahrer wiederholt.

Die nächste Methode PUT /drivers/0 HTTP/1.1 modifizeirt den Fahrer mit der Id 0 oder legt einen neuen Fahrer mit der angegebenen Id an. D. H. nach Ausführung der Methode existiert unter der angebenen URI ein Fahrer mit dem angebenen Inhalt.

  • In Zeile 65 wird geprüft, ob die angebene URI mit der Id des Fahrers übereinstimmt. Im Fehlerfall wird ein HTTP-Statuscode 409 Conflict ausgelöst.
  • In Zeile 73 wird geprüft, ob ein neuer Fahrer erzeugt oder ein existierender Fahrer geändert werden soll. Im Falle des Erzeugens eines Fahrers wird ein HTTP-Statuscode 201 Created zurückgegeben. Falls der Fahrer geändert wurde, wird der HTTP-Statuscode 200 OK und dem geänderten Fahrer im Inhalt zurückgeliefert. Es hätte auch der HTTP-Statuscode 204 No Content ohne den geänderten Fahrer im Inhalt verwendet werden können.

Mit dem ersten Kommando wird der Vorname des Fahrers mit der Id 0 geändert und der geänderte Fahrer wird im Context zurückgeliefert. Mit dem zweiten Kommando wird der geänderten Fahrer nochmals gelesen.

In diesem Kommando wird ein Konflikt erzeugt, in dem die Id des Fahrers nicht mit der URI übereinstimmt.

Mit dem folgendem Kommando wird ein neuer Fahrer mit der Id 4711 angelegt.

Leider hat die letzte Funktion ein Problem: Es wurde der Fahrer an der Datenbanksequenz rahn.DriverSEQ vorbei erzeugt. Dieses führt irgendwann natürlich zu einem Problem, da die Id 4711 dann nochmals vergeben wird.

Der letzte Service auf einen Fahrer ist das Löschen eines Fahrers. Dazu wird der Controller um eine Methode zum Löschen erweitert.

Im folgenden Kommando wird der Fahrer mit der Id 0 zweimal gelöscht. Das doppelte Löschen führt nicht zu einem Fehler, da DELETE idemtopent ist. D. H. sie muss beliebig oft ausgeführt werden können, ohne das sie auf einen Fehler läuft.

REST-Schnittstelle zur Fahrerverwaltung

Für die Erweiterung der Schnittstelle der Fahrerverwaltung muss am Controller einige Änderungen vorgenommen werden.

  • In Zeile 70 muss die existierende Methode für die Zuständigkeit der Aufrufe aus einem Browser markiert werden. Dieses geschied durch die Angabe des Ausgabeformats text/html.
  • Ab Zeile 83 wird die neue Methode des Webservices für das Abfragen aller Fahrere aufgeführt. Dieser kann nur den Inhalt Content-Type: application/json liefern, dafür aber auch die HTTP-Methode HEAD bedienen.

In diesem Kommando wird die normale Webseite, wie sie im Browser dargestellt wird abgerufen. Darum wird auch das Cookie in Zeile 4 gesetzt.

Dieses Kommando ruft den Webservice auf und bekommt die Liste der Fahrer zurück.

Im folgenden Kommando wird nur die Kopfzeile der Response für das JSON-Format abgeholt.

Zum Abschluß fehlt noch die POST-Methode des Webservices.

  • In Zeile 113 wird für die alte Methode der Content-Type für die Aufrufe aus dem Browser gesetzt.
  • Ab Zeile 141 wird die Methode für die Webservice-Aufrufe dargestellt.
  • Ab Zeile 156 wird die URI des neuen Fahrers bestimmt und durch das HTTP-Attribute Location zurückgeliefert.

Mit folgendem Kommando wird ein neuer Fahrer angelegt.

Der Quellcode und Download des Beispiels

Den Quellcode ansehen bei GitHub:
Spring mit JPA und Hibernate
Spring mit einer einfachen Webanwendung

Der Download einer ZIP-Datei von GitHub:
Spring mit JPA und Hibernate
Spring mit einer einfachen Webanwendung

Update am 28.09.2012

Es wurden folgende Änderungen an allen Projekten vorgenommen.

  1. Die Projekte wurden aus meinem lokalen Apache Subversion Repository in meine öffentlichen GitHub Repositories verschoben.
  2. Die folgenden typischen Anpassungen an Git wurden an allen Projekten durchgeführt.
    • .directory gelöscht
    • .gitignore hinzugefügt
    • README.md hinzugefügt
    • COPYRIGHT.md hinzugefügt
    • In jedem Repository wurde für jeden Beitrag der Serie ein Branch angelegt.
      • develop-spring-an-einem-einfachen-beispiel
      • develop-spring-mit-aop
      • develop-spring-mit-jpa-und-hibernate
      • develop-spring-mit-einer-einfachen-webanwendung
      • develop-spring-mit-einer-webanwendung-mit-jpa-und-validierung
      • develop-spring-security-mit-einer-webanwendung
      • develop-spring-mit-restful-webservice

Updates von 06.10.2012 bis zum 14.10.2012

Es wurden folgende Änderungen an allen Projekten vorgenommen.

  1. Aktualisierung des OpenJDK auf die Version 1.7.0.
  2. Aktualisierung der Entwicklungsumgebung Eclipse auf die Version 4.2.1.
    Die benötigten Plugins aus dem Eclipse Marketplace:

  3. Aktualisierung der Datei pom.xml:
    • Anpassungen an die OpenJDK Version
    • GitHub Einträge (SCM und URL) hinzugefügt
    • Aktualisierung der Libraries auf aktuellerer Versionen (z. B. Spring Version 3.1.2.RELEASE, Hibernate Version 4.1.7.Final, JUnit Version 4.10, mockito Version 1.9.0, …)
      Die genaueren Versionen bitte aus den jeweiligen pom.xml auf GitHub entnehmen.

Frank Rahn

Frank Rahn ist Softwarearchitekt. Er unterstützt bei der Konzeption von Softwarearchitekturen mit Java-Technologie. Folge Sie ihm auf Facebook, Twitter oder Google+.

Benötigen Sie Unterstützung? Kontaktieren Sie ihn.

Hat Ihnen dieser Beitrag gefallen? Wir würden uns über Ihren Kommentar freuen! Bitte verwenden Sie Ihren bürgerlichen Namen und eine E-Mail-Adresse mit Gravatar.

Letzte Artikel von Frank Rahn (Alle anzeigen)

0 Kommentare

Dein Kommentar

Want to join the discussion?
Feel free to contribute!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.