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 Spring RESTful Webservices.
  • Das Testen eines Spring 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.
/**
 * Die Klasse eines Fahrers.
 * @author Frank W. Rahn
 */
@Entity
@Table(schema = "rahn")
@Access(AccessType.FIELD)
@NamedQueries(@NamedQuery(name = Driver.FIND_ALL, query = "from Driver d"))
@XmlRootElement
public class Driver {
  • Von folgender Erweiterung in Zeile 54 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.
    /** Der Name des Fahrers. */
    @Basic(optional = false)
    @Column(nullable = false)
    @NotNullOrBlank
    @XmlElement(required = true)
    private String name;
  • In Zeile 18 wird die Entität des Autos als ein Wurzelelement für eine XML-Repräsentation gekennzeichnet.
/**
 * Die Klasse eines Autos.
 * @author Frank W. Rahn
 */
@Entity
@Table(schema = "rahn")
@Access(AccessType.FIELD)
@XmlRootElement
public class Car {

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

/**
 * Das Package der Entitäten für den Fahrerservice.
 * @author Frank W. Rahn
 * @see de.rahn.services.drivers.Drivers
 */
@XmlSchema(namespace = "urn:rahn:drivers", elementFormDefault = QUALIFIED)
package de.rahn.services.drivers.entity;

import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;

import javax.xml.bind.annotation.XmlSchema;

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

   /**
     * Lösche den Fahrer.
     * @param id die Id eines Fahrers
     */
    void deleteDriver(Long id);
    /**
     * {@inheritDoc}
     * @see Drivers#deleteDriver(Long)
     */
    @Override
    @Transactional
    public void deleteDriver(Long id) {
        driverDAO.remove(id);
    }

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.
    <!-- Diese Interceptoren werden auf die Request-Handler angewendet -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/drivers" />
            <mvc:mapping path="/drivers/*" />
            <bean p:entityManagerFactory-ref="entityManagerFactory"
                class="org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor" />
            </mvc:interceptor>
    </mvc:interceptors>

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.
/**
 * Der Controller für die Operationen auf einen Fahrer des Service Drivers.
 * @author Frank W. Rahn
 */
@Controller
@RequestMapping("/drivers/{id}")
public class DriverController {

    private static final Logger logger = getLogger(DriverController.class);

    @Autowired
    private Drivers drivers;

    /**
     * Lese einen Fahrer.
     * @param id die Id eines Fahrers
     * @return der existierende Fahrer
     */
    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public Driver getDriver(@PathVariable long id) {
        logger
            .info(
                "Die Methode DriverController.getDriver() wurde mit aufgerufen. id={}",
                id);

        return drivers.getDriver(id);
    }

Die Implementierung kann direkt mit dem Kommando curl getestet werden.

$ curl <Parameters> <Url der Anwendung>

Die folgenden Parameter kann das Kommando verarbeiten:

  • -X <Methode>
    Mit diesem Parameter wird die HTTP Methode (GET, HEAD, PUT, DELETE, POST, etc.) festgelegt.
$ curl -X GET http://localhost:8080/test-spring-web/drivers
$ curl -X HEAD http://localhost:8080/test-spring-web/drivers
  • -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.
$ curl -H "Accept: text/plain" http://localhost:8080/test-spring-web/drivers
$ curl -H "Accept: text/plain" -H "Via: localhost" http://localhost:8080/test-spring-web/drivers
  • -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.
$ curl -d "<book><title>Titel</title></book>" -H "Content-Type: application/xml" http://localhost:8080/test-spring-web/drivers
$ curl -d @book.xml -H "Content-Type: application/xml" http://localhost:8080/test-spring-web/drivers
$ curl -d "title=Titel" http://localhost:8080/test-spring-web/drivers

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.

$ curl -i -X GET http://localhost:8080/test-spring-web/drivers/0
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Mon, 09 Apr 2012 17:08:08 GMT

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><driver xmlns="urn:rahn:drivers"><firstname>Martin</firstname><id>0</id><name>Rahn</name></driver>

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.

$ curl -i -X GET -H "Accept: application/json" http://localhost:8080/test-spring-web/drivers/0
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 09 Apr 2012 17:13:53 GMT

{"id":0,"name":"Rahn","firstname":"Martin","cars":[]}

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 Anwendungsserver in HTML-Format zurück.

$ curl -i -X GET -H "Accept: image/jpeg" http://localhost:8080/test-spring-web/drivers/0
HTTP/1.1 406 Not Acceptable
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 1070
Date: Mon, 09 Apr 2012 17:27:06 GMT

<html><head><title>Apache Tomcat/7.0.25 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 406 - </h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers ().</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/7.0.25</h3></body></html>

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

$ curl -i -X GET http://localhost:8080/test-spring-web/drivers/4711
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Length: 0
Date: Mon, 09 Apr 2012 17:56:18 GMT
 
 

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ück zu liefern, wird der Controller entsprechend geändert. Dazu wird die Klasse ResponseEntity verwendet. Dieser Klasse kann ein HTTP-Statuscode und ggf. HTTP-Attribute mitgegeben werden.

