尝试使用 Spring 引导 REST 从 POST 读取 JSON 字符串
Trying to use Spring Boot REST to Read JSON String from POST
我正在使用最新版本的 Spring 引导通过 Restful Web 服务读取示例 JSON...
这是我的 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>
这是我的网络服务代码:
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);
}
}
当我使用以下命令调用它时:
curl -H "Accept: application/json" -H "Content-type: application/json"
-X POST -d '{"name":"value"}' http://localhost:8080/myservice/process
我收到此错误消息:
{"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"
我唯一想做的就是传入一些有效的 JSON(通过 curl 作为字符串)并查看字符串有效负载是否作为 {"name":"value"}
我可能做错了什么?
感谢您花时间阅读本文...
从请求 body 解析 JSON 时出现问题,典型的无效 JSON。如果您在 windows 上使用 curl,请尝试像 -d "{"name":"value"}"
甚至 -d "{"""name""":"value"""}"
那样转义 json
另一方面,您可以省略 content-type header,在这种情况下,发送的 whetewer 将转换为您的字符串参数
我认为 simplest/handy 消费 JSON 的方法是使用类似于您的 JSON 的 Java class:
但是如果您不能使用 Java class 您可以使用这两种解决方案之一。
解决方案 1: 您可以从您的控制器接收 Map<String, Object>
:
@RequestMapping(
value = "/process",
method = RequestMethod.POST)
public void process(@RequestBody Map<String, Object> payload)
throws Exception {
System.out.println(payload);
}
使用您的请求:
curl -H "Accept: application/json" -H "Content-type: application/json" \
-X POST -d '{"name":"value"}' http://localhost:8080/myservice/process
解决方案 2: 否则您可以获得 POST 负载作为 String
:
@RequestMapping(
value = "/process",
method = RequestMethod.POST,
consumes = "text/plain")
public void process(@RequestBody String payload) throws Exception {
System.out.println(payload);
}
然后根据需要解析字符串。请注意,必须在您的控制器上指定 consumes = "text/plain"
。
在这种情况下,您必须使用 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 的解决方案中,例如,如果您要传递一个 JSON 数组
[
{"name":"value"},
{"name":"value2"}
]
然后您需要像这样设置 Spring 引导控制器:
@RequestMapping(
value = "/process",
method = RequestMethod.POST)
public void process(@RequestBody Map<String, Object>[] payload)
throws Exception {
System.out.println(payload);
}
要进一步处理地图数组,以下内容可能会有所帮助:
@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);
}
要在 Spring-Boot 中接收任意 Json,您可以简单地使用 Jackson 的 JsonNode
。自动配置适当的转换器。
@PostMapping(value="/process")
public void process(@RequestBody com.fasterxml.jackson.databind.JsonNode payload) {
System.out.println(payload);
}
Jackson Library 是我们需要的 将 Json 字符串直接注入到响应中,无需任何额外的解析。
如果我们有一个已经转义的 属性 并且需要在没有任何进一步转义的情况下对其进行序列化,我们可能希望在该字段上使用 Jackson 的 @JsonRawValue
注释。
也在其文档中指出:
Marker annotation that indicates that the annotated method or field
should be serialized by including literal String value of the property
as is, without quoting of characters. This can be useful for injecting
values already serialized in JSON or passing javascript function
definitions from server to a javascript client. Warning: the resulting
JSON stream may be invalid depending on your input value.
这是我的 DTO class:
public class UserProfileResponse {
private Long id;
private String userName;
@JsonRawValue
private String profile;
@JsonRawValue
private String settings;
}
不使用 使用 @JsonRawValue
我的回复如下所示,因为我的个人资料和设置字段正在从我的数据库(Oracle for例如),并且 spring 在想要为客户端创建响应时再次序列化它们:
{
"id": 25,
"userName": "admin",
"profile": "{ \"gender\": \"male\", \"nationalId\": \"0123456789\", \"contacts\": { \"phone\": \"02112341234\" } }",
"settings": "{\"lang\":\"fa-IR\",\"cols\":[],\"watch_lists\":{\"list_2\":[\"2\",\"3\"],\"list_1\":[\"1\",\"2\",\"3\"]}}"
}
但是当我将 @JsonRawValue
放在这些变量上时,响应将像这样序列化:
{
"id": 25,
"userName": "admin",
"profile": {
"gender": "male",
"nationalId": "0123456789",
"contacts": {
"phone": "02112341234"
}
},
"settings": {
"lang": "fa-IR",
"cols": [],
"watch_lists": {
"list_2": [
"2",
"3"
],
"list_1": [
"1",
"2",
"3"
]
}
}
}
我正在使用最新版本的 Spring 引导通过 Restful Web 服务读取示例 JSON...
这是我的 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>
这是我的网络服务代码:
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);
}
}
当我使用以下命令调用它时:
curl -H "Accept: application/json" -H "Content-type: application/json"
-X POST -d '{"name":"value"}' http://localhost:8080/myservice/process
我收到此错误消息:
{"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"
我唯一想做的就是传入一些有效的 JSON(通过 curl 作为字符串)并查看字符串有效负载是否作为 {"name":"value"}
我可能做错了什么?
感谢您花时间阅读本文...
从请求 body 解析 JSON 时出现问题,典型的无效 JSON。如果您在 windows 上使用 curl,请尝试像 -d "{"name":"value"}"
甚至 -d "{"""name""":"value"""}"
另一方面,您可以省略 content-type header,在这种情况下,发送的 whetewer 将转换为您的字符串参数
我认为 simplest/handy 消费 JSON 的方法是使用类似于您的 JSON 的 Java class:
但是如果您不能使用 Java class 您可以使用这两种解决方案之一。
解决方案 1: 您可以从您的控制器接收 Map<String, Object>
:
@RequestMapping(
value = "/process",
method = RequestMethod.POST)
public void process(@RequestBody Map<String, Object> payload)
throws Exception {
System.out.println(payload);
}
使用您的请求:
curl -H "Accept: application/json" -H "Content-type: application/json" \
-X POST -d '{"name":"value"}' http://localhost:8080/myservice/process
解决方案 2: 否则您可以获得 POST 负载作为 String
:
@RequestMapping(
value = "/process",
method = RequestMethod.POST,
consumes = "text/plain")
public void process(@RequestBody String payload) throws Exception {
System.out.println(payload);
}
然后根据需要解析字符串。请注意,必须在您的控制器上指定 consumes = "text/plain"
。
在这种情况下,您必须使用 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 的解决方案中,例如,如果您要传递一个 JSON 数组
[
{"name":"value"},
{"name":"value2"}
]
然后您需要像这样设置 Spring 引导控制器:
@RequestMapping(
value = "/process",
method = RequestMethod.POST)
public void process(@RequestBody Map<String, Object>[] payload)
throws Exception {
System.out.println(payload);
}
要进一步处理地图数组,以下内容可能会有所帮助:
@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);
}
要在 Spring-Boot 中接收任意 Json,您可以简单地使用 Jackson 的 JsonNode
。自动配置适当的转换器。
@PostMapping(value="/process")
public void process(@RequestBody com.fasterxml.jackson.databind.JsonNode payload) {
System.out.println(payload);
}
Jackson Library 是我们需要的 将 Json 字符串直接注入到响应中,无需任何额外的解析。
如果我们有一个已经转义的 属性 并且需要在没有任何进一步转义的情况下对其进行序列化,我们可能希望在该字段上使用 Jackson 的 @JsonRawValue
注释。
也在其文档中指出:
Marker annotation that indicates that the annotated method or field should be serialized by including literal String value of the property as is, without quoting of characters. This can be useful for injecting values already serialized in JSON or passing javascript function definitions from server to a javascript client. Warning: the resulting JSON stream may be invalid depending on your input value.
这是我的 DTO class:
public class UserProfileResponse {
private Long id;
private String userName;
@JsonRawValue
private String profile;
@JsonRawValue
private String settings;
}
不使用 使用 @JsonRawValue
我的回复如下所示,因为我的个人资料和设置字段正在从我的数据库(Oracle for例如),并且 spring 在想要为客户端创建响应时再次序列化它们:
{
"id": 25,
"userName": "admin",
"profile": "{ \"gender\": \"male\", \"nationalId\": \"0123456789\", \"contacts\": { \"phone\": \"02112341234\" } }",
"settings": "{\"lang\":\"fa-IR\",\"cols\":[],\"watch_lists\":{\"list_2\":[\"2\",\"3\"],\"list_1\":[\"1\",\"2\",\"3\"]}}"
}
但是当我将 @JsonRawValue
放在这些变量上时,响应将像这样序列化:
{
"id": 25,
"userName": "admin",
"profile": {
"gender": "male",
"nationalId": "0123456789",
"contacts": {
"phone": "02112341234"
}
},
"settings": {
"lang": "fa-IR",
"cols": [],
"watch_lists": {
"list_2": [
"2",
"3"
],
"list_1": [
"1",
"2",
"3"
]
}
}
}