使用SpringWebFlux的反应式Web应用程序

1.反应式编程简介

反应式编程是为具有以下特征的应用程序创造的术语:

  • 非阻塞应用
  • 事件驱动和异步
  • 需要少量线程来垂直扩展(即在JVM中)

就像面向对象的编程,函数式编程或过程式编程一样,反应式编程只是另一种编程范例。 它使我们的程序成为:响应式,弹性,弹性。

2. Spring的反应式编程

Spring框架内部使用Reactor为其自身提供响应式支持。 Reactor是Reactive Streams(发布程序,在Java9中引入)的实现。 Reactor具有以下两种数据类型:

  • 助焊剂(它是一个可以发射0个或多个元素的流)
  • 单声道(它是一个可以发出0或1个元素的流)

Spring从其API中公开这些类型,从而使应用程序具有响应性。

在Spring5中,引入了一个名为WebFlux的新模块,该模块支持使用以下方式创建反应式Web应用程序:HTTP(REST)和Web套接字。

Spring Web Flux支持以下两种模型:

  • 功能模型
  • 注释模型

在本文中,我们将探讨功能模型。

下表比较了普通Spring和Web Flux:

传统堆栈 反应堆
Spring Web MVC SpringWebFlux
控制器和处理程序映射 路由器功能
Servlet API HTTP /反应流
Servlet容器 任何支持Servlet 3.1 +,Tomcat 8.x,Jetty,Netty,UnderTow的servlet容器

3.用例

必须为员工管理系统创建一个使用Spring Web Flux的REST API,该系统将在员工身上公开CRUD。

注意:项目的DAO层是硬编码的。

4.所需的软件和环境

  • Java:1.8以上
  • Maven:3.3.9或更高
  • Eclipse Luna或以上
  • Spring靴:2.0.0.M4
  • Spring Boot Starter WebFlux
  • 邮递员测试应用程序

5.申请流程

Spring5 WebFlux的功能模型是使用Spring MVC样式注释的替代方法。 在Spring WebFlux功能模型中,路由器和处理程序函数用于创建MVC应用程序.HTTP请求通过路由器函数路由(替代@RequestMapping注解),请求通过处理程序函数 (替代@Controller处理程序方法)进行处理。

每个处理程序函数都将ServerRequestorg.springframework.web.reactive.function.server.ServerRequest )作为参数,结果将返回Mono<ServerResponse>Flux<ServerResponse>org.springframework.web.reactive.function.server.ServerResponse )。

6.用例代码和描述

pom.xml

<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.webflux</groupId><artifactId>Demo_Spring_MVC_Web_Flux</artifactId><version>0.0.1-SNAPSHOT</version><repositories><repository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><snapshots><enabled>true</enabled></snapshots></repository><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></repository></repositories><pluginRepositories><pluginRepository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><snapshots><enabled>true</enabled></snapshots></pluginRepository><pluginRepository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></pluginRepository></pluginRepositories><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.0.M4</version><relativePath /><!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><!-- Configuring Java 8 for the Project --><java.version>1.8</java.version></properties><!--Excluding Embedded tomcat to make use of the Netty Server--><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

EmployeeDAO.java

package com.webflux.dao;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import com.webflux.bussiness.bean.Employee;
@Repository
public class EmployeeDAO {/*** Map is used to Replace the Database * */static public Map mapOfEmloyeess = new LinkedHashMap();static int count=10004;static{mapOfEmloyeess.put(10001, new Employee("Jack",10001,12345.6,1001));mapOfEmloyeess.put(10002, new Employee("Justin",10002,12355.6,1002));mapOfEmloyeess.put(10003, new Employee("Eric",10003,12445.6,1003));}/*** Returns all the Existing Employees as Flux* */public Flux getAllEmployee(){return Flux.fromStream(mapOfEmloyeess.values().stream());		}/**Get Employee details using EmployeeId .* Returns a Mono response with Data if Employee is Found* Else returns a null* */public Mono getEmployeeDetailsById(int id){Monores = null;Employee emp =mapOfEmloyeess.get(id);if(emp!=null){res=Mono.just(emp);}return res;}/**Create Employee details.* Returns a Mono response with auto-generated Id* */public Mono addEmployee(Employee employee){count++;employee.setEmployeeId(count);mapOfEmloyeess.put(count, employee);return Mono.just(count);}/**Update the Employee details,* Receives the Employee Object and returns the updated Details* as Mono  * */public Mono updateEmployee (Employee employee){mapOfEmloyeess.put(employee.getEmployeeId(), employee);return Mono.just(employee);}/**Delete the Employee details,* Receives the EmployeeID and returns the deleted employee Details* as Mono  * */public Mono removeEmployee (int id){Employee emp= mapOfEmloyeess.remove(id);return Mono.just(emp);}	
}

