Первая проблема заключается в том, что используемый вами API возвращает не один объект, а массив объектов, указанных в квадратных скобках ([]
).
Это означает, что вы должны хотя бы реорганизовать код для использования bodyToFlux()
вместо bodyToMono()
:
client
.get()
.retrieve()
// bodyToFlux() in stead of bodyToMono()
.bodyToFlux(Map.class)
// ...
Вторая проблема заключается в том, что в этом случае работать с Map
нелегко, поскольку вам придется все время разыгрывать, поскольку вы не смогли пройти ни одного дженерика. Работа с соответствующим классом облегчит все. Например, вы можете написать следующий класс:
public class VersionContent {
private String version;
private List<String> content;
// TODO: Getters + Setters
}
И измените свой код на:
client
.get()
.retrieve()
.bodyToFlux(VersionContent.class)
.map(VersionContent::getContent)
.flatMap(Flux::fromIterable)
// ...
Этот фрагмент кода извлекает содержимое для каждого объекта, а flatMap
так, чтобы каждое отдельное значение передавалось отдельно.
Прямо сейчас каждый элемент в массиве content
будет публиковаться отдельно. Это подводит нас к третьей проблеме, которая заключается в том, что вы не объединяете свои строки.
Для объединения элементов вы можете использовать оператор reduce()
:
client
.get()
.retrieve()
.bodyToFlux(VersionContent.class)
.map(VersionContent::getContent)
.flatMap(Flux::fromIterable)
// reduce() can be used to merge all individual items to a single item
.reduce((sites, site) -> sites + "|" + site)
// ...
Последняя проблема в том, что вы используете toString()
, который не будет работать. Одним из ключевых аспектов реактивного программирования является то, что все происходит асинхронно . Это означает, что если вы попытаетесь что-либо сделать со своими данными в главном потоке, ничего не произойдет.
Кроме того, еще одна особенность таких издателей, как Mono
и Flux
, заключается в том, что они ленивые . Без надлежащей подписки ничего не произойдет.
Решение состоит в том, чтобы правильно subscribe()
получить ваше значение, например:
client
.get()
.retrieve()
.bodyToFlux(VersionContent.class)
.map(VersionContent::getContent)
.flatMap(Flux::fromIterable)
.reduce((sites, site) -> sites + "|" + site)
.subscribe(System.out::println);
Для вашего примера приведенный выше код выведет на консоль следующее:
12345|67076|123462|604390|1331999|1332608|1785581
Имейте в виду, это также означает, что все операции, которые вы хотите выполнять с этими сайтами, должны выполняться асинхронно.
Если вы не хотите работать асинхронно, вы можете использовать оператор block()
. Однако вы НЕ ДОЛЖНЫ делать это . Если вы используете оператор block()
, это означает, что вы вообще не заинтересованы в использовании реактивных потоков, и вам следует спросить себя, является ли использование WebClient
хорошим решением в этом случае.
В демонстрационных целях вы можете написать свой код так:
String sites = client
.get()
.retrieve()
.bodyToFlux(VersionContent.class)
.map(VersionContent::getContent)
.flatMap(Flux::fromIterable)
.reduce((sites, site) -> sites + "|" + site)
// You can use this, but you shouldn't
.block();