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



修复实现
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
相关产品推荐
相关产品推荐

