構建超媒體驅動的 RESTful Web 服務

本指南將引導您完成使用 Spring 建立“Hello, World”超媒體驅動 REST Web 服務的過程。

超媒體是 REST 的一個重要方面。它允許您構建在很大程度上解耦客戶端和伺服器並使其獨立發展的服務。為 REST 資源返回的表示形式不僅包含資料,還包含指向相關資源的連結。因此,表示形式的設計對於整個服務的設計至關重要。

您將構建什麼

您將使用 Spring HATEOAS 構建一個超媒體驅動的 REST 服務:這是一個 API 庫,您可以使用它建立指向 Spring MVC 控制器的連結、構建資源表示形式,並控制它們如何渲染成受支援的超媒體格式(例如 HAL)。

該服務將接受對 https://:8080/greeting 的 HTTP GET 請求。

它將響應一個問候語的 JSON 表示形式,該表示形式透過最簡單的超媒體元素(指向資源本身的連結)進行豐富。以下列表顯示了輸出

{
  "content":"Hello, World!",
  "_links":{
    "self":{
      "href":"https://:8080/greeting?name=World"
    }
  }
}

響應已經表明您可以透過查詢字串中的可選 name 引數來自定義問候語,如下列表所示

https://:8080/greeting?name=User

name 引數值會覆蓋預設值 World 並反映在響應中,如下列表所示

{
  "content":"Hello, User!",
  "_links":{
    "self":{
      "href":"https://:8080/greeting?name=User"
    }
  }
}

您需要準備什麼

如何完成本指南

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

從頭開始,請繼續閱讀從 Spring Initializr 開始

跳過基礎部分,請執行以下操作

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

從 Spring Initializr 開始

您可以使用這個預初始化專案,然後點選 Generate 下載 ZIP 檔案。此專案已配置好以適合本教程中的示例。

手動初始化專案

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

  2. 選擇 Gradle 或 Maven,以及您想使用的語言。本指南假定您選擇了 Java。

  3. 點選 Dependencies 並選擇 Spring HATEOAS

  4. 點選 Generate

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

如果您的 IDE 集成了 Spring Initializr,您可以直接在 IDE 中完成此過程。
您還可以從 Github 上 Fork 專案,然後在您的 IDE 或其他編輯器中開啟。

建立資源表示類

現在您已經設定好了專案和構建系統,可以建立您的 Web 服務了。

從考慮服務互動開始。

該服務將在 /greeting 暴露一個資源來處理 GET 請求,可選地帶有查詢字串中的 name 引數。GET 請求應該返回 200 OK 響應,其主體中包含 JSON 來表示問候語。

除此之外,資源的 JSON 表示形式將透過一個 _links 屬性中的超媒體元素列表進行豐富。最基本的形式是指向資源本身的連結。表示形式應類似於以下列表

{
  "content":"Hello, World!",
  "_links":{
    "self":{
      "href":"https://:8080/greeting?name=World"
    }
  }
}

content 是問候語的文字表示。_links 元素包含一個連結列表(在此例中,只有一個,其關係型別為 relhref 屬性指向被訪問的資源)。

為了對問候語表示形式建模,建立一個資源表示類。由於 _links 屬性是表示模型的一個基本屬性,Spring HATEOAS 提供了一個基類(名為 RepresentationModel),允許您新增 Link 例項,並確保它們像之前所示那樣渲染。

