【发布时间】:2021-05-09 22:31:43
【问题描述】:
基本上,我想要实现的是调用第二个存储库(ReactiveCrudRepository)或抛出异常,具体取决于调用第一个存储库的结果。
我最初的想法是这样的:
/** Reactive with blocking code */
public Flux<SecondThing> getThings(String firstThingName) {
FirstThing firstThing = firstRepo
.findByName(firstThingName)
// Warning: "Inappropriate blocking method call"
.blockOptional() // this fails in test-context
.orElseThrow(() -> new FirstThingNotFound(firstThingName));
return secondRepo.findAllByFirstThingId(firstThing.getId());
}
这对应于以下非反应性方法:
/** Non-reactive */
public List<SecondThing> getThings(String firstThingName) {
FirstThing firstThing = firstRepo
.findByName(firstThingName)
.orElseThrow(() -> new FirstThingNotFound(firstThingName));
return secondRepo.findAllByFirstThingId(firstThing.getId());
}
我还没有找到一种以反应式非阻塞方式执行此操作的方法。如果第一次调用出现空的Mono,我只需要抛出一个错误,如果不为空则继续管道;但我似乎无法在这里正确使用onErrorStop 或doOnError,并且map 没有帮助,因为它跳过了空的Mono。
如果我使用id 而不是name,我有一个解决方法,但我对它不太满意,因为它在FirstThing 的实例但没有@ 的情况下表现出不同的行为987654332@链接到它:
/** Reactive workaround 1 */
public Flux<SecondThing> getThings(Long firstThingId) {
return secondRepo
.findAllByFirstThingId(firstThingId)
.switchIfEmpty(
Flux.error(() -> new FirstThingNotFound(firstThingName))
);
}
我发现的另一种解决方法如下,它将空的 Mono 替换为 null 值,但它看起来不正确并且也会引发警告:
/** Reactive workaround 2 */
public Flux<SecondThing> getThings(String firstThingName) {
return firstRepo
.findByName(firstThingName)
// Warning: "Passing 'null' argument to parameter annotated as @NotNull"
.defaultIfEmpty(null)
.flatMapMany(
firstThing -> secondRepo.findAllByFirstThingId(firstThing.getId()
)
.onErrorMap(
NullPointerException.class, e -> new FirstThingNotFound(firstThingName)
);
}
将调用链接到两个存储库的正确方法是什么,以便FirstThing 与请求的firstThingName 的存在或不存在决定对第二个存储库的调用?
【问题讨论】:
-
没有仔细看,但请注意,如果反应流为空,则反应流不会继续。所以,在我看来,您可以只调用 get firstThingName,如果它返回为空,则不会调用 getFirstThing,所以有问题吗?
-
@K.Nicholas 问题是,我想在没有找到 FirstThing 时抛出异常。所以我想有人可以将我的问题改写为:“如何从空的 Mono 映射到错误?”
-
好吧,如果 firstRepo 返回一个 Optional 那么你可以做 'orElseThrow' 。我认为这是最干净的答案。
.map(op->op.orElseThrow(()->new IllegalArgumentException("name not found"))) -
@K.Nicholas 同意,但
ReactiveCrudRepository返回Mono并将其转换为Optional需要阻塞操作,我试图避免这种操作。您的建议需要Mono<Optional<FirstThing>>才能工作。在我的情况下这是不可能的,因为存储库类是自动生成的,但我会把这个想法留到其他时间。
标签: reactive-programming spring-webflux project-reactor