可以观察到, EmployeeDAO所有方法都返回Mono或Flux Response,从而使DAO层处于活动状态。

EmployeeHandler.java

package com.webflux.web.handler;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.reactive.function.BodyExtractors;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import com.webflux.bussiness.bean.Employee;
import com.webflux.dao.EmployeeDAO;
@Controller
public class EmployeeHandler {@Autowiredprivate EmployeeDAO employeeDAO;/*** Receives a ServerRequest.* Invokes the method getAllEmployee() from EmployeeDAO.* Prepares a Mono and returns the same.* */	public Mono getEmployeeDetails(ServerRequest request) {Flux  res=employeeDAO.getAllEmployee();		return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(res,Employee.class);}/*** Receives a ServerRequest.* Extracts the Path Variable (named id) from the Request.* Invokes the method [getEmployeeDetailsById()] from EmployeeDAO.* Verifies if the object returned in the previous step is null * then returns a Bad request with appropriate message.* Else Returns the Mono with the Employee Data.* */public Mono getEmployeeDetailByEmployeeId(ServerRequest request) {//Extracts the Path Variable id from the Requestint id =Integer.parseInt(request.pathVariable("id"));Mono employee = employeeDAO.getEmployeeDetailsById(id);Mono res= null;if(employee==null){res=ServerResponse.badRequest().body(fromObject("Please give a valid employee Id"));}else{//Converting Mono of Mono type to Monores=employee.flatMap(x->ServerResponse.ok().body(fromObject(x))); }return res;}/*** Receives a ServerRequest.* Makes use of BodyExtractors and Extracts the Employee Data as * Mono from the ServerRequest.* Invokes the method [addEmployee()] of the EmployeeDAO.* Prepares a Mono and returns the same. * */public Mono addEmployee(ServerRequest request) {Mono requestBodyMono = request.body(BodyExtractors.toMono(Employee.class));Mono mono= employeeDAO.addEmployee(requestBodyMono.block());//Converting Mono of Mono type to MonoMono res= mono.flatMap(x->ServerResponse.ok().body(fromObject("Employee Created with Id"+x))); return res;}/*** Receives a ServerRequest.* Makes use of BodyExtractors and Extracts the Employee Data as * Mono from the ServerRequest.* Finds the Employee and updates the details by invoking updateEmployee() of   * EmployeeDAO. * Prepares a Mono and returns the same.* */public Mono updateEmployee(ServerRequest request) {Mono requestBodyMono = request.body(BodyExtractors.toMono(Employee.class));Employee employee =  requestBodyMono.block();Mono employeeRet = employeeDAO.getEmployeeDetailsById(employee.getEmployeeId());Mono res= null;if(employeeRet==null){res=ServerResponse.badRequest().body(fromObject("Please Give valid employee details to update"));}else{Mono emp= employeeDAO.updateEmployee(employee);//Converting Mono of Mono type to Monores=emp.flatMap(x->ServerResponse.ok().body(fromObject(x)));}return res;				}/*** Receives a ServerRequest.* Makes use of BodyExtractors and Extracts the Employee Data as * Mono from the ServerRequest.* Finds the Employee and deletes the details by invoking removeEmployee() of   * EmployeeDAO. * Prepares a Mono and returns the same.* */public Mono deleteEmployee(ServerRequest request) {int myId = Integer.parseInt(request.pathVariable("id"));Mono res= null;if (employeeDAO.getEmployeeDetailsById(myId) == null) {res=ServerResponse.badRequest().body(fromObject("Please Give valid employee details to delete"));}else{Mono employee = employeeDAO.removeEmployee(myId);//Converting Mono of Mono type to Monores=employee.flatMap(x->ServerResponse.ok().body(fromObject(x))); }return res;}
}

可以看出,Handler的所有方法都返回Mono<ServerResponse> ,从而使表示层处于响应状态。

注意 :事件处理程序方法应接受ServerRequest并应返回Mono<ServerResponse>

RouterConfiguration.java

package com.webflux.web.router.config;
import static org.springframework.web.reactive.function.server.RequestPredicates.DELETE;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
import static org.springframework.web.reactive.function.server.RequestPredicates.PUT;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import com.webflux.web.handler.EmployeeHandler;
@Configuration
/*** Router is configuration class.* It links the incoming requests with appropriate HTTP methods to the * respective method of the EmployeeHandler.* Method references are used for the mapping.* */
public class RouterConfiguration{@AutowiredEmployeeHandler employeeHandler;@Beanpublic RouterFunction monoRouterFunction() {RouterFunctionrouterFunction=  RouterFunctions.		route(GET("/emp/controller/getDetails").and(accept(MediaType.APPLICATION_JSON)),          employeeHandler::getEmployeeDetails).andRoute(GET("/emp/controller/getDetailsById/{id}").and(accept(MediaType.APPLICATION_JSON)),            employeeHandler::getEmployeeDetailByEmployeeId).andRoute(POST("/emp/controller/addEmp").and(accept(MediaType.APPLICATION_JSON)), employeeHandler::addEmployee).andRoute(PUT("/emp/controller/updateEmp").and(accept(MediaType.APPLICATION_JSON)), employeeHandler::updateEmployee).andRoute(DELETE("/emp/controller/deleteEmp/{id}").and(accept(MediaType.APPLICATION_JSON)), employeeHandler::deleteEmployee);return routerFunction;} }

ApplicationBootUp.java

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

在application.properties内部,仅提及服务器端口: server.port=8090

可以使用以下命令部署应用程序: clean install spring-boot:run并使用postman client进行测试。

7.参考:

