Как проверить, нет ли Моно?

Я разрабатываю приложение с Spring Boot 2.0 и Kotlin, используя среду WebFlux.

Я хочу проверить, выходит ли пользовательский идентификатор перед сохранением транзакции. Я застрял в простой вещи, такой как проверка, если моно пусто.

fun createTransaction(serverRequest: ServerRequest) : Mono<ServerResponse> { val transaction = serverRequest.body(BodyExtractors.toMono(Transaction::class.java)) transaction.flatMap { val user = userRepository.findById(it.userId) // If it's empty, return badRequest() } return transaction.flatMap { transactionRepository.save(it).then(created(URI.create("/transaction/" + it.id)).build()) } } 

Можно делать то, что я хочу?

Позвольте мне начать с того, что я новичок в реактивной (java) и на этом форуме. Я думаю, вы не можете проверить этот код, если моно пусто, потому что моно представляет собой код, который будет выполнен позже, поэтому в этом теле кода вы еще не узнаете, если он пуст. Имеет ли это смысл?

Я просто написал что-то подобное на Java, которое, похоже, работает (но не на 100% это лучший подход):

  public Mono<ServerResponse> queryStore(ServerRequest request) { Optional<String> postalCode = request.queryParam("postalCode"); Mono<ServerResponse> badQuery = ServerResponse.badRequest().build(); Mono<ServerResponse> notFound = ServerResponse.notFound().build(); if (!postalCode.isPresent()) { return badQuery; } Flux<Store> stores = this.repository .getNearByStores(postalCode.get(), 5); return ServerResponse.ok().contentType(APPLICATION_JSON) .body(stores, Store.class) .switchIfEmpty(notFound); } 

Методы, позволяющие проверять, является ли Flux / Mono пустым

Использование операторов .switchIfEmpty / .defaultIfEmpty / Mono.repeatWhenEmpty

Используя упомянутые операторы, вы сможете реагировать на случай, когда Stream был завершен без каких-либо элементов. Прежде всего, помните, что операторы, такие как .map , .flatMap , .filter и многие другие, вообще не будут вызываться, если не было вызвано onNext . Это означает, что в вашем случае следующий код

 transaction.flatMap { val user = userRepository.findById(it.userId) // If it's empty, return badRequest() } return transaction.flatMap { transactionRepository.save(it).then(created(URI.create("/transaction/" + it.id)).build()) } 

вообще не будет вызываться, если transaction будет пустой

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

 transaction .flatMap(it -> { val user = userRepository.findById(it.userId) }) .swithIfEmpty(Flux.defer(() -> Flux.just(badRequest()))); 

Фактическое решение

Кроме того, я отметил, что вы создали два подпотока из основной transaction . Собственно, следующий код не будет выполнен вообще:

 transaction.flatMap { val user = userRepository.findById(it.userId) // If it's empty, return badRequest() } 

и будет выполняться только последний, который возвращается из метода. Это происходит потому, что вы не подписываетесь на использование оператора .subscrube(...) .

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

 fun createTransaction(serverRequest: ServerRequest) : Mono<ServerResponse> { val transaction = serverRequest.body(BodyExtractors.toMono(Transaction::class.java)).cache() transaction .flatMap { userRepository.findById(it.userId) } .flatMap(user -> transaction.flatMap { transactionRepository.save(it) }) .map { created(URI.create("/transaction/" + it.id)).build() } .switchIfEmpty { transaction.map {badRequest("missed User for transaction " + it.id) }} } 

Или более простой случай без обмена потоком транзакций, но с использованием Tuple :

 fun createTransaction(serverRequest: ServerRequest) : Mono<ServerResponse> { val transaction = serverRequest.body(BodyExtractors.toMono(Transaction::class.java)).cache() return transaction .flatMap { transaction -> userRepository.findById(it.userId) .map { Tuples.of(transaction, it) } .defaultIfEmpty(Tuples.of(transaction, null)) } .flatMap { if(it.getT2() != null) { return transactionRepository.save(it.getT1()) } else { return Flux.error(badRequest(...)) } } } 
Intereting Posts
метод расширения для класса утилиты из внешней библиотеки Возвращаемое значение условия if / else, но также запускает код Котлин с, если не нуль Как получить правильный тип при возврате шаблона <T?> Из статической функции с нулевым значением Обработчик ответа соответствия с запросом в VertX Как объявить и инициализировать MutableSet в Котлине? Kotlin: общая коллекция в общий массив Kotlin – не работает «привет мир» в intellij Невозможно скомпилировать функцию расширения с параметром типа reified в Kotlin Использование Kotlin в сопутствующем объекте вызывает непредвиденную ошибку Android Studio – java.io.IOException: Не удалось создать подпись v1 Инициализировать ArrayList <ArrayList <Int >> с размером в kotlin Применить @JvmStatic и @JvmField автоматически ко всем файлам в Котлине Android-устройство logcat продолжает работать Как я могу сделать параметр IntelliJ refactor-> rename только переименовать локальную версию? (Котлин)