Spring WebFlux使用函數語言程式設計之HandlerFunction
本篇主要內容:
- RouterFunction的使用
概述
路由器函式用於將請求路由到相應的HandlerFunction。通常情況下,你不需要自己編寫路由器函式,而是使用RouterFunctions類中的方法來建立一個。RouterFunctions.route()(無引數)為建立路由器函式提供了一個流暢的構建器,而RouterFunctions.route(RequestPredicate, HandlerFunction)提供了建立路由器的直接方法。
通常,建議使用route()構建器,因為它為典型的對映場景提供了方便的快捷方式,而不需要難以發現的靜態匯入。例如,路由器函式構建器提供了方法GET(String, HandlerFunction)來為GET請求建立對映;和POST(String, HandlerFunction)用於POST。
除了基於HTTP方法的對映之外,路由構建器還提供了一種在對映到請求時引入附加謂詞的方法。對於每個HTTP方法,都有一個以RequestPredicate作為引數的過載變體,儘管可以表示附加的約束。
謂詞Predicates
你可以編寫自己的RequestPredicate,但RequestPredites類提供了常用的實現,基於請求路徑、HTTP方法、內容型別等。以下示例使用請求謂詞根據Accept標頭建立約束:
RouterFunction<ServerResponse> route = RouterFunctions.route() .GET("/hello-world", accept(MediaType.TEXT_PLAIN), request -> ServerResponse.ok().bodyValue("Hello World")).build();
你可以使用以下命令將多個請求謂詞組合在一起:
- RequestPredicate.and(RequestPredicate) // 兩者必須匹配。
- RequestPredicate.or(RequestPredicate) // 兩者都可以匹配。
RequestPredicates中的許多謂詞都是組合的。例如,RequestPredicates.GET(String)由RequestPredicates.method(HttpMethod)和RequestPredicates.path(String)組合而成。上面顯示的示例還使用了兩個請求謂詞,因為構建器使用RequestPredicates.GET內部,並用accept謂詞組合它。
路由Routes
路由器函式按順序計算:如果第一個路由不匹配,則計算第二個路由,依此類推。因此,在一般路由之前宣告更具體的路由是有意義的。這在將路由器函式註冊為Spring bean時也很重要,稍後將對此進行描述。注意,此行為不同於基於註釋的程式設計模型,後者自動選擇“最特定的”控制器方法。
當使用路由器函式構建器時,所有定義的路由被組合到一個RouterFunction中,該RouterFunction從build()返回。還有其他方法可以將多個路由器功能組合在一起:
- add(RouterFunction) on the RouterFunctions.route() builder。
- RouterFunction.and(RouterFunction)。
- RouterFunction.andRoute(RequestPredicate, HandlerFunction) — shortcut for RouterFunction.and() with nested RouterFunctions.route()。
下面的例子展示了四條路由的組合:
import static org.springframework.http.MediaType.APPLICATION_JSON; import static org.springframework.web.reactive.function.server.RequestPredicates.*; PersonRepository repository = ... PersonHandler handler = new PersonHandler(repository); RouterFunction<ServerResponse> otherRoute = ... RouterFunction<ServerResponse> route = route() .GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson) // 1 .GET("/person", accept(APPLICATION_JSON), handler::listPeople) // 2 .POST("/person", handler::createPerson) // 3 .add(otherRoute) // 4 .build();
- 帶有匹配JSON的Accept頭的GET /person/{id}被路由到 PersonHandler.getPerson。
- 帶有與JSON匹配的Accept頭的GET /person被路由到 PersonHandler.listPeople。
- 沒有附加謂詞的POST /person被對映到 PersonHandler.createPerson。
- otherRoute是一個在別處建立的路由器函式,並新增到構建的路由中。
巢狀路由Nested Routes
一組路由器函式通常具有一個共享謂詞,例如共享路徑。在上面的示例中,共享謂詞將是一個與/person匹配的路徑謂詞,由三條路由使用。在使用註釋時,可以通過使用對映到/person的型別級 @RequestMapping 註釋來消除這種重複。在WebFlux.Fn,路徑謂詞可以通過路由器函式構建器上的路徑方法共享。例如,上面例子的最後幾行可以通過使用巢狀路由通過以下方式進行改進:
RouterFunction<ServerResponse> route = route() .path("/person", builder -> builder // 1 .GET("/{id}", accept(APPLICATION_JSON), handler::getPerson) .GET(accept(APPLICATION_JSON), handler::listPeople) .POST(handler::createPerson)) .build();
注意:path的第二個引數是接受路由器構建器的消費者。
儘管基於路徑的巢狀是最常見的,但是你可以通過在構建器上使用巢狀方法來巢狀任何型別的謂詞。上面的內容仍然以共享的Accept-header謂詞的形式包含了一些重複。我們可以通過使用nest方法和accept來進一步改進:
RouterFunction<ServerResponse> route = route() .path("/person", b1 -> b1 .nest(accept(APPLICATION_JSON), b2 -> b2 .GET("/{id}", handler::getPerson) .GET(handler::listPeople)) .POST(handler::createPerson)) .build();
總結:
- 路由函式中 RouteFunction 的使用。
- 巢狀路由的使用。
- Spring中實現非同步呼叫的方式有哪些?
- 帶引數的全型別 Python 裝飾器
- 整理了幾個Python正則表示式,拿走就能用!
- SOLID:開閉原則Go程式碼實戰
- React中如何引入CSS呢
- 一個新視角:前端框架們都卷錯方向了?
- 編碼中的Adapter,不僅是一種設計模式,更是一種架構理念與解決方案
- 手寫程式語言-遞迴函式是如何實現的?
- 一文搞懂模糊匹配:定義、過程與技術
- 新來個阿里 P7,僅花 2 小時,做出一個多執行緒永動任務,看完直接跪了
- Puzzlescript,一種開發H5益智遊戲的引擎
- @Autowired和@Resource到底什麼區別,你明白了嗎?
- CSS transition 小技巧!如何保留 hover 的狀態?
- React如此受歡迎離不開這4個主要原則
- LeCun再炮轟Marcus: 他是心理學家,不是搞AI的
- Java保證執行緒安全的方式有哪些?
- 19個殺手級 JavaScript 單行程式碼,讓你看起來像專業人士
- Python 的"self"引數是什麼?
- 別整一坨 CSS 程式碼了,試試這幾個實用函式
- 再有人問你什麼是MVCC,就把這篇文章發給他!