SpringBoot 2.0 Webflux 介绍 和Demo示例

 Spring WebFlux

 1.1 WebFlux 简介

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) {
        // ...
    }
}

【Tip】如果你再pom中同时引用了spring-boot-starter-webspring-boot-starter-webflux的话,优先会使用spring-boot-starter-web


1.2 Webflux 静态资源

默认情况下,Spring Boot从类路径中名为/static( /public或/resources或/META-INF/resources)的目录中提供静态内容。它使用 ResourceWebHandlerSpring WebFlux,以便您可以通过添加自己WebFluxConfigureraddResourceHandlers方法来修改该行为并覆盖该方法。

默认情况下,会映射资源/**,但您可以通过设置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目录。


1.3 Webflux 模版配置

除REST Web服务外,您还可以使用Spring WebFlux来提供动态HTML内容。

Spring Boot包含对以下模板引擎的自动配置支持:

  • - FreeMarker
  • - Thymeleaf
  • - Mustache

当您使用其中一个模板引擎和默认配置时,您的模板将自动从中获取src/main/resources/templates

 

1.4 统一错误处理和自定义错误页面

 

1.4.1错误处理

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直接子类化并覆盖特定方法。

 

1.4.2自定义错误页面

如果要显示给定状态代码的自定义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);
    }

}

 


  1.5 Webflux 过滤器


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



WebFlux Demo 

2.1 项目结构

SpringBoot 2.0 Webflux 介绍 和Demo示例_第1张图片

2.2 创建maven项目

    
idea->file->new->spring Initializr ->勾选 web->Reactive Web 和 core->lombok(非必须,精简代码用)

2.3 创建实体类User 

 

@Data
public class User {

    private  String name;
    private  int age;

    public User() {}

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

 

2.4 创建User服务类 (内存模拟数据库)

 

@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());
    }


}

2.5 创建解释器UserHandler 
 


@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);
    }
}

2.6 创建路由UserRoutes

 


@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));
    }

}

2.7 初始化内存数据  Init (模拟数据库)

 

@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));

    }
}

 


2.8 SpringBoot 启动类 WebfluxApplication

 

@SpringBootApplication
@EnableWebFlux
public class WebfluxApplication {

    public static void main(String[] args) {
        SpringApplication.run(WebfluxApplication.class, args);
    }
}

 

2.9 运行 WebfluxApplication 并查看结果

打开浏览器 地址栏输入借口地址并得到验证返回值:


#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]

你可能感兴趣的:(spring,boot,webflux)