[英]Use flatMap after method returning Mono<Void>
I'm stuck with understanding of some aspects of Project Reactor.我对 Project Reactor 的某些方面的理解感到困惑。
I have the following list of components:我有以下组件列表:
Mono<Void>
or Mono.error()
Mono<Void>
或Mono.error()
Mono<Item>
Mono<Item>
Mono<Void
Mono<Void
A business logic is quite simple: validate params (1), save an item to db (2) and log actions (3).业务逻辑非常简单:验证参数 (1)、将项目保存到数据库 (2) 和记录操作 (3)。 The problem is validator (1) returns
Mono.empty()
if there are no errors with input data and Mono.error()
if input params contain some errors.问题是验证器 (1) 如果输入数据没有错误,则返回
Mono.empty()
Mono.error()
如果输入参数包含一些错误,则返回 Mono.error()。
I would like to achieve the next things:我想实现以下目标:
Mono.empty()
then continue chainMono.empty()
则继续链Mono.error()
then immediately stop processing and throw error which will be handled by exceptionHanlder
Mono.error()
则立即停止处理并抛出将由exceptionHanlder
处理的错误I have tried two options:我尝试了两种选择:
First with .then(Mono<Item> item)
after validation.验证后首先使用
.then(Mono<Item> item)
。 It allows me to execute saving operation after validation.它允许我在验证后执行保存操作。 Given that
.then()
ignores any errors, I can't rise an exception.鉴于
.then()
忽略任何错误,我不能引发异常。
return inputValidator.validateFields(userId, projectId)
.then(repository.save(item))
.onErrorMap(RepoException.class, ex -> new UnexpectedError("Failed to save item", ex))
.subscribeOn(Schedulers.boundedElastic())
.doOnSuccess(n -> logService.logActivity(new Activity(adminId, n))
.subscribe());
Second with .flatMap(Function<Mono<Void>, <Mono<? extends Item> func)
after validation.第二个是
.flatMap(Function<Mono<Void>, <Mono<? extends Item> func)
验证后。 This approach can rise an exception from validator, but I can't execute saving operation because flatMap()
doesn't trigger on empty result.这种方法可能会引发验证器异常,但我无法执行保存操作,因为
flatMap()
不会触发空结果。
return inputValidator.validateFields(userId, projectId)
.flatMap(v -> repository.save(item))
.onErrorMap(RepoException.class, ex -> new UnexpectedError("Failed to save item", ex))
.subscribeOn(Schedulers.boundedElastic())
.doOnSuccess(n -> logService.logActivity(new Activity(adminId, n))
.subscribe());
It is also important to have access for created object after saving (step 2), because I need to pass it to logger service.在保存(步骤 2)后访问创建的对象也很重要,因为我需要将它传递给记录器服务。
You can't use flatMap
because there is no onNext
signal - use then
instead.您不能使用
flatMap
因为没有onNext
信号 - 使用then
代替。 Not sure what do you mean by "called" but there is a difference between Assembly and Subscription time in reactive.不知道“被调用”是什么意思,但反应中的装配时间和订阅时间之间存在差异。 Publisher you specified in
then
will not be resolved in case inputValidator.validateFields
returns onError
signal.如果
inputValidator.validateFields
返回onError
信号,您在then
中指定的发布者将不会被解析。
Here is a test for failed validation and as you may see subscription was not triggered这是验证失败的测试,您可能会看到未触发订阅
@Test
void saveWasNotCalledIfValidationFailed() {
var saveMock = PublisherProbe.of(Mono.just("id"));
var repo = mock(Repository.class);
when(repo.save())
.thenReturn(saveMock.mono());
var res = validateFields()
.then(repo.save())
.onErrorMap(IllegalArgumentException.class,
ex -> new IllegalStateException("Failed to save item", ex)
);
StepVerifier.create(res)
.expectError(IllegalStateException.class)
.verify();
saveMock.assertWasNotSubscribed();
}
private Mono<Void> validateFields() {
return Mono.error(new IllegalArgumentException("oops"));
}
public static class Repository {
public Mono<String> save() {
return Mono.just("id");
}
}
and here is a test for passed validation这是通过验证的测试
@Test
void saveIsCalledIfValidationPassed() {
var saveMock = PublisherProbe.of(Mono.just("id"));
var repo = mock(Repository.class);
when(repo.save())
.thenReturn(saveMock.mono());
var res = validateFields()
.then(repo.save())
.onErrorMap(IllegalArgumentException.class,
ex -> new IllegalStateException("Failed to save item", ex)
);
StepVerifier.create(res)
.expectNext("id")
.verifyComplete();
saveMock.assertWasSubscribed();
}
private Mono<Void> validateFields() {
return Mono.empty();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.