消費 RESTful Web 服務

本指南將引導您完成建立一個消費 RESTful Web 服務的應用程式的過程。

您將構建什麼

您將構建一個使用 Spring 的 RestTemplate 來在 https://:8080/api/random 獲取隨機 Spring Boot 引語的應用程式。

你需要什麼

如何完成本指南

與大多數 Spring 入門指南一樣,您可以從頭開始並完成每個步驟,也可以跳過您已熟悉的基本設定步驟。無論哪種方式,您最終都會得到可工作的程式碼。

從頭開始,請轉到從 Spring Initializr 開始

跳過基礎知識,請執行以下操作

完成後,您可以對照 gs-consuming-rest/complete 中的程式碼檢查您的結果。

從 Spring Initializr 開始

您可以使用這個預初始化專案,然後點選“生成”下載一個 ZIP 檔案。該專案已配置好以適應本教程中的示例。

手動初始化專案

  1. 導航到 https://start.spring.io。此服務會為您拉取應用程式所需的所有依賴項,併為您完成大部分設定。

  2. 選擇 Gradle 或 Maven 以及您想要使用的語言。

  3. 點選 Dependencies 並選擇 HTTP Client

  4. 單擊生成

  5. 下載生成的 ZIP 檔案,這是一個已根據您的選擇配置好的 Web 應用程式存檔。

如果您的 IDE 集成了 Spring Initializr,您可以從 IDE 中完成此過程。
您還可以從 GitHub fork 專案,並在您的 IDE 或其他編輯器中開啟它。

獲取 REST 資源

專案設定完成後,您可以建立一個簡單的應用程式來消費 RESTful 服務。

在此之前,您需要一個 REST 資源的來源。我們提供了一個此類服務的示例,地址是 https://github.com/spring-guides/quoters。您可以在一個單獨的終端中執行該應用程式,並在 https://:8080/api/random 訪問結果。該地址會隨機獲取關於 Spring Boot 的引語,並以 JSON 文件的形式返回。其他有效地址包括 https://:8080/api/(所有引語)和 https://:8080/api/1(第一個引語)、https://:8080/api/2(第二個引語),依此類推(目前最多 10 個)。

如果您透過網路瀏覽器或 curl 請求該 URL,您會收到一個類似以下的 JSON 文件

{
   type: "success",
   value: {
      id: 10,
      quote: "Really loving Spring Boot, makes stand alone Spring apps easy."
   }
}

這足夠簡單,但是透過瀏覽器或 curl 獲取時並沒有太大用處。

透過程式設計方式消費 REST web 服務是更實用的方法。為了幫助您完成這項任務,Spring 提供了一個方便的模板類,名為 RestClientRestClient 使與大多數 RESTful 服務的互動成為一行咒語。它甚至可以將資料繫結到自定義域型別。

首先,您需要建立一個域類(一個 Java 記錄類或 Kotlin 資料類)來包含所需的資料。以下清單顯示了 Quote 類,您可以將其用作您的域類

Java
package com.example.consumingrest;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public record Quote(String type, Value value) { }
Kotlin
package com.example.consumingrest

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties(ignoreUnknown = true)
data class Quote(
    val type: String,
    val value: Value
)

該域類使用 Jackson JSON 處理庫的 @JsonIgnoreProperties 註解,表示應忽略此型別中未繫結的任何屬性。

要將資料直接繫結到您的自定義型別,您需要指定變數名與從 API 返回的 JSON 文件中的鍵完全相同。如果您的變數名和 JSON 文件中的鍵不匹配,您可以使用 @JsonProperty 註解來指定 JSON 文件的確切鍵。(本例將每個變數名與一個 JSON 鍵匹配,因此您不需要在此處使用該註解。)

您還需要一個額外的域類來嵌入內部引語本身。Value 類滿足了這一需求,如下面的清單所示

Java
package com.example.consumingrest;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public record Value(Long id, String quote) { }
Kotlin
package com.example.consumingrest

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties(ignoreUnknown = true)
data class Value(
    val id: Long,
    val quote: String
)

