Spring 5 WebFlux中RouterFunction如何返回正确的Destination列表?
问题:WebFlux RouterFunction返回的目的地列表无法正确序列化
嘿,我帮你看看这个问题~你现在遇到的情况是,用ResponseData包装反应式流Flux<Destination>时,返回的不是实际的目的地数据列表,而是Flux对象的内部属性。先梳理下你的现有代码和错误返回结果:
你的RouterFunction Bean
@Bean RouterFunction<?> routes(DestinationHandler destinationHandler) { return nest(path("/destination"), route(method(GET), destinationHandler::findAll)); }
处理器函数及相关方法
public Mono<ServerResponse> findAll(ServerRequest request) { Flux<Destination> destinations = destinationService.findAll(); ResponseData responseData = buildResponseData(destinations); return ok().body(Mono.just(responseData), ResponseData.class); } private ResponseData buildResponseData(Flux<Destination> destinations) { ResponseData responseData = new ResponseData(); responseData.setStatus(HttpStatus.OK.value()); responseData.setCode(DESTINATION_LIST_SUCCESS_CODE); responseData.setMessage(DESTINATION_LIST_SUCCESS_MESSAGE); responseData.setData(destinations); return responseData; }
错误返回结果
{ "status":200, "code":"destination_list_success", "message":"Retorno realizado com sucesso", "data":{ "scanAvailable":true, "prefetch":-1 } }
问题原因
这是因为你直接把Flux<Destination>这个反应式流对象赋值给了ResponseData的data字段。序列化框架(比如Jackson)处理它时,只会输出Flux自身的内部属性,并不会去订阅这个流、获取里面的实际目的地数据。
解决方案:将Flux转换为List的Mono
要拿到正确的列表数据,我们需要先把Flux中的元素收集成一个List,再放到ResponseData里。修改后的代码如下:
修改后的处理器函数
public Mono<ServerResponse> findAll(ServerRequest request) { // 先把Flux收集为List的Mono,再构建ResponseData return destinationService.findAll() .collectList() .map(this::buildResponseData) .flatMap(responseData -> ServerResponse.ok().bodyValue(responseData)); }
修改后的buildResponseData方法
// 参数从Flux<Destination>改为List<Destination> private ResponseData buildResponseData(List<Destination> destinations) { ResponseData responseData = new ResponseData(); responseData.setStatus(HttpStatus.OK.value()); responseData.setCode(DESTINATION_LIST_SUCCESS_CODE); responseData.setMessage(DESTINATION_LIST_SUCCESS_MESSAGE); responseData.setData(destinations); return responseData; }
修改后的正确返回结果
调整后,你就能得到预期的目的地列表了:
{ "status":200, "code":"destination_list_success", "message":"Retorno realizado com sucesso", "data":[ {"id":1,"local":"Paris"}, {"id":2,"local":"London"} ] }
补充说明
如果需要处理大数据量,不想一次性把所有元素加载到内存中,可以考虑直接返回Flux<Destination>(不用ResponseData包装),这样WebFlux会流式输出数据。但如果必须用统一的ResponseData包装,上面的方法是最稳妥的——因为ResponseData是同步的包装对象,需要实际的数据集合而非反应式流对象。
内容的提问来源于stack exchange,提问作者Fabio
相关产品推荐
相关产品推荐

