ant匹配規則;PathMatcher介面;通過測試用例看AntPathMatcher的使用
最近在看SpringMVC的源碼,發現request分發時,路徑匹配最後是委托給AntPathMatcher實現的.索性看看吧.
文章摘要:
1. ant匹配規則
2. PathMatcher介面
3. 通過測試用例看AntPathMatcher的使用
ant匹配規則
AntPathMatcher如名使用的ant 的匹配規則,我們先看看吧.
字元wildcard 描述
? 匹配一個字元
* 匹配0個及以上字元
** 匹配0個及以上目錄directories
看幾個官方的例子吧:
com/t?st.jsp - 匹配: com/test.jsp , com/tast.jsp , com/txst.jsp
com/*.jsp - 匹配: com文件夾下的全部.jsp文件
com/**/test.jsp - 匹配: com文件夾和子文件夾下的全部.jsp文件,
org/springframework/**/*.jsp - 匹配: org/springframework文件夾和子文件夾下的全部.jsp文件
org/**/servlet/bla.jsp - 匹配: org/springframework/servlet/bla.jsp , org/springframework/testing/servlet/bla.jsp , org/servlet/bla.jsp
PathMatcher介面
主要是判斷是否匹配pattern,並解析出path中的參數
1 package org.springframework.util; 2 3 public interface PathMatcher { 4 5 /** 6 * 判斷傳入的path是否可以作為pattern使用 7 */ 8 boolean isPattern(String path); 9 10 /** 11 * 使用pattern匹配path 12 */ 13 boolean match(String pattern, String path); 14 15 /** 16 * 如名,是否開始部分匹配 17 */ 18 boolean matchStart(String pattern, String path); 19 20 /** 21 * 提取path中匹配到的部分,如pattern(myroot/*.html),path(myroot/myfile.html),返回myfile.html 22 */ 23 String extractPathWithinPattern(String pattern, String path); 24 25 /** 26 * 提取path中匹配到的部分,只是這邊還需跟占位符配對為map, 27 * 如pattern(/hotels/{hotel}),path(/hotels/1),解析出"hotel"->"1" 28 */ 29 Map<String, String> extractUriTemplateVariables(String pattern, String path); 30 31 /** 32 * 提供比較器 33 */ 34 Comparator<String> getPatternComparator(String path); 35 36 /** 37 * 合併pattern,pattern1然後pattern2 38 */ 39 String combine(String pattern1, String pattern2); 40 41 }
通過測試用例看AntPathMatcher的使用
一看測試用例,瞬間服了,人家開發真是規範.
人家整這麼規範,還是有空直接看源碼好了.這邊挑幾個簡單的例子看看就好
1. match 跟 matchStart 的差異,這個我們在測試用例看下麵的情況會比較明確
這邊的代碼,我截取了一小部分
1 package org.springframework.util; 2 public class AntPathMatcherTests { 3 @Test 4 public void match() { 5 // ... 6 assertFalse(pathMatcher.match("/x/x/**/bla", "/x/x/x/")); 7 // ... 8 } 9 @Test 10 public void withMatchStart() { 11 // ... 12 assertTrue(pathMatcher.matchStart("/x/x/**/bla", "/x/x/x/")); 13 // ... 14 } 15 }
2. extractPathWithinPattern,代碼很清楚,不廢話
1 package org.springframework.util; 2 public class AntPathMatcherTests { 3 @Test 4 public void extractPathWithinPattern() throws Exception { 5 // ... 6 assertEquals("", pathMatcher.extractPathWithinPattern("/docs/commit.html", "/docs/commit.html")); 7 assertEquals("cvs/commit", pathMatcher.extractPathWithinPattern("/docs/*", "/docs/cvs/commit")); 8 assertEquals("docs/cvs/commit", pathMatcher.extractPathWithinPattern("/d?cs/*", "/docs/cvs/commit")); 9 // ... 10 } 11 }
3. extractUriTemplateVariables
1 package org.springframework.util; 2 public class AntPathMatcherTests { 3 @Test 4 public void extractUriTemplateVariables() throws Exception { 5 Map<String, String> result = pathMatcher.extractUriTemplateVariables("/hotels/{hotel}", "/hotels/1"); 6 assertEquals(Collections.singletonMap("hotel", "1"), result); 7 // ... 8 result = pathMatcher.extractUriTemplateVariables("/{page}.*", "/42.html"); 9 assertEquals(Collections.singletonMap("page", "42"), result); 10 // ... 11 } 12 /** 13 * SPR-7787 14 */ 15 @Test 16 public void extractUriTemplateVarsRegexQualifiers() { 17 Map<String, String> result = pathMatcher.extractUriTemplateVariables( 18 "{symbolicName:[\\p{L}\\.]+}-sources-{version:[\\p{N}\\.]+}.jar", 19 "com.example-sources-1.0.0.jar"); 20 assertEquals("com.example", result.get("symbolicName")); 21 assertEquals("1.0.0", result.get("version")); 22 // ... 23 } 24 }
4. combine
1 package org.springframework.util; 2 public class AntPathMatcherTests { 3 @Test 4 public void combine() { 5 // ... 6 assertEquals("/hotels", pathMatcher.combine("/hotels", null)); 7 assertEquals("/hotels/booking", pathMatcher.combine("/hotels/*", "/booking")); 8 assertEquals("/hotels/**/booking", pathMatcher.combine("/hotels/**", "booking")); 9 assertEquals("/hotels/**/booking", pathMatcher.combine("/hotels/**", "/booking")); 10 assertEquals("/hotels/booking", pathMatcher.combine("/hotels", "/booking")); 11 assertEquals("/hotels/{hotel}", pathMatcher.combine("/hotels/*", "{hotel}")); 12 assertEquals("/hotels/**/{hotel}", pathMatcher.combine("/hotels/**", "{hotel}")); 13 assertEquals("/hotels/*/booking/{booking}", pathMatcher.combine("/hotels/*/booking", "{booking}")); 14 } 15 }