https://127.0.0.1:8080/hello
建構反應式 RESTful Web 服務
本指南將引導您使用 Spring WebFlux(Spring Boot 2.0 的新功能)建立「Hello, Spring!」RESTful Web 服務,然後使用 WebClient(也是 Spring Boot 2.0 的新功能)使用該服務。
本指南展示了使用 Spring WebFlux 的函數式方法。您也可以使用帶有 WebFlux 的註解。 |
您將建構什麼
您將建構一個具有 Spring Webflux 的 RESTful Web 服務和一個 WebClient 的消費者服務。您將能夠在 System.out 和
您需要什麼
-
約 15 分鐘
-
您喜愛的文字編輯器或 IDE
-
Java 17 或更高版本
-
您也可以直接將程式碼匯入您的 IDE
如何完成本指南
與大多數 Spring 入門指南一樣,您可以從頭開始並完成每個步驟,或者您可以跳過您已經熟悉的基礎設定步驟。 無論哪種方式,您最終都會得到可運作的程式碼。
要從頭開始,請移至 使用 Spring Initializr 開始。
要跳過基礎知識,請執行以下操作
-
下載並解壓縮本指南的原始碼儲存庫,或使用 Git 克隆它:
git clone https://github.com/spring-guides/gs-reactive-rest-service.git
-
cd 進入
gs-reactive-rest-service/initial
當您完成時,您可以將您的結果與 gs-reactive-rest-service/complete
中的程式碼進行比較。
使用 Spring Initializr 開始
您可以使用這個 預先初始化的專案,然後點擊 Generate (產生) 下載 ZIP 檔案。 此專案已配置為適合本教學中的範例。
手動初始化專案
-
導覽至 https://start.spring.io。 此服務會提取應用程式所需的所有依賴項,並為您完成大部分設定。
-
選擇 Gradle 或 Maven 以及您想要使用的語言。 本指南假設您選擇 Java。
-
點擊 Dependencies (依賴項) 並選擇 Spring Reactive Web。
-
點擊 Generate (產生)。
-
下載產生的 ZIP 檔案,這是一個使用您選擇的配置的 Web 應用程式的存檔。
如果您的 IDE 有 Spring Initializr 整合,您可以從您的 IDE 完成此過程。 |
您也可以從 Github 分叉專案,並在您的 IDE 或其他編輯器中打開它。 |
建立 WebFlux Handler
我們將從一個 Greeting
POJO 開始,它將由我們的 RESTful 服務序列化為 JSON
src/main/java/hello/Greeting.java
package com.example.reactivewebservice;
public class Greeting {
private String message;
public Greeting() {
}
public Greeting(String message) {
this.message = message;
}
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String toString() {
return "Greeting{" +
"message='" + message + '\'' +
'}';
}
}
在 Spring Reactive 方法中,我們使用處理器來處理請求並建立回應,如下例所示
src/main/java/hello/GreetingHandler.java
package com.example.reactivewebservice;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@Component
public class GreetingHandler {
public Mono<ServerResponse> hello(ServerRequest request) {
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(new Greeting("Hello, Spring!")));
}
}
這個簡單的反應式類別總是傳回一個具有 "Hello, Spring!" 問候語的 JSON 主體。它可以傳回許多其他東西,包括來自資料庫的項目流、由計算產生的項目流等等。請注意反應式程式碼:一個保存 ServerResponse
主體的 Mono
物件。
建立路由器
在本應用程式中,我們使用路由器來處理我們公開的唯一路由 (/hello
),如下例所示
src/main/java/hello/GreetingRouter.java
package com.example.reactivewebservice;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
@Configuration(proxyBeanMethods = false)
public class GreetingRouter {
@Bean
public RouterFunction<ServerResponse> route(GreetingHandler greetingHandler) {
return RouterFunctions
.route(GET("/hello").and(accept(MediaType.APPLICATION_JSON)), greetingHandler::hello);
}
}
路由器監聽 /hello
路徑上的流量,並傳回我們的反應式處理器類別提供的值。
建立 WebClient
Spring RestTemplate
類別本質上是阻塞的。因此,我們不想在反應式應用程式中使用它。對於反應式應用程式,Spring 提供了 WebClient
類別,它是非阻塞的。我們使用基於 WebClient 的實現來使用我們的 RESTful 服務
src/main/java/hello/GreetingClient.java
package com.example.reactivewebservice;
import reactor.core.publisher.Mono;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
@Component
public class GreetingClient {
private final WebClient client;
// Spring Boot auto-configures a `WebClient.Builder` instance with nice defaults and customizations.
// We can use it to create a dedicated `WebClient` for our component.
public GreetingClient(WebClient.Builder builder) {
this.client = builder.baseUrl("https://127.0.0.1:8080").build();
}
public Mono<String> getMessage() {
return this.client.get().uri("/hello").accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(Greeting.class)
.map(Greeting::getMessage);
}
}
WebClient
類別使用反應式特性,以 Mono
的形式保存訊息的內容(由 getMessage
方法傳回)。這是使用函數 API,而不是命令式 API,來鏈接反應式運算符。
可能需要時間來習慣 Reactive APIs,但是 WebClient
具有有趣的功能,並且也可以在傳統的 Spring MVC 應用程式中使用。
您也可以使用 WebClient 與非反應式、阻塞的服務進行通信。 |
使應用程式可執行
我們將使用 main()
方法來驅動我們的應用程式並從我們的端點取得 Greeting 訊息。
src/main/java/hello/Application.java
package com.example.reactivewebservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class ReactiveWebServiceApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(ReactiveWebServiceApplication.class, args);
GreetingClient greetingClient = context.getBean(GreetingClient.class);
// We need to block for the content here or the JVM might exit before the message is logged
System.out.println(">> message = " + greetingClient.getMessage().block());
}
}
@SpringBootApplication
是一個方便的註解,它增加了以下所有內容
-
@Configuration
:將該類別標記為應用程式上下文的 Bean 定義來源。 -
@EnableAutoConfiguration
:告訴 Spring Boot 根據類別路徑設定、其他 Bean 和各種屬性設定開始新增 Bean。例如,如果spring-webmvc
在類別路徑上,則此註解將應用程式標記為 Web 應用程式並激活關鍵行為,例如設定DispatcherServlet
。 -
@ComponentScan
:告訴 Spring 在hello
封裝中尋找其他元件、配置和服務,讓它找到控制器。
main()
方法使用 Spring Boot 的 SpringApplication.run()
方法來啟動應用程式。您是否注意到沒有任何 XML 程式碼?也沒有 web.xml
檔案。此 Web 應用程式是 100% 純 Java,您無需處理配置任何基礎結構。
建構可執行 JAR
您可以使用 Gradle 或 Maven 從命令列執行應用程式。您還可以建構一個包含所有必要依賴項、類別和資源的單個可執行 JAR 檔案並執行它。建構可執行 jar 使得在整個開發生命週期中,跨不同環境等,都可以輕鬆地將該服務作為應用程式進行發布、版本控制和部署。
如果您使用 Gradle,您可以使用 ./gradlew bootRun
執行應用程式。或者,您可以使用 ./gradlew build
建構 JAR 檔案,然後執行 JAR 檔案,如下所示
如果您使用 Maven,您可以使用 ./mvnw spring-boot:run
執行應用程式。或者,您可以使用 ./mvnw clean package
建構 JAR 檔案,然後執行 JAR 檔案,如下所示
此處描述的步驟會建立一個可執行的 JAR。您也可以建構一個經典的 WAR 檔案。 |
顯示日誌輸出。該服務應在幾秒鐘內啟動並執行。
服務啟動後,您可以看到一行讀取
>> message = Hello, Spring!
該行來自 WebClient 使用的反應式內容。當然,您可以找到比將其放入 System.out 中更有趣的事情來處理您的輸出。
測試應用程式
現在應用程式正在執行,您可以測試它。首先,您可以打開瀏覽器並前往 https://127.0.0.1:8080/hello
並看到「Hello, Spring!」。對於本指南,我們還建立了一個測試類別,讓您可以開始使用 WebTestClient
類別進行測試。
src/test/java/hello/GreetingRouterTest.java
package com.example.reactivewebservice;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.assertj.core.api.Assertions.assertThat;
@ExtendWith(SpringExtension.class)
// We create a `@SpringBootTest`, starting an actual server on a `RANDOM_PORT`
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class GreetingRouterTest {
// Spring Boot will create a `WebTestClient` for you,
// already configure and ready to issue requests against "localhost:RANDOM_PORT"
@Autowired
private WebTestClient webTestClient;
@Test
public void testHello() {
webTestClient
// Create a GET request to test an endpoint
.get().uri("/hello")
.accept(MediaType.APPLICATION_JSON)
.exchange()
// and use the dedicated DSL to test assertions against the response
.expectStatus().isOk()
.expectBody(Greeting.class).value(greeting -> {
assertThat(greeting.getMessage()).isEqualTo("Hello, Spring!");
});
}
}
總結
恭喜!您已經開發了一個包含 WebClient 的 Reactive Spring 應用程式來使用 RESTful 服務!
想要編寫新指南或貢獻現有指南?查看我們的貢獻指南。
所有指南均以 ASLv2 許可證發布用於程式碼,並以 歸屬、禁止衍生創作的 Creative Commons 許可證發布用於寫作。 |