建立一個繼承 RepresentationModel 的普通 Java 物件,併為內容新增欄位、訪問器以及一個建構函式,如下列表所示(來自 src/main/java/com/example/resthateoas/Greeting.java

package com.example.resthateoas;

import org.springframework.hateoas.RepresentationModel;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class Greeting extends RepresentationModel<Greeting> {

	private final String content;

	@JsonCreator
	public Greeting(@JsonProperty("content") String content) {
		this.content = content;
	}

	public String getContent() {
		return content;
	}
}
  • @JsonCreator:指示 Jackson 如何建立此 POJO 的例項。

  • @JsonProperty:標記 Jackson 應該將此建構函式引數放入的欄位。

正如您在本指南後面將看到的那樣,Spring 將使用 Jackson JSON 庫自動將 Greeting 型別的例項封送為 JSON。

接下來,建立將提供這些問候語的資源控制器。

建立 REST 控制器

在 Spring 構建 RESTful Web 服務的方法中,HTTP 請求由控制器處理。元件由 @RestController 註解標識,該註解結合了 @Controller@ResponseBody 註解。以下 GreetingController(來自 src/main/java/com/example/resthateoas/GreetingController.java)透過返回 Greeting 類的新例項來處理對 /greetingGET 請求

package com.example.resthateoas;

import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@RestController
public class GreetingController {

	private static final String TEMPLATE = "Hello, %s!";

	@RequestMapping("/greeting")
	public HttpEntity<Greeting> greeting(
		@RequestParam(value = "name", defaultValue = "World") String name) {

		Greeting greeting = new Greeting(String.format(TEMPLATE, name));
		greeting.add(linkTo(methodOn(GreetingController.class).greeting(name)).withSelfRel());

		return new ResponseEntity<>(greeting, HttpStatus.OK);
	}
}

這個控制器簡潔明瞭,但其中包含了許多內容。我們將一步一步地進行解析。

@RequestMapping 註解確保對 /greeting 的 HTTP 請求對映到 greeting() 方法。

上面的例子沒有指定 GETPUTPOST 等的區別,因為 @RequestMapping 預設對映所有 HTTP 操作。使用 @GetMapping("/greeting") 可以縮小此對映範圍。在這種情況下,您還需要 import org.springframework.web.bind.annotation.GetMapping;

@RequestParam 將查詢字串引數 name 的值繫結到 greeting() 方法的 name 引數。由於使用了 defaultValue 屬性,此查詢字串引數隱式地不是 required。如果在請求中缺失,則使用 defaultValueWorld

由於類上存在 @RestController 註解,因此隱式地為 greeting 方法添加了 @ResponseBody 註解。這使得 Spring MVC 將返回的 HttpEntity 及其載荷(Greeting)直接渲染到響應中。

方法實現中最有趣的部分是如何建立指向控制器方法的連結以及如何將其新增到表示模型中。linkTo(…)methodOn(…) 都是 ControllerLinkBuilder 的靜態方法,它們允許您模擬對控制器的 方法呼叫。返回的 LinkBuilder 將檢查控制器方法的對映註解,以精確地構建出該方法對映到的 URI。

Spring HATEOAS 遵循各種 X-FORWARDED- 頭。如果您將 Spring HATEOAS 服務放在代理後面,並使用 X-FORWARDED-HOST 頭正確配置,則生成的連結將得到正確格式化。

呼叫 withSelfRel() 建立一個 Link 例項,您將其新增到 Greeting 表示模型中。

@SpringBootApplication 是一個便利註解,它添加了以下所有內容

  • @Configuration:將類標記為應用程式上下文的 bean 定義源。

  • @EnableAutoConfiguration:告訴 Spring Boot 根據類路徑設定、其他 bean 和各種屬性設定開始新增 bean。例如,如果 spring-webmvc 在類路徑上,此註解會將應用程式標記為 Web 應用程式並激活關鍵行為,例如設定 DispatcherServlet

  • @ComponentScan:告訴 Spring 在 com/example 包中查詢其他元件、配置和服務,從而找到控制器。

main() 方法使用 Spring Boot 的 SpringApplication.run() 方法啟動應用程式。您注意到沒有一行 XML 程式碼嗎?也沒有 web.xml 檔案。這個 Web 應用程式是 100% 純 Java 的,您無需處理任何底層或基礎設施的配置。

構建可執行 JAR

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

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

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

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

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

將顯示日誌輸出。服務應在幾秒鐘內啟動並執行。

測試服務

現在服務已啟動,訪問 https://:8080/greeting,您應該會看到以下內容

{
  "content":"Hello, World!",
  "_links":{
    "self":{
      "href":"https://:8080/greeting?name=World"
    }
  }
}

透過訪問以下 URL 提供 name 查詢字串引數:https://:8080/greeting?name=User。注意 content 屬性的值如何從 Hello, World! 變為 Hello, User!,並且 self 連結的 href 屬性也反映了這種變化,如下列表所示

{
  "content":"Hello, User!",
  "_links":{
    "self":{
      "href":"https://:8080/greeting?name=User"
    }
  }
}

這一變化表明 GreetingController 中的 @RequestParam 配置按預期工作。name 引數被賦予了預設值 World,但始終可以透過查詢字串顯式覆蓋。

總結

恭喜!您剛剛使用 Spring HATEOAS 開發了一個超媒體驅動的 RESTful Web 服務。

獲取程式碼