使用WebClient獲取JSON對象列表

    1.概述

    我們的服務通常與其他REST服務進行通信以獲取信息。

    從Spring 5開始,我們將使用WebClient以反應性,非阻塞的方式執行這些請求。 WebClient是新WebFlux框架的一部分,該框架基於Project Reactor構建。它具有流暢的反應式API,並且在其底層實現中使用HTTP協議。

    當我們發出Web請求時,數據通常以JSON返回。 WebClient可以為我們轉換此內容。

    在這篇文章中,我們將介紹如何將一個JSON數組轉換為Java ArrayObjectArray POJO的,和List使用POJO的WebClient

    2.依賴關係

    要使用WebClient,我們需要在pom.xml: 添加幾個依賴項pom.xml:

    <dependency>
    
     <groupId>org.springframework.boot</groupId>
    
     <artifactId>spring-boot-starter-webflux</artifactId>
    
     </dependency>
    
     <dependency>
    
     <groupId>org.projectreactor</groupId>
    
     <artifactId>reactor-spring</artifactId>
    
     <version>1.0.1.RELEASE</version>
    
     </dependency>

    3. JSON,POJO和服務

    讓我們從端點http://localhost:8080/readers開始,該端點以JSON數組的形式返回讀者及其喜愛的書籍的列表:

    [{
    
     "id": 1,
    
     "name": "reader1",
    
     "favouriteBook": {
    
     "author": "Milan Kundera",
    
     "title": "The Unbearable Lightness of Being"
    
     }
    

    我們將需要相應的ReaderBook類來處理數據:

    public class Reader {
    
     private int id;
    
     private String name;
    
     private Book favouriteBook;
    
    
    
     // getters and setters..
    
     }
    public class Book {
    
     private final String author;
    
     private final String title;
    
    
    
     // getters and setters..
    
     }

    對於我們的接口實現,我們編寫一個ReaderConsumerServiceImpl並將其作為WebClient的依賴項:

    public class ReaderConsumerServiceImpl implements ReaderConsumerService {
    
    
    
     private final WebClient webClient;
    
    
    
     public ReaderConsumerServiceImpl(WebClient webclient) {
    
     this.webclient = webclient;
    
     }
    
    
    
     // ...
    
     }

    4.映射JSON對象List

    當我們從REST請求接收到JSON數組時,有多種方法可以將其轉換為Java集合。讓我們看一下各種選項,看看處理返回的數據有多麼容易。我們將研究提取讀者最喜歡的書。

    4.1。 MonoFlux

    Project Reactor引入了Publisher: **Mono**兩種實現Publisher: **Mono****Flux**

    當我們需要處理零到許多或可能無限的結果時, Flux<T>很有用。我們可以以Twitter供稿為例。

    當我們知道一次返回所有結果時(如在用例中一樣),我們可以使用Mono<T>

    4.2。 WebClientObject數組

    首先,讓我們使用WebClient.get進行GET調用,並使用Object[]類型的Mono來收集響應:

    Mono<Object[]> response = webClient.get()
    
     .accept(MediaType.APPLICATION_JSON)
    
     .retrieve()
    
     .bodyToMono(Object[].class).log();

    接下來,讓我們將主體提取到Object數組中:

    Object[] objects = response.block();

    實際的Object這裡是包含我們的數據中的任意結構。讓我們將其轉換為Reader對象的數組。

    為此,我們需要一個ObjectMapper

    ObjectMapper mapper = new ObjectMapper();

    在這裡,我們將其聲明為內聯,儘管通常將其作為類的private static final成員來完成。

    最後,我們準備提取讀者喜愛的書籍並將其收集到列表中:

    return Arrays.stream(objects)
    
     .map(object -> mapper.convertValue(object, Reader.class))
    
     .map(Reader::getFavouriteBook)
    
     .collect(Collectors.toList());

    當我們要求Jackson的反序列化器將Object作為目標類型生成時,它實際上將JSON反序列化為一系列LinkedHashMap對象。使用convertValue後處理效率低下。如果我們在反序列化期間向Jackson提供所需的類型,則可以避免這種情況。

    4.3。帶Reader陣列的WebClient

    我們可以向WebClient提供Reader[]而不是Object[]

    Mono<Reader[]> response = webClient.get()
    
     .accept(MediaType.APPLICATION_JSON)
    
     .retrieve()
    
     .bodyToMono(Reader[].class).log();
    
     Reader[] readers = response.block();
    
     return Arrays.stream(readers)
    
     .map(Reader:getFavouriteBook)
    
     .collect(Collectors.toList());

    在這裡,我們可以看到我們不再需要ObjectMapper.convertValue 。但是,我們仍然需要進行其他轉換以使用Java Stream API並使我們的代碼與List一起使用。

    4.4。帶Reader List WebClient

    如果我們希望Jackson生成ReaderList而不是數組,則需要描述我們要創建的List 。為此,我們向該方法提供一個由匿名內部類產生的ParameterizedTypeReference

    Mono<List> response = webClient.get()
    
     .accept(MediaType.APPLICATION_JSON)
    
     .retrieve()
    
     .bodyToMono(new ParameterizedTypeReference<List>() {});
    
     List readers = response.block();
    
    
    
     return readers.stream()
    
     .map(Reader::getFavouriteBook)
    
     .collect(Collectors.toList());

    這為我們提供了我們可以使用的List

    讓我們更深入地探討為什麼需要使用**ParameterizedTypeReference** .

    當類型信息在運行時可用時,Spring的WebClient可以輕鬆地將JSON反序列化為Reader.class

    但是,對於泛型,如果我們嘗試使用List<Reader>.class ,則會發生類型擦除。因此,Jackson將無法確定泛型的類型參數。

    通過使用ParameterizedTypeReference ,我們可以克服此問題。將其實例化為匿名內部類利用了以下事實:泛型類的子類包含編譯時類型信息,該信息不受類型擦除的影響,可以通過反射使用。

    5.結論

    在本教程中,我們看到了使用WebClient處理JSON對象的三種不同方式.我們看到了指定Object數組類型和我們自己的自定義類的方法。

    然後,我們學習瞭如何使用ParameterizedTypeReference提供類型信息以生成List