如何以反应方式编写此简单代码?

时间:2018-07-13 16:39:07

标签: java spring spring-webflux project-reactor

我是项目反应堆的新手,在以下用例中很难找到一个干净的解决方案。

我的用例:

我想在数据库中保存一个新对象。如果对象已经存在于数据库中,那么我想发送一个错误响应,否则我想保存它并将保存的对象返回给客户端。

在受阻止的Web MVC应用程序中,代码如下所示:

    @PostMapping("/cards")
    public ResponseEntity<?> addCard(@RequestBody Card card) {
        Card c = repo.findOneByWord(card.getWord());

        if(c == null) {
            Card savedCard = repo.save(card);
            return ResponseEntity.ok(savedCard);
        }

        return ResponseEntity.unprocessableEntity().body("Card already exists");
    }

我的非阻塞式webflux方法:

@PostMapping("/cards")
public Mono<ResponseEntity<?>> addCard(@RequestBody Card card) {

    return repo.findOneByWord(card.getWord())
            .map(c -> {
                return new Card();
            })
            .switchIfEmpty(Mono.defer(() -> repo.save(card)))
            .map(c -> {
                if (c.getWord() == null) {
                    return ResponseEntity.unprocessableEntity().body("Card already exists.");
                }

                return ResponseEntity.ok(c);
            });
}

代码工作正常,但可读性很差,感觉更像是一种解决方法...

关于如何使它更清晰/可读性的任何建议?

1 个答案:

答案 0 :(得分:0)

我将通过以下方式重写该代码:

@PostMapping("/cards")
public Mono<ResponseEntity<?>> addCard(@RequestBody Card card) {

    return repo.findOneByWord(card.getWord())                     // (1)

               .map(c ->                                          // (2)
                   ResponseEntity.unprocessableEntity()           // (2.1)
                                 .body("Card already exists.")    //
               )                                                  // 

               .switchIfEmpty(                                    // (3)
                   repo.save(card)                                // (3.1)
                       .map(c -> ResponseEntity.ok(c)             // (3.2)
               );                                                 //
}
  1. 执行数据库查询,该查询可能返回带有值或空响应的Mono
  2. 仅在返回值的情况下,才会执行后续的.map,因此我们会将卡映射到422响应
  3. 否则,在数据库中没有这样的购物车的情况下,将跳过.map函数,因此将订阅传递给.switchIfEmpty的发布者。 注意,不必将后备Mono(第3.1点)的创建包装到Mono.defer中,因为只有在订阅给定流的情况下才会发生实际元素的存储。因此,由于仅在处理swithIfEmpty时执行该执行,因此我们可以减少不必要的包装。最后,在点(3.2),结果将与存储的Card对象映射到200响应。