You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Webflux如何正确格式化带shipment键的JSON响应

解决Spring Webflux返回JSON结构不符合预期的问题

期望的JSON结构

{
    "shipment": {
        "111": [
            "ITEM1",
            "ITEM2",
            "ITEM3"
        ],
        "222": [
            "ITEM4",
            "ITEM5",
            "ITEM6"
        ]
    }
}

传统Java实现方式

Map<String, List<String>> shipment = new HashMap<>();
shipment.put("111", Arrays.asList("ITEM1", "ITEM2", "ITEM3"));
shipment.put("222", Arrays.asList("ITEM4", "ITEM5", "ITEM6"));
Map.of("shipment", shipment);

当前Spring Webflux代码

public Flux<Map<String, List<String>>> getShipment(List<String> shipmentOrderNumbers) {
    final String apiUrl = "/some-path";
    final String queryParam = "some-query-param";
    
    ParameterizedTypeReference<List<String>> expectedType = new ParameterizedTypeReference<List<String>>() {};
    
    Flux<Map<String, List<String>>> values = Flux.fromIterable(shipmentOrderNumbers)
        .flatMap(orderNo -> this.client.get()
        .uri(uriBuilder -> uriBuilder.path(apiUrl).queryParam(queryParam, orderNo).build()).retrieve()
        .bodyToMono(expectedType).map(product -> Map.of(orderNo, product)));
    
    return values;
}

当前返回的不符合预期的JSON结构

[
    {
        "111": [
            "ITEM1",
            "ITEM2",
            "ITEM3"
        ]
    },
    {
        "222": [
            "ITEM4",
            "ITEM5",
            "ITEM6"
        ]
    }
]

解决方案

问题核心在于当前代码返回Flux<Map<String, List<String>>>,会被序列化为多个Map组成的JSON数组。而目标结构是单一JSON对象,需要将所有订单条目合并到一个Map中,再包装到shipment键下。具体修改如下:

修改后的完整代码

public Mono<Map<String, Map<String, List<String>>>> getShipment(List<String> shipmentOrderNumbers) {
    final String apiUrl = "/some-path";
    final String queryParam = "some-query-param";
    
    ParameterizedTypeReference<List<String>> expectedType = new ParameterizedTypeReference<List<String>>() {};
    
    return Flux.fromIterable(shipmentOrderNumbers)
        .flatMap(orderNo -> this.client.get()
            .uri(uriBuilder -> uriBuilder.path(apiUrl).queryParam(queryParam, orderNo).build())
            .retrieve()
            .bodyToMono(expectedType)
            .map(product -> Map.entry(orderNo, product))) // 生成键值对,方便后续合并
        .collectMap(Map.Entry::getKey, Map.Entry::getValue) // 合并所有键值对为一个大Map
        .map(shipmentMap -> Map.of("shipment", shipmentMap)); // 包装到外层的shipment键中
}

关键修改点说明

  1. 返回类型调整:从Flux改为Mono,因为最终要返回一个单一的JSON对象,而非数据流。
  2. 合并Map:用Map.entry生成键值对,再通过collectMap将所有订单条目合并到一个大Map中,对应目标结构里的shipment值。
  3. 包装外层结构:最后用map将合并后的大Map放入包含shipment键的外层Map,序列化后就是目标JSON结构。

内容的提问来源于stack exchange,提问作者heisenberg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 09:45:02