Spring Boot 2WebFlux Restful 基于annotation实现教程(二)

    技术2025-10-21  14

    一、简介

    Spring WebFlux

    Spring 官方文档对 Spring WebFlux 介绍如下:

    FROM https://docs.spring.io/spring-framework/docs/5.0.0.BUILD-SNAPSHOT/spring-framework-reference/html/web-reactive.html

    Spring Framework 5 includes a new spring-webflux module. The module contains support for reactive HTTP and WebSocket clients as well as for reactive server web applications including REST, HTML browser, and WebSocket style interactions.

    Spring Framework 5 提供了一个新的 spring-webflux 模块。该模块包含了:

    对响应式支持的 HTTP 和 WebSocket 客户端。对响应式支持的 Web 服务器,包括 Rest API、HTML 浏览器、WebSocket 等交互方式。

    On the server-side WebFlux supports 2 distinct programming models:

    Annotation-based with @Controller and the other > annotations supported also with Spring MVCFunctional, Java 8 lambda style routing and handling

    下图显示了服务端的技术栈,左侧是 spring-webmvc 模块中传统的、基于 Servlet 的 Spring MVC ,右侧是 spring-webflux 模块中的响应式技术栈。

    仔细看第一层的两个框框,分别是上面提到的 WebFlux 的两种编程模型。表达的是 SpringMVC 不支持 Router Functions 方式,而 WebFlux 支持。

    WebFlux can run on Servlet containers with support for the Servlet 3.1 Non-Blocking IO API as well as on other async runtimes such as Netty and Undertow.

    WebFlux 可以运行在:

    支持 Servlet 3.1 非阻塞 IO API 的 Servlet 容器上也可以运行在支持异步运行时的,例如说 Netty 或者 Undertow 上

    Each runtime is adapted to a reactive ServerHttpRequest and ServerHttpResponse exposing the body of the request and response as Flux, rather than InputStream and OutputStream, with reactive backpressure.

    每一个运行时(runtime)适用于将响应式的 ServerHttpRequest 和 ServerHttpResponse 中 request 和 response 的 body 暴露成 Flux<DataBuffer> 对象,而不是 InputStream 和 InputStream 对象,可用于响应式中的背压(backpressure)。这段有点晦涩,简单来说:

    对于 Servlet 来说, ServletRequest#getInputStream() 方法,获得请求的主体内容返回的是 InputStream 对象。对于 WebFlux 来说,ServerHttpRequest#getBody() 方法,获得请求的主体内容返回的是 Flux<DataBuffer> 对象。

    REST-style JSON and XML serialization and deserialization is supported on top as a Flux<Object>, and so is HTML view rendering and Server-Sent Events.

    REST 风格 API 使用到的 JSON 和 XML 序列化和反序列化,需要提供对 Flux<Object> 的支持。对于 HTML 渲染,和 SSE 也要提供对 Flux<Object> 的支持。

    二、快速入门   1、引入依赖

    <?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> <artifactId>spring-boot-parent</artifactId> <groupId>org.springframework.boot</groupId> <version>2.3.1.RELEASE</version> </parent> <groupId>com.mscloudmesh</groupId> <artifactId>springboot-webflux</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>

    2.实体类UserInfo

    package com.mscloudmesh.webflux.annotation.model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; @Data @Slf4j @AllArgsConstructor @NoArgsConstructor public class UserInfo implements java.io.Serializable { private Long id; private String userName; private Integer age; }

    3、数据交互层UserRepository(这里用一个map模拟数据库操作)

    package com.mscloudmesh.webflux.annotation.repository; import com.mscloudmesh.webflux.annotation.model.UserInfo; import org.springframework.stereotype.Repository; import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; @Repository public class UserRepository { private ConcurrentMap<Long, UserInfo> userDataMap = new ConcurrentHashMap<Long, UserInfo>(); private static final AtomicLong idGenerator = new AtomicLong(0); public UserInfo save(UserInfo userInfo) { Long id = idGenerator.incrementAndGet(); UserInfo info = new UserInfo(id, "kevin", 30); userDataMap.put(id, userInfo); return userInfo; } public Collection<UserInfo> findAll() { return userDataMap.values(); } public UserInfo findByUsrId(Long id) { return userDataMap.get(id); } public UserInfo updateUserInfo(UserInfo userInfo) { userDataMap.put(userInfo.getId(), userInfo); return userInfo; } public Long deleteUserById(Long id) { userDataMap.remove(id); return id; } }

    4.handler实现

    package com.mscloudmesh.webflux.annotation.service; import com.mscloudmesh.webflux.annotation.model.UserInfo; import com.mscloudmesh.webflux.annotation.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @Service public class UserHandler { @Autowired private UserRepository repository; public Mono<UserInfo> save(UserInfo userInfo) { return Mono.create(userInfoMonoSink -> userInfoMonoSink.success(repository.save(userInfo))); } public Mono<UserInfo> findByUserId(Long id) { return Mono.justOrEmpty(repository.findByUsrId(id)); } public Mono<UserInfo> updateUser(UserInfo userInfo) { return Mono.create(userInfoMonoSink -> userInfoMonoSink.success(repository.save(userInfo))); } public Mono<Long> deleteUserById(Long id) { return Mono.create(userInfoMongoSink -> userInfoMongoSink.success(repository.deleteUserById(id))); } }

    5.controller测试类

    package com.mscloudmesh.webflux.annotation.controller; import com.mscloudmesh.webflux.annotation.model.UserInfo; import com.mscloudmesh.webflux.annotation.service.UserHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; @RestController @RequestMapping("/webflux") public class UserWebfluxController { @Autowired private UserHandler userHandler; @RequestMapping("/save") public Mono<UserInfo> save(UserInfo info){ return userHandler.save(info); } @RequestMapping("/findById") public Mono<UserInfo> findById(Long id ){ return userHandler.findByUserId(id); } } 开始测试一下:   

    Processed: 0.010, SQL: 9