SpringBoot系列:基于SpringBoot2.0的WebFlux应用入门

2024-02-15 16:48

本文主要是介绍SpringBoot系列:基于SpringBoot2.0的WebFlux应用入门,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Spring WebFlux是在Spring框架5中引入的一种新的反应式Web框架。与Spring MVC不同,它不需要servlet API,完全异步和非阻塞,并通过Reactive Project实现Reactive Streams规范。

官网文档地址:

https://docs.spring.io/spring/docs/5.0.5.RELEASE/spring-framework-reference/web-reactive.html#webflux

1、创建一个SpringBoot2.0项目

Eclipse中创建Maven工程,也可以使用Spring Initializer创建,在Pom.xml中添加依赖:

注意:SpringBoot2.0仅支持JDK8.0以上,不支持JDK6、JDK7

<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.sample</groupId><artifactId>sun-sample-springboot-webflux</artifactId><version>0.0.1-SNAPSHOT</version><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.0.1.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

Spring-boot-starter-webflux 将 spring-webflux、netty 以及其他必须的依赖包引入到类路径中。

h2database 是h2内存数据库,用于快速测试

jpa 是ORM操作,快速编写CRUD

工程主函数代码如下:

package com.suncht.sample;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class WebfluxApplication {public static void main(String[] args) {SpringApplication.run(WebfluxApplication.class, args);}
}

application.properties属性文件配置如下:

server.port=8080spring.datasource.url=jdbc:h2:file:D\:/h2/h2test;AUTO_SERVER=TRUE;DB_CLOSE_DELAY=-1
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=truespring.h2.console.enabled=true
spring.h2.console.path=/console
spring.h2.console.settings.trace=false
spring.h2.console.settings.web-allow-others=false#logging.level.root=debug

2、创建 HttpServer 

package com.suncht.sample.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;import reactor.ipc.netty.http.server.HttpServer;/*** 配置HttpServer* 可以配置基于Netty、基于Tomcat、基于Jetty* @author suncht**/
@Configuration
public class HttpServerConfig {@Autowiredprivate Environment environment;@Beanpublic HttpServer httpServer(RouterFunction<?> routerFunction) {HttpHandler httpHandler = RouterFunctions.toHttpHandler(routerFunction);ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);HttpServer server = HttpServer.create("localhost", Integer.valueOf(environment.getProperty("server.port")));server.newHandler(adapter);return server;}
}

这个根据应用配置中指定的端口创建一个 Netty HttpServer 服务器。Spring 支持例如 Tomcat 或者 Undertow 等其他服务器。因为 Netty 本身是异步的和事件驱动的,因此它更适合用来运行 Reactive 应用。而 Tomcat 使用 Java NIO 来实现 Servlet 规范。Netty 的 NIO 实现专门针对异步、事件驱动和非堵塞应用进行了优化。

3、编写Http请求的业务逻辑

WebFlux 支持两种编程:

(1)使用@Controller这种基于注解的姿势, 与Sring MVC的姿势相同,最简单最简洁

(2)基于Java 8 Lambda的函数式编程风格,需要编写Handler和Router

第一方式:基于注解

package com.suncht.sample.controller;import java.util.List;
import java.util.Optional;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import com.suncht.sample.model.User;
import com.suncht.sample.service.UserRepository;/*** WebFlux的第一种方式: annotation-based(注解)* @author suncht**/
@RestController
@RequestMapping("/users")
public class UserRestController {@Autowiredprivate UserRepository userRepository;@GetMapping("/")public List<User> getAllUser() {return userRepository.findAll();}@GetMapping("/{id}")public User getUser(@PathVariable Long id) {Optional<User> user = userRepository.findById(id);return user.get();}@GetMapping("/add/{userName}/{age}")public Long getUser(@PathVariable("userName") String userName, @PathVariable("age") Integer age) {User user = new User();user.setUserName(userName);user.setAge(age);User result = userRepository.save(user);return result.getId();}}

第二种方式:基于函数

