我是Reactive编程的新手,我想并行进行两个API调用并处理结果,并返回一个简单的数组或项目列表。
我有两个函数,一个函数返回一个Flux,另一个函数返回一个Mono,然后我根据那个Mono的结果对Flux发出的项目进行非常简单的过滤逻辑。
我尝试使用zipWith
,但是无论采用哪种过滤逻辑,只有一项可以使用到最后。我也尝试过block
,但是在控制器内部是不允许的:/
@GetMapping("/{id}/offers")
fun viewTaskOffers(
@PathVariable("id") id: String,
@AuthenticationPrincipal user: UserPrincipal
) : Flux<ViewOfferDTO> {
data class TaskOfferPair(
val task: TaskDTO,
val offer: ViewOfferDTO
)
return client.getTaskOffers(id).map {
it.toViewOfferDTO()
}.zipWith(client.getTask(id), BiFunction {
offer: ViewOfferDTO, task: TaskDTO -> TaskOfferPair(task, offer)
}).filter {
it.offer.workerUser.id == user.id || it.task.creatorUser == user.id
}.map {
it.offer
}
}
getTaskOffers
返回OfferDTO
的通量getTask
返回TaskDTO
的Mono 如果您不能回答我的问题,请至少告诉我如何并行执行多个API调用并等待WebClient中的结果
答案 0 :(得分:2)
这是并行调用的用例。
public Mono<UserInfo> fetchCarrierUserInfo(User user) {
Mono<UserInfo> userInfoMono = fetchUserInfo(user.getGuid());
Mono<CarrierInfo> carrierInfoMono = fetchCarrierInfo(user.getCarrierGuid());
return Mono.zip(userInfoMono, carrierInfoMono).map(tuple -> {
UserInfo userInfo = tuple.getT1();
userInfo.setCarrier(tuple.getT2());
return userInfo;
});
}
这里:
fetchUserInfo
进行http调用以从其他服务获取用户信息并返回Mono
fetchCarrierInfo
方法进行HTTP调用以从另一个服务获取carrierInfo并返回Mono
Mono.zip()
将给定的Monos合并到一个新的Mono中,当所有给定的Monos都生成一个项目时,将满足该条件,并将其值汇总到Tuple2中。 然后,调用fetchCarrierUserInfo().block()
以获得最终结果。
答案 1 :(得分:1)
您已经知道,zipWith
不会对您有所帮助,因为它将产生min(a.size, b.size)
,如果其中之一为Mono
,它将始终为1。 / p>
但是由于这两个是独立的,因此您可以将它们拆分:
val task: Mono<TaskDTO> = client.getTask(id)
val result: Flux<ViewOfferDTO> =
task.flatMapMany {t ->
client.getTaskOffers(id).map {offer ->
t to offer
}
}.filter {
it.second.workerUser.id == user.id || it.first.creatorUser == user.id
}.map {
it.second
}
请注意,如果要具有一对元素,则可以使用内置的Pair
。
此外,此检查没有太大意义,因为您只有Mono
:it.first.creatorUser
答案 2 :(得分:1)
使用repeat()将您的Mono转换为助焊剂:
client.getTask(id).cache().repeat();
这样您的代码就会变成
return client.getTaskOffers(id).map {
it.toViewOfferDTO()
}.zipWith(client.getTask(id).cache().repeat(), BiFunction {
offer: ViewOfferDTO, task: TaskDTO -> TaskOfferPair(task, offer)
}).filter {
it.offer.workerUser.id == user.id || it.task.creatorUser == user.id
}.map {
it.offer
}