如何在 Spring Boot Api post 方法中接收自定义的 JSON 对象

Posted

技术标签:

【中文标题】如何在 Spring Boot Api post 方法中接收自定义的 JSON 对象【英文标题】:How to receive customized JSON Object in Spring boot Api post Method 【发布时间】: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(如上所示)都有相关类。 【参考方案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 的快速回复。每个答案都对我有帮助,但我必须将一个标记为答案,所以...... :)

以上是关于如何在 Spring Boot Api post 方法中接收自定义的 JSON 对象的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Boot Api post 方法中接收自定义的 JSON 对象

如何使用 Postman 表单数据将 POST 请求发送到 Spring Boot REST API?

Spring Boot - 模拟对外部 API 的 POST REST 请求

Spring Boot - 如何通过带有查询参数的 url 发送 POST 请求并将响应存储在方法中?

500内部服务器错误;在spring Boot rest api中使用POST方法时

Spring Boot Rest Controller 通用 POST 类型