如何让Spring控制器接受多种类型的JSON

时间:2017-01-14 17:52:22

标签: json spring spring-mvc groovy

我有一个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) {
    // Does some processing on appData and then saves
    // its 'payload' field to a MongoDB
}

当它收到以下形式的JSON时,它的工作原理非常好:

{
    "id" : "12345",
    "payload" : "Please save me to a MongoDB",
    "fizzbuzz" : "wakka wakka"
}

我在这里使用Jackson来处理JSON序列化。

问题是我现在希望payload属性为真JSON,而不是String。所以我希望能够发送这样的端点:

{
    "id" : "12345",
    "payload" : {
        "foo" : 24,
        "bar" : false,
        "whistlefeather" : "Yes of course"
    },
    "fizzbuzz" : "wakka wakka"
}

将有效负载妥善保存到MongoDB。但是这里有一个问题:

许多不同的团队(可能有数百人)将发送此端点AppData,并且他们的所有有效负载看起来完全不同(每个团队都有不同的有效负载,他们希望发送给我并保存在MongoDB的)。而且我不想为每个新的团队编写一个新的端点和AppData子类(因此将此端点公开)。

我有什么办法可以:

  • 保持我的端点完全按照它的方式;但
  • 允许AppData#payload属性以任何形式接受JSON吗?

保持我的代码完全按照它的方式,如果我发送一个JSON消息,其中payload也是JSON(并且不是一个字符串),Spring只返回一个带有空响应体的400。这是因为Spring期望payload是一个String,但是看到它是一个JSON对象。

关于我在AppData课程中可以做些什么来处理这个问题的想法,或者关于最佳实践的概念是什么?

2 个答案:

答案 0 :(得分:2)

使用JsonNode作为有效负载的类型:

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());

    }
}

输出:

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"

请注意,要获取有效内容的JSON字符串,不应使用上面示例中的toString()。您应该使用objectMapper.writeValueAsString(payload)

答案 1 :(得分:0)

您可以尝试使用Map,我不知道它在Groovy中是什么,但这将是Java中的结构。

public class AppData {
    String id;
    Map<String, Object> payload;
    String fizzbuzz;
}