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键中 }
关键修改点说明
- 返回类型调整:从
Flux改为Mono,因为最终要返回一个单一的JSON对象,而非数据流。 - 合并Map:用
Map.entry生成键值对,再通过collectMap将所有订单条目合并到一个大Map中,对应目标结构里的shipment值。 - 包装外层结构:最后用
map将合并后的大Map放入包含shipment键的外层Map,序列化后就是目标JSON结构。
内容的提问来源于stack exchange,提问作者heisenberg
相关产品推荐
相关产品推荐

