Возврат нескольких Monos в Spring Webflux

Я пытаюсь поиграться с SpringBoot 2.0 и новой реактивной библиотекой webFlux. Я хочу знать, как я могу вернуть результаты двух вызовов, выполненных через не блокирующий WebClient, вызывающей стороне моего Springboot API. Код, который у меня есть:

@RequestMapping("/search")
public CombinedResults perfomSearch(@RequestParam final String searchTerm) {
    Mono<SearchResponse> fasMono = searchService.getSearchResults(searchTerm, "fh");
    Mono<SearchResponse> esMono = searchService.getSearchResults(searchTerm, "es");
    CombinedResults combinedResults = new CombinedResults(fasMono, esMono);
    return combinedResults;

}

Объект CombinedResult - это просто POJO:

public class CombinedResults {

private Mono<SearchResponse> fasSearchResponse;

private Mono<SearchResponse> esSearchResponse;

public CombinedResults(final Mono<SearchResponse> fasSearchResponse, final Mono<SearchResponse> esSearchResponse) {
    this.fasSearchResponse = fasSearchResponse;
    this.esSearchResponse = esSearchResponse;
}

public Mono<SearchResponse> getFasSearchResponse() {
    return fasSearchResponse;
}

public void setFasSearchResponse(final Mono<SearchResponse> fasSearchResponse) {
    this.fasSearchResponse = fasSearchResponse;
}

public Mono<SearchResponse> getEsSearchResponse() {
    return esSearchResponse;
}

public void setEsSearchResponse(final Mono<SearchResponse> esSearchResponse) {
    this.esSearchResponse = esSearchResponse;
}

Однако, если я назову это, ответ, который я верну, будет

{
  "fasSearchResponse": {
    "scanAvailable": true
  },
  "esSearchResponse": {
    "scanAvailable": true
  }
}

Вместо содержимого объектов SearchResponse. Я чувствую, что могу упустить фундаментальный принцип того, как это должно работать! Я думал, что, поскольку WebClient не блокирует, я могу запустить два вызова веб-сервисов, а затем объединить их без необходимости в завершаемых фьючерсах и т. Д.?


person Sutty1000    schedule 11.04.2018    source источник


Ответы (2)


Я думаю, что вы должны вернуть Mono объекта, который представляет модель, на которую это действие отреагировало. Предположим, что CombinedResults - ваша модель. Этот класс должен выглядеть примерно так:

public class CombinedResults {

    private SearchResponse fasSearchResponse;

    private SearchResponse esSearchResponse;

    public CombinedResults(final SearchResponse fasSearchResponse, final SearchResponse esSearchResponse) {
        this.fasSearchResponse = fasSearchResponse;
        this.esSearchResponse = esSearchResponse;
    }

    //... getters AND/OR setters
}

И на вашем контроллере вы делаете что-то вроде этого:

@RequestMapping("/search")
public Mono<CombinedResults> perfomSearch(@RequestParam final String searchTerm) {
    Mono<SearchResponse> fasMono = searchService.getSearchResults(searchTerm, "fh");
    Mono<SearchResponse> esMono = searchService.getSearchResults(searchTerm, "es");
    Mono<CombinedResults> combinedResults = 
        fasMono
          .flatMap(fh -> esMono.map(es -> new CombinedResults(fh, es)));
    return combinedResults;
}

Таким образом, вы возвращаете объект Mono, содержащий то, что вы хотели в качестве ответа. Цепочка операций fasMono.flatMap с esMono.map строит CombinedResults, когда оба Mono генерируют элементы. Эта комбинация довольно часто встречается при попытке объединить два моноблока в один. Я думаю, вы также можете использовать оператор zip, чтобы присоединиться к Monos. Все это не связано с WebClient. Если ваш getSearchResults выполняет только асинхронные неблокирующие операции, тогда все асинхронно-неблокирующее.

person Felipe Moraes    schedule 11.04.2018

Spring WebFlux не поддерживает вложенные реактивные типы. Вместо этого у вас должно получиться что-то вроде этого:

Mono<SearchResponse> fasMono = searchService.getSearchResults(searchTerm, "fh");
Mono<SearchResponse> esMono = searchService.getSearchResults(searchTerm, "es");
Mono<CombinedResults> results = fasMono.zipWith(esMono, 
    (fas, es) -> {return new CombinedResults(fas, es);});
person Brian Clozel    schedule 12.04.2018
comment
Казалось, что это дало мне тот же результат - person Sutty1000; 12.04.2018
comment
Вы изменили класс комбинированных результатов, чтобы он также не содержал реактивных типов? - person Brian Clozel; 12.04.2018
comment
ИМО, это лучший ответ на вопрос - person abstractKarshit; 30.01.2019