使用 spring webclient with flux 避免多次调用 API

Avoid multiple calls to API using spring webclient with flux

这两个调用都是客户端 http api:

Flux<SavingsViewFilter> views = savingsApi.getViewFilterSavings(viewId);
            Flux<Group> groups = groupsApi.getAllGroups();

和return一个通量

requestBodySpec.retrieve().bodyToFlux(returnType);

我需要根据来自 eacg view.getGroupId()

的值过滤 Flux<Group> 中的元素
        return views.flatMap(view ->
                groups
                        .filter(group -> Objects.equals(group.getGroupId(), view.getGroupId()))
                        .flatMap(group -> Flux.just(DepositAccount.builder()
                                .agencyName(group.getGroupName())
                                .settlementAccount(view.getName())
                                .build())));

它正在工作,但问题是它正在为每个视图对象执行一个到 getAllGroups 的 HTTP 请求。

如何避免对 getAllGroups 的多次请求?

问题是您正在为每个视图元素订阅组。

可以使用join只订阅each一次,然后逐个元素join。

views
    //Join fluxes and create tuple for each pair
    .join(groups, s-> Flux.never(),s-> Flux.never(),Tuples::of)
    //Filter out any that don't have matching groupIds
    .filter(t -> t.getT1().getGroupId().equals(t.getT2().getGroupId()))
    //Use map, not flatMap since builder is not blocking
    .map(t -> DepositAccount.builder()
        .agencyName(t.getT2().getGroupName())
        .settlementAccount(t.getT1().getName())
        .build()
     );

确实这不是正确的问题,需要更好地考虑一下。

最终结果是您试图将 viewsidsgroupsids 相匹配,并创建一个连接对象。这不是 Flux API 的目的。最后看起来你正试图用两个循环来完成这个任务,这是一种非常低效的方法。

如果您研究替代方法会更好。

1) 如果groupview和数据库表都使用SQL加入。创建一个高效的新端点。

2) 将一个集合放入地图中,并使用它来组合两个实体。

@AllArgsConstructor
@Getter
class View {
    Integer id;
    String view;
}

@AllArgsConstructor
@Getter
class Group {
    Integer id;
    String group;
}

@Data
@AllArgsConstructor
class Combined {
    String view;
    String group;
}

private void run() {
    Flux<View> views = Flux.just(new View(1, "v1"), new View(2, "v2"), new View(3, "v3"));
    Flux<Group> groups = Flux.just(new Group(2, "g2"), new Group(3, "g3"), new Group(4, "g4"));

    views.collectMap(View::getId)
            .flatMapMany(viewMap -> groups.filter(group -> viewMap.containsKey(group.getId()))
                    .map(group ->
                            new Combined(viewMap.get(group.getId()).getView(), group.getGroup()))
            )
            .subscribe(System.out::println);
}