我正在使用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()) }
}
有可能做我想要的吗?
允许检查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()
}
并且只会执行从方法返回的最后一个。这是因为您没有使用运算符.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)
}
}
}
首先让我说我是反应(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);
}