繁体   English   中英

在方法返回 Mono 后使用 flatMap<Void>

[英]Use flatMap after method returning Mono<Void>

我对 Project Reactor 的某些方面的理解感到困惑。

我有以下组件列表:

  1. 输入参数的验证器,返回Mono<Void>Mono.error()
  2. 服务将数据保存到数据库,返回Mono<Item>
  3. 记录用户成功操作的记录器,返回Mono<Void

业务逻辑非常简单:验证参数 (1)、将项目保存到数据库 (2) 和记录操作 (3)。 问题是验证器 (1) 如果输入数据没有错误,则返回Mono.empty() Mono.error()如果输入参数包含一些错误,则返回 Mono.error()。

我想实现以下目标:

  1. 如果验证器返回Mono.empty()则继续链
  2. 如果验证器返回Mono.error()则立即停止处理并抛出将由exceptionHanlder处理的错误

我尝试了两种选择:

验证后首先使用.then(Mono<Item> item) 它允许我在验证后执行保存操作。 鉴于.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());

第二个是.flatMap(Function<Mono<Void>, <Mono<? extends Item> func)验证后。 这种方法可能会引发验证器异常,但我无法执行保存操作,因为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());

在保存(步骤 2)后访问创建的对象也很重要,因为我需要将它传递给记录器服务。

您不能使用flatMap因为没有onNext信号 - 使用then代替。 不知道“被调用”是什么意思,但反应中的装配时间和订阅时间之间存在差异。 如果inputValidator.validateFields返回onError信号,您在then中指定的发布者将不会被解析。

这是验证失败的测试,您可能会看到未触发订阅

@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");
    }
}

这是通过验证的测试

@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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM