1. 程式人生 > >Spring-WebFlux簡介與使用

Spring-WebFlux簡介與使用


簡介

Spring WebFlux是Spring Framework 5.0中引入的新的反應式Web框架。 與Spring MVC不同,它不需要Servlet API,完全非同步和非阻塞, 並通過Reactor專案實現Reactive Streams規範。 並且可以在諸如Netty,Undertow和Servlet 3.1+容器的伺服器上執行。

Reactor中的Mono和Flux

Flux 和 Mono 是 Reactor 中的兩個基本概念。Flux 表示的是包含 0 到 N 個元素的非同步序列。 在該序列中可以包含三種不同型別的訊息通知:正常的包含元素的訊息、序列結束的訊息和序列出錯的訊息。 當訊息通知產生時,訂閱者中對應的方法 onNext(), onComplete()和 onError()會被呼叫。Mono 表示的是包含 0 或者 1 個元素的非同步序列。 該序列中同樣可以包含與 Flux 相同的三種類型的訊息通知。Flux 和 Mono 之間可以進行轉換。 對一個 Flux 序列進行計數操作,得到的結果是一個 Mono物件。把兩個 Mono 序列合併在一起,得到的是一個 Flux 物件。 

瞭解更多

WebFlux的使用方式

圖片簡介

如圖所示,WebFlux支援兩種程式設計方式

  • 基於SpringMvc註解@Controller
  • 基於Java8 lambda樣式路由和處理

使用WebFlux需要單獨引用它的依賴,我使用的springboot,依賴如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency
> <!--reactor的測試依賴--> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-test</artifactId> <scope>test</scope> </dependency>

示例

  • 基於SpringMvc註解

    與使用SpringMvc不同的是使用SpringWebFlux同一使用Mono<>,Flux<>物件同意返回資料,如下

    @RestController
    @RequestMapping("/api/user")
    public class WebFluxController {
    
        private Map<Long,User> map = new HashMap<Long,User>(10);
        @PostConstruct
        public void init(){
            map.put(1L,new User(1,"admin","admin"));
            map.put(2L,new User(1,"admin2","admin2"));
            map.put(3L,new User(1,"admin3","admin3"));
        }
        @GetMapping("/getAll")
        public Flux<User> getAllUser(){
            return Flux.fromIterable(map.entrySet().stream().map(Map.Entry::getValue)
                    .collect(Collectors.toList()));
        }
        @GetMapping("/{id}")
        public Mono<User> getUserById(@PathVariable("id") Long id){
            return Mono.just(map.get(id));
        }
        @PostMapping("/save")
        public Mono<ResponseEntity<String>> save(@RequestBody User user){
            map.put(user.getUid(),user);
            return Mono.just(new ResponseEntity<>("新增成功", HttpStatus.CREATED));
        }
    }

    具體實現程式碼可檢視springboot-webflux

  • 基於功能

    處理請求的類,實現具體的業務邏輯,介面 ServerRequest 表示的是一個 HTTP 請求體。通過ServerRequest 物件可獲取到請求的相關資訊,如請求路徑、查詢引數和請求內容等。方法 的返回值是一個 Mono物件。介面 ServerResponse 用來表示 HTTP 響應。ServerResponse 中包含了很多靜態方法來建立不同 HTTP 狀態碼的響應物件

    @Component
    public class UserHandler {
    
        private IUserService userService;
        @Autowired
        public UserHandler(IUserService userService) {
            this.userService = userService;
        }
    
        public Mono<ServerResponse> getAllUser(ServerRequest serverRequest){
            Flux<User> allUser = userService.getAllUser();
            return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(allUser,User.class);
        }
    
        public Mono<ServerResponse> getUserById(ServerRequest serverRequest){
            //獲取url上的id
            Long uid = Long.valueOf(serverRequest.pathVariable("id"));
            Mono<User> user = userService.getUserById(uid);
            return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(user,User.class);
        }
    
        public Mono<ServerResponse> saveUser(ServerRequest serverRequest){
            Mono<User> user = serverRequest.bodyToMono(User.class);
            return ServerResponse.ok().build(userService.saveUser(user));
        }
    
    }

    為Handler類新增路由資訊,

    @Configuration
    public class RoutingConfiguration {
    
        @Bean
        public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler){
            return route(GET("/api/user").and(accept(MediaType.APPLICATION_JSON)),userHandler::getAllUser)
                    .andRoute(GET("/api/user/{id}").and(accept(MediaType.APPLICATION_JSON)),userHandler::getUserById)
                    .andRoute(POST("/api/save").and(accept(MediaType.APPLICATION_JSON)),userHandler::saveUser);
        }
    
    }

    具體實現程式碼可檢視springboot-webflux-functional