最近在看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匹配path12 */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.html22 */23 String extractPathWithinPattern(String pattern, String path);24 25 /**26 * 提取path中匹配到的部分,只是这边还需跟占位符配对为map,27 * 如pattern(/hotels/{hotel}),path(/hotels/1),解析出"hotel"->"1"28 */29 MapextractUriTemplateVariables(String pattern, String path);30 31 /**32 * 提供比较器33 */34 Comparator getPatternComparator(String path);35 36 /**37 * 合并pattern,pattern1然后pattern238 */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 @Test10 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 Mapresult = 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-778714 */15 @Test16 public void extractUriTemplateVarsRegexQualifiers() {17 Map 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 }