允许检查Flux
/Mono
是否为空的技术
使用操作符.switchIfEmpty
/.defaultIfEmpty
/Mono.repeatWhenEmpty
使用上述操作符,您将能够对流已完成但未发出任何元素的情况做出反应。
首先,请记住,如果没有调用onNext
,那么诸如.map
、.flatMap
、.filter
等操作符根本不会被调用。
这意味着在您的情况下,下一个代码
transaction.flatMap {
val user = userRepository.findById(it.userId)
}
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.flatMap {
val user = userRepository.findById(it.userId)
}
只有最后一个被执行并从该方法返回,这是因为您没有使用运算符 .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)
}
}
}