SpringBoot基于WebFlux注解的RestAPIs示例源码 githup
Spring 5通过引入一个名为Spring WebFlux的全新反应框架,采用了反应式编程范式。
Spring WebFlux是一个自下而上的异步框架。它可以使用Servlet 3.1非阻塞IO API以及其他异步运行时环境(如netty或afow)在Servlet容器上运行。
它将与Spring MVC一起使用。是的,Spring MVC不会去任何地方。它是开发人员长期使用的流行Web框架。
但是您现在可以在新的反应框架和传统的Spring MVC之间进行选择。您可以根据使用情况选择使用其中任何一种。
小编学习的途径是先直接到官网看看,于是看到了最明显的区别就是下图
图先放这里,先不着急,先看下,有一个印象,后面会说到。
Spring Framework 5.0支持完全异步和非阻塞的WebFlux,并且不需要Servlet API(与Spring MVC不同)。
Spring WebFlux支持2种不同的编程模型:
在本教程中,我们将介绍带有Functional的 WebFlux 。
对于从WebFlux开始,SpringBoot支持集合依赖:spring-boot-starter-webflux。
使用Spring WebFlux Functional,我们使用{ HandlerFunctions,RouterFunctions}来开发。
1. HandlerFunctions
HandlerFunctions将处理传入的HTTP请求ServerRequest,并返回一个Mono
@Component
public class CustomerHandler {
...
public Mono getAll(ServerRequest request) {
...
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(customers, Customer.class);
}
...
public Mono putCustomer(ServerRequest request) {
...
return responseMono
.flatMap(cust -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(fromObject(cust)));
}
...
public Mono deleteCustomer(ServerRequest request) {
...
return responseMono
.flatMap(strMono -> ServerResponse.ok().contentType(MediaType.TEXT_PLAIN).body(fromObject(strMono)));
}
}
2. RouterFunction
RouterFunction处理所有传入的请求。需要一个ServerRequest,并返回一个。如果请求与特定路由匹配,则返回处理函数; 否则它返回一个空的Mono。Mono
@Configuration
public class RoutingConfiguration {
@Bean
public RouterFunction monoRouterFunction(CustomerHandler customerHandler) {
return route(GET("/api/customer").and(accept(MediaType.APPLICATION_JSON)), customerHandler::getAll)
.andRoute(GET("/api/customer/{id}").and(accept(MediaType.APPLICATION_JSON)), customerHandler::getCustomer)
.andRoute(POST("/api/customer/post").and(accept(MediaType.APPLICATION_JSON)), customerHandler::postCustomer)
.andRoute(PUT("/api/customer/put/{id}").and(accept(MediaType.APPLICATION_JSON)), customerHandler::putCustomer)
.andRoute(DELETE("/api/customer/delete/{id}").and(accept(MediaType.APPLICATION_JSON)), customerHandler::deleteCustomer);
}
}
好了,当你已经读到这里,相信已经对SpringBoot1.0和SpringBoot2.0有一个比较清晰的认识了(当用过Netty通信框架类的童鞋一定是非常清晰的,如果还不清晰,就要补补课了),所以我们不得不说SpringBoot2.0的性能一定是比1.0有所提升的。不过各有所爱,企业具体技术选型还要看业务需求,不能盲目追求新技术,毕竟新技术还不太稳定,没有被大规模的实践。好了,理论的知识就先讲到这里,开始实战编码吧。
在本教程中,我们创建一个SpringBoot项目,如下所示:
步骤:
使用SpringToolSuite,创建一个具有Reactive Web依赖关系的SpringBoot项目:
创建后检查pom.xml:
org.springframework.boot
spring-boot-starter-webflux
org.springframework.boot
spring-boot-starter-test
test
io.projectreactor
reactor-test
test
org.springframework.boot
spring-boot-maven-plugin
spring-snapshots
Spring Snapshots
https://repo.spring.io/snapshot
true
spring-milestones
Spring Milestones
https://repo.spring.io/milestone
false
spring-snapshots
Spring Snapshots
https://repo.spring.io/snapshot
true
spring-milestones
Spring Milestones
https://repo.spring.io/milestone
false
创建客户数据模型:
package com.javasampleapproach.webflux.model;
public class Customer {
private long custId;
private String firstname;
private String lastname;
private int age;
public Customer(){}
public Customer(long custId, String firstname, String lastname, int age){
this.custId = custId;
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
}
public long getCustId() {
return custId;
}
public void setCustId(Long custId) {
this.custId = custId;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
String info = String.format("custId = %d, firstname = %s, lastname = %s, age = %d", custId, firstname, lastname, age);
return info;
}
}
3.1定义接口CustomerRepository
package com.javasampleapproach.webflux.repo;
import com.javasampleapproach.webflux.model.Customer;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface CustomerRepository {
public Mono getCustomerById(Long id);
public Flux getAllCustomers();
public Mono saveCustomer(Mono customer);
public Mono putCustomer(Long id, Mono customer);
public Mono deleteCustomer(Long id);
}
3.2创建CustomerRepository
package com.javasampleapproach.webflux.repo.impl;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Repository;
import com.javasampleapproach.webflux.model.Customer;
import com.javasampleapproach.webflux.repo.CustomerRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Repository
public class CustomerRepositoryImpl implements CustomerRepository{
private Map custStores = new HashMap();
@PostConstruct
public void initIt() throws Exception {
custStores.put(Long.valueOf(1), new Customer(1, "Jack", "Smith", 20));
custStores.put(Long.valueOf(2), new Customer(2, "Peter", "Johnson", 25));
}
@Override
public Mono getCustomerById(Long id) {
return Mono.just(custStores.get(id));
}
@Override
public Flux getAllCustomers() {
return Flux.fromIterable(this.custStores.values());
}
@Override
public Mono saveCustomer(Mono monoCustomer) {
Mono customerMono = monoCustomer.doOnNext(customer -> {
// do post
custStores.put(customer.getCustId(), customer);
// log on console
System.out.println("########### POST:" + customer);
});
return customerMono.then();
}
@Override
public Mono putCustomer(Long id, Mono monoCustomer) {
Mono customerMono = monoCustomer.doOnNext(customer -> {
// reset customer.Id
customer.setCustId(id);
// do put
custStores.put(id, customer);
// log on console
System.out.println("########### PUT:" + customer);
});
return customerMono;
}
@Override
public Mono deleteCustomer(Long id) {
// delete processing
custStores.remove(id);
return Mono.just("Delete Succesfully!");
}
}
4.1 RouterFunction
package com.javasampleapproach.webflux.functional.router;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import com.javasampleapproach.webflux.functional.handler.CustomerHandler;
import static org.springframework.web.reactive.function.server.RequestPredicates.*;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import org.springframework.http.MediaType;
@Configuration
public class RoutingConfiguration {
@Bean
public RouterFunction monoRouterFunction(CustomerHandler customerHandler) {
return route(GET("/api/customer").and(accept(MediaType.APPLICATION_JSON)), customerHandler::getAll)
.andRoute(GET("/api/customer/{id}").and(accept(MediaType.APPLICATION_JSON)), customerHandler::getCustomer)
.andRoute(POST("/api/customer/post").and(accept(MediaType.APPLICATION_JSON)), customerHandler::postCustomer)
.andRoute(PUT("/api/customer/put/{id}").and(accept(MediaType.APPLICATION_JSON)), customerHandler::putCustomer)
.andRoute(DELETE("/api/customer/delete/{id}").and(accept(MediaType.APPLICATION_JSON)), customerHandler::deleteCustomer);
}
4.2 CustomerHandler
package com.javasampleapproach.webflux.functional.handler;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.http.MediaType;
import com.javasampleapproach.webflux.model.Customer;
import com.javasampleapproach.webflux.repo.CustomerRepository;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Component
public class CustomerHandler {
private final CustomerRepository customerRepository;
public CustomerHandler(CustomerRepository repository) {
this.customerRepository = repository;
}
/**
* GET ALL Customers
*/
public Mono getAll(ServerRequest request) {
// fetch all customers from repository
Flux customers = customerRepository.getAllCustomers();
// build response
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(customers, Customer.class);
}
/**
* GET a Customer by ID
*/
public Mono getCustomer(ServerRequest request) {
// parse path-variable
long customerId = Long.valueOf(request.pathVariable("id"));
// build notFound response
Mono notFound = ServerResponse.notFound().build();
// get customer from repository
Mono customerMono = customerRepository.getCustomerById(customerId);
// build response
return customerMono
.flatMap(customer -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(fromObject(customer)))
.switchIfEmpty(notFound);
}
/**
* POST a Customer
*/
public Mono postCustomer(ServerRequest request) {
Mono customer = request.bodyToMono(Customer.class);
return ServerResponse.ok().build(customerRepository.saveCustomer(customer));
}
/**
* PUT a Customer
*/
public Mono putCustomer(ServerRequest request) {
// parse id from path-variable
long customerId = Long.valueOf(request.pathVariable("id"));
// get customer data from request object
Mono customer = request.bodyToMono(Customer.class);
// get customer from repository
Mono responseMono = customerRepository.putCustomer(customerId, customer);
// build response
return responseMono
.flatMap(cust -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(fromObject(cust)));
}
/**
* DELETE a Customer
*/
public Mono deleteCustomer(ServerRequest request) {
// parse id from path-variable
long customerId = Long.valueOf(request.pathVariable("id"));
// get customer from repository
Mono responseMono = customerRepository.deleteCustomer(customerId);
// build response
return responseMono
.flatMap(strMono -> ServerResponse.ok().contentType(MediaType.TEXT_PLAIN).body(fromObject(strMono)));
}
}
使用命令行构建和运行SpringBoot项目:{ mvn clean install,mvn spring-boot:run}。
发出删除请求: http://localhost:8080/api/customer/delete/1
SpringBoot基于WebFlux注解的RestAPIs示例源码 githup
“随着微服务架构的发展,Spring Cloud 使用得越来越广泛。驰狼课堂 Spring Boot 快速入门,Spring Boot 与Spring Cloud 整合,docker+k8s,大型电商商城等多套免费实战教程可以帮您真正做到快速上手,将技术点切实运用到微服务项目中。”
关注公众号,每天精彩内容,第一时间送达!