父工程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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>Spring-WebFlux-Demo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>DemoServer</module>
<module>DemoClient</module>
</modules>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!--将项目打包成可执行jar用到的插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
DemoServer
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>Spring-WebFlux-Demo</artifactId>
<groupId>com.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>DemoServer</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
ServerApp.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ServerApp {
public static void main(String[] args) {
System.setProperty("server.port","16000");
SpringApplication.run(ServerApp.class, args);
}
}
DemoOldController.java
package com.example.mvc;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/old")
public class DemoOldController {
// http://127.0.0.1:16000/old/get
@GetMapping("/get")
public Mono<String> getFunction() {
return Mono.just("GET|Old|Msg: Hello World");
}
// http://127.0.0.1:16000/old/post
@PostMapping("/post")
public Mono<String> postFunction(@RequestBody String body){
System.out.println(body);
return Mono.just("POST|Old|Msg: " + body);
}
}
DemoHandlers.java
package com.example.webflux;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import java.util.Optional;
@Component
public class DemoHandlers {
private static final String Msg = "Hello World!";
// http://127.0.0.1:16000/new/get
public Mono<ServerResponse> getFunction(ServerRequest request){
//REST 方式获取
//路由url /new/get/{data}
//String data = request.pathVariable("data");
//请求的url中传参, 例如: /new/get?data=xxx
Optional<String> date = request.queryParam("data");
String retValue = "GET|New|Msg: " + date.orElse(Msg);
return ServerResponse.ok()
.contentType(MediaType.TEXT_PLAIN)
.bodyValue(retValue);
}
// http://127.0.0.1:16000/new/post
public Mono<ServerResponse> postFunction(ServerRequest request){
//如果请求体中为空时,返回默认值
Mono<String> stringMono = request.bodyToMono(String.class).defaultIfEmpty(Msg);
//这样获取请求中的数据会报错
//String reqBody = stringMono.block();
//如果需要对Mono中的数据进行处理,就需要使用flatMap
return stringMono.flatMap((value)->{
return ServerResponse.ok()
.contentType(MediaType.TEXT_PLAIN)
.bodyValue("POST|New|Msg: " + value);
});
}
}
Routers.java
package com.example.webflux;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.*;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
@Configuration
public class Routers {
@Bean
public RouterFunction<ServerResponse> routerFunction(DemoHandlers demoHandlers) {
//统一的前缀,相当于mvc中在类的上面加@RequestMapping("/new")
RouterFunction<ServerResponse> routeFormat1 = RouterFunctions
.route()
.nest(RequestPredicates.path("/new"), () ->
RouterFunctions
.route(GET("/get"), demoHandlers::getFunction)
.andRoute(POST("/post"), demoHandlers::postFunction)
).build();
//统一前缀的第二张方式
RouterFunction<ServerResponse> routeFormat2 = RouterFunctions
.route()
.nest(RequestPredicates.path("/new"), () ->
RouterFunctions.route()
.GET("/get", demoHandlers::getFunction)
.POST("/post", demoHandlers::postFunction)
.build())
.build();
//每个url中都自己写全
RouterFunction<ServerResponse> routeFormat3 = RouterFunctions
.route()
.GET("/new/get", demoHandlers::getFunction)
.POST("/new/post", demoHandlers::postFunction)
.build();
return routeFormat1;
}
}
DemoClient
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>Spring-WebFlux-Demo</artifactId>
<groupId>com.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>DemoClient</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
ClientApp.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ClientApp {
public static void main(String[] args) {
System.setProperty("server.port","16001");
SpringApplication.run(ClientApp.class, args);
}
}
DemoController.java
package com.example;
import io.netty.handler.codec.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.netty.ByteBufMono;
import reactor.netty.http.client.HttpClient;
@RestController
@RequestMapping("/demo")
public class DemoController {
/** WebClient 是 web flux提供的http客户端 */
private static final WebClient webClient = WebClient.create();
/** HttpClient 是 reactor.-netty提供的http客户端 */
private static final HttpClient httpClient = HttpClient.create();
private static final String URL_PREFIX = "http://127.0.0.1:16000";
private static final String HelloWorld = "hello world";
/**
*
* http://127.0.0.1:16001/demo/webclient/get
*/
@RequestMapping("/webclient/get")
public Mono<String> webClientGet() {
return webClient.get()
.uri(URL_PREFIX + "/old/get")
.retrieve()//发起请求并获得响应
.bodyToMono(String.class);//将请求结果需要处理为String,并包装为Reactor的Mono对象
}
/**
* http://127.0.0.1:16001/demo/webclient/post
*/
@RequestMapping("/webclient/post")
public Mono<String> webClientPost() {
return webClient.post()
.uri(URL_PREFIX + "/old/post")
.contentType(MediaType.TEXT_PLAIN)
.bodyValue(HelloWorld)
.retrieve()//发起请求并获得响应
.bodyToMono(String.class);//将请求结果需要处理为String,并包装为Reactor的Mono对象
}
/**
* http://127.0.0.1:16001/demo/httpclient/get
*/
@RequestMapping("/httpclient/get")
public Flux<String> httpClientGet() {
return httpClient.request(HttpMethod.GET)
.uri(URL_PREFIX + "/new/get")
.responseContent() //读取响应体
.asString();
}
/**
* http://127.0.0.1:16001/demo/httpclient/post
*/
@RequestMapping("/httpclient/post")
public Flux<String> httpClientPost() {
return httpClient.request(HttpMethod.POST)
.uri(URL_PREFIX + "/new/post")
.send(ByteBufMono.fromString(Mono.just(HelloWorld)))
.responseContent()
.asString();
}
}
官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#spring-webflux