如何在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
相关产品推荐
相关产品推荐

