响应式编程WebFlux基础实战练习

什么是WebFlux?
响应式编程WebFlux是Spring Framework 5中引入的一个全新的响应式编程框架,它基于Reactor库构建,提供了异步和非阻塞的事件处理。WebFlux框架设计用于处理长时间运行的异步任务,例如网络调用或数据库操作,而不会阻塞线程。这样可以提高系统的吞吐量和伸缩性。并在Netty,Undertow和Servlet 3.1 +容器等服务器上运行。

WebFlux基础实战练习

0. WebFlun环境准备

基于Spring Boot,项目依赖

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.6</version>
    </parent>

    <artifactId>chapter04-webflux</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>io.projectreactor</groupId>
                <artifactId>reactor-bom</artifactId>
                <version>2023.0.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


    <dependencies>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot Starter Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.7.2</version>
            <scope>test</scope>
        </dependency>

    </dependencies>
</project>

启动类
Spring Boot 有一个 WebFlux 启动器,默认情况下,启动器使用 Netty

@SpringBootApplication
public class WebFluxMainApplication {

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

1. 基于注解的编程模式

WebFlux提供了两种主要的编程模式,分别是基于注解的编程模式(Annotation-based Programming)和函数式编程模式(Functional Programming)。

基于注解的编程模式(Annotation-based Programming): 这是类似于传统的Spring MVC风格的编程模式。开发者可以使用注解来定义Controller、请求映射、参数绑定等,类似于Spring MVC的@Controller和@RequestMapping注解。使用这种模式,开发者可以通过注解轻松地定义和配置应用程序的各个组件。

WebFlux基于注解的编程模式的工作流程图:
请求到达
注解映射
业务逻辑处理
响应构建
客户端请求
Controller
RequestMapping
Mono
客户端
代码示例
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
public class WebFluxController {

    @GetMapping("/mono")
    public Mono<String> monoExample() {
        return Mono.just("Hello, Mono!");
    }

    @GetMapping("/flux")
    public Flux<Integer> fluxExample() {
        return Flux.just(1, 2, 3, 4, 5);
    }
}

测试

GET http://localhost:8080/mono 返回响应:Hello, Mono!

GET http://localhost:8080/flux 返回响应:[1,2,3,4,5]

相关API
  1. Mono

    • Mono 是 Reactor 中表示包含零个或一个元素的响应式类型。
    • 适用于表示异步操作的结果,例如从数据库查询、网络调用或其他异步任务中返回的单个结果。
    • 可以通过 Mono.just(value) 创建包含单个值的 Mono,也可以通过各种操作符对 Mono 进行组合、转换和操作。
    • Mono 可以表示一个成功的结果,也可以表示错误或空值。
  2. Flux

    • Flux 是 Reactor 中表示包含零个、一个或多个元素的响应式类型。
    • 适用于表示异步流的结果,例如从事件流、消息队列或其他异步源中返回的多个元素。
    • 可以通过 Flux.just(value1, value2, ...) 创建包含多个值的 Flux,也可以通过各种操作符对 Flux 进行处理和转换。
    • Flux 支持背压(backpressure),可以有效地处理大量的异步数据。

在使用 WebFlux 框架时,MonoFlux 通常用于表示响应的内容。Mono 表示单一值的响应,而 Flux 表示包含多个值的响应,适用于处理异步请求和构建响应式应用程序。

2. 函数式编程模式

函数式编程模式(Functional Programming): 这是WebFlux的另一种编程模式,它使用Router和Handler函数。开发者通过编写函数式的路由和处理器来定义请求的处理逻辑,而不是使用注解。这种模式更加灵活,并且适用于需要更直观、函数式风格的代码。

WebFlux基于函数式编程模式的工作流程图:
请求到达
路由
业务逻辑处理
响应构建
客户端请求
RouterFunction
HandlerFunction
ServerResponse
客户端
代码示例
@Configuration
public class WebFluxRouter {

    @Bean
    public RouterFunction<ServerResponse> routeExample(WebFluxHandler handler) {
        return route()
                .GET("/router/mono", handler::monoExample)
                .GET("/router/flux", handler::fluxExample)
                .build();
    }
}

@Component
class WebFluxHandler {

