Spring WebFlux是Spring Framework 5.0中引入的新的反应式Web框架。与Spring MVC不同,它不需要Servlet API,完全异步且无阻塞,并 通过Reactor项目实现Reactive Streams规范。
Spring WebFlux有两种版本:基于功能和注释。基于注释的注释非常接近Spring MVC模型,如以下示例所示:
@RestController
@RequestMapping("/users")
public class MyRestController {
@GetMapping("/{user}")
public Mono getUser(@PathVariable Long user) {
// ...
}
@GetMapping("/{user}/customers")
public Flux getUserCustomers(@PathVariable Long user) {
// ...
}
@DeleteMapping("/{user}")
public Mono deleteUser(@PathVariable Long user) {
// ...
}
}
“WebFlux.fn”是功能变体,它将路由配置与请求的实际处理分开,如以下示例所示:
@Configuration
public class RoutingConfiguration {
@Bean
public RouterFunction monoRouterFunction(UserHandler userHandler) {
return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)
.andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)
.andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);
}
}
@Component
public class UserHandler {
public Mono getUser(ServerRequest request) {
// ...
}
public Mono getUserCustomers(ServerRequest request) {
// ...
}
public Mono deleteUser(ServerRequest request) {
// ...
}
}
默认情况下,Spring Boot从类路径中名为/static( /public或/resources或/META-INF/resources)的目录中提供静态内容。它使用 ResourceWebHandlerSpring WebFlux,以便您可以通过添加自己WebFluxConfigurer的addResourceHandlers方法来修改该行为并覆盖该方法。
默认情况下,会映射资源/**,但您可以通过设置spring.webflux.static-path-pattern属性来调整它 。例如,/resources/**可以按如下方式重新定位所有资源 :
spring.webflux.static-path-pattern = / resources / **
您还可以使用自定义静态资源位置 spring.resources.static-locations。这样做会将默认值替换为目录位置列表。如果这样做,默认的欢迎页面检测会切换到您的自定义位置。因此,如果index.html您的任何位置在启动时存在,则它是应用程序的主页。
除了前面列出的“标准”静态资源位置之外,还为Webjars内容制作了一个特例。具有路径的任何资源 /webjars/**都是从jar文件提供的,如果它们以Webjars格式打包的话。
【Tip】Spring WebFlux应用程序并不严格依赖于Servlet API,因此它们不能作为war文件部署,也不能使用该src/main/webapp目录。
除REST Web服务外,您还可以使用Spring WebFlux来提供动态HTML内容。
Spring Boot包含对以下模板引擎的自动配置支持:
当您使用其中一个模板引擎和默认配置时,您的模板将自动从中获取src/main/resources/templates。
Spring Boot提供了WebExceptionHandler一种以合理的方式处理所有错误的方法。它在处理顺序中的位置紧接在WebFlux提供的处理程序之前,这被认为是最后的。对于计算机客户端,它会生成一个JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。对于浏览器客户端,有一个“whitelabel”错误处理程序,它以HTML格式呈现相同的数据。您还可以提供自己的HTML模板来显示错误。
自定义此功能的第一步通常涉及使用现有机制,但替换或扩充错误内容。为此,您可以添加类型的bean ErrorAttributes。
要更改错误处理行为,可以实现ErrorWebExceptionHandler并注册该类型的bean定义。由于 WebExceptionHandler是一个非常低级别的,Spring Boot还提供了一个方便AbstractErrorWebExceptionHandler的让你以WebFlux功能方式处理错误,如下例所示:
public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
// Define constructor here
@Override
protected RouterFunction getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions
.route(aPredicate, aHandler)
.andRoute(anotherPredicate, anotherHandler);
}
}
您还可以DefaultErrorWebExceptionHandler直接子类化并覆盖特定方法。
如果要显示给定状态代码的自定义HTML错误页面,可以将文件添加到文件/error目录下。错误页面可以是静态HTML或使用模板构建。文件名应该是确切的状态代码或系列掩码。
例如,要映射404到静态HTML文件,您的文件夹结构如下所示:
public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
// Define constructor here
@Override
protected RouterFunction getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions
.route(aPredicate, aHandler)
.andRoute(anotherPredicate, anotherHandler);
}
}
Spring WebFlux提供了一个WebFilter可以实现过滤HTTP请求 - 响应交换的接口。WebFilter在应用程序上下文中找到的bean将自动用于过滤每个exchange。
如果过滤器的顺序很重要,则可以实现Ordered或注释@Order。Spring Boot自动配置可以为您配置Web过滤器。执行此操作时,将使用下表中显示的订单:
Web Filter | Order |
HttpTraceWebFilter | Ordered.LOWEST_PRECEDENCE - 10 |
MetricsWebFilter | Ordered.HIGHEST_PRECEDENCE + 1 |
WebFilterChainProxy | -100 |
@Data
public class User {
private String name;
private int age;
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
@Service
public class UserService {
private Map userMap =new ConcurrentHashMap<>();
public void setUser(String userId,User user) {
userMap.put(userId,user);
}
public Mono findUserById(String userId){
User user = userMap.getOrDefault(userId,new User("nick",18));
return Mono.just(user);
}
public Flux findUserList(){
List userList = new ArrayList<>();
Set> entries =userMap.entrySet();
entries.stream().forEach(entry->userList.add(entry.getValue()));
return Flux.fromStream(userList.stream());
}
}
@Component
@Slf4j
public class UserHandler {
@Autowired
UserService userService;
public Mono getUserList(ServerRequest request) { //Lambda 匿名参数
Flux userFlux = userService.findUserList();
userFlux.subscribe(user -> log.info(user.toString()));
return ServerResponse.ok().body(userFlux,User.class);
}
public Mono getUser(ServerRequest request) {
String userId = request.pathVariable("userId");
Mono userMono = userService.findUserById(userId);
userMono.subscribe(user -> log.info(user.toString()));
return ServerResponse.ok().body(userMono,User.class);
}
}
@Configuration
public class UserRoutes {
@Bean
@Autowired
public RouterFunction routersFunction(UserHandler userHandler){
return RouterFunctions
.route(RequestPredicates.GET("/api/users"),userHandler::getUserList)
.and(RouterFunctions.route(RequestPredicates.GET("/api/user/{userId}"),userHandler::getUser));
}
}
@Component
public class Init implements CommandLineRunner {
@Autowired
UserService userService;
@Override
public void run(String... args) throws Exception {
userService.setUser("1",new User("carlos",18));
userService.setUser("2",new User("lisa",19));
userService.setUser("3",new User("mike",17));
userService.setUser("4",new User("tom",16));
userService.setUser("5",new User("amy",15));
}
}
@SpringBootApplication
@EnableWebFlux
public class WebfluxApplication {
public static void main(String[] args) {
SpringApplication.run(WebfluxApplication.class, args);
}
}
打开浏览器 地址栏输入借口地址并得到验证返回值:
#findUserList()
-->http://localhost:8080/api/users
--< [{"name":"carlos","age":18},{"name":"lisa","age":19},{"name":"mike","age":17},{"name":"tom","age":16},{"name":"amy","age":15}]
#findUserById()
-->http://localhost:8080/api/user/1
--< {"name":"carlos","age":18}
代码地址:spring boot webflux demo
(设置了两分,有分的大佬就给点,没有的 留邮箱或联系[email protected])