這使用相同的註解,但對映到其他資料欄位。

完成應用程式

Initializr 建立了一個帶有 main() 方法的類,如下面的清單所示

Java
package com.example.consumingrest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ConsumingRestApplication {

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

}
Kotlin
package com.example.consumingrest

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class ConsumingRestApplication

fun main(args: Array<String>) {
    runApplication<ConsumingRestApplication>(*args)
}

現在您需要向 ConsumingRestApplication 類新增一些其他內容,以使其能夠顯示來自我們的 RESTful 源的引語。您需要新增

  • 一個日誌記錄器,用於將輸出傳送到日誌(本例中是控制檯)。

  • 一個 CommandLineRunner,它使用自動配置的 RestClient.Builder 構建一個 RestClient 例項,並使用它在啟動時獲取我們的引語。

以下清單顯示了完成的 ConsumingRestApplication

Java
package com.example.consumingrest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.web.client.RestClient;

@SpringBootApplication
public class ConsumingRestApplication {

	private static final Logger log = LoggerFactory.getLogger(ConsumingRestApplication.class);

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

	@Bean
	@Profile("!test")
	public ApplicationRunner run(RestClient.Builder builder) {
		RestClient restClient = builder.baseUrl("https://:8080").build();
		return args -> {
			Quote quote = restClient
					.get().uri("/api/random")
					.retrieve()
					.body(Quote.class);
			log.info(quote.toString());
		};
	}
}
Kotlin
package com.example.consumingrest

import org.slf4j.LoggerFactory
import org.springframework.boot.ApplicationRunner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Profile
import org.springframework.web.client.RestClient
import org.springframework.web.client.toEntity

private val log = LoggerFactory.getLogger(ConsumingRestApplication::class.java)

@SpringBootApplication
class ConsumingRestApplication {

    @Bean
    @Profile("!test")
    fun run(builder: RestClient.Builder) = ApplicationRunner {
        val quote = builder.build().get().uri("https://:8080/api/random")
            .retrieve().toEntity<Quote>()
        log.info(quote.toString())
    }
}

fun main(args: Array<String>) {
    runApplication<ConsumingRestApplication>(*args)
}

執行應用程式

您可以使用 Gradle 或 Maven 從命令列執行應用程式。您還可以構建一個包含所有必要依賴項、類和資源並執行的單個可執行 JAR 檔案。構建可執行 JAR 使在整個開發生命週期中,跨不同環境等,輕鬆交付、版本化和部署服務作為應用程式。

如果您使用 Gradle,您可以透過使用 ./gradlew bootRun 執行應用程式。或者,您可以透過使用 ./gradlew build 構建 JAR 檔案,然後按如下方式執行 JAR 檔案

java -jar build/libs/gs-consuming-rest-0.1.0.jar

如果您使用 Maven,您可以透過使用 ./mvnw spring-boot:run 執行應用程式。或者,您可以使用 ./mvnw clean package 構建 JAR 檔案,然後按如下方式執行 JAR 檔案

java -jar target/gs-consuming-rest-0.1.0.jar
這裡描述的步驟建立了一個可執行的 JAR。您還可以構建一個經典的 WAR 檔案

您應該會看到類似以下內容的輸出,但引語是隨機的

2019-08-22 14:06:46.506  INFO 42940 --- [           main] c.e.c.ConsumingRestApplication           : Quote{type='success', value=Value{id=1, quote='Working with Spring Boot is like pair-programming with the Spring developers.'}}
如果您看到錯誤提示 Could not extract response: no suitable HttpMessageConverter found for response type [class com.example.consumingrest.Quote],則可能是您所處的環境無法連線到後端服務(如果能連線到,它會發送 JSON)。也許您位於公司代理後面。請嘗試將 http.proxyHosthttp.proxyPort 系統屬性設定為適合您環境的值。

總結

恭喜!您剛剛使用 Spring Boot 開發了一個簡單的 REST 客戶端。

獲取程式碼