如何检查 Mono 是否为空?

新手上路,请多包涵

我正在使用 WebFlux 框架开发带有 Spring Boot 2.0 和 Kotlin 的应用程序。

我想在保存交易之前检查用户 ID 是否存在。我陷入了一个简单的事情,比如验证 Mono 是否为空。

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

有可能做我想做的事吗?

原文由 voliveira89 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 3.2k
1 个回答

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

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

使用提到的运算符,您将能够在 Stream 完成时对情况做出反应,而无需发出任何元素。

First of all, remember that operators such .map , .flatMap , .filter and many others will not be invoked at all if there no 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 为空

如果需要在流程为空时处理情况,则应按以下方式考虑像 next 这样的运算符:

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

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

第二点,您不能一次订阅同一个请求主体(对 WebClient 的响应的一种限制)。因此,您需要以下一种方式共享您的请求正文,因此完整的示例将是:

 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

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

原文由 Oleh Dokuka 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题