Spring Webflux Webclient Response конвертировать список строк в строку - PullRequest
0 голосов
/ 15 июня 2019

Ответ:

[ 
 {
  "version": "1.0",
  "content": [
    "12345",
    "67076",
    "123462",
    "604340",
    "1331999",
    "1332608",
    "1785581",
   ]
 }
]

Код:

Mono<List<String>> mp = webClient.get().uri(accountMgmtURI)
    .retrieve()
    .bodyToMono(Map.class)
    .flatMap(trans-> {
       List<String> content= (List<String>) trans.get("content");
       System.out.println("content :: "+content);
       return Mono.just(content);
     }); 
System.out.println("content :: "+mp.toString()); 
String sites=mp.toString();

Ответы [ 2 ]

0 голосов
/ 17 июня 2019

Первая проблема заключается в том, что используемый вами 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();
0 голосов
/ 15 июня 2019

Пожалуйста, используйте готовые решения. Вы не должны использовать List<String> content= (List<String>) trans.get("content"). Java - это язык строгой типизации, поэтому создавайте классы для типов. А рамки как пружина работают с классами и объектами.

В этом случае:

public class VersionedDataResponse {
   private List<VersionedData> versionedDataList;
}
....
public class VersionedData {
    private String version;
    private List<String> content;
}

И весна преобразует его в bodyToMono(VersionedDataResponse.class)

...