Функционал WebFlux: как определить пустой поток и вернуть 404?

У меня есть следующая упрощенная функция обработчика (Spring WebFlux и функциональный API с использованием Kotlin). Однако мне нужна подсказка, как определить пустой поток, а затем использовать noContent () для 404, когда поток пуст.

fun findByLastname(request: ServerRequest): Mono<ServerResponse> {
    val lastnameOpt = request.queryParam("lastname")
    val customerFlux = if (lastnameOpt.isPresent) {
        service.findByLastname(lastnameOpt.get())
    } else {
        service.findAll()
    }
    // How can I detect an empty Flux and then invoke noContent() ?
    return ok().body(customerFlux, Customer::class.java)
}

person Juergen Zimmermann    schedule 27.08.2017    source источник


Ответы (4)


От Mono:

return customerMono
           .flatMap(c -> ok().body(BodyInserters.fromObject(c)))
           .switchIfEmpty(notFound().build());

От Flux:

return customerFlux
           .collectList()
           .flatMap(l -> {
               if(l.isEmpty()) {
                 return notFound().build();

               }
               else {
                 return ok().body(BodyInserters.fromObject(l)));
               }
           });

Обратите внимание, что collectList буферизует данные в памяти, поэтому это может быть не лучшим выбором для больших списков. Может быть лучший способ решить эту проблему.

person Brian Clozel    schedule 28.08.2017
comment
модифицированный вариант тоже не работает. customerFlux.collectList() приводит к Mono, который содержит пустой список, когда исходный Flux пуст. Следовательно, Mono не является пустым (потому что он содержит пустой список) и вызывается ok (). - person Juergen Zimmermann; 28.08.2017
comment
Решение найдено. Внутри flatMap() требуется оператор if: if (l.isEmpty()) notFound()... else ok()... Then switchIfEmpty(...) здесь устарел. - person Juergen Zimmermann; 28.08.2017
comment
Это все еще лучший способ вернуть 404 на пустой Flux? - person Gavin; 29.01.2021

Используйте функцию Flux.hasElements() : Mono<Boolean>:

return customerFlux.hasElements()
                   .flatMap {
                     if (it) ok().body(customerFlux)
                     else noContent().build()
                   }
person RJ.Hwang    schedule 05.05.2019

В дополнение к решению Брайана, если вы не хотите постоянно выполнять пустую проверку списка, вы можете создать функцию расширения:

fun <R> Flux<R>.collectListOrEmpty(): Mono<List<R>> = this.collectList().flatMap {
        val result = if (it.isEmpty()) {
            Mono.empty()
        } else {
            Mono.just(it)
        }
        result
    }

И назовите это так, как вы делаете это для Mono:

return customerFlux().collectListOrEmpty()
                     .switchIfEmpty(notFound().build())
                     .flatMap(c -> ok().body(BodyInserters.fromObject(c)))
person zennon    schedule 11.01.2018

Я не уверен, почему никто не говорит об использовании функции hasElements () в Flux.java, которая вернула бы Mono.

person ayush prashar    schedule 24.04.2019