如何让Spring控制器接受多种类型的JSON [英] How to get Spring controller to accept multiple types of JSON

查看:117
本文介绍了如何让Spring控制器接受多种类型的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