Spring WebFlux-通过WebClient为Mono内列表中的每个元素发送HTTP请求

问题描述

我们正在尝试将MVC,resttemplate,阻止,应用程序转换为WebFlux应用程序。

在“阻塞世界”中非常简单,在请求有效负载获取一个列表,进行迭代,然后将N个http请求发送给第三方rest API。

非常重要的一点是它是第三方rest API,完全没有对它的控制,并且不能要求他们实现采用列表的版本,它必须一个一个地列出。

与resttemplate相对,请问WebFlux等效什么? 这有点挑战,因为它需要一个Mono并返回一个Mono。 一小段代码就很棒。

谢谢

@SpringBootApplication
@RestController
public class QuestionApplication {

    public static void main(String[] args) {
        SpringApplication.run(QuestionApplication.class,args);
    }

    @PostMapping("question")
    MyResponse question(@RequestBody MyRequest myRequest) {
        List<String>  myStrings = myRequest.getlistofString();
        List<Integer> myIds     = iterateAndSendRequestOneByOneGetIdFromString(myStrings);
        return new MyResponse(myIds);
    }

    private List<Integer> iterateAndSendRequestOneByOneGetIdFromString(List<String> myStrings) {
        List<Integer> ids = new ArrayList<>();
        for (String string : myStrings) {
            Integer id = new RestTemplate().postForObject("http://external-service:8080/getoneIdFromOnestring",string,Integer.class);
            ids.add(id);
        }
        return ids;
    }

//    @PostMapping("how-to-do-the-same-with-WebFlux-WebClient-please?")
//    Mono<MyResponse> question(@RequestBody Mono<MyRequest> myRequestMono) {
//        return null;
//    }

}

class MyResponse {
    private List<Integer> myIds;
}

class MyRequest {
    private List<String> strings;
}

解决方法

方法是使用Flux中的flatMap

public Mono<MyResponse> getIdsFromStrings(MyRequest myRequest) {

  WebClient client =
      WebClient.builder().baseUrl("http://external-service:8080").build();

  return Flux.fromIterable(myRequest.getStrings())
      .flatMap(s -> client.post().uri("/getOneIdFromOneString").body(s,String.class).retrieve().bodyToMono(Integer.class))
      .collectList()
      .map(MyResponse::new);
}

.flatMap是异步操作,将同时执行您的请求。您还可以选择使用flatMap的重载方法来设置并发限制(请参阅文档)。