    /**
     * Lese einen Fahrer.
     * @param id die Id eines Fahrers
     * @return der existierende Fahrer
     */
    @RequestMapping(method = RequestMethod.GET)
    public ResponseEntity<Driver> getDriver(@PathVariable long id) {
        logger
            .info(
                "Die Methode DriverController.getDriver() wurde mit aufgerufen. id={}",
                id);

        Driver driver = drivers.getDriver(id);
        if (driver == null) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity<>(driver, HttpStatus.OK);
    }

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

$ curl -i -X GET http://localhost:8080/test-spring-web/drivers/4711
HTTP/1.1 404 Not Found
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 952
Date: Sat, 14 Apr 2012 09:25:22 GMT

<html><head><title>Apache Tomcat/7.0.25 - Error report</title><style>...

Die nächste Methode PUT /drivers/0 HTTP/1.1 modifiziert 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 angegebenen URI ein Fahrer mit dem angegebenen Inhalt.

  • In Zeile 65 wird geprüft, ob die angegebene 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.
    /**
     * Speichere einen Fahrer.
     * @param id die Id eines Fahrers
     * @param driver der aktuelle Fahrer
     * @return der geänderte Fahrer
     */
    @RequestMapping(method = RequestMethod.PUT)
    public ResponseEntity<Driver> saveDriver(@PathVariable long id,
        @RequestBody Driver driver) {
        logger
            .info(
                "Die Methode DriverController.saveDriver() wurde mit aufgerufen. Id={}, driver={}",
                id, driver);

        if (driver.getId() != null && !driver.getId().equals(id)) {
            // URI und Fahrer stimmen nicht überein => 409 Conflict
            return new ResponseEntity<>(HttpStatus.CONFLICT);
        }

        // Normaler Rückgabestatus
        HttpStatus status = HttpStatus.OK;

        if (driver.getId() == null) {
            // Rückgabe: 201 Created
            status = HttpStatus.CREATED;
            driver.setId(id);
        }

        // Speichere den Fahrer
        driver = drivers.save(driver);

        return new ResponseEntity<>(driver, status);
    }

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.

$ curl -i -X PUT -H "Content-Type: application/json; charset=UTF-8" -d '{"id":0,"name":"Rahn","firstname":"Frank"}' http://localhost:8080/test-spring-web/drivers/0
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Sat, 14 Apr 2012 10:08:22 GMT

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><driver xmlns="urn:rahn:drivers"><firstname>Frank</firstname><id>0</id><name>Rahn</name></driver>
$ curl -i -X GET -H "Accept: application/json" http://localhost:8080/test-spring-web/drivers/0
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sat, 14 Apr 2012 10:08:30 GMT

{"id":0,"name":"Rahn","firstname":"Frank","cars":[]}

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

$ curl -i -X PUT -H "Content-Type: application/json; charset=UTF-8" -d '{"id":0,"name":"Rahn","firstname":"Frank"}' http://localhost:8080/test-spring-web/drivers/1
HTTP/1.1 409 Conflict
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 1004
Date: Sat, 14 Apr 2012 10:20:02 GMT

<html><head><title>Apache Tomcat/7.0.25 - Error report</title><style>...

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

$ curl -i -X PUT -H "Content-Type: application/json; charset=UTF-8" -d '{"name":"Rahn","firstname":"Walter"}' http://localhost:8080/test-spring-web/drivers/4711
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Sat, 14 Apr 2012 13:03:35 GMT

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><driver xmlns="urn:rahn:drivers"><firstname>Walter</firstname><id>4711</id><name>Rahn</name></driver>

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.

    /**
     * Speichere einen Fahrer.
     * @param driver der aktuelle Fahrer
     * @return der existierende Fahrer
     */
    @RequestMapping(method = RequestMethod.DELETE)
    @ResponseStatus(value = HttpStatus.NO_CONTENT)
    public void deleteDriver(@PathVariable long id) {
        logger
            .info(
                "Die Methode DriverController.deleteDriver() wurde mit aufgerufen. Id={}",
                id);

        Driver driver = drivers.getDriver(id);
        if (driver != null) {
            drivers.deleteDriver(id);
        }
    }

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.

$ curl -i -X DELETE http://localhost:8080/test-spring-web/drivers/0
HTTP/1.1 204 No Content
Server: Apache-Coyote/1.1
Date: Sat, 14 Apr 2012 14:42:13 GMT
 
 
$ curl -i -X DELETE http://localhost:8080/test-spring-web/drivers/0
HTTP/1.1 204 No Content
Server: Apache-Coyote/1.1
Date: Sat, 14 Apr 2012 14:42:20 GMT
 
 

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 geschieht durch die Angabe des Ausgabeformats text/html.
  • Ab Zeile 83 wird die neue Methode des Webservices für das Abfragen aller Fahrer aufgeführt. Dieser kann nur den Inhalt Content-Type: application/json liefern, dafür aber auch die HTTP-Methode HEAD bedienen.
    /**
     * Liste alle Fahrer auf.
     * @return die Liste der Fahrer
     */
    @RequestMapping(method = GET, produces = "text/html")
    @ModelAttribute("drivers")
    public List<Driver> listDriverForView() {
        logger
            .info("Die Methode DriversController.listDriverForView() wurde aufgerufen.");

        return drivers.getDrivers();
    }

