探索Spring 5 WebFlux URL匹配
1.概述
Spring 5帶來了一個新的PathPatternParser
用於解析URI模板模式.
這是以前使用的AntPathMatcher
的替代方法。
AntPathMatcher
是Ant樣式路徑模式匹配的實現。 PathPatternParser
將路徑分為PathElements
的鏈接列表。這一鏈條PathElements
採取的是PathPattern
的模式快速匹配的類。
通過PathPatternParser
,還引入了對新URI變量語法的支持。
在本文中,我們將介紹Spring 5.0 WebFlux中引入的新/更新的URL模式匹配器,以及自Spring的較早版本以來一直使用的URL模式匹配器。
2. Spring 5.0中的新URL模式匹配器
Spring 5.0發行版添加了一個非常易於使用的URI變量語法:{* foo},以在模式末尾捕獲任意數量的路徑段。
2.1。使用處理程序方法的URI變量語法{* foo}
我們來看一個URI變量模式{*foo}
示例,另一個使用@GetMapping
和處理程序方法的示例。我們在“/spring5”
之後的路徑中“/spring5”
都將存儲在路徑變量“ id”中:
@GetMapping("/spring5/{*id}")
public String URIVariableHandler(@PathVariable String id) {
return id;
}
@Test
public void whenMultipleURIVariablePattern_thenGotPathVariable() {
client.get()
.uri("/spring5/baeldung/tutorial")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/baeldung/tutorial");
client.get()
.uri("/spring5/baeldung")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/baeldung");
}
2.2。使用RouterFunction
URI變量語法{* foo}
讓我們來看一個使用RouterFunction
的新URI變量路徑模式的RouterFunction
:
private RouterFunction<ServerResponse> routingFunction() {
return route(GET("/test/{*id}"),
serverRequest -> ok().body(fromObject(serverRequest.pathVariable("id"))));
}
在這種情況下,我們在“ / test”之後編寫的任何路徑都將被捕獲在路徑變量“ id”中。因此,測試用例可能是:
@Test
public void whenMultipleURIVariablePattern_thenGotPathVariable()
throws Exception {
client.get()
.uri("/test/ab/cd")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/ab/cd");
}
2.3。使用URI變量語法{* foo}來訪問資源
如果要訪問資源,則需要編寫與上一個示例類似的路徑模式。
假設我們的模式是: “/files/{*filepaths}”.
在這種情況下,如果路徑為/files/hello.txt,
則路徑變量“filepaths”
的值為“ /hello.txt”,而如果路徑為/files/test/test.txt,
則路徑值為“filepaths”
=“ /test/test.txt”。
我們的路由功能用於訪問/files/
目錄下的文件資源:
private RouterFunction<ServerResponse> routingFunction() {
return RouterFunctions.resources(
"/files/{*filepaths}",
new ClassPathResource("files/")));
}
假設我們的文本文件hello.txt
和test.txt
包含“hello”
和“test”
。這可以通過JUnit測試用例進行演示:
@Test
public void whenMultipleURIVariablePattern_thenGotPathVariable()
throws Exception {
client.get()
.uri("/files/test/test.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("test");
client.get()
.uri("/files/hello.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("hello");
}
3. 之前版本中的現有URL模式
現在,讓我們看一看Spring的較早版本支持的所有其他URL模式匹配器。所有這些模式都可以通過RouterFunction
與RouterFunction
和Handler方法一起@GetMapping
。
3.1。 '?'完全匹配一個字符
如果我們將路徑模式指定為: “/t?
st “,
則將匹配以下路徑: “/test”
和“/tast”,
但不匹配“/tst”
和“/teest”.
使用RouterFunction
及其JUnit測試用例的示例代碼:
private RouterFunction<ServerResponse> routingFunction() {
return route(GET("/t?st"),
serverRequest -> ok().body(fromObject("Path /t?st is accessed")));
}
@Test
public void whenGetPathWithSingleCharWildcard_thenGotPathPattern()
throws Exception {
client.get()
.uri("/test")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("Path /t?st is accessed");
}
3.2。 '*'匹配路徑段中的0個或更多字符
如果我們將路徑模式指定為: “/baeldung/*Id”,
則將匹配以下路徑模式like:”/baeldung/Id”, “/baeldung/tutorialId”,
“ / baeldung / articleId”等:
private RouterFunction<ServerResponse> routingFunction() {
returnroute(
GET("/baeldung/*Id"),
serverRequest -> ok().body(fromObject("/baeldung/*Id path was accessed"))); }
@Test
public void whenGetMultipleCharWildcard_thenGotPathPattern()
throws Exception {
client.get()
.uri("/baeldung/tutorialId")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/baeldung/*Id path was accessed");
}
3.3。 '**'匹配0個或更多路徑段,直到路徑結束
在這種情況下,模式匹配不限於單個路徑段。如果我們將模式指定為“/resources/**”,
它將使所有路徑與“/resources/”:
之後的任意數量的路徑段匹配“/resources/”:
private RouterFunction<ServerResponse> routingFunction() {
return RouterFunctions.resources(
"/resources/**",
new ClassPathResource("resources/")));
}
@Test
public void whenAccess_thenGot() throws Exception {
client.get()
.uri("/resources/test/test.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("content of file test.txt");
}
3.4。路徑變量中的'{baeldung:[az]+}'
表達式
我們還可以為path變量的值指定一個正則表達式。因此,如果我們的模式類似於“/{baeldung:[az]+}”,
則路徑變量“baeldung”
的值將是與給定正則表達式匹配的任何路徑段:
private RouterFunction<ServerResponse> routingFunction() {
return route(GET("/{baeldung:[az]+}"),
serverRequest -> ok()
.body(fromObject("/{baeldung:[az]+} was accessed and "
+ "baeldung=" + serverRequest.pathVariable("baeldung"))));
}
@Test
public void whenGetRegexInPathVarible_thenGotPathVariable()
throws Exception {
client.get()
.uri("/abcd")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/{baeldung:[az]+} was accessed and "
+ "baeldung=abcd");
}
3.5。 '/{var1}_{var2}'
同一路徑段中'/{var1}_{var2}'
多個路徑變量
Spring 5確保只有在由定界符分隔時,才允許在單個路徑段中使用多個路徑變量。只有這樣,Spring才能區分兩個不同的路徑變量:
private RouterFunction<ServerResponse> routingFunction() {
return route(
GET("/{var1}_{var2}"),
serverRequest -> ok()
.body(fromObject( serverRequest.pathVariable("var1") + " , "
+ serverRequest.pathVariable("var2"))));
}
@Test
public void whenGetMultiplePathVaribleInSameSegment_thenGotPathVariables()
throws Exception {
client.get()
.uri("/baeldung_tutorial")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("baeldung , tutorial");
}
4。結論
在本文中,我們介紹了Spring 5中的新URL匹配器以及Spring的舊版本中可用的URL匹配器。
與往常一樣,我們討論的所有示例的實現都可以在GitHub上找到。