    public Mono<ServerResponse> monoExample(ServerRequest request) {
        return ok().contentType(MediaType.TEXT_PLAIN)
                .bodyValue("Hello, Mono from Router!");
    }

    public Mono<ServerResponse> fluxExample(ServerRequest request) {
        return ok().contentType(MediaType.APPLICATION_JSON)
                .body(Flux.just(1, 2, 3, 4, 5).collectList(), List.class);
    }

}

测试

GET http://localhost:8080/router/mono 返回响应:Hello, Mono from Router!

GET http://localhost:8080/flux 返回响应:[1,2,3,4,5]

相关API
  1. RouterFunction<ServerResponse>
    • RouterFunction 是 Spring WebFlux 中用于定义路由的函数接口。
    • RouterFunction<ServerResponse> 表示这个函数定义了一组路由规则,每个路由规则都映射到一个处理器函数,用于处理特定的HTTP请求。
    • 在这个例子中,routeExample 方法创建了一个路由函数,定义了两个GET请求的路由规则,分别映射到 "/router/mono""/router/flux" 路径,并指定了相应的处理器函数。
  2. ServerRequest
    • ServerRequest 是 Spring WebFlux 中表示HTTP请求的对象。
    • 在处理器函数中,ServerRequest 包含了与请求相关的信息,例如HTTP方法、路径、请求头等。
    • 在这个例子中,monoExamplefluxExample 方法的参数中都包含了一个 ServerRequest 对象,用于处理相关的请求信息。
  3. ServerResponse
    • ServerResponse 是 Spring WebFlux 中表示HTTP响应的对象。
    • 通过 ServerResponse,可以设置响应的状态码、头部信息、内容类型等,并定义响应体。
    • 在这个例子中,monoExamplefluxExample 方法的返回类型是 Mono<ServerResponse>,表示响应是一个响应式单值。
  4. MediaType
    • MediaType 是 Spring 框架中表示媒体类型的枚举,用于指定HTTP请求和响应的媒体类型。
    • 在这个例子中,MediaType.TEXT_PLAIN 表示文本媒体类型,而 MediaType.APPLICATION_JSON 表示JSON媒体类型。
  5. MonoFlux
    • MonoFlux 是 Reactor 框架中的类型,用于处理响应式编程和异步数据流。
    • 在这个例子中,monoExample 方法返回的是一个 Mono<ServerResponse>,而 fluxExample 方法返回的是一个 Mono<ServerResponse>,表示响应是异步单值或异步数据流。
  6. .bodyValue("Hello, Mono from Router!")
    • .bodyValueServerResponse 中的方法,用于设置响应体的值。
    • 在这个例子中,通过 .bodyValue("Hello, Mono from Router!") 设置了响应体的值为字符串 “Hello, Mono from Router!”。
    • 这是一个简单的方式,适用于需要返回一个确定的值作为响应体的情况。
  7. .body(Flux.just(1, 2, 3, 4, 5).collectList(), List.class)
    • .body 方法用于设置响应体,与 .bodyValue 不同,.body 可以处理更复杂的情况,例如异步数据流。
    • 在这个例子中,使用了 .body(Flux.just(1, 2, 3, 4, 5).collectList(), List.class),表示响应体是一个包含整数 1, 2, 3, 4, 5 的 Flux,通过 collectList() 转换为 Mono<List<Integer>>
    • List.class 参数提供了响应体的元素类型信息。

这些API和注解共同构建了一个基于WebFlux的响应式路由和处理器。路由定义通过 RouterFunction 创建,处理逻辑通过 WebFluxHandler 中的方法实现,而 MonoFlux 用于表示异步的响应。

3. 异常处理和全局错误处理

代码示例
@Component
@Order(-2)
public class WebFluxExceptionHandler implements WebExceptionHandler {

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        if (ex instanceof ResponseStatusException) {
            return handleResponseStatusException(exchange, (ResponseStatusException) ex);
        }

        // Handle other types of exceptions if needed

        return Mono.error(ex);
    }