    /**
     * Liste alle Fahrer auf.
     * @return die Liste der Fahrer
     */
    @RequestMapping(method = { GET, HEAD }, produces = "application/json")
    @ResponseBody
    public List<Driver> listDriverForService() {
        logger
            .info("Die Methode DriversController.listDriverForService() wurde aufgerufen.");

        return drivers.getDrivers();
    }

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

$ curl -i -X GET -H "Accept: text/html" http://localhost:8080/test-spring-web/drivers
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=53B828DB7E3001984274B11676FFEB0C; Path=/test-spring-web/; HttpOnly
Content-Type: text/html;charset=UTF-8
Content-Language: de-DE
Content-Length: 1241
Date: Sat, 14 Apr 2012 15:52:56 GMT

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">...

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

$ curl -i -X GET -H "Accept: application/json" http://localhost:8080/test-spring-web/drivers
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sat, 14 Apr 2012 15:52:20 GMT

[{"id":0,"name":"Rahn","firstname":"Martin","cars":[]},{"id":50,"name":"Rahn","firstname":"Frank","cars":[]},{"id":51,"name":"Rahn","firstname":"Gerd","cars":[]}]

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

$ curl -i -X HEAD -H "Accept: application/json" http://localhost:8080/test-spring-web/drivers
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json
Content-Length: 162
Date: Sat, 14 Apr 2012 16:39:27 GMT

curl: (18) transfer closed with 162 bytes remaining to read

Zum Abschluss 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.
    /**
     * Speichere einen Fahrer.
     * @param driver der aktuelle Fahrer
     * @param model das Modell
     * @return die Liste der Fahrer
     */
    @RequestMapping(method = POST,
        consumes = "application/x-www-form-urlencoded")
    @ModelAttribute("drivers")
    public List<Driver> saveDriver(Driver driver, Model model) {
        logger
            .info(
                "Die Methode DriversController.saveDriver() wurde mit aufgerufen. driver={}",
                driver);

        if (driver.getId() == null) {
            drivers.create(driver);
        } else {
            drivers.save(driver);
        }

        model.addAttribute("statusMessage",
            "Der Fahrer mit der Id " + driver.getId()
                + " wurde gespeichert.<br/>Anzahl Autos des Fahrers "
                + driver.getCars().size() + ".");
        return drivers.getDrivers();
    }

    /**
     * Speichere einen neuen Fahrer.
     * @param driver der neue Fahrer
     * @param request der aktuelle Request
     * @return der neue Fahrer
     */
    @RequestMapping(method = POST, consumes = "application/*")
    public ResponseEntity<Driver> saveDriver(@RequestBody Driver driver,
        HttpServletRequest request) {
        logger
            .info(
                "Die Methode DriversController.saveDriver() wurde mit aufgerufen. driver={}",
                driver);

        // Schreiben des Fahrers
        drivers.create(driver);

        String baseUrl =
            String.format("%s://%s:%d%s/drivers/{id}", request.getScheme(),
                request.getServerName(), request.getServerPort(),
                request.getContextPath());
        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(new UriTemplate(baseUrl).expand(driver.getId()));

        return new ResponseEntity<>(driver, headers, HttpStatus.CREATED);
    }

Mit folgendem Kommando wird ein neuer Fahrer angelegt.

$ curl -i -X POST -H "Content-Type: application/json" -d '{"name":"Rahn","firstname":"Frank"}' http://localhost:8080/test-spring-web/drivers
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: http://localhost:8080/test-spring-web/drivers/50
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Sat, 14 Apr 2012 17:24:19 GMT

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><driver xmlns="urn:rahn:drivers"><firstname>Frank</firstname><id>50</id><name>Rahn</name></driver>

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
Letzte Artikel von Frank Rahn (Alle anzeigen)
0 Kommentare

Hinterlasse einen Kommentar

An der Diskussion beteiligen?
Hinterlasse uns deinen Kommentar!

Schreibe einen Kommentar

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

Ihre E-Mail-Adresse wird nicht veröffentlicht. Ihr Kommentar wird verschlüsselt an meinen Server gesendet. Erforderliche Felder sind mit * markiert.

Weitere Informationen und Widerrufshinweise finden Sie in meiner Datenschutzerklärung.