![](/img/trans.png)
[英]Spring WebFlux: block() method return null in Spring Data Reactive MongoDB
[英]Spring WebFlux: Reactive MongoDB
我是Spring Reactor的新手,所以我想重構這個簡單的spring數據(在kotlin上):
fun save(user: User): Mono<User> {
if (findByEmail(user.email).block() != null) {
throw UserAlreadyExistsException()
}
user.password = passwordEncoder.encode(user.password)
return userRepository.save(user)
}
謝謝
這樣的事情應該起作用:
open fun save(req: ServerRequest): Mono<ServerResponse> {
logger.info { "${req.method()} ${req.path()}" }
return req.bodyToMono<User>().flatMap {
// You might need to "work out" this if since I don't know what you are doing
if (null != findByEmail(it.email).block()) {
throw UserAlreadyExistsException()
}
it.password = passwordEncoder.encode(it.password)
repository.save(it).flatMap {
logger.debug { "Entity saved successfully! Result: $it" }
ServerResponse.created(URI.create("${req.path()}/${it.id}")).build()
}
}
}
注意,我正在使用MicroUtils / kotlin-logging 。 如果您不知道或只是不想刪除它們,請刪除它們。
基本上,您需要首先“消費”(aka 訂閱 ) ServerRequest
中的內容,以訪問內容。
另外,除了引發異常外,您還可以使用處理該情況的實際流程; 就像是:
open fun ...
return ServerResponse.ok()
// Keep doing stuff here...if something is wrong
.switchIfEmpty(ServerResponse.notFound().build())
}
如果確實要傳遞示例而不是
ServerRequest
則可以將示例調整為您的User
類型。
(如果Kotlin語法錯誤,並且我使用Java風格:o,請原諒我)
fun save(user: User): Mono<User> {
//we'll prepare several helpful Monos and finally combine them.
//as long as we don't subscribe to them, nothing happens.
//first we want to short-circuit if the user is found (by email).
//the mono below will onError in that case, or be empty
Mono<User> failExistingUser = findByEmail(user.email)
.map(u -> { throw new UserAlreadyExistsException(); });
//later we'll need to encode the password. This is likely to be
//a blocking call that takes some time, so we isolate that call
//in a Mono that executes on the Elastic Scheduler. Note this
//does not execute immediately, since it's not subscribed to yet...
Mono<String> encodedPassword = Mono
.fromCallable(() -> passwordEncoder.encode(user.password))
.subscribeOn(Schedulers.elastic());
//lastly the save part. We want to combine the original User with
//the result of the encoded password.
Mono<User> saveUser = user.toMono() //this is a Kotlin extension
.and(encodedPassword, (u, p) -> {
u.password = p;
return u;
})
//Once this is done and the user has been updated, save it
.flatMap(updatedUser -> userRepository.save(updatedUser));
//saveUser above is now a Mono that represents the completion of
//password encoding, user update and DB save.
//what we return is a combination of our first and last Monos.
//when something subscribes to this combination:
// - if the user is found, the combination errors
// - otherwise, it subscribes to saveUser, which triggers the rest of the process
return failExistingUser.switchIfEmpty(saveUser);
}
沒有中介變量或注釋的簡化版本:
fun save(user: User): Mono<User> {
return findByEmail(u.email)
.map(u -> { throw new UserAlreadyExistsException(); })
.switchIfEmpty(user.toMono())
.and(Mono.fromCallable(() -> passwordEncoder.encode(user.password))
.subscribeOn(Schedulers.elastic()),
(u, p) -> {
u.password = p;
return u;
})
.flatMap(updatedUser -> userRepository.save(updatedUser));
}
您可以在Mono中使用hasElement()
函數。 看一下Mono的擴展功能:
inline fun <T> Mono<T>.errorIfEmpty(crossinline onError: () -> Throwable): Mono<T> {
return this.hasElement()
.flatMap { if (it) this else Mono.error(onError()) }
}
inline fun <T> Mono<T>.errorIfNotEmpty(crossinline onError: (T) -> Throwable): Mono<T> {
return this.hasElement()
.flatMap { if (it) Mono.error(onError.invoke(this.block()!!)) else this }
}
switchIfEmpty
的問題在於,它總是評估在參數中傳遞的表達式-編寫此類代碼將始終產生Foo對象:
mono.switchIfEmpty(Foo())
您可以編寫自己的擴展名以延遲傳入參數的惰性求值表達式:
inline fun <T> Mono<T>.switchIfEmpty(crossinline default: () -> Mono<T>): Mono<T> {
return this.hasElement()
.flatMap { if (it) this else default() }
}
這是另外兩個擴展功能-您可以使用它們來檢查密碼是否正確:
inline fun <T> Mono<T>.errorIf(crossinline predicate: (T) -> Boolean, crossinline throwable: (T) -> Throwable): Mono<T> {
return this.flatMap { if (predicate(it)) Mono.error(throwable(it)) else Mono.just(it) }
}
inline fun <T> Mono<T>.errorIfNot(crossinline predicate: (T) -> Boolean, crossinline throwable: (T) -> Throwable): Mono<T> {
return this.errorIf(predicate = { !predicate(it) }, throwable = throwable)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.