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

创建react应用程序

1.React式编程简介

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

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

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

2. Spring的React式编程

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

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

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

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

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

  • 功能模型
  • 注释模型

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

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

传统堆栈 React堆
Spring Web MVC SpringWebFlux
控制器和处理程序映射 路由器功能
Servlet API HTTP /React流
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或以上
  • Sprint Boot: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响应,从而使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 {

	@Autowired
	private 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 Request
		int 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 Mono
			res=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 Mono
		Mono 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 Mono
			res=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 Mono
		  res=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{
    @Autowired
    EmployeeHandler employeeHandler;
    
    @Bean
    public 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.参考:

8.下载Eclipse项目

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

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

创建react应用程序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值