package com.suncht.sample.handler;import java.util.Optional;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;import com.suncht.sample.model.User;
import com.suncht.sample.service.UserRepository;import reactor.core.publisher.Mono;/*** UserHandler* 用户操作的业务逻辑* @author suncht**/
@Service
public class UserHandler {@Autowiredprivate UserRepository userRepository;public Mono<ServerResponse> handleGetUserById(ServerRequest request) {Long userId = Long.valueOf(request.pathVariable("id"));Optional<User> user = userRepository.findById(userId);return ServerResponse.ok().body(Mono.just(user.get()), User.class).switchIfEmpty(ServerResponse.notFound().build());}	
}

这是针对用户的handler,其实就是用户的业务逻辑操作而已。跟我们平时写的业务逻辑不同是:返回对象Mono和Flux。

关于Mono和Flux,请参考官网:https://docs.spring.io/spring/docs/5.0.5.RELEASE/spring-framework-reference/web-reactive.html#webflux-fn-handler-functions

package com.suncht.sample.route;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 com.suncht.sample.handler.UserHandler;/*** WebFlux的第二种方式: functional(java方法)* Router路由,其实就是用代码实现http请求路径,类似于Python Web框架django,手动编写路由代码* @author suncht**/
@Configuration
public class UserRouter {@Beanpublic RouterFunction<?> routerFunction(UserHandler userHandler) {return RouterFunctions.route(RequestPredicates.GET("/api/user/{id}").and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), userHandler::handleGetUserById);}
}

这是用户http请求的路由规则,手动编写。较第一方法而言,比较麻烦。

4、测试

可以在浏览器中直接输入HTTP地址:http://127.0.0.1:8080/api/user/2 进行测试

也可以使用WebFlux中的WebClient测试,代码如下:

package com.suncht.sample.test;import java.util.List;import org.junit.Before;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;import com.suncht.sample.model.User;import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;public class WebTest {private WebClient client = null;@Beforepublic void init() {client = WebClient.create("http://127.0.0.1:8080/");}@Testpublic void testUserById() {Mono<User> result = client.get()// 请求方法,get,post....uri("users/{id}", "1")// 请求相对地址以及参数.accept(MediaType.APPLICATION_JSON).retrieve()// 请求类型.bodyToMono(User.class);// 返回类型User user = result.block();System.out.println(user);}@Testpublic void testUserById2() {Mono<User> result2 = client.get()// 请求方法,get,post....uri("api/user/{id}", "1")// 请求相对地址以及参数.accept(MediaType.APPLICATION_JSON).retrieve()// 请求类型.bodyToMono(User.class);// 返回类型User user2 = result2.block();System.out.println(user2);}@Testpublic void testAllUsers() {Flux<User> userFlux = client.get().uri("users/").accept(MediaType.APPLICATION_JSON).retrieve()// 请求类型.bodyToFlux(User.class);// 返回类型List<User> users = userFlux.collectList().block();System.out.println(users);}}

WebClient是远程调用Http请求的一种工具类、新思路

5、其他代码

User实体:

package com.suncht.sample.model;import java.io.Serializable;import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;@Entity
@Table(name = "t_user")
public class User implements Serializable {private static final long serialVersionUID = 1L;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(name="user_name", nullable=false, length=50)private String userName;@Column(name="age")private Integer age;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "User [id=" + id + ", userName=" + userName + ", age=" + age + "]";}}

针对User的JPA CRUD操作:

package com.suncht.sample.service;import org.springframework.data.jpa.repository.JpaRepository;import com.suncht.sample.model.User;public interface UserRepository extends JpaRepository<User, Long> {
}

6、整个工程项目结构预览


GitHub代码: https://github.com/suncht/sun-test/tree/master/springboot2.webflux.test

这篇关于SpringBoot系列:基于SpringBoot2.0的WebFlux应用入门的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/711954

相关文章

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll

Java中的工具类命名方法

《Java中的工具类命名方法》:本文主要介绍Java中的工具类究竟如何命名,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Java中的工具类究竟如何命名?先来几个例子几种命名方式的比较到底如何命名 ?总结Java中的工具类究竟如何命名?先来几个例子JD

Java Stream流使用案例深入详解

《JavaStream流使用案例深入详解》:本文主要介绍JavaStream流使用案例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录前言1. Lambda1.1 语法1.2 没参数只有一条语句或者多条语句1.3 一个参数只有一条语句或者多

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依