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

如何在Quarkus响应式应用中用Vertx & Mutiny链式调用外部API与DB?

基于Quarkus + Vert.x Mutiny的响应式链式实现方案

一、外部API调用的正确姿势

你用Unirest同步调用再包装成Uni的做法不符合响应式非阻塞原则,同步调用会阻塞Vert.x事件循环,浪费Quarkus响应式模型的优势。应该使用Quarkus官方推荐的io.quarkus.vertx.webclient.ReactiveWebClient——这是Vert.x WebClient的Mutiny适配版,天生支持非阻塞响应式调用,和Quarkus生态集成更顺畅。

二、完整代码实现

1. 依赖配置(pom.xml)

确保引入核心依赖:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-reactive-web-client</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-hibernate-reactive-panache</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-reactive-pg-client</artifactId>
</dependency>

2. 数据模型定义

先明确DTO与数据库实体结构:

// 外部API返回的Response DTO
public class Response {
    public String abc;
    public List<AnotherClass> anotherClasses;
}

public class AnotherClass {
    public Long id; // 关联数据库查询的ID
    public List<Role> roles;
}

public class Role {
    // 外部API返回的Role字段,如name、code等
}

// Postgres数据库实体
@Entity
public class RoleFromDB extends PanacheEntityBase {
    @Column(name = "another_id")
    public Long anotherId;
    // 数据库存储的其他字段,如roleName、roleCode等
}

3. 响应式链式调用核心逻辑

import io.quarkus.vertx.webclient.ReactiveWebClient;
import io.smallrye.mutiny.Uni;
import jakarta.inject.Inject;
import java.util.List;
import java.util.stream.Collectors;

public class ResponseService {

    @Inject
    ReactiveWebClient webClient;

    public Uni<Response> fetchAndMergeData() {
        // 1. 响应式调用外部API获取初始Response
        return webClient.get()
                .uri("https://external-api/your-target-endpoint")
                .retrieve()
                .body(Response.class)
                // 2. 基于API返回的ID批量查询数据库
                .onItem().transformToUni(response -> {
                    // 收集所有需要查询的AnotherClass ID
                    List<Long> anotherIds = response.anotherClasses.stream()
                            .map(AnotherClass::getId)
                            .collect(Collectors.toList());

                    // 批量查询数据库,避免循环调用提升性能
                    return RoleFromDB.list("anotherId in ?1", anotherIds)
                            .onItem().transform(dbRoles -> {
                                // 3. 将数据库结果合并到原Response中
                                response.anotherClasses.forEach(another -> {
                                    // 匹配当前AnotherClass对应的数据库角色
                                    List<RoleFromDB> matchedRoles = dbRoles.stream()
                                            .filter(role -> role.anotherId.equals(another.getId()))
                                            .collect(Collectors.toList());
                                    // 转换数据库实体为API的Role格式并合并
                                    another.roles.addAll(matchedRoles.stream()
                                            .map(this::convertToRole)
                                            .collect(Collectors.toList()));
                                });
                                return response;
                            });
                });
    }

    // 数据库实体到API Role的字段映射方法
    private Role convertToRole(RoleFromDB dbRole) {
        Role role = new Role();
        // 根据实际业务字段映射,例如:
        // role.setName(dbRole.roleName);
        // role.setCode(dbRole.roleCode);
        return role;
    }
}

4. 关键细节说明

  • 非阻塞调用:ReactiveWebClient基于Vert.x事件循环执行,全程不阻塞线程,完全契合Quarkus响应式模型。
  • 批量查询优化:通过一次批量查询替代循环单查,减少数据库连接开销,提升性能。
  • 链式异步流:用onItem().transformToUni衔接异步操作,保证整个流程的响应式连续性,避免回调地狱。

三、Axle WebClient兼容方案(不推荐)

如果因特殊需求必须使用io.vertx.axle.ext.web.client.WebClient,需要手动将Axle的CompletionStage转换为Mutiny的Uni:

import io.vertx.axle.ext.web.client.WebClient;
import io.smallrye.mutiny.Uni;
import jakarta.inject.Inject;

public class AxleWebClientDemo {

    @Inject
    WebClient axleWebClient;

    public Uni<Response> fetchWithAxle() {
        return Uni.createFrom().completionStage(
                axleWebClient.getAbs("https://external-api/your-endpoint")
                        .send()
                        .thenApply(response -> response.bodyAsJson(Response.class))
        );
    }
}

注意:该方案需要手动处理转换,不如ReactiveWebClient原生适配流畅,优先推荐前者。

内容的提问来源于stack exchange,提问作者Vemai Clan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 10:12:53