WebFlux是什么
Spring WebFlux 是 Spring MVC 的完全非阻塞响应式替代方案,它可以在不增加硬件资源的情况下实现更好的垂直扩展。作为反应式,它现在利用反应式流来允许异步处理从调用返回到服务器的数据。这意味着我们将看到更少的
List
s、Collection
s 甚至单个对象,取而代之的是它们的反应式等价物,例如Flux
和Mono
(来自 Reactor)
简单例子
上面代码是否看起来很熟悉,它与标准的 Spring MVC 控制器看起来并没有什么不同,但是在阅读这些方法之后,我们可以看到与我们通常期望的返回类型是不一样的。在这个例子中
userDao
必须是一个反应式存储库或继承于一个反应式存储库,因为我们已经能够直接返回他们的搜索查询的结果,作为参考,反应式存储库将返回一个Flux
用于集合和一个Mono
用于单一实体。
请求地址路由
在 SpringMVC 中,我们可以通过如下一些注解来控制请求 URL 和处理器之间的映射关系:
- @RequestMapping
- @GetMapping
- @PostMapping
- @DeleteMapping
- @PutMapping
这些注解虽然在 WebFlux 中还可以继续使用,不过 WebFlux 也提供了自己的方案:Router。
编写处理器
删除掉UserController
编写我们的UserHandler
package com.jarvan.springwebfluxmongodb.config;
import com.jarvan.springwebfluxmongodb.dao.UserDao;
import com.jarvan.springwebfluxmongodb.entity.User;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
@Component
public class UserHandler {
final UserDao userDao;
public UserHandler(UserDao userDao) {
this.userDao = userDao;
}
public Mono<ServerResponse> add(ServerRequest serverRequest) {
return ok().contentType(MediaType.APPLICATION_JSON)
.body(userDao.saveAll(serverRequest.bodyToMono(User.class)), User.class);
}
public Mono<ServerResponse> delete(ServerRequest serverRequest) {
return userDao.findById(serverRequest.pathVariable("id"))
.flatMap(p -> userDao.delete(p).then(ok().build()))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> getAll(ServerRequest serverRequest) {
return ok().contentType(MediaType.APPLICATION_JSON)
.body(userDao.findAll(), User.class);
}
public Mono<ServerResponse> findById(ServerRequest serverRequest) {
return ok().contentType(MediaType.APPLICATION_JSON)
.body(userDao.findById(serverRequest.pathVariable("id")), User.class);
}
}
配置路由
接下来我们把请求的 URL 地址和这些处理器之间关联起来,配置如下
package com.jarvan.springwebfluxmongodb.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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 org.springframework.web.reactive.function.server.ServerResponse;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.server.RequestPredicates.*;
@Configuration
public class UserRouter {
@Bean
public RouterFunction<ServerResponse> route(UserHandler userHandler) {
return RouterFunctions.nest(RequestPredicates.path("/user"),
RouterFunctions.route(RequestPredicates.POST("/add"), userHandler::add)
.andRoute(RequestPredicates.DELETE("/delete/{id}"), userHandler::delete)
.andRoute(RequestPredicates.GET("/getAll").and(accept(APPLICATION_JSON)), userHandler::getAll)
.andRoute(RequestPredicates.GET("/{id}").and(accept(APPLICATION_JSON)), userHandler::findById)
);
}
}
上面这个配置类
1、
首先调用
nest()方法,第一个参数配置的相当于是接下来配置的地址的一个前缀,这有点类似于我们在
Controller类上直接写
@RequestMapping` 注解去配置地址。2、
nest()
方法的第二个参数就是RouterFunction
实例了,每一个RouterFunction
实例通过RouterFunctions.route
方法来构建,它的第一个参数就是请求的 URL 地址(注意这个时候配置的地址都是有一个共同的前缀),第二个参数我们通过方法引用的方式配置了一个HandlerFunction
,这个就是当前请求的处理器了。3、通过
.andRoute
可以配置多个路由。
此处注意路由匹配的优先级,如下图,如果先匹配/{id},则/user/getAll
方法将会匹配/{id},然后去查id为getAll的数据
测试
add
查询
删除
如果删除的数据存在响应200、不存在将返回404