    private Mono<Void> handleResponseStatusException(ServerWebExchange exchange, ResponseStatusException ex) {
        exchange.getResponse().setStatusCode(ex.getStatusCode());
        return exchange.getResponse().setComplete();
    }
}
相关API
  1. WebExceptionHandler接口

    • org.springframework.web.server.WebExceptionHandler是用于处理WebFlux应用程序中异常的接口。
    • 通过实现这个接口,你可以自定义异常处理逻辑,并在应用程序中注册它。
  2. ServerWebExchange接口

    • org.springframework.web.server.ServerWebExchange表示一次HTTP请求-响应交换。
    • 它包含了请求和响应的所有信息,可以在处理器中使用。
  3. Mono<Void>

    • reactor.core.publisher.Mono是Reactor库中的一种响应式流类型,它表示包含零或一个元素的异步序列。
    • 在这个例子中,Mono<Void>表示一个不包含元素的Mono,用于表示异步操作的完成状态。
  4. ResponseStatusException类

    • org.springframework.web.server.ResponseStatusException是Spring WebFlux中的异常类,它表示特定的HTTP响应状态码和可选的原因。
    • 在这个例子中,我们使用它来检查是否存在特定类型的异常,并将其转换为对应的HTTP响应状态码。
  5. @Component注解

    • org.springframework.stereotype.Component是Spring框架中用于声明组件的注解。
    • 通过将CustomWebFluxExceptionHandler类标记为@Component,我们告诉Spring框架要将它识别为一个组件,并在应用程序上下文中进行管理。
  6. @Order注解

    • org.springframework.core.annotation.Order是Spring框架中用于定义组件排序顺序的注解。
    • 在这个例子中,@Order(-2)表示将CustomWebFluxExceptionHandler组件的处理顺序设置为-2,确保它在默认处理器之前执行。

4. WebFlux集成测试

代码示例
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class WebFluxIntegrationTest {

    @Autowired
    private WebTestClient webTestClient;

    @Test
    void testMonoEndpoint() {
        webTestClient.get()
                .uri("/router/mono")
                .exchange()
                .expectStatus().isOk()
                .expectBody(String.class).isEqualTo("Hello, Mono from Router!");
    }

    @Test
    void testFluxEndpoint() {
        webTestClient.get()
                .uri("/router/flux")
                .exchange()
                .expectStatus().isOk()
                .expectBodyList(Integer.class).isEqualTo(List.of(1, 2, 3, 4, 5));
    }
}

相关API
  1. @SpringBootTest 注解:

    • 该注解表示这是一个Spring Boot的集成测试。
    • webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT 表示在测试过程中随机选择一个可用端口。
  2. WebTestClient 对象:

    • 通过@Autowired注入WebTestClient,这是Spring框架提供的用于进行Web请求的测试客户端。
  3. testMonoEndpoint 方法:

    • 这是一个测试方法,用于测试一个返回单一值的WebFlux端点。
    • webTestClient.get() 发起一个GET请求。
    • .uri("/router/mono") 设置请求的URI为"/router/mono"。
    • .exchange() 发送请求并获取响应。
    • .expectStatus().isOk() 验证响应的HTTP状态码是否为OK(200)。
    • .expectBody(String.class).isEqualTo("Hello, Mono from Router!") 验证响应体的内容是否为指定的字符串。
  4. testFluxEndpoint 方法:

    • 这是另一个测试方法,用于测试一个返回Flux(反应式流)的WebFlux端点。
    • testMonoEndpoint类似,不同之处在于使用了.expectBodyList(Integer.class)来验证响应体是否为一个List,并且该List的元素类型为整数。
    • 使用.isEqualTo(List.of(1, 2, 3, 4, 5))验证返回的整数列表是否与期望的一致。

总体来说,这个测试类通过WebTestClient发送HTTP请求到"/router/mono"和"/router/flux"端点,然后验证返回的响应是否符合预期。这样可以确保WebFlux端点的行为是正确的,同时也是一种测试反应式流的方式。

学习打卡day09:响应式编程WebFlux基础实战练习

  • 15
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摸魚散人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值