1. 概述
我們知道,HttpClient 類,自 Java 11 引入以來,用於從服務器請求 HTTP 資源。它支持同步和異步編程模式。
在本教程中,我們將探索如何將 HTTP 響應映射到 Plain Old Java Object (POJO) 類中的不同方法。
2. 示例設置
讓我們編寫一個簡單的程序,Todo。該程序將消費一個假 REST API。我們將執行一個 GET 請求,並在稍後操作響應。
2.1. Maven 依賴
我們將使用 Maven 管理我們的依賴項。讓我們將 Gson 和 Jackson 依賴添加到我們的 pom.xml 中,以便在我們的程序中使用這些庫:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.0</version>
</dependency>2.2. 示例項目
在本教程中,我們將使用一個虛假的 REST API 進行快速原型設計。
首先,讓我們查看在發出 GET 請求時,示例 API 的響應:
[
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
},
]樣本API返回一個包含四個屬性的JSON響應。JSON響應包含多個對象,但為了簡化,我們跳過了它們。
接下來,我們創建一個POJO類用於數據綁定。類字段與JSON數據屬性相匹配。我們將包含構造函數、getter、setter、equals()和toString()。
public class Todo {
int userId;
int id;
String title;
boolean completed;
// Standard constructors, getters, setters, equals(), and toString()
}然後,讓我們創建一個名為 TodoAppClient</em/> 的類,其中包含我們的邏輯:
public class TodoAppClient {
ObjectMapper objectMapper = new ObjectMapper();
Gson gson = new GsonBuilder.create();
// ...
}我們還創建了新的 ObjectMapper 和 GsonBuilder 實例。 這使得它對任何方法都可訪問且可重用。 在方法內部創建 ObjectMapper 實例可能是一種昂貴的操作。
最後,我們將編寫一個方法,該方法在樣本 API 上同步執行 GET 請求:
public class TodoAppClient {
// ...
String sampleApiRequest() throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://jsonplaceholder.typicode.com/todos"))
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
return response.body();
}
// ...
}ofString() 方法來自 BodyHandlers,用於將響應體字節轉換為 String。 響應是一個 JSON String,方便在程序中進行操作。 在後續章節中,我們將探討如何將響應映射到 POJO 類。
讓我們為sampleApiRequest() 方法編寫一個單元測試:
@Test
public void givenSampleRestApi_whenApiIsConsumedByHttpClient_thenCompareJsonString() throws Exception {
TodoAppClient sampleApi = new TodoAppClient();
assertNotNull(sampleApi.sampleApiRequest());
}測試確認API調用響應結果不為null。
3. 使用 Jackson 將響應映射到 POJO 類
Jackson 是一個流行的 Java JSON 庫。 它有助於將 JSON 序列化和反序列化,以便進行進一步的操縱。 我們將使用它來反序列化示例設置中的 JSON 響應。 我們將把響應映射到 Todo POJO 類。
讓我們增強包含我們客户端邏輯的類。 我們將創建一個新方法並調用 sampleApiRequest() 方法以使響應可供映射:
public Todo syncJackson() throws Exception {
String response = sampleApiRequest();
Todo[] todo = objectMapper.readValue(response, Todo[].class);
return todo[0];
}接下來,我們聲明瞭一個名為 Todo 的數組。最後,我們調用了 ObjectMapper 中的 readValue() 方法,將 JSON 字符串映射到 POJO 類。
讓我們通過將返回的 Todo 與一個預期的 Todo 實例進行比較來測試該方法:
@Test
public void givenSampleApiCall_whenResponseIsMappedByJackson_thenCompareMappedResponseByJackson() throws Exception {
Todo expectedResult = new Todo(1, 1, "delectus aut autem", false);
TodoAppClient jacksonTest = new TodoAppClient();
assertEquals(expectedResult, jacksonTest.syncJackson());
}測試將預期結果與映射的 JSON 進行比較。它確認兩者相等。
4. 使用 Gson 將響應映射到 POJO 類
Gson 是 Google 開發的 Java 庫。它在 Java 生態系統中非常流行,與 Jackson 同樣受歡迎。它能夠幫助將 JSON 字符串映射到 Java 對象,以便進行進一步的處理。該庫還可以將 Java 對象轉換為 JSON。
我們將使用它將示例設置中的 JSON 響應映射到其對應的 POJO 類 Todo。讓我們在包含我們邏輯的類中編寫一個新的方法 syncGson()。
我們將調用 sampleApi() 以使 JSON 字符串可用,以便進行反序列化。
public Todo syncGson() throws Exception {
String response = sampleApiRequest();
List<Todo> todo = gson.fromJson(response, new TypeToken<List<Todo>>(){}.getType());
return todo.get(0);
}首先,我們創建了一個 Todo 類型列表。然後我們調用了 fromJson() 方法,將 JSON String 映射到 POJO 類。
JSON String 現在已映射到 POJO 類,以便進行進一步的操縱和處理。
讓我們為 syncGson() 編寫一個單元測試,通過將預期結果與返回的 Todo 進行比較:
@Test
public void givenSampleApiCall_whenResponseIsMappedByGson_thenCompareMappedGsonJsonResponse() throws Exception {
Todo expectedResult = new Todo(1, 1, "delectus aut autem", false);
TodoAppClient gsonTest = new TodoAppClient();
assertEquals(expectedResult, gsonTest.syncGson());
}測試結果表明,預期結果與返回值相匹配。
5. 異步調用
現在,讓我們實現異步 API 調用。在異步模式中,線程不會等待其他線程完成。這種編程模式使數據獲取更健壯和可擴展。
讓我們異步地獲取樣板 API 並將 JSON 響應映射到 POJO 類。
5.1. 使用 Jackson 進行異步調用和映射到 POJO 類
在本教程中,我們使用兩個 Java 庫來反序列化 JSON 響應。讓我們使用 Jackson 實現異步調用和映射到 POJO 類的功能。首先,讓我們在 TodoAppClient 中創建一個方法,readValueJackson()。
該方法反序列化 JSON 響應並將其映射到 POJO 類:
List<Todo> readValueJackson(String content) {
try {
return objectMapper.readValue(content, new TypeReference<List<Todo>>(){});
} catch (IOException ioe) {
throw new CompletionException(ioe);
}
}
然後,讓我們為我們的邏輯類添加一個新方法:
public Todo asyncJackson() throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://jsonplaceholder.typicode.com/todos"))
.build();
TodoAppClient todoAppClient = new TodoAppClient();
List<Todo> todo = HttpClient.newHttpClient()
.sendAsync(request, BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenApply(todoAppClient::readValueJackson)
.get();
return todo.get(0);
}該方法發起異步 GET 請求,並通過調用 readValueJackson() 將 JSON String 映射到 POJO 類。
最後,我們編寫一個單元測試,以將反序列化的 JSON 響應與 Todo 實例進行比較。
@Test
public void givenSampleApiAsyncCall_whenResponseIsMappedByJackson_thenCompareMappedJacksonJsonResponse() throws Exception {
Todo expectedResult = new Todo(1, 1, "delectus aut autem", false);
TodoAppClient sampleAsyncJackson = new TodoAppClient();
assertEquals(expectedResult, sampleAsyncJackson.asyncJackson());
}預期結果與映射的JSON響應相等。
5.2. 使用 Gson 進行異步調用和映射到 POJO 類
讓我們通過將異步 JSON 響應映射到 POJO 類來進一步增強程序。首先,讓我們創建一個方法,用於反序列化 TodoAppClient 中的 JSON String:
List<Todo> readValueGson(String content) {
return gson.fromJson(content, new TypeToken<List<Todo>>(){}.getType());
}
接下來,讓我們為包含程序邏輯的類添加一個新的方法:
public Todo asyncGson() throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://jsonplaceholder.typicode.com/todos"))
.build();
TodoAppClient todoAppClient = new TodoAppClient();
List<Todo> todo = HttpClient.newHttpClient()
.sendAsync(request, BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenApply(todoAppClient::readValueGson)
.get();
return todo.get(0);
}該方法發起一個異步的 GET 請求,並將 JSON 響應映射到 POJO 類。最後,我們調用 readValueGson() 來執行將響應映射到 POJO 類的過程。
現在,我們來編寫一個單元測試。我們將比較預期的 Todo 實例與映射後的響應。
@Test
public void givenSampleApiAsyncCall_whenResponseIsMappedByGson_thenCompareMappedGsonResponse() throws Exception {
Todo expectedResult = new Todo(1, 1, "delectus aut autem", false);
TodoAppClient sampleAsyncGson = new TodoAppClient();
assertEquals(expectedResult, sampleAsyncGson.asyncGson());
}測試結果顯示,預期結果與映射的JSON響應相匹配。
6. 結論
在本文中,我們學習了四種將 JSON 響應映射到 POJO 類的方法,當使用 HttpClient 時。此外,我們還深入研究了使用 HttpClient 的同步和異步編程模式。我們還使用 Jackson 和 Gson 庫來反序列化 JSON 響應並將 JSON String 映射到 POJO 類。