如何仅当 Mono 为空时才执行操作,如果非空则抛出错误

我正在尝试将项目转换为使用 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));

    }

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


慕村225694
浏览 258回答 5
5回答

慕姐8265434

经过额外的测试,并考虑了其他开发人员的反馈,我得出了以下解决方案:&nbsp; &nbsp; public Mono<User> insertUser(User user) {&nbsp; &nbsp; &nbsp; &nbsp; return userRepository.findByUsername(user.username())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .flatMap(__ -> Mono.error(new DuplicateResourceException("User already exists with username [" + user.username() + "]")))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .switchIfEmpty(Mono.defer(() -> userRepository.insertUser(user)))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .cast(User.class);&nbsp; &nbsp; }正如托马斯所说,编译器变得混乱。我的假设是因为flatMap返回一个带有错误的 Mono,并且switchIfEmpty返回一个带有用户的 Mono,因此它恢复为带有对象的 Mono(因此.cast需要额外的运算符来编译它)。另一个添加是Mono.defer在switchMap. 否则,switchIfEmpty总是会开火。我仍然愿意接受其他建议/替代方案(因为这似乎是一个相当普遍的需求/模式)。

慕仙森

我正在使用具有类型参数的抽象类,E因此我无法使用.cast(E.class).&nbsp;我们的解决方案是private&nbsp;Mono<E>&nbsp;checkIfStatementExists(E&nbsp;statement)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.statementService.getByStatementRequestId(statement.getStatementRequestId()) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.flatMap(sr&nbsp;->&nbsp;Mono.<E>error(new&nbsp;ValidationException("Statement&nbsp;already&nbsp;exists&nbsp;for&nbsp;this&nbsp;request!"))) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.switchIfEmpty(Mono.just(statement)); }我想下周我需要和同事们讨论一下这个问题。编辑。我们与同事进行了讨论,更新的代码如下。

梵蒂冈之花

为什么您会收到此编译器错误是由于以下原因。flatmap获取您已完成的内容Mono并尝试将其转换为它可以推断的任何类型。Mono.error包含一个类型,并且该类型是Object。一种方法是将您的逻辑移至平面图中。// This is just example code using strings instead of repospublic Mono<String> insertUser(String user) {&nbsp; &nbsp; return Mono.just(user)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Here we map/convert instead based on logic&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .flatMap(__ -> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (__.isEmpty())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Mono.error(new IllegalArgumentException("User already exists with username [" + user + "]"));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Mono.just(user);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }).switchIfEmpty(Mono.just(user));}switchIfEmpty恕我直言,不太适合做出逻辑决策。文档指出如果此单声道在没有数据的情况下完成,则回退到替代 Mono如果我们没有得到任何东西,这更像是一种后备措施,这样我们就可以保持数据流的继续。你也可以Mono.empty().doOnNext(o -> {&nbsp; &nbsp; &nbsp; &nbsp; throw new IllegalArgumentException("User already exists with username [" + o + "]");&nbsp; &nbsp; }).switchIfEmpty(Mono.just("hello")).subscribe(System.out::println);

DIEA

遇到了同样的问题,最后做了下面的事情,请注意:这不需要类型转换并且适用于两种情况,即如果数据库中已存在元素,则抛出错误。插入元素,否则返回 Mono。&nbsp; public Mono<UserDTO> insertUser(User user) {&nbsp; &nbsp; &nbsp;return this.userRepository.findByUsername(user.getUsername())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.flatMap(foundUser-> null != foundUser ? Mono&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.error(new UserAlreadyExistsException(ExceptionsConstants.USER_ALREADY_EXISTS_EXCEPTION))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: Mono.just(user))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.switchIfEmpty(this.userRepository.save(user))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.map(userCreated -> copyUtils.createUserDTO(userCreated));&nbsp; }

至尊宝的传说

可以通过使用一些 Java 通用魔法以 的形式Mono::cast指定 的类型来解决这个问题,而不是使用 来更改 Mono 的类型。这还有一个额外的优点,即您不需要通过向具有 null 处理的方法添加逻辑来更改 Mono 管道的流程,但实际上永远不会接收 null。Mono.errorMono.<User>error(...)flatMap这看起来如下:public Mono<User> insertUser(User user) {&nbsp; &nbsp; return userRepository.findByUsername(user.username())&nbsp; &nbsp; &nbsp; &nbsp; .flatMap(__ -> Mono.<User>error(new DuplicateResourceException("User already exists with username [" + user.username() + "]")))&nbsp; &nbsp; &nbsp; &nbsp; .switchIfEmpty(userRepository.insertUser(user));}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java