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

Spring WebFlux Mono返回List响应仅返回单条记录问题排查

问题定位

代码存在3个核心问题,直接导致单条返回、类型报错的现象:

  • 映射逻辑错误:mapper函数仅初始化了1个RemoteActionHistoryDTO对象,遍历多条数据库记录时反复修改同一个对象的属性值,循环结束后仅保留最后1条记录的数据,从未构造DTO列表返回。
  • 泛型强转错误:mapper实际返回类型为Mono<ResponseEntityDTO<RemoteActionHistoryDTO>>(单DTO包装),与方法签名要求的Mono<ResponseEntityDTO<List<RemoteActionHistoryDTO>>>(DTO列表包装)泛型不匹配,直接强制类型转换掩盖了编译期错误,运行时触发类型转换异常。
  • 重试逻辑缺陷:Repository层认证失败触发递归重试时,未返回递归调用的结果,即使重试成功也会继续抛出首次请求的异常,引发偶发接口报错。

期望返回的多记录结果格式
当前接口返回的单条记录结果
Mono相关代码运行报错截图

修复实现

1. 修正Service层映射逻辑,移除错误强转

删除原有错误的mapper函数,直接在flatMap算子中完成列表映射,返回匹配泛型的结果:

@Override
public Mono<ResponseEntityDTO<List<RemoteActionHistoryDTO>>> getRemoteActionHistory(String deviceId) throws Exception {
    return arrowFlightRepository.getRemoteActionDetailsByDeviceId(deviceId)
            .collectList()
            .flatMap(remoteActionList -> {
                if (CollectionUtils.isEmpty(remoteActionList)) {
                    return Mono.just(new ResponseEntityDTO<>(
                            RemoteActionHistoryConstants.CODE_RET_000,
                            null,
                            Collections.emptyList()
                    ));
                }
                // 逐条映射实体为DTO,收集为列表
                List<RemoteActionHistoryDTO> dtoList = remoteActionList.stream()
                        .map(action -> {
                            RemoteActionHistoryDTO dto = new RemoteActionHistoryDTO();
                            dto.setStartDateTime(action.getStartDateTime());
                            dto.setEndDateTime(action.getEndDateTime());
                            dto.setRemoteActionType(action.getCommand());
                            dto.setTaskStatus(action.getStatus());
                            return dto;
                        })
                        .collect(Collectors.toList());
                return Mono.just(new ResponseEntityDTO<>(
                        RemoteActionHistoryConstants.CODE_RET_000,
                        null,
                        dtoList
                ));
            });
}

2. 修复Repository层重试逻辑

递归重试时补充return语句,返回重试获取的结果:

catch (Exception ex) {
    log.error(String.format("Exception string : %s with retryEnabled is %s", ex.toString(),retry));
    if (retry && StringUtils.containsIgnoreCase(ex.toString(), RemoteActionHistoryConstants.UNAUTHENTICATED_ERROR)) {
        adhocFlightClientConfig.removeToken();
        // 补充return,返回重试结果
        return getExcaliburData(query, false);
    }
    throw ex;
}
开发注意事项
  • 禁止对Reactor响应式对象做泛型强转:响应式泛型的类型校验不会被编译期类型擦除跳过,强转只会把类型不匹配问题延后到运行时抛出,直接在算子中构造对应泛型的返回值即可。
  • 若需要使用Spring原生ResponseEntity设置HTTP状态码、响应头,可将接口返回类型改为Mono<ResponseEntity<ResponseEntityDTO<List<RemoteActionHistoryDTO>>>>,通过ResponseEntity.ok().body(响应体)构造返回即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 09:12:22