英文:
Spring Webflux How to do call 2 different services sequentially without blocking?
问题
我遇到了与WebFlux有关的问题。
让我描述一下我想要同步执行的内容。
首先,我想要将产品保存到数据库并获得生成的ID。
接下来,我想要保存产品的评论,带有产品ID。
我希望能在一个微服务控制器的单个服务调用中完成这些操作。我不清楚在没有阻塞的情况下如何在控制器中实现这一点(我知道这是不应该做的事情)。
我将数据发送到我的RestController,如下所示:
{
  "name": "product 1",
  "weight": 5,
  "reviews": [
    {
      "rating": 5,
      "post": "review post"
    },
    {
      "rating": 10,
      "post": "Second review post"
    }
  ]
}
public class MyService {
  // 这将调用另一个微服务并返回带有保存的产品的Mono
  public Mono<Product> saveProduct(Product product) { ... }
  // 这将调用另一个微服务来保存评论
  public Mono<Void> saveReview(Review review) { ... }
}
@RestController
public class MyController {
  @Autowired
  MyService service;
  
  @PostMapping("/composite-product")
  public Mono<Void> saveCompositeProduct(CompositeProduct cp) {
    // 此时id为空
    Product product = new Product(cp.getName(), cp.getWeight());
   
    return service.saveProduct(product)
      .flatMapMany(savedProduct -> {
         if(cp.getReviews() == null) return Flux.empty();
         
         // 我向评论添加产品id
         List<Review> reviews = cp.getReviews().stream()
           .map(review -> new Review(savedProduct.getId(), review.getRating(), review.getPost()))
           .collect(Collectors.toList());
        // 我尝试保存评论,但不起作用,因为没有任何东西订阅它。
        // 我不想添加任何类型的subscribe方法或block方法,我知道在WebFlux应用程序中这样做是错误的
         return Flux.fromIterable(reviews)
           .flatMap(r -> service.saveReview(r));
      }).then();
  }
}
我该如何让这个工作起来?
英文:
I am having an issue with webflux
let me describe what I want to do synchronously.
First, I want to save a product to the db and get a generated ID
Next I want to save reviews of the product with productId.
I want to do this in one service call to the microservice controller. I do not see how this can be accomplished in controller without blocking (which I know is something I should not do)
I am sending data like the following to my restcontroller
{
  name: "product 1",
  weight: 5,
  reviews: [
  {
      rating: 5,
      post: "review post"
  }, {
     rating: 10,
     post: "Second review post"
  }]
}
public class MyService {
  //This will call another micro-service and returns a Mono with the saved product
  public Mono<Product> saveProduct(Product product) { ... }
  //This will call another micro-service to save the review
  public Mono<Void> saveReview(Review review) { ... }
}
@RestController
public class MyController {
@Autowired
MyService service;
@PostMapping("/composite-product")
public Mono<Void> saveCompositeProduct(CompositeProduct cp) {
  // The id is null at this time
  Product product = new Product(cp.getName(), cp.getWeight());
 
  return service.saveProduct(product)
    .flatMapMany(savedProduct -> {
       if(cp.getReviews() == null) return Flux.empty();
       
       // I add the product id to the review
       List<Review> reviews = cp.getReviews().stream()
         .map(review -> new Review(savedProduct.getId(), review.getRating(), review.getPost())
         .collect(Collectors.toList());
      // I try to save the reviews but it does not work because nothing ever 
      //subscribes to it. I do not want to add any type of subscribe method
      // or block method which I know is wrong to have in a webflux application
       return Flux.fromIterable(reviews)
         .map(r -> service.saveReview(r));
    }).then();
}
How can I make this work?
答案1
得分: 0
使用flatMap而不是map操作符。flatMap内部像flatMapMany一样订阅了Mono,就像Flux订阅一样。
return Flux.fromIterable(reviews)
           .flatMap(r -> service.saveReview(r));
英文:
Use flatMap instead of map operator. flatMap subscribes to Mono internally just like flatMapMany does to Flux.
return Flux.fromIterable(reviews)
           .flatMap(r -> service.saveReview(r));
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论