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

如何在Spring Boot中使用WebClient以非阻塞方式获取分页REST API的全量数据

使用Spring Boot WebClient非阻塞获取所有星球大战角色

我来帮你搞定这个问题!想要用WebClient非阻塞地遍历分页API并收集所有数据,咱们可以利用Spring反应式编程的特性,尤其是Flux的expand操作符来优雅处理递归分页请求。下面是具体的实现步骤和代码示例:

第一步:定义响应DTO类

首先得创建对应SWAPI响应结构的DTO,方便WebClient解析JSON:

import java.util.List;

public class SwapiPeopleResponse {
    private List<Person> results;
    private String next; // 下一页的URL,没有更多数据时为null

    // 省略getter、setter、构造方法
}

public class Person {
    private String name;
    private String height;
    private String mass;
    // 其他你需要的字段,比如birth_year、gender等

    // 省略getter、setter、构造方法
}

第二步:配置WebClient

创建一个WebClient的Bean,方便在服务中注入使用:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class WebClientConfig {

    @Bean
    public WebClient swapiWebClient() {
        return WebClient.builder()
                .baseUrl("https://swapi.dev/api")
                .build();
    }
}

第三步:实现分页遍历的服务逻辑

核心就是用expand操作符递归处理每一页的请求,直到没有下一页为止:

import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Service
public class SwapiPeopleService {

    private final WebClient swapiWebClient;

    // 构造方法注入WebClient
    public SwapiPeopleService(WebClient swapiWebClient) {
        this.swapiWebClient = swapiWebClient;
    }

    public Flux<Person> getAllPeople() {
        // 发起第一页请求
        return getPage("people")
                // expand操作符:对每个分页响应,继续请求下一页(如果存在)
                .expand(response -> {
                    if (response.getNext() == null) {
                        return Mono.empty(); // 没有下一页,结束递归
                    }
                    // 注意这里要用完整的URL,因为SWAPI的next是全路径
                    return swapiWebClient.get()
                            .uri(response.getNext())
                            .retrieve()
                            .bodyToMono(SwapiPeopleResponse.class);
                })
                // 把每个分页响应里的results展开成Person的流
                .flatMap(response -> Flux.fromIterable(response.getResults()));
    }

    // 封装单页请求的方法
    private Mono<SwapiPeopleResponse> getPage(String endpoint) {
        return swapiWebClient.get()
                .uri(endpoint)
                .retrieve()
                .bodyToMono(SwapiPeopleResponse.class);
    }
}

关键知识点解释

  • expand操作符:这是实现递归分页的核心,它会把每个分页响应转换成新的Mono(下一页的请求),直到返回Mono.empty()时停止整个流。整个过程是非阻塞的,所有请求都是异步处理。
  • 非阻塞特性:WebClient本身就是反应式的客户端,所有请求都不会阻塞线程,适合处理大量分页数据的场景。
  • 错误处理(可选):你可以在retrieve()之后添加onErrorResume来处理请求失败的情况,比如:
    .retrieve()
    .onStatus(HttpStatus::isError, response -> Mono.error(new RuntimeException("请求SWAPI失败: " + response.statusCode())))
    .bodyToMono(SwapiPeopleResponse.class)
    

使用示例

在你的控制器或者其他组件中调用这个服务:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@RestController
public class PeopleController {

    private final SwapiPeopleService peopleService;

    public PeopleController(SwapiPeopleService peopleService) {
        this.peopleService = peopleService;
    }

    @GetMapping("/all-people")
    public Flux<Person> getAllPeople() {
        return peopleService.getAllPeople();
    }
}

这样当你访问/all-people时,就会非阻塞地获取所有星球大战角色的数据啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 05:47:37