• Link zu Xing
  • Link zu LinkedIn
  • Link zu X
  • Link zu Rss dieser Seite
  • Link zu GitHub
  • Newsletter
  • Kontaktieren Sie mich
Frank W. Rahn
  • Meine BlogbeiträgeZeigt meinen Blog an
  • RessourcenZeigt Ihnen eine Auswahl von Ressourcen
    • Franks aktueller IT-Werkzeugkasten
      • Diese Werkzeuge setze ich zur Zeit ein
    • Meine Präsentationen
      • Zeigt Ihnen meine Präsentationen
    • Weblinks
      • Meine Linksammlung
    • Buchtipps
      • Eine Liste von mir empfohlener Literatur
    • XML-Namespace
      • Zeigt meinem XML-Namespace
  • Franks aktueller IT-WerkzeugkastenDiese Werkzeuge setze ich zur Zeit ein
  • Meine PräsentationenZeigt Ihnen meine Präsentationen
  • WeblinksMeine Linksammlung
  • BuchtippsEine Liste von mir empfohlener Literatur
  • XML-NamespaceZeigt meinem XML-Namespace
  • Über mich …Die persönlichen Informationen über den Softwarearchitekt Frank Rahn
  • Click to open the search input field Click to open the search input field Suche
  • Menü Menü
SOA

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.

Inhaltsverzeichnis [anzeigen]

  • Die Struktur des Projektes
  • Die Literaturempfehlungen für dieses Beispiel
  • Die Erweiterungen des Projektes test-spring-jpa
  • Die Fahrerverwaltung als RESTful Webservice
  • Die Erweiterungen des Projektes test-spring-web
  • Die REST-Schnittstelle zum Fahrer
  • REST-Schnittstelle zur Fahrerverwaltung
  • Der Quellcode und Download des Beispiels
  • Update am 28.09.2012
  • Updates von 06.10.2012 bis zum 14.10.2012

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 benötigten Bibliotheken (Dependencies) für das Projekt "test-spring-jpa"
Die benötigten Bibliotheken (Dependencies) für das Projekt "test-spring-jpa"
Die benötigten Bibliotheken (Dependencies) für das Projekt "test-spring-web"
Die benötigten Bibliotheken (Dependencies) für das Projekt "test-spring-web"

Die Literaturempfehlungen für dieses Beispiel

  • Referenzdokumentation des Spring Framework’s
  • Spring 3: Framework für die Java-Entwicklung (*)
  • Pro Spring 3 (*)
  • REST und HTTP: Einsatz der Architektur des Web für Integrationsszenarien (*)

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.
    • Projekt test-spring-simple
    • Projekt test-spring-jpa
    • Projekt test-spring-web
  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:
    • EGit – Git Team Provider, Version 2.1.0
    • GitHub Mylyn Connector, Version 2.0
    • Eclipse m2e – Maven support in Eclipse IDE
    • Spring IDE, Version 3.0.0.RELEASE
    • AspectJ Development Tools (AJDT), Version 2.2.0
    • Markdown Text Editor, Version 0.9.0
  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.

Weitere Beiträge dieser Serie. [verstecken]

  • Einführung in das Spring Framework
    • Spring an einem einfachem Beispiel
    • Spring mit AOP
    • Spring mit JPA und Hibernate
    • Spring mit einer einfachen Webanwendung
    • Spring mit einer Webanwendung mit JPA und Validierung
    • Spring Security mit einer Webanwendung
    • Spring mit RESTful Webservice
    • Spring und Stored Procedures mit User-defined Types
  • Über
  • Letzte Artikel
Frank Rahn
Frank Rahn
Frank Rahn ist Softwarearchitekt. Er unterstützt bei der Konzeption von Softwarearchitekturen mit Java-Technologie. Folge Sie ihm auf Facebook oder Twitter.

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.
Frank Rahn
Letzte Artikel von Frank Rahn (Alle anzeigen)
  • Wer ist der optimale Java Bean Mapper? - Freitag, 22. September 2023
  • Spring Boot Webanwendung: Die ersten Schritte (Tutorial) - Montag, 28. März 2016
  • Mainframe-Zugriff via Java - Sonntag, 04. Mai 2014
0 Kommentare/von Frank Rahn
Schlagworte: Annotations, AOP, Architektur, Content Negotation, CRUD, DAO, DI, HTTP, Idempotent, IoC, Java, Java SE, JPA, JSON, Linux, MVC, Open Source Software, POJO, REST (RESTful), Serviceorientierte, Shell, Spring, SQL, URI, URL, URN, WADL, Webservice, XML
Eintrag teilen
  • Teilen auf X
  • Teilen auf WhatsApp
  • Teilen auf LinkedIn
  • Per E-Mail teilen
  • Teilen auf Xing
https://www.frank-rahn.de/wp-content/uploads/Spring-mit-RESTful-Webservice.png 448 1132 Frank Rahn /wp-content/uploads/logo.png Frank Rahn2012-04-08 21:35:112025-02-02 20:34:01Spring mit RESTful Webservice (Tutortial)
Das könnte Dich auch interessieren
Klassendiagramm dieses Beispiels Spring an einem einfachem Beispiel (Tutorial)
Die Stored Procedure "searchPersons" mit User-defined Types (UDT) Stored Procedure mit User-defined Types unter Oracle
Debian Paketsystem APT (Advanced Packaging Tool)
Serviceorientierte Architektur für WebSphere und WebSphere Portal Serviceorientierte Architektur für WebSphere
Schaubild des asymmetrisches Verschlüsselungsverfahrens GnuPG benutzen
Mehrere PDF- oder PS-Dokumente zusammenfügen Mehrere PDF- oder PS-Dokumente zusammenfügen
0 Kommentare

Hinterlasse einen Kommentar

An der Diskussion beteiligen?
Hinterlasse uns deinen Kommentar!

Schreibe einen Kommentar Antwort abbrechen

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.

Wollen Sie kein neuen Beiträge mehr verpassen?
Dann abonnieren Sie bitte meinen Newsletter.
Meinen Newsletter abonnieren

Themen

  • Wer ist der optimale Java Bean Mapper?
  • Einführung in das Spring Framework, Boot, Batch, Data, REST, Security, Web, …
  • Franks aktueller IT-Werkzeugkasten
  • Git, GitHub, EGit, …

Navigation

  • Buchtipps
  • Newsletter
  • Weblinks
Search Search

Werbung

  • JProfiler
Beliebt
  • Das Klassendiagramm für den Java Bean Mapper Test am Beispiel "ByHand"
    Wer ist der optimale Java Bean Mapper?Freitag, 22. September 2023 - 20:59 Uhr
  • Das offizielle Logo von EGit
    GitHub mit Eclipse (EGit)Freitag, 26. Oktober 2012 - 16:15 Uhr
  • Grobe Übersicht üder den Spring Framework Container
    Einführung in das Spring FrameworkSonntag, 01. Mai 2011 - 18:30 Uhr
  • Die Stored Procedure "searchPersons" mit User-defined Types (UDT)
    Spring und Stored Procedure mit User-defined Types (Tut...Freitag, 26. Oktober 2012 - 21:45 Uhr
  • Spring Boot Webanwendung
    Spring Boot Webanwendung: Die ersten Schritte (Tutorial...Montag, 28. März 2016 - 16:29 Uhr
Schlagworte
Annotations AOP Architektur Autorisierung Cookies CRUD DAO DI Git HTML HTTP IoC Java Java EE Java SE JPA JSR Linux MVC Open Source Software PDF POJO REST (RESTful) ROCA Self-contained Systems Serviceorientierte Shell Sicherheit (Security) SOAP Spring SQL SVN Test Toolchain URI URL URN User-defined Type Versionsverwaltung VPN Webservice WS-* WSDL XML XML-Schema

Blogarchiv

Links

Mastodon
Twitter
LinkedIn
Xing
GitHub

Lizenz

Creative Commons Lizenzvertrag Die Texte (nicht Bilder) von Frank Rahn stehen unter einer Creative Commons Namensnennung - Keine Bearbeitungen 4.0 Deutschland Lizenz.

Affiliate-Links

Die mit (*) gekennzeichnete Links sind sogenannte Affiliate-Links. Kommt über einen solchen Link ein Einkauf zustande, werde ich mit einer Provision beteiligt. Für Sie entstehen dabei keine Mehrkosten. Wo, wann und wie Sie ein Produkt kaufen, bleibt natürlich Ihnen überlassen.

Blogkategorien

Copyright © Frank W. Rahn
  • Impressum / HaftungsausschlussDie notwendigen gesetzlichen Angaben dieser Webseite von Frank Rahn
  • DatenschutzerklärungDie Datenschutzerklärung von Frank Rahn
  • NewsletterKeine neuen Beiträge mehr verpassen!
  • BildnachweisDer komplette Bildnachweis von Frank Rahn
Link to: Social Share Privacy (2-Klick-Buttons für mehr Datenschutz) Link to: Social Share Privacy (2-Klick-Buttons für mehr Datenschutz) Social Share Privacy (2-Klick-Buttons für mehr Datenschutz)2 Klicks für mehr Datenschutz Link to: Git: Wie Du Git mit GitHub nutzt (Howto) Link to: Git: Wie Du Git mit GitHub nutzt (Howto) Wie Du Git mit GitHub nutztGit: Wie Du Git mit GitHub nutzt (Howto)
Nach oben scrollen Nach oben scrollen Nach oben scrollen

Wir setzen auf unserer Webseite verschiedene Arten von Cookies ein, die auf Ihrem Gerät gespeichert werden. Einige dieser Cookies sind für die einwandfreie Funktion der Webseite notwendig, während andere Cookies Ihnen ein besseres Besuchererlebnis bieten.

DatenschutzerklärungImpressumAlle Cookies akzeptierenKeine Cookies akzeptierenIndividuelle Cookie-Einstellungen vornehmen

Cookie- und Datenschutzeinstellungen



Wie wir Cookies verwenden

Wir setzen auf unserer Webseite verschiedene Arten von Cookies ein, die auf Ihrem Gerät gespeichert werden.

Einige dieser Cookies sind für die einwandfreie Funktion der Webseite notwendig, während andere Cookies Ihnen ein besseres Besuchererlebnis bieten.

Klicken Sie links auf die verschiedenen Reitern, um mehr zu erfahren. Sie können auch einige Cookie-Einstellungen individuell anpassen. Beachten Sie, dass das Blockieren einiger Cookies die einwandfreie Funktion unserer Webseite beeinträchtigt.

Technisch notwendige Cookies

Diese Cookies sind unbedingt erforderlich, denn sie ermöglichen grundlegende Funktionen und sind für die einwandfreie Funktion der Webseite erforderlich.

Sie können diese Cookies jederzeit blockieren oder löschen, indem Sie Ihre Browsereinstellungen ändern und die Blockierung aller Cookies auf dieser Webseite erzwingen. Leider werden Sie dann immer wieder gefragt, ob Sie Cookies akzeptieren oder ablehnen wollen, wenn Sie unsere Webseite erneut besuchen.

Wir setzen die Cookies aviaPrivacyEssentialCookiesEnabled, aviaPrivacyMustOptInSetting, aviaPrivacyRefuseCookiesHideBar und aviaCookieConsent ein, um Ihre individuellen Cookie-Einstellungen zu speichern. Diese Informationen geben wir an keinen Drittanbietern weiter.

Diese Cookies haben eine Laufzeit von einem Jahr, dann müssen Sie die Einstellungen wiederholen.

Die VG WORT setzt das Sitzungscookie srp zur Messung von Zugriffen auf Texten, um die Kopierwahrscheinlichkeit des Textes zu erfassen. Damit partizipieren ich an den Ausschüttungen der VG WORT, welche die gesetzliche Vergütung für die Nutzungen urheberrechtlich geschützter Werke gemäß § 53 UrhG sicherstellen. Das Cookie wird dazu verwendet, um den Nutzer zu identifizieren und ggf. Daten mehrerer Aufrufe von Texten miteinander verknüpfen zu können.

Nach Angaben der VG WORT stellt das eingesetzte Verfahren sicher, dass einzelne Nutzer oder ihr Leseverhalten nicht ermittelbar sind, wenn die Anzahl der Textaufrufe gezählt wird. Alle von der VG Wort erfassten Daten werden sofort sicher verschlüsselt. Der Einsatz des Zählpixels wurde durch das Bayerische Landesamt für Datenschutzaufsicht begutachtet und als datenschutzkonform bewertet.

Datenschutzerklärung der VG WORT

Marketing-Cookies

Die Marketing-Cookies werden von Drittanbietern oder Publishern, wie z. B. Google Analytics, verwendet, um personalisierte Werbung anzuzeigen. Sie tun dies, indem sie Besucher über Webseiten hinweg verfolgen (Tracking).

Wir setzen keine Marketing-Cookies ein.

Datenschutzbestimmungen

Sie können unsere Cookies und Datenschutzeinstellungen im Detail in unserer Datenschutzerklärung nachlesen.

Cookie-Einstellungen übernehmenKeine Cookies akzeptieren
Nachrichtenleiste öffnen Nachrichtenleiste öffnen Nachrichtenleiste öffnen