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

使用SpringWebFlux的反应式Web应用程序相关推荐

  1. 创建react应用程序_使用SpringWebFlux的React式Web应用程序

    创建react应用程序 1.React式编程简介 React式编程是为具有以下特征的应用程序创造的术语: 非阻塞应用 事件驱动和异步 需要少量线程来垂直扩展(即在JVM中) 就像面向对象的编程,函数式 ...

  2. java局部网内通话杂音_在Spring Boot反应式Web应用程序上启用SSL,并在控制台中对该打印进行http调用时出现异常噪音...

    在我创建了我的spring boot反应式Web应用程序以支持SSL之后,当我尝试对服务器进行http调用时,它会在控制台中的异常跟踪下面打印 . 作为应用程序所有者,我无法阻止任何人使用我的服务 . ...

  3. node.js 静态属性_如何使用静态站点和Node.js开发和部署第一个全栈式Web应用程序

    node.js 静态属性 This tutorial will show you how to convert a static website that uses HTML, CSS and Jav ...

  4. Rxjs 响应式编程-第四章 构建完整的Web应用程序

    Rxjs 响应式编程-第一章:响应式 Rxjs 响应式编程-第二章:序列的深入研究 Rxjs 响应式编程-第三章: 构建并发程序 Rxjs 响应式编程-第四章 构建完整的Web应用程序 Rxjs 响应 ...

  5. heroku_了解如何使用Heroku部署全栈Web应用程序

    heroku Building a full stack web app is no mean feat. Learning to deploy one to production so that y ...

  6. [译] 响应式 Web 应用(一)

    本文由 Shaw 发表在 ScalaCool 团队博客. 原书 www.manning.com/books/react- 第一章:你是说「响应式」? 本章内容 响应式应用及其起源 为什么响应式应用是必 ...

  7. 渐进式Web应用程序的深入概述

    概述 如果您是Web开发人员,您可能已经了解渐进式Web应用程序(PWA)或已经实现了自己的应用程序. 如果您不熟悉,本文将深入概述渐进式Web应用程序的实现原理,以及它们在现代Web开发中的重要程度 ...

  8. 使用Spring boot,Thymeleaf,AngularJS从零开始构建一个新的Web应用程序-第1部分

    在这一系列博客文章中,我们将使用以下技术堆栈构建完整的响应式Web应用程序: 1)弹簧靴 – Spring MVC网站 – Spring Data JPA –Spring安全 2)Thymeleaf用 ...

  9. terracotta_具有Spring Web Flow和Terracotta的Spring Web应用程序

    terracotta 抽象 Spring Web Flow是Spring Framework Web应用程序堆栈的一个组件,它提供了一种编写有状态,会话式Web应用程序的简单方法. 通过允许您将Spr ...

最新文章

  1. Android环境结构--安装Eclipse错
  2. 今年世界杯的广告有毒,创意总监都该被fire
  3. 苹果隐藏应用_使用iMazing导出苹果设备中的录音文件
  4. Java GUI 基础知识2 监听机制
  5. sha256---利用java自带的实现加密
  6. python 坐标轴刻度 格式_matplotlib命令与格式之tick坐标轴日期格式(设置日期主副刻度)...
  7. mac os x 安装mysql遇到 Access denied for user 'root'@'localhost' (using password: YES)的解决方法...
  8. 极限学习机︱R语言快速深度学习进行回归预测
  9. 数据结构与算法(一):线性表、栈、树(二叉树,AVL树)、图
  10. python下载完是什么样的图片_[宅男福利]用Python下载页面中所有的图片
  11. VB代码 VB小程序
  12. VGG-16网络结构
  13. [裴礼文数学分析中的典型问题与方法习题参考解答]5.1.25
  14. 自动化测试框架cucumber_10分钟学会 Cucumber+Watir 自动化测试框架
  15. 蓝懿iOS 技术内容交流和学习心得 11.11
  16. 2019京东全球科技探索者大会议程抢先曝光!
  17. 国网入职计算机考试题库,2019年国家电网入职考试题库.pdf
  18. 脚本语言【JavaScript基础】JavaScript函数:声明+调用
  19. 【pytorch】torchvision.transforms 图像的变换详解;图像的预处理;数据增强
  20. 最佳化三维建模与重构中的神经网络先验

热门文章

  1. MySQL死锁如何处理
  2. MySQL substring()函数
  3. js实现页面跳转重定向的几种方式
  4. [初级]Java中的switch对整型、字符型、字符串的具体实现细节
  5. Selector 实现原理
  6. 厉害了,Servlet3的异步处理机制
  7. git创建tag标签
  8. Vue.js基础体验(一)
  9. el表达式与jstl的用法
  10. 计算机视觉论文doc,嘉炬-计算机视觉论文资料.doc