如何让Spring控制器接受多种类型的JSON [英] How to get Spring controller to accept multiple types of JSON
问题描述
我有一个Spring REST服务(用Groovy编写,尽管这不重要),它公开了一个安全端点,如下所示:
class AppData {
String id
String payload
String fizzbuzz
}
@RequestMapping(method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
@ResponseBody AppResponse onAppData(@RequestBody AppData appData){
//对appData进行一些处理,然后将
//其'payload'字段保存到一个MongoDB
}
当它接收到以下形式的JSON时,
{
id:12345,
payload:Please save me to MongoDB,
fizzbuzz:wakka wakka
}
我在这里使用Jackson来处理JSON序列化。
问题是我现在想把有效载荷
属性设置为是真正的JSON,而不是一个字符串。因此,我希望能够发送端点如下所示:
{
id:12345 ,
payload:{
foo:24,
bar:false,
whistlefeather:当然是
},
fizzbuzz:wakka wakka
}
保存到MongoDB。但这里有一个问题:
许多不同的团队(可能有数百个)将发送这个端点 AppData
,并且他们的所有有效载荷看起来都完全不同(每个团队都有不同的有效载荷,他们希望发送给我并保存在MongoDB中)。我不希望为每个新的团队编写一个新的端点和 AppData
子类(从而将这个端点公开给它)。
有什么办法可以:
AppData#有效负载
属性以任何形式接受JSON
如果我发送JSON消息,其中有效负载
也是JSON(并且不是一个字符串),Spring只是返回一个400为空的响应体。这是因为Spring期望 payload
是一个String,但是它看到它是一个JSON对象。
任何想法我可以在 AppData
类中做什么来处理这个问题,或者是什么最佳实践的概念?
使用JsonNode作为有效负载的类型:
public class AppData {
字符串ID;
JsonNode有效载荷;
String fizzbuzz;
public String getId(){
return id;
}
public void setId(String id){
this.id = id;
}
public JsonNode getPayload(){
return payload;
}
public void setPayload(JsonNode payload){
this.payload = payload;
}
public String getFizzbuzz(){
return fizzbuzz;
}
public void setFizzbuzz(String fizzbuzz){
this.fizzbuzz = fizzbuzz;
}
public static void main(String [] args)throws IOException {
String json ={\ n+
\id \\ :\\12345 \,\\\
+
\payload \:{\ n+
\foo \:24, \\\
+
\bar \:false,\\\
+
\whistlefeather \:\当然是\\\\
+
},\\\
+
\fizzbuzz\:\wakka wakka\\\\
+
};
ObjectMapper om = new ObjectMapper();
AppData appData = om.readValue(json,AppData.class);
System.out.println(appData ID =+ appData.getId());
System.out.println(appData fizzbuzz =+ appData.getFizzbuzz());
System.out.println(appData payload =+ appData.getPayload());
String json2 ={\ n+
\id \:\12345\,\\\
+
\\ \\payload \:\请将我保存到MongoDB \,\ n+
\fizzbuzz\:\wakka wakka \\\\
+
};
appData = om.readValue(json2,AppData.class);
System.out.println(appData ID =+ appData.getId());
System.out.println(appData fizzbuzz =+ appData.getFizzbuzz());
System.out.println(appData payload =+ appData.getPayload());
$ b
输出:
appData ID = 12345
appData fizzbuzz = wakka wakka
appData payload = {foo:24,bar: false,whistlefeather:当然是}
appData ID = 12345
appData fizzbuzz = wakka wakka
appData payload =请将我保存到MongoDB
请注意,要获取有效负载的JSON字符串,您不应该使用toString(),如上例所示。你应该使用 objectMapper.writeValueAsString(payload)
。
I have a Spring REST service (written in Groovy; although that shouldn't matter) that exposes a secured endpoint like so:
class AppData {
String id
String payload
String fizzbuzz
}
@RequestMapping(method=RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
@ResponseBody AppResponse onAppData(@RequestBody AppData appData) {
// Does some processing on appData and then saves
// its 'payload' field to a MongoDB
}
And this works perfectly fine when it receives JSON of the following form:
{
"id" : "12345",
"payload" : "Please save me to a MongoDB",
"fizzbuzz" : "wakka wakka"
}
I'm using Jackson to handle JSON serialization here.
The problem is that I now want the payload
property to be true JSON, not a String. So I want to be able to send the endpoint something like this:
{
"id" : "12345",
"payload" : {
"foo" : 24,
"bar" : false,
"whistlefeather" : "Yes of course"
},
"fizzbuzz" : "wakka wakka"
}
And have the payload properly saved off to MongoDB. But here's the catch:
Lots of different teams (potentially hundreds) are going to be sending this endpoint AppData
, and all of their payloads are going to look completely different (each team has different payloads they want to send me and have saved in MongoDB). And I don't want to have to write a new endpoint and AppData
subclass for each new team I onboard (and thus expose this endpoint to).
Is there any way I can:
- Keep my endpoint exactly the way it is; but
- Allow the
AppData#payload
property to accept JSON in any form?
Keeping my code exactly the way it is, if I send a JSON message where the payload
is also JSON (and isn't a string), Spring just returns a 400 with an empty response body. This is happening because Spring expects payload
to be a String, but sees that its a JSON object.
Any ideas on what I can do inside the AppData
class to handle this, or any notions of what the best practice is here?
Use a JsonNode as the type for the payload:
public class AppData {
String id;
JsonNode payload;
String fizzbuzz;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public JsonNode getPayload() {
return payload;
}
public void setPayload(JsonNode payload) {
this.payload = payload;
}
public String getFizzbuzz() {
return fizzbuzz;
}
public void setFizzbuzz(String fizzbuzz) {
this.fizzbuzz = fizzbuzz;
}
public static void main(String[] args) throws IOException {
String json = "{\n" +
" \"id\" : \"12345\",\n" +
" \"payload\" : {\n" +
" \"foo\" : 24,\n" +
" \"bar\" : false,\n" +
" \"whistlefeather\" : \"Yes of course\"\n" +
" },\n" +
" \"fizzbuzz\" : \"wakka wakka\"\n" +
"}";
ObjectMapper om = new ObjectMapper();
AppData appData = om.readValue(json, AppData.class);
System.out.println("appData ID = " + appData.getId());
System.out.println("appData fizzbuzz = " + appData.getFizzbuzz());
System.out.println("appData payload = " + appData.getPayload());
String json2 = "{\n" +
" \"id\" : \"12345\",\n" +
" \"payload\" : \"Please save me to a MongoDB\",\n" +
" \"fizzbuzz\" : \"wakka wakka\"\n" +
"}";
appData = om.readValue(json2, AppData.class);
System.out.println("appData ID = " + appData.getId());
System.out.println("appData fizzbuzz = " + appData.getFizzbuzz());
System.out.println("appData payload = " + appData.getPayload());
}
}
Output:
appData ID = 12345
appData fizzbuzz = wakka wakka
appData payload = {"foo":24,"bar":false,"whistlefeather":"Yes of course"}
appData ID = 12345
appData fizzbuzz = wakka wakka
appData payload = "Please save me to a MongoDB"
Note that to get back a JSON string for the payload, you shouldn't use toString() as in the above example. You should use objectMapper.writeValueAsString(payload)
.
这篇关于如何让Spring控制器接受多种类型的JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!