当前位置: 首页 > 知识库问答 >
问题:

使用Webclient-Webflux将两个api响应合并为一个

何峰
2023-03-14

我正在使用WebFlux和WebClient,需要使用两个API并合并其响应。

第一个API接收类型和文档编号并返回一个列表,其中包含一个包含客户数据的元素(这就是它的定义方式)。

第二个API接收客户id并返回客户付款列表。

我需要使用这两个API并返回一个包含客户数据及其付款的实体。

API客户响应

public class CustomerResponseApi {
    private List<CustomerApi> clientList;
}
public class CustomerApi {
    private int customerId;
    private String documentNumber;
    private String documentType;
    private String firstName;
    private String lastName;
}

API付款响应

public class PaymentResponseApi {
    private int customerId;
    private LocalDate paymentDate;
    private float amount;
    private String paymentType;
}

最后我应该吃这个

CustomerResponse.java

public class CustomerResponse {
    private int customerId;
    private String documentNumber;
    private String documentType;
    private String firstName;
    private String lastName;
    
    private List<PaymentResponseApi> payments;
}

我有一个代理类负责进行API调用

CustomerProxy。Java语言

public class CustomerProxy {

    @Value("${api.base-url}")
    private String baseUrl;

    public Mono<CustomerResponseApi> getCustomer(String documentType, String documentNumber) {
        log.info("baseUrl: {}", baseUrl);
        WebClient webClient = WebClient.create(baseUrl);

        return webClient.get()
                .uri(uri -> uri
                        .path("/customers")
                        .queryParam("documentNumber", documentNumber)
                        .queryParam("documentType", documentType)
                        .build()
                )
                .retrieve()
                .bodyToMono(CustomerResponseApi.class);
    }
}

付款代理。Java语言

public class PaymentProxy {

    @Value("${api.base-url}")
    private String baseUrl;

    public Flux<PaymentResponseApi> getCustomerPayment(int customerId) {
        log.info("baseUrl: {}", baseUrl);
        WebClient webClient = WebClient.create(baseUrl);

        return webClient.get()
                .uri(uri -> uri
                        .path("/payments")
                        .queryParam("customerId", customerId)
                        .build()
                )
                .retrieve()
                .bodyToFlux(PaymentResponseApi.class);
    }
}

以及负责合并响应CustomerServiceImpl的服务。Java语言

public class CustomerServiceImpl implements CustomerService {
    
    @Autowired
    private CustomerProxy customerProxy;
    
    @Autowired
    private PaymentProxy paymentProxy;

    @Override
    public Mono<CustomerResponse> getCustomerAndPayments(String documentType, String documentNumber) {
        return customerProxy.getCustomer(documentType, documentNumber).flatMap(resp -> {
            CustomerApi customerApi = resp.getClientList().get(0); //always returns one customer
            
            // Here is my problem, because getCustomerPayment method returns a Flux
            List<PaymentResponseApi> payments = paymentProxy.getCustomerPayment(customerApi.getCustomerId());
            
            CustomerResponseBuilder customerBuilder = CustomerResponse.builder()
                    .customerId(customerApi.getCustomerId())
                    .documentNumber(customerApi.getDocumentNumber())
                    .documentType(customerApi.getDocumentType())
                    .firstName(customerApi.getFirstName())
                    .lastName(customerApi.getLastName())
                    .payments(payments);
            
            return Mono.just(customerBuilder.build());
        });
    }
}

共有2个答案

轩辕海
2023-03-14

在这种情况下,可以缓存第一次调用的结果,以防止调用API两次。

有时,通过创建一个包装类来不处理tuple,使用zip操作符也更容易。在这种情况下,需要付款的客户:

public class CustomerWithPayments {
    private final CustomerApi customerApi;
    private final List<PaymentResponseApi> paymentResponseApis;
}

缓存API结果的解决方案:

public Mono<CustomerResponse> getCustomerAndPayments(String documentType, String documentNumber) {
    Mono<CustomerApi> customerMono = customerProxy.getCustomer(documentType, documentNumber)
            .map(resp -> resp.getClientList().get(0))
            .cache();
    Mono<List<PaymentResponseApi>> paymentResponseMono = customerMono.map(CustomerApi::getCustomerId)
            .flatMapMany(paymentProxy::getCustomerPayment)
            .collectList();

    return customerMono.zipWith(paymentResponseMono, CustomerWithPayments::new)
            .map(customerWithPayments -> {
                CustomerApi customer = customerWithPayments.getCustomerApi();
                List<PaymentResponseApi> payments = customerWithPayments.getPaymentResponseApis();
                return CustomerResponse.builder()
                        .customerId(customer.getCustomerId())
                        .documentNumber(customer.getDocumentNumber())
                        .documentType(customer.getDocumentType())
                        .firstName(customer.getFirstName())
                        .lastName(customer.getLastName())
                        .payments(payments)
                        .build();
            });
}
钱言
2023-03-14

