Spring Webflux: извлечение значения из Mono - PullRequest
1 голос
/ 13 января 2020

Я новичок в Spring Webflux и пытаюсь выполнить некоторую арифметику c для значений двух моно. У меня есть служба продукта, которая получает информацию об учетной записи, вызывая службу учетной записи через webClient. Я хочу определить, превышает ли текущий баланс на счете цену продукта или равна ей.

Mono<Account> account = webClientBuilder.build().get().uri("http://account-service/user/accounts/{userId}/",userId)
.retrieve().bodyToMono(Account.class);


//productId is a path variable on method
Mono<Product> product =this.productService.findById(productId);

Когда я пытаюсь заблокировать поток, я получаю сообщение об ошибке

block () / blockFirst () / blockLast () - это блокировка, которая не поддерживается в thread-http-nio-2

//Causes Error
Double accountBalance = account.map(a->a.getBalance()).block():

Double productPrice = product.map(p->p.getPrice()).block();

///Find difference, send response accordingly....

Это правильный подход, если есть другой Лучший способ добиться этого? Я также думал о чем-то вроде:

Mono<Double> accountBalance = account.map(a->a.getBalance()):

Mono<Double> productPrice = product.map(p->p.getPrice());

Mono<Double> res = accountBalance.zipWith(productPrice,(b,p)-> b-p);

//Something after this.....

1 Ответ

1 голос
/ 14 января 2020

Нельзя использовать блочный метод на главном потоке реактора. Это запрещено block может работать, когда publi sh mono в каком-то другом потоке, но это не так.

В принципе, ваш подход к сжатию двух моно верен. Вы можете создать какой-нибудь вспомогательный метод для расчета. В вашем случае это может выглядеть так:

public boolean isAccountBalanceGreater(Account acc, Product prd) {
   return acc.getBalance() >= prd.getPrice();
}

И тогда в вашем моно потоке вы можете передать ссылку на метод и сделать его более читабельным.

Mono<Boolean> result = account.zipWith(productPrice, this::isAccountBalanceGreater)

Вопрос в том, что вы хотите сделать с этой информацией позже. Если вы хотите вернуться к своему контроллеру, просто true или false, это нормально. В противном случае вам могут потребоваться некоторые другие сопоставления, zippings и др. c.

Обновление

return account.zipWith(productPrice, this::createResponse);

...

ResponseEntity createResponse(Account acc, Product prd) {
   int responseCode = isAccountBalanceGreater(acc, prd) ? 200 : 500;
   return ResponseEntity.status(responseCode).body(prd);
}
...