如何检查Mono是否为空? [英] How to check if Mono is empty?

查看:3197
本文介绍了如何检查Mono是否为空?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用WebFlux框架使用Spring Boot 2.0和Kotlin开发应用程序.

I'm developing a app with Spring Boot 2.0 and Kotlin using the WebFlux framework.

我想在保存事务之前检查用户ID是否退出.我陷入了一个简单的问题,例如验证Mono是否为空.

I want to check if a user id exits before save a transaction. I'm stucked in a simple thing like validate if a Mono is empty.

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()) }
}

可以做我想做的事吗?

推荐答案

允许检查Flux/Mono是否为空的技术

The techniques that allow checking whether Flux/Mono is empty

使用运算符.switchIfEmpty/.defaultIfEmpty/Mono.repeatWhenEmpty

使用上述运算符,您将能够对Stream已完成的情况做出反应,而不会发出任何元素.

Using mentioned operators you will be able to react to the case when Stream has been completed without emitting any elements.

首先,请记住,如果没有调用onNext,则根本不会调用诸如.map.flatMap.filter之类的运算符. 这意味着在您的情况下,下一个代码

First of all, remember that operators such .map, .flatMap, .filter and many others will not be invoked at all if there no onNext has been invoked. That means that in your case next code

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为空,则完全不会调用

.

will not be invoked at all, if transaction will be empty.

如果在流程为空的情况下需要处理案件,则应按照以下方式考虑下一个操作符:

In case if there is a requirement for handling cases when your flow is empty, you should consider operators like next in the following manner:

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

实际解决方案

此外,我注意到您从主transaction创建了两个子流.实际上,以下代码将根本不会执行:

Actual solution

Also, I have noted that you created two sub-flows from the main transaction. Actually, following code will not be executed at all:

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

,并且只会执行最后一个,该方法是从方法返回的.发生这种情况是因为您没有使用运算符.subscribe(...)进行订阅.

and will be only executed the last one, which is returned from the method. That happens because you ain't subscribed using operator .subscribe(...).

第二点,您一次不能再订阅同一请求正文(WebClient的响应有一定限制).因此,您需要以另一种方式共享您的请求正文,因此完整的示例将是:

The second point, you can't subscribe to the same request body more the one time (kind of limitation for WebClient's reponse). Thus you are required to share your request body in the next way, so completed example will be:

fun createTransaction(serverRequest: ServerRequest): Mono<ServerResponse> {
    val transaction = serverRequest.body(BodyExtractors.toMono(Transaction::class.java)).cache()

    transaction
            .flatMap { userRepository.findById(it.userId) }
            .flatMap { transaction.flatMap { transactionRepository.save(it) } }
            .flatMap { ServerResponse.created(URI.create("/transaction/" + it.id)).build() }
            .switchIfEmpty(transaction.flatMap { ServerResponse.badRequest().syncBody("missed User for transaction " + it.id) })
}

或更简单的情况,不共享事务流,而是使用Tuple:

Or more simple case without sharing transaction flow but using Tuple:

fun createTransaction(serverRequest: ServerRequest): Mono<ServerResponse> {
    val emptyUser = !User()
    val transaction = serverRequest.body<Mono<Transaction>>(BodyExtractors.toMono(Transaction::class.java))

    transaction
            .flatMap { t ->
                userRepository.findById(t.userId)
                        .map { Tuples.of(t, it) }
                        .defaultIfEmpty(Tuples.of(t, emptyUser))
            }
            .flatMap {
                if (it.t2 != emptyUser) {
                    transactionRepository.save(it.t1)
                            .flatMap { ServerResponse.created(URI.create("/transaction/" + it.id)).build() }
                } else {
                    ServerResponse.badRequest().syncBody("missed User for transaction " + it.t1.id)
                }
            }
}

这篇关于如何检查Mono是否为空?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