本指南将引导您使用Spring WebFlux完成创建“Hello, Spring!”的RESTful Web服务的过程,然后使用WebClient调用该服务。你能够在system.out和浏览器访问http://localhost:8080/hello后看到输出。
程序结构
└── src
└── main
└── java
└── hello
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-reactive-rest-service</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Spring Boot将会你做如下的事:
- 将 classpath 里面所有用到的jar包构建成一个可执行的 JAR 文件,方便执行你的程序
- 搜索public static void main()方法并且将它当作可执行类
- 根据springboot版本,去查找相应的依赖类版本,当然你可以定义其它版本。
建立一个WebFlux处理器
在Spring响应式方法中,我们使用一个处理程序来处理请求并创建响应,如下例所示:
src/main/java/hello/GreetingHandler.java
package hello;
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.TEXT_PLAIN)
.body(BodyInserters.fromObject("Hello, Spring!"));
}
}
这个简单的响应类总是返回“Hello, Spring!”.它也可以返回许多其他东西,包括数据库中的数据流、通过计算后生成的一个数据流等等。注意响应式代码返回:一个包含ServerResponse主体的Mono对象。
创建一个路由器类
在这个应用程序中,我们使用路由器类来处理我们公开的唯一路由(“/hello”),如下例所示:
src/main/java/hello/GreetingRouter.java
package hello;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
@Configuration
public class GreetingRouter {
@Bean
public RouterFunction<ServerResponse> route(GreetingHandler greetingHandler) {
return RouterFunctions
.route(RequestPredicates.GET("/hello").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), greetingHandler::hello);
}
}
路由器类监听/hello
路径上的流量,并返回我们的响应式处理程序类提供的值。
创建一个WebClient
Spring MVC RestTemplate类本质上是阻塞的。因此,我们不想在响应式应用程序中使用它。对于响应式应用程序,Spring提供了WebClient类,它是非阻塞的。我们将使用WebClient实现来使用我们的RESTful服务:
src/main/java/hello/GreetingWebClient.java
package hello;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
public class GreetingWebClient {
private WebClient client = WebClient.create("http://localhost:8080");
private Mono<ClientResponse> result = client.get()
.uri("/hello")
.accept(MediaType.TEXT_PLAIN)
.exchange();
public String getResult() {
return ">> result = " + result.flatMap(res -> res.bodyToMono(String.class)).block();
}
}
WebClient使用Mono类型的响应式来保存我们请求的URI的内容,并使用函数(在getResult 方法中)将该内容转换为字符串。如果我们有不同的需求,我们可以把它转换成字符串以外的东西。因为我们要将结果放入System.out,所以这里需要一个字符串。
WebClient也可以用于与非响应、阻塞服务通信。
创建Application
尽管可以将此服务打包为用于部署到外部应用服务器的传统war文件,但下面演示的简单方法是创建了一个独立的应用程序。在一个单一的、可执行的JAR文件中打包所有的东西,由一个好的Java main()方法驱动。在此过程中,您使用响应式Spring的支持将Netty服务器嵌入为HTTP运行时,而不是部署到外部实例。
src/main/java/hello/Application.java
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
GreetingWebClient gwc = new GreetingWebClient();
System.out.println(gwc.getResult());
}
}
@SpringBootApplication包含如下注解:
@Configuration 将类标记为应用程序上下文的bean定义源。
@EnableAutoConfiguration 告诉SpringBoot根据类路径设置、其他bean和各种属性设置开始添加bean。
通常,您会为SpringMVC应用程序添加@EnableWebMVC,但当SpringBoot在类路径上看到spring-webmvc 时,它会自动添加。这将应用程序标记为Web应用程序,并激活关键行为,如设置DispatcherServlet。
@ComponentScan 告诉Spring在hello包中查找其他组件、配置和服务。
执行应用程序
在STS下,右键-选择Run as-Spring Boot App ,输出如下:
>> result = Hello, Spring!
测试程序
现在应用程序运行后,您可以测试它。首先,您可以打开一个浏览器并转到http://localhost:8080/hello,然后看到“Hello, Spring!”对于本指南,我们还创建了一个测试类,让您开始使用WebTestClient类进行测试。
src/test/java/hello/GreetingRouterTest.java
package hello;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(SpringRunner.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.TEXT_PLAIN)
.exchange()
// and use the dedicated DSL to test assertions against the response
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello, Spring!");
}
}
祝贺你!您开发了一个响应式Spring应用程序,其中包括一个WebClient来使用RESTful服务!