如何使用spring webflux在功能性反应java中编写具有多个if else的复杂代码

Posted

技术标签:

【中文标题】如何使用spring webflux在功能性反应java中编写具有多个if else的复杂代码【英文标题】:How to write complex code with multiple if else in functional reactive java using spring webflux 【发布时间】:2019-09-22 01:58:38 【问题描述】:

我是 RXjava 函数式编程的新手。我正在编写具有多个条件的 post 端点:

    当 post 端点被产品击中时 如果登录用户的购物车在数据库中不存在,则创建一个新购物车 如果购物车已经存在于沙发底座中,则提取该记录并检查产品 JSON 是否给定产品 ID 已存在于产品 JSON 中。 如果它在产品 JSON 中不可用,则必须创建新产品 应使用新创建的 productId 更新购物车 如果它存在于产品 JSON 中,则获取产品记录并验证数量。 如果数量相同,则什么也不做 否则,更新记录。

我面临着在函数式编程中编写这些 if else 条件的挑战。尝试使用switchifEmpty 并无法在其中编写代码。

这是一个示例代码。

public Mono<Product> createProduct(final Tuple2<String, productdto> tuple2) 
    final Product productdto = tuple2.getT2();
    return Mono.just(tuple2.getT1())
        .map(cartRepository::findById)
        .defaultIfEmpty(cartRepository.save(
            cart.builder()
                .id(tuple2.getT1())
                .build()))
        .flatMap(cartres -> cartres)
        .flatMap(cartres -> 
             final Product product = Product.builder()
                 .id(1234)
                 .productId(productDTO.getProductId())
                 .productName(productDTO.getProductName())
                 .build();
             return productRepository.save(product)
                 .map(saveCart -> cart.builder()
                     .id(cartres.getId()).build())
                 .flatMap(cartRepository::save);
        );
    ).then(Mono.just(productDto));

【问题讨论】:

【参考方案1】:

我知道有一个复杂的 if-else-logic,您必须使用带有 .map().flatMap()defaultIfEmpty() 的 Spring WebFlux 调用的反应链来实现。

这些反应式运算符不能总是替换复杂的 if-else-logic。

必须在 .map().flatMap() 处理程序中执行 if-else-decisions。

在您的情况下,您可以为每个步骤 1..8 实现 java.util.Function&lt;&gt; 或简单方法

下面是第一个示例,该功能通过从 repo 加载或创建新的来为您提供购物车。

此外,它还展示了如何使用zipWith() 运算符向反应链添加更多数据。

这里检查数据库中产品的存在,并将结果作为布尔值传递给下游。

基于此布尔值,您可以使用 if-else-statement 来返回现有产品或创建新产品。


    public Mono<Product> createProduct(final Tuple2<String, Product> tuple2) 
        final Product productDTO = tuple2.getT2();
        return Mono.just(tuple2.getT1())
                //   .map(cartRepository::findById)
                //           .defaultIfEmpty(cartRepository.save(
                //               cart.builder()
                //                   .id(tuple2.getT1())
                //                   .build()))
                .flatMap(provideCart(tuple2)) // see implemented method further below
                .flatMap(cartres -> cartres)
                .map(cartres -> cartres)
                .zipWith(productRepository.existsById(productDTO.getId()))
                .flatMap(maybeCreateProduct(productDTO)); // see implemented method further below
    

    private Function<String, Mono<Cart>> provideCart(final Tuple2<String, Product> tuple2) 
        return id -> cartRepository.findById(id)
                .switchIfEmpty(cartRepository.save(
                        Cart.builder()
                                .id(tuple2.getT1())
                                .build()));
    

    private Function<Tuple2<Cart, Boolean>, Mono<Product>> maybeCreateProduct(Product productDTO) 
        return cartresAndProductExists -> 
            Cart cart = cartresAndProductExists.getT1();
            Boolean productExists = cartresAndProductExists.getT2();
            if (productExists) 
                return productRepository.findById(productDTO.getProductId())
             else 
                return productRepository.save(Product.builder()
                        .id("1234")
                        .productId(productDTO.getProductId())
                        .productName(productDTO.getProductName())
                        .build());
            
        ;
    

必须小心保持代码可读性并避免无休止的反应步骤链。

将复杂的步骤提取到单独的方法中,甚至可能首先重新考虑流程以获得更简单和精简的解决方案

【讨论】:

以上是关于如何使用spring webflux在功能性反应java中编写具有多个if else的复杂代码的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot Webflux 反应式 API

Spring WebFlux 教程:如何构建反应式 Web 应用程序

反应式编程:Spring WebFlux:如何构建微服务调用链?

如何使 WebFilter 在非 WebFlux/非反应式 Spring Boot 应用程序中工作?

技术使用 Spring 5 的 WebFlux 开发反应式 Web 应用

Spring webflux 和 Angular