如果找到值则返回 Mono.empty() 但不执行其他步骤

问题描述 投票:0回答:2

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

我想通过 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
2个回答
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() }
                    }

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


0
投票

我没有找到一个很好的 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:感谢您提供示例存储库。这确实有助于尝试不同的事情!

© www.soinside.com 2019 - 2024. All rights reserved.