Versuch, Spring Boot REST zum Lesen des JSON-Strings aus dem POST zu verwenden

74

Ich verwende die neueste Version von Spring Boot, um ein Beispiel-JSON über Restful Web Service einzulesen ...

Hier ist meine pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"       
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/maven-v4_0_0.xsd"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>myservice</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.2.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.7</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-rest-webmvc</artifactId>
        </dependency>
        <dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-releases</id>
            <name>Spring Releases</name>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
        <repository>
            <id>org.jboss.repository.releases</id>
            <name>JBoss Maven Release Repository</name>
            <url>https://repository.jboss.org/nexus/content/repositories/releases</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <name>Spring Releases</name>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>

</project>

Hier ist mein Webdienstcode:

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/myservice")
public class BaseService {  

    @RequestMapping(value="/process", method = RequestMethod.POST)
    public void process(@RequestBody String payload) throws Exception {
        System.out.println(payload);
    }
}

Wenn ich es mit dem folgenden Befehl aufrufe:

curl -H "Accept: application/json" -H "Content-type: application/json" 
-X POST -d '{"name":"value"}' http://localhost:8080/myservice/process

Ich erhalte diese Fehlermeldung:

{"timestamp":1427515733546,"status":400,
 "error":"Bad Request",

"exception":
"org.springframework.http.converter.HttpMessageNotReadableException","
 message":
 "Could not read JSON: Can not deserialize instance of java.lang.String
  out of START_OBJECT token\n at 

 [Source: java.io.PushbackInputStream@8252f; line: 1, column: 1]; 
  nested    exception is com.fasterxml.jackson.databind.JsonMappingException:
  Can not deserialize instance of java.lang.String out of START_OBJECT token\n    
  at [Source: java.io.PushbackInputStream@8252f; line: 1, column: 1]",
  "path":"/myservice/process"

Das einzige, was ich versuche, ist, einen gültigen JSON (als String via Curl) zu übergeben und zu prüfen, ob die String-Nutzdaten als {"name": "value"} in die Prozessmethode eingegeben werden.

Was mache ich möglicherweise falsch?

Vielen Dank, dass Sie sich die Zeit genommen haben, dies zu lesen ...

PacificNW_Lover
quelle
Sie haben einen Fehler in Ihrem pom.xml: einem nutzlosen / nicht geschlossenen Tag <dependency>vor <dependencies>. Aber ist das nicht dein Problem ...
Andrea

Antworten:

136

Ich denke, der einfachste / praktischste Weg, JSON zu konsumieren, ist die Verwendung einer Java-Klasse, die Ihrem JSON ähnelt: https://stackoverflow.com/a/6019761

Wenn Sie jedoch keine Java-Klasse verwenden können, können Sie eine dieser beiden Lösungen verwenden.

Lösung 1: Sie können dies tun, indem Sie eine Map<String, Object>von Ihrem Controller empfangen :

@RequestMapping(
    value = "/process", 
    method = RequestMethod.POST)
public void process(@RequestBody Map<String, Object> payload) 
    throws Exception {

  System.out.println(payload);

}

Verwenden Sie Ihre Anfrage:

curl -H "Accept: application/json" -H "Content-type: application/json" \
-X POST -d '{"name":"value"}' http://localhost:8080/myservice/process

Lösung 2: Andernfalls können Sie die POST-Nutzdaten wie folgt abrufen String:

@RequestMapping(
    value = "/process", 
    method = RequestMethod.POST,
    consumes = "text/plain")
public void process(@RequestBody String payload) throws Exception {

  System.out.println(payload);

}

Analysieren Sie dann die Zeichenfolge nach Ihren Wünschen. Beachten Sie, dass dies consumes = "text/plain"auf Ihrem Controller angegeben werden muss . In diesem Fall müssen Sie Ihre Anfrage ändern mit Content-type: text/plain:

curl -H "Accept: application/json" -H "Content-type: text/plain" -X POST \
-d '{"name":"value"}' http://localhost:8080/myservice/process
Andrea
quelle
Das hat funktioniert! Ich habe gerade Ihre zweite Lösung ausprobiert ... Vielen Dank. Das Problem ist, dass für diesen Dienst ständig unterschiedliche JSONs verfügbar sind und kein Schema vorhanden ist. Würden Map <String, Object> und auch die String-Nutzdaten alle JSON-Typen korrekt aufnehmen können?
PacificNW_Lover
@socal_javaguy Die erste Lösung analysiert jeden JSON für Sie in ein MapObjekt. Wenn Sie die zweite Lösung verwenden, müssen Sie die Zeichenfolge validieren und in einen JSON analysieren, z. B.: Baeldung.com/jackson-json-to-jsonnode
Andrea
Ich erhalte
vishal sundararajan
10

Zum Hinzufügen zu Andrea's Lösung, wenn Sie beispielsweise ein Array von JSONs übergeben

[
    {"name":"value"},
    {"name":"value2"}
]

Dann müssen Sie den Spring Boot Controller folgendermaßen einrichten:

@RequestMapping(
    value = "/process", 
    method = RequestMethod.POST)
public void process(@RequestBody Map<String, Object>[] payload) 
    throws Exception {

    System.out.println(payload);

}
S. Pan
quelle
5

Um beliebigen Json in Spring-Boot zu erhalten, können Sie einfach Jacksons verwenden JsonNode. Der entsprechende Konverter wird automatisch konfiguriert.

    @PostMapping(value="/process")
    public void process(@RequestBody com.fasterxml.jackson.databind.JsonNode payload) {
        System.out.println(payload);
    }
Mateusz Stefek
quelle
4

Um weiter mit einer Reihe von Karten zu arbeiten, könnten die folgenden Punkte hilfreich sein:

@RequestMapping(value = "/process", method = RequestMethod.POST, headers = "Accept=application/json")
public void setLead(@RequestBody Collection<? extends Map<String, Object>> payload) throws Exception {

  List<Map<String,Object>> maps = new ArrayList<Map<String,Object>>();
  maps.addAll(payload);

}
Rusli Usman
quelle
2

Das Problem tritt beim Parsen des JSON aus dem Anforderungshauptteil auf, was für einen ungültigen JSON typisch ist. Wenn Sie Curl unter Windows verwenden, versuchen Sie, dem JSON wie -d "{"name":"value"}"oder sogar zu entkommen-d "{"""name""":"value"""}"