  • https://docs.spring.io/spring/docs/5.0.0.BUILD-SNAPSHOT/spring-framework-reference/html/web-reactive.html
  • http://www.baeldung.com/reactor-core
  • http://www.baeldung.com/spring-5-functional-web

8.下载Eclipse项目

下载
您可以在此处下载此示例的完整源代码: SpringWebFlux

翻译自: https://www.javacodegeeks.com/2018/01/reactive-web-applications-using-springwebflux.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/348342.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

对linux的mv命令设计测试用例,测试用例中的细节 - 八音弦的个人空间 - OSCHINA - 中文开源技术交流社区...

编写测试用例是在实际测试执行开始之前进行的软件测试活动的重要组成部分。因此&#xff0c;在编写测试用例时必须头脑清晰地理解需求。测试执行阶段的顺利程度主要取决于测试用例的编写质量&#xff0c;还取决于对需求的理解程度。理论上来讲应避免在测试用例中放入不必要或不…

linux python whl md5,Python计算一个目录下的所有文件的md5值,在Linux系统下面

实现代码如下&#xff1a;#!/usr/bin/python#*-*coding:utf8*-*import osimport sysimport hashlibdef md5sum(data):with open(data, "rb") as f:md5 hashlib.md5() #赋空值for i in f.read(4096): #防止遇到大文件打开太占用内存&#xff0c;所以一次打开4…

Java命令行界面(第28部分):getopt4j

getopt4j的页面将其描述为“一个根据GNU样式解析命令行参数的库。” 然后&#xff0c; 页面介绍getopt4j &#xff1a;“getopt4j库旨在以与glibc &#xff08;GNU C运行时库&#xff09;中的C getopt&#xff08;&#xff09;函数相同的方式解析命令行选项。 与原始产品相比&a…

c语言找出公共子字符串,经典C语言面试题:求解最大公共子串

今天去面试&#xff0c;面试官出了一道题&#xff0c;求两个字符串的最大公共子串(Longest Common Substring)&#xff0c;一听起来不是很难&#xff0c;但让我在纸上写着写着就迷糊了。回来特地网搜了一下。面试下面经过两种方法来求两个字符串的最大连续公共子串。数组方法1&…

c语言中如何防止输入的格式存在错误,C语言如何避免输入

C语言如何处理输入下面这个题&#xff0c;数据的处理很简单&#xff0c;方法也很多。但是数据的输入如何处理呢&#xff0c;还要分多行输入&#xff01;&#xff01;引用标题&#xff1a;错误票据某涉密单位下发了某种票据&#xff0c;并要在年终全部收回。每张票据有唯一的ID号…

lucene 增加相关性_事务性Lucene

lucene 增加相关性许多用户不喜欢Lucene API的事务性语义&#xff0c;以及这在搜索应用程序中如何有用。 首先&#xff0c;Lucene实现了ACID属性&#xff1a; 一个 tomicity&#xff1a;当您在更改&#xff08;添加&#xff0c;删除文件&#xff09; IndexWriter会话&#xff…

新版ipados可以编辑C语言吗,iPadOS新增了五个有用的功能,看你需不需要

主屏幕上的可自定义小部件苹果通过“ iOS 14”对“小工具”进行了大修&#xff0c;引入了新的设计&#xff0c;功能和自定义选项。这些“小部件”也出现在在iPhone上&#xff0c;您可以抓住任何小部件并将其添加到应用程序图标旁边的“主屏幕”中&#xff0c;但是不能在“ iPad…

JavaParser生成,分析和修改Java代码

作为开发人员&#xff0c;我们经常鄙视手动进行重复工作的人员。 我们认为&#xff0c; 他们应该实现这一目标 。 尽管如此&#xff0c;我们还是进行与编码有关的所有活动。 当然&#xff0c;我们使用的高级IDE可以为我们执行一些重构&#xff0c;但这基本上就是结束了。 我们…

C语言去括号编程题,去括号 - C语言网

题目描述当老师不容易&#xff0c;尤其是当小学的老师更难:现在的小朋友做作业喜欢滥用括号。虽然不影响计算结果&#xff0c;但不够美观&#xff0c;容易出错&#xff0c;而且可读性差。但又不能一棒子打死&#xff0c;也许他们就是将来的“陈景润”呢&#xff01;为了减轻老师…

c语言中删除有序数组中重复元素,去除有序列表中的重复元素

2014-10-27 09:13:00更新你仔细研究一下我写的 testAsignPoint 和 testAsignPointAgain 函数就会明白为什么你的二级指针无效了。还是那句话&#xff0c;你要记住&#xff0c;指针就是一个变量&#xff0c;存的是32位数据&#xff0c;记住这个才能真正的理解指针。另外 pezy 说…

阿卡接口_阿卡vs风暴

阿卡接口我最近在Twitter的Storm上工作了一段时间&#xff0c;这让我想知道&#xff0c;它与另一个高性能的并发数据处理框架Akka相比如何 。 什么是Akka和Storm&#xff1f; 让我们从两个系统的简短描述开始。 Storm是一种分布式实时计算系统。 在Storm集群上&#xff0c;您执…

c 语言已知两点求第三点,已知3点座标,求第一点到第二点和第三点构成的直线的距离。...

已知3点座标&#xff0c;求第一点到第二点和第三点构成的直线的距离。以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;已知3点座标&#xff0c;求第一点到第二点和第三点构成的直线的距离。解…

连续交付友好的Maven版本

持续交付管道需要可预测的软件和依赖版本。 Maven软件项目中常见的快照版本与“持续交付”背后的动机背道而驰。 为了将快照版本更新为发行版本&#xff0c;开发人员通常手动或通过诸如maven-release-plugin来编辑pom.xml文件。 但是&#xff0c;Maven还提供了将版本号定义为属…

android u盘检测工具,android USBU盘 接入检测

如果是在注册的静态广播一般必须含有以上的权限&#xff0c;这里必须注意添加如果在代码中注册广播则必须iFilter.addDataScheme("file")这样接受广播判断U盘public class RemovableDiskManagerReceiver extends BroadcastReceiver {public RemovableDiskManagerRece…

android 组合属性动画,Android属性动画组合(sequence串行、together并行)

在android中用原生api实现一系列复杂动画会很麻烦&#xff0c;所以对属性动画进行了一定封装&#xff0c;让使用起来更简单&#xff0c;能够按照人的思维依次编写动画。简单效果&#xff1a;使用方法&#xff1a;添加依赖&#xff1a;dependencies { compile"com.steven:A…

jta atomikos_带有Atomikos示例的Tomcat中的Spring JTA多个资源事务

jta atomikos在本教程中&#xff0c;我们将向您展示如何使用Atomikos Transaction Manager在Tomcat服务器中实现JTA多个资源事务。 Atomicos事务管理器为分布式事务提供支持。 这些是多阶段事务&#xff0c;通常使用多个数据库&#xff0c;必须以协调的方式提交。 分布式事务由…

android 音量键 广播,【Android 7.0 Audio】: 按键调节音量的调用过程

转载自http://blog..net/xiashaohua/article/details/53842337只简单描述调用过程&#xff0c;需对照代码看&#xff0c;不画图了&#xff0c;也不贴代码)1.在key Event处理部分&#xff0c;Phonewindow会捕获到音量按键事件&#xff0c;Phonewindow.onkeydown--MediaSessionLe…

台电+android+电话,通话系统_台电 G17s_平板电脑评测-中关村在线

通话系统将两张联通3G的SIM卡插入台电G17s之后&#xff0c;我们来感受一下它通话系统的使用是否令人满意。和一般的双卡Android手机平板一样&#xff0c;该机也不支持热插拔&#xff0c;需要将机器彻底关闭后插入SIM卡再开机。并且在开机后屏幕会弹出SIM卡信息&#xff0c;并询…

在Payara Server和GlassFish中配置密码

回答Stackoverflow问题可以为我发现我最喜欢的开源工具的正式文档中的空白提供很好的反馈。 我在这里回答的问题之一是如何在docker容器中更改Payara Server主密码 。 显然&#xff0c;在标准服务器安装中&#xff0c;这很简单–只需使用asadmin change-master-password命令&am…

功能Java示例 第2部分–讲故事

这是称为“ Functional Java by Example”的系列文章的第2部分。 我在本系列的每个部分中发展的示例是某种“提要处理程序”&#xff0c;用于处理文档。 在上一部分中&#xff0c;我从一些原始代码开始&#xff0c;并应用了一些重构来描述“什么”而不是“如何”。 为了帮助代…