【问题标题】:How to receive customized JSON Object in Spring boot Api post Method如何在 Spring Boot Api post 方法中接收自定义的 JSON 对象
【发布时间】:2019-08-23 09:50:55
【问题描述】:

我试图在@RequestBody 中接收一个我不知道的 JSON 对象,即 JSON 对象可以是任何长度和数据。

假设JSON可以如下所示

{'seqNo': 10 }

{'country': 'US', 'state': 'CA'}

{'customer': 'Alex', product: 'UPS', date:'25-Mar-2018'}

在 Spring Boot Api 中,我有一个方法来接收那个 JSON 对象。

@PostMapping(value = "/lookup")
public ResponseEntity<AppResponse> getLookup(@RequestBody LookupRequestObject lookupRequestObject) {

        // THIS METHOD KNOWS WHICH FIELD TO USE
        // FURTHER LOGIC WOULD BE HERE.


        return ResponseEntity.ok(response);

    }

我已阅读有关 Jackson 序列化的信息,但仍在寻找解决方案。

Customize the Jackson ObjectMapper

任何帮助将不胜感激。

【问题讨论】:

  • 您可以接受请求正文为 String ,然后自己使用 Jackson 将字符串反序列化为相关类。
  • @Arnaud,相关类意味着每个 JSON(如上所示)都有相关类。

标签: java json spring-boot jackson domain-object


【解决方案1】:

您可以只使用地图作为输入。 然后您可以根据它包含的字段类型访问地图中的字段。

@PostMapping(value = "/lookup")
public ResponseEntity<AppResponse> getLookup(@RequestBody Map<String, Object> lookupRequestObject) {

    // THIS METHOD KNOWS WHICH FIELD TO USE
    // FURTHER LOGIC WOULD BE HERE.

    return ResponseEntity.ok(response);
}

【讨论】:

    【解决方案2】:

    如果JSON object 结构未知,您始终可以使用Map&lt;String, Object&gt; 类型并将其转换为POJO 或直接处理Map。如果您需要POJO,您可以使用convertValue 方法:

    @PostMapping(value = "/lookup")
    public ResponseEntity<AppResponse> getLookup(@RequestBody Map<String, Object> payload) {
        // read map
        ObjectMapper objectMapper = new ObjectMapper();
        if (payload.containsKey("seqNo")) {
            Sequence seq = objectMapper.convertValue(payload, Sequence.class);
            // other logic
        } else if (payload.containsKey("country")) {
            Country country = objectMapper.convertValue(payload, Country.class);
        }
        // the same for other types
    
        // FURTHER LOGIC WOULD BE HERE.
        return ResponseEntity.ok(response);
    }
    

    您也可以尝试反序列化到com.fasterxml.jackson.databind.JsonNode,但它会将控制器与Jackson 绑定,这从另一边来说不好。

    【讨论】:

    • Map,我需要在使用时输入对象。会不会很贵?
    • @TAB,铸造成本不高。在Java 中,泛型被替换为随处可见的转换,并且工作正常。所以,以 Integer seq = (Integer)payload.get("seqNo") 的方式使用 map 就可以了。
    【解决方案3】:

    @Patrick Adler 的回答是绝对正确的。您可以使用 Map 作为方法的参数。两个重要的补充: Map 对应于 JSON 对象,因此当 JSON 对象传递给您的方法时,Spring(默认使用 Jackson)会将其转换为 map,因此不需要额外的代码。还要确保您可以将您希望接收 JSON 输入的注释添加到您的注释中: 所以换行

    @PostMapping(value = "/lookup")

    到

    @PostMapping(value = "/lookup", headers = "Accept=application/json")

    最后,您发布的输入不是有效的单个 JSON 对象。它是 3 个独立的 JSON 对象。因此,您要么期望包含 JSON 对象的 JSON 数组,要么期望包含单个 JSON 对象。如果您期望 JSON 数组,那么在您的方法中使用 List&lt;Map&lt;String, Object&gt;&gt; 而不是 Map&lt;String, Object&gt; 参数,因此您的解决方案应该看起来是

    @PostMapping(value = "/lookup", headers = "Accept=application/json")
    public ResponseEntity<AppResponse> getLookup(@RequestBody Map<String, Object> lookupRequestObject) {
    
        // THIS METHOD KNOWS WHICH FIELD TO USE
        // FURTHER LOGIC WOULD BE HERE.
    
        return ResponseEntity.ok(response);
    }
    

    或相同但使用List&lt;Map&lt;String, Object&gt;&gt; 参数而不是仅映射

    【讨论】:

    • 更安全一点的是List&lt;Object&gt; 而不是List&lt;Map&lt;String, Object&gt;&gt;,因为在原始数组[1,2,3] 的情况下,它会默认工作。
    • 是的,我有一些复杂的 JSON,例如 { 'seqNo': 10, 'sort': { 'field': 'ctry', 'desc': 0 } 'filter': { ' field': 'region', 'operator': 'startsWith', 'value': 'europe' } page: 0, size: 20, userData: { ... } }
    • @TAB,你的 JSON 很好,在这种情况下你的参数仍然是 Map。它会工作得很好。顺便说一句,如果解决方案对您有用,请将其标记为已接受的答案:)
    • MichaelGantman,是的,我正在工作,现在我几乎完成了我的工作。特别感谢 MichaelGantman、@MichałZiober 和 PatrickAdler 的快速回复。每个答案都对我有帮助,但我必须将一个标记为答案,所以...... :)
    猜你喜欢
    • 2018-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-20
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    相关资源
    最近更新 更多