Auf der anderen Seite können Sie den Header vom Inhaltstyp weglassen. In diesem Fall wird das gesendete Netz in Ihr String-Argument konvertiert

Master Slave
quelle
Vielen Dank, Master Slave. Der Grund, warum ich kein POJO verwendet habe, ist, dass dieser Dienst verschiedene Arten von JSON (mit unterschiedlichen Inhalten) erhalten wird. Verstehen Sie, was ich fragen möchte?
PacificNW_Lover
Ich verstehe jetzt). Auf der anderen Seite ist Ihre Serverseite tatsächlich in Ordnung. Es beschwert sich darüber, dass es nicht möglich ist, json zu analysieren und eine Antwort zu bearbeiten
Master Slave
Ich verwende Bash von OS X Mavericks ... Ich versuche, einen JSON zu übergeben, damit ich ihn analysieren kann, um eine benutzerdefinierte Antwort zurückzugeben, unabhängig davon, ob sie gültig ist oder nicht. Dies ist der erste Schritt, um zuerst eine JSON-Zeichenfolge von der Post abzurufen. Mache ich es falsch
PacificNW_Lover
mhm, na ja, wenn ich dich richtig verstehe, nicht wirklich. Die Tatsache, dass Sie einen Content-Typ-Header senden, der auf application / json festgelegt ist, bedeutet, dass die Konvertierung versucht wird, bevor die Anforderung die Handler-Methode erreicht. Bei ungültigem json schlägt dies mit einer fehlerhaften Anforderung 400 fehl. Sie sollten jedoch ohne senden Der Inhaltstyp-Header, als die Anforderung Ihre Methode erreicht, und dort können Sie die Konvertierung programmgesteuert versuchen und die entsprechende Antwort zurückgeben. Ich bin mir nicht sicher, ob dies ein praktikabler Ansatz für Sie ist, aber wir werden mit Sicherheit daran arbeiten
Master Slave
Ohne den Inhaltstyp wurde Folgendes zurückgegeben:% 7B% 22name% 22% 3A% 22value% 22% 7D =
PacificNW_Lover