【问题标题】:Return Mono.empty() if a value is found but without executing other steps如果找到值但不执行其他步骤,则返回 Mono.empty()
【发布时间】:2019-12-21 04:55:11
【问题描述】:

这个问题很难用文字来描述,所以如果标题不符合要求,很抱歉。

我想通过 Project Reactor Flux 和 Mono 来实现一个特定的目标,乍一看这似乎很简单。

一个代码示例,在“阻塞方式”中会比长描述更好:

    fun findGroupToCreateBlocking(userId: UUID, groupLabel: String): Optional<LinkUserToGroup> {
        val group = lib.findGroupsOfUser(userId)
                .flatMapIterable { it.items }
                .filter { it.label == groupLabel }
                .toMono()
                .blockOptional()

        if(group.isPresent) {
            return Optional.empty()
        }

        return lib.searchGroups(groupLabel)
                .flatMapIterable { it.items }
                .filter { it.label == groupLabel }
                .toMono()
                .map { LinkUserToGroup(userId, it.id) }
                .switchIfEmpty { IllegalStateException("Group $groupLabel not found").toMono() }
                .blockOptional()
    }

当然,我尝试在没有block 部分的情况下实现相同的目标。我最终得到了以下代码:

fun findGroupToCreateReactive(userId: UUID, groupLabel: String): Mono<LinkUserToGroup> =
            lib.findGroupsOfUser(userId)
                    .flatMapIterable { it.items }
                    .filter { it.label == groupLabel }
                    .toMono()
                    .map { Optional.of(it) }
                    .defaultIfEmpty(Optional.empty())
                    .filter { g -> g.isEmpty }
                    .flatMap { lib.searchGroups(groupLabel)
                            .flatMapIterable { it.items }
                            .toMono()
                            .map { LinkUserToGroup(userId, it.id) }
                            .switchIfEmpty { IllegalStateException("Group $groupLabel not found").toMono() }
                    }

我认为(而且我不是唯一一个 ????)我们可以做得更好,而不是依赖流中间的 Optional 用法......但我没有找到任何其他解决方案.

这是我第四次与这种“模式”作斗争,所以欢迎一些帮助!

我在 Gitlab (here) 上生成了一个演示项目,其中包含机器人响应式和阻塞式实现的单元测试,以查看命题是否符合要求。如果需要,您可以分叉并使用该项目。

【问题讨论】:

    标签: reactive-programming project-reactor reactive


    【解决方案1】:

    我没有使用Mono.empty,而是使用Flux.hasElement 方法(如@yossarian),但添加了一个否定过滤器。它似乎可以工作,因为单元测试仍然通过。

        fun findGroupToCreateReactive(userId: UUID, groupLabel: String): Mono<LinkUserToGroup> =
                lib.findGroupsOfUser(userId)
                        .flatMapIterable { it.items }
                        .map { it.label }
                        .hasElement(groupLabel)
                        .filter { g -> !g }
                        .flatMap { lib.searchGroups(groupLabel)
                                .flatMapIterable { it.items }
                                .toMono()
                                .map { LinkUserToGroup(userId, it.id) }
                                .switchIfEmpty { IllegalStateException("Group $groupLabel not found").toMono() }
                        }
    

    由于我们只想在用户不属于某个组时才搜索组,因此使用否定过滤器可以更加明确。

    【讨论】:

      【解决方案2】:

      我没有找到一个很好的 Reactor 解决方案。但是,由于您使用的是 Kotlin,因此您可能会接受该模式并为其创建扩展函数:

          fun findGroupToCreateReactive(userId: UUID, groupLabel: String): Mono<LinkUserToGroup> =
              lib.findGroupsOfUser(userId)
                  .flatMapIterable { it.items }
                  .filter { it.label == groupLabel }
                  .toMono()
                  .switchIfEmptyOrEmpty {
                      lib.searchGroups(groupLabel)
                          .flatMapIterable { it.items }
                          .toMono()
                          .map { LinkUserToGroup(userId, it.id) }
                          .switchIfEmpty { IllegalStateException("Group $groupLabel not found").toMono() }
                  }
      
          fun <T> Mono<*>.switchIfEmptyOrEmpty(monoIfEmpty: () -> Mono<T>): Mono<T> =
              this.map { Optional.of(it) }
                  .defaultIfEmpty(Optional.empty())
                  .filter { g -> g.isEmpty }
                  .flatMap { monoIfEmpty.invoke() }
      

      hasElement 运算符的另一种选择:

          fun findGroupToCreateReactive(userId: UUID, groupLabel: String): Mono<LinkUserToGroup> =
              lib.findGroupsOfUser(userId)
                  .flatMapIterable { it.items }
                  .filter { it.label == groupLabel }
                  .toMono()
                  .hasElement()
                  .flatMap { hasElement ->
                      if (hasElement)
                      {
                          return@flatMap Mono.empty<LinkUserToGroup>()
                      } else
                      {
                          lib.searchGroups(groupLabel)
                              .flatMapIterable { it.items }
                              .toMono()
                              .map { LinkUserToGroup(userId, it.id) }
                              .switchIfEmpty { IllegalStateException("Group $groupLabel not found").toMono() }
                      }
                  }
      

      PS:感谢您的示例回购。这真的有助于尝试不同的事情!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-31
        • 2017-04-08
        • 1970-01-01
        相关资源
        最近更新 更多