Spring WebClient 检索 json 结果中包含的对象 属性

Spring WebClient retrieve json object wrapped under results property

我目前正在开发一个 Spring 引导应用程序,将外部 REST API 包装到我自己的 GraphQL API.

到目前为止,我已经使用此方法返回 SerieDetails :

public SerieDetails findOrThrow(long id) throws RuntimeException {
        try {
            return this.webClient
                    .get()
                    .uri("/tv/{id}?api_key={apiKey}&language={lang}", id, this.apiKey, this.lang)
                    .retrieve()
                    .bodyToMono(SerieDetails.class)
                    .log()
                    .block();
        } catch(Exception e ) {
            throw new RuntimeException("Can't reach the API");
        }
}

将这个 JSON 变成我自己的对象 :

{
  "id": 71912,
  "name": "The Witcher",
  "overview": "Geralt of Rivia, a mutated monster-hunter for hire, journeys toward his destiny in a turbulent world where people often prove more wicked than beasts."
  "last_air_date": "2019-12-20",
  ...
}

效果很好。但现在我正在做另一个调用,返回一个 SerieDetails 列表和给定的查询,它 returns result 数组下的结果:

{
  "page": 1,
  "results": [
      {
        "id": 71912,
        "name": "The Witcher",
        "overview": "Geralt of Rivia, a mutated monster-hunter for hire, journeys toward his destiny in a turbulent world where people often prove more wicked than beasts."
        "first_air_date": "2019-12-20",
        ...
      },
      {
        "id": 106541,
        "name": "The Witcher: Blood Origin",
        "overview": "Set in an elven world 1200 years before the world of The Witcher, the show charts the origins of the very first Witcher, and the events that lead to the pivotal “conjunction of the spheres,” when the worlds of monsters, men, and elves merged to become one.",
        "first_air_date": "2002-09-22",
        ...
      }
  ]
}

而且我不知道如何使用 WebClient 访问它。 到目前为止我试过了:

public List<SerieDetails> findByQuery(String query) {
        return this.webClient
                .get()
                .uri("/search/tv?api_key={apiKey}&language={lang}&query={query}", this.apiKey, this.lang, query)
                .retrieve()
                .bodyToFlux(SerieDetails.class)
                .log()
                .collect(Collectors.toList())
                .block();
}

但是没用。

您需要更改 JSON 反序列化的对象。函数 bodyToMonobodyToFlux 创建两个不同的流,其中 MonoFlux 是发布者:

  • Mono 最多发出一个项目;
  • Flux 发出从零到 N 项的序列。

这些项目是指定 class 的实例。在您的例子中,JSON 响应被转换为 SerieDetails。 多个项目并不意味着 SerieDetails 的数组,而是具有 SerieDetails 结构的多个 JSON 响应。您可以将其想象成相同 class.

的不同对象实例

更简单的解决方案是创建以下 class:

class PaginatedSerieDetails {
    private int page;
    private List<SerieDetails> results;

    // getters and setters
}

那么你调用的时候会用到这个:

public List<SerieDetails> findByQuery(String query) {
        return this.webClient
                .get()
                .uri("/search/tv?api_key={apiKey}&language={lang}&query={query}", this.apiKey, this.lang, query)
                .retrieve()
                .bodyToMono(PaginatedSerieDetails.class)
                .map(PaginatedSerieDetails::getResults())
                .log()
                .block();
}

作为旁注,请在使用 WebFlux 时尽量避免 .block()。当你这样做时,你就打败了使用反应式堆栈的全部目的,因为你是在说你实际上想让线程等待 Mono 或 Flux 发出一个值。