如何仅在 Mono 为空时执行操作并在非空时抛出错误

cga*_*ill 10 java spring spring-boot spring-webflux

我正在尝试将项目转换为使用 Spring WebFlux,但在使一些基本业务逻辑正常工作时遇到了问题。我有一个负责检索/持久化记录的存储库层和一个负责应用程序业务规则的服务层。我想要做的(在服务中)层是检查给定用户名的用户是否已经存在。如果是这样,我想回复一个错误。如果没有,我想允许插入发生。

我在存储库层调用一个方法,该方法将通过用户名查找用户,如果找不到,它将返回一个空的 Mono。这按预期工作;但是,我尝试了 flatMap 和(defaultIfEmpty 和 swithIfEmpty)的各种组合,但无法编译/构建。

    public Mono<User> insertUser(User user) {
        return userRepository.findByUsername(user.username())
            .flatMap(__ -> Mono.error(new DuplicateResourceException("User already exists with username [" + user.username() + "]")))
            .switchIfEmpty(userRepository.insertUser(user));
    }
Run Code Online (Sandbox Code Playgroud)

我得到的错误是Mono<Object> cannot be converted to Mono<User>,所以swithIfEmpty似乎没有反映适当的类型,并且转换似乎也不起作用。

cga*_*ill 14

经过额外的测试,并考虑到我的开发人员的反应,我找到了以下解决方案:

    public Mono<User> insertUser(User user) {
        return userRepository.findByUsername(user.username())
            .flatMap(__ -> Mono.error(new DuplicateResourceException("User already exists with username [" + user.username() + "]")))
            .switchIfEmpty(Mono.defer(() -> userRepository.insertUser(user)))
            .cast(User.class);
    }
Run Code Online (Sandbox Code Playgroud)

正如托马斯所说,编译器很困惑。我的假设是因为flatMap正在返回一个带有错误的 Mono 并且switchIfEmpty正在返回一个带有用户的 Mono,因此它恢复为带有对象的 Mono(因此需要额外的.cast运算符来编译它)。

另一个添加是Mono.deferswitchMap. 否则,switchIfEmpty总是在开火。

我仍然对其他建议/替代方案持开放态度(因为这似乎是一个相当普遍的需求/模式)。


hej*_*itk 6

我正在使用具有类型参数的抽象类,E因此我无法使用.cast(E.class). 我们的解决方案是

private Mono<E> checkIfStatementExists(E statement) {
    return this.statementService.getByStatementRequestId(statement.getStatementRequestId())
            .flatMap(sr -> Mono.<E>error(new ValidationException("Statement already exists for this request!")))
            .switchIfEmpty(Mono.just(statement));
}
Run Code Online (Sandbox Code Playgroud)

我想下周我需要和同事们讨论一下这个问题。

编辑。我们与同事进行了讨论,更新后的代码如下。