解决此问题的两种方法:

  1. 使用嵌套贴图:
public Mono<CustomerResponse> getCustomerAndPayments(String documentType, String documentNumber) {

    return customerProxy.getCustomer(documentType, documentNumber)
        .map(resp -> resp.getClientList().get(0))
        .flatMap(customerApi -> {
          Flux<PaymentResponseApi> paymentProxyFlux = paymentProxy.getCustomerPayment(customerApi.getCustomerId());
          return paymentProxyFlux.collectList()
              .map(payments -> {
                CustomerResponseBuilder customerBuilder = CustomerResponse.builder()
                    .customerId(customerApi.getCustomerId())
                    .documentNumber(customerApi.getDocumentNumber())
                    .documentType(customerApi.getDocumentType())
                    .firstName(customerApi.getFirstName())
                    .lastName(customerApi.getLastName())
                    .payments(payments);
                return customerBuilder.build();
              });
        });


  }

因此,基本上使用Method od2您需要:

  public Mono<CustomerResponse> getCustomerAndPayments(String documentType, String documentNumber) {


    Mono<CustomerApi> customerApiMono =  customerProxy.getCustomer(documentType, documentNumber)
        .map(resp -> resp.getClientList().get(0));
    Mono<List<PaymentResponseApi>> paymentResponseApiListMono = customerApiMono
        .flatMapMany(customerApi -> paymentProxy.getCustomerPayment(customerApi.getCustomerId()))
        .collectList();

    return customerApiMono.zipWith(paymentResponseApiListMono)
        .map(tuple -> {
          CustomerApi customerApi = tuple.getT1();
          List<PaymentResponseApi> payments = tuple.getT2();
          CustomerResponseBuilder customerBuilder = CustomerResponse.builder()
              .customerId(customerApi.getCustomerId())
              .documentNumber(customerApi.getDocumentNumber())
              .documentType(customerApi.getDocumentType())
              .firstName(customerApi.getFirstName())
              .lastName(customerApi.getLastName())
              .payments(payments);
          return customerBuilder.build();
        });

  }

方法2的缺点:Api1即客户API将被订阅两次。

 类似资料:
  • 问题内容: 如何将这两个JToken合并为一个JToken。听起来应该很简单,但无法解决。 谢谢您的帮助! 到目前为止,这是我尝试过的: 我首先将第一个对象分配给变量,然后尝试将其连接到第二个变量。我有一个循环,可以带回具有三个字段的多个页面。最终目标是抓取每个页面并创建一个包含所有页面的大J。 像这样的东西: 问题答案: 您可以用来将一个合并到另一个。请注意,可以控制数组的合并方式。从Enume

  • 我有两个微服务,用户微服务和订单微服务。 因此客户端只需要调用一个endpointhttp://localhost:9090/api/getdetail 我们如何在API网关级别实现这一点?

  • 问题内容: 结合这两个查询的正确语法是什么? 和 我试过了: 但我收到“ UNION和ORDER BY的用法不正确”。 编辑 此外,我希望结果在一行中返回。这样我就可以访问php中的值,例如 根据西蒙的建议,我不应该使用UNION,因为我想返回一行数据 问题答案: 您不能先进入,然后再进入。 编辑 但是你可以 将ORDER BY或LIMIT应用于单个SELECT,将子句放在包围SELECT的括号内

  • 我已经开始编写两个web应用程序项目 使用Spring REST API的移动客户端的RESFful API 我的问题是,两个Web应用程序都使用相同的数据库,我认为,而不是有两个Web应用程序,我实际上应该开始这个项目,只使用一个Web应用程序来处理Web和移动客户端的请求。 我现在遇到的问题是,我不知道如何“合并”这两个家伙,以及我是否应该坚持使用Spring RESTAPI,或者是否应该使用

  • 问题内容: 如何合并这两个SQL语句? 两个表中都存在hits10,hits11和hits12。 问题答案: 使用UNION查询-只需在两个查询之间填入“ UNION”即可: 更新 将联合包装在另一个查询中:

  • 我有两个(或更多)