關(guān)于Spring的路徑, 問的最多的問題就是如何攔截所有以.do結(jié)尾的請(qǐng)求.
大家都是在猜, 網(wǎng)上給出的答案五花八門, 比如: *do, /*do, /**do, /** 等..然而這些都是錯(cuò)的.
正確答案是/**/*.do, 如果要攔截/api下的所有.do結(jié)尾的請(qǐng)求, 那么應(yīng)該使用/api/**/*.do, 以此類推.
言歸正傳, Spring中無論是handler路徑映射, 還是interceptor路徑匹配, 還是sping.xml中加載配置文件時(shí)使用的”classpath*”, 都使用的是AntMathcer規(guī)則( 見PathMatcher文檔), 實(shí)現(xiàn)類是org.springframework.util.AntPathMatcher. 這里是這個(gè)類的官方文檔AntPathMatcher文檔
里面有這樣的說明
匹配符規(guī)則?
?匹配一個(gè)字符?
*匹配0或更多字符?
**匹配path路徑中的0個(gè)或更多目錄?
{spring:[a-z]+}匹配正則[a-z]+并作為一個(gè)路徑變量, 賦值給變量spring?
注意在AntPathMatcher中, 有個(gè)路徑分隔符的概念, 路徑分隔符是不能被 ? 或單個(gè) * 匹配的, 路徑分隔符默認(rèn)是 / , 在匹配類全限定名時(shí), 設(shè)置成 . 其他規(guī)則不變.
以下是簡(jiǎn)單的介紹: (注意**可以匹配0個(gè)或更多的目錄)
規(guī)則簡(jiǎn)介匹配不匹配
/goods/t?st.jsp/goods路徑下只相差一個(gè)字符的路徑/good/test.jsp /goods/text.jsp /goods/tast.jsp等/goods/taast.jsp /google/tast.jsp等
/**/test.jsp匹配任何以test.jsp結(jié)尾的路徑/test.jsp/goods/test.jsp /my/goods/test.jsp /my/favorite/goods/test.jsp等/goods/abc.jsp等
/**/*.jsp任何以jsp結(jié)尾的路徑/test.jsp /goods/test.jsp /my/goods/test.jsp等/hello.html /my/hello.html等
/goods/**匹配goods下的所有路徑/goods /goods/a.html /goods/a.jsp /goods/test/a.jsp等非/goods/下的路徑
/或/goods只匹配/或/goods這一個(gè)路徑,千萬不要誤認(rèn)為是所有路徑只有/和/goods其他任何路徑
/**匹配所有路徑/test/goods/test /test.html /test.jsp /goods/test.jsp /my/goods/test.jsp等無
完整用法可見Sping的托管在github的測(cè)試代碼AntPathMatcherTests.java
以下是我從中摘取的一部分. 可以不用看這個(gè).
// 完全匹配
assertTrue(pathMatcher.match("test","test"));
assertTrue(pathMatcher.match("/test","/test"));
//不匹配
assertFalse(pathMatcher.match("/test.jpg","test.jpg"));
assertFalse(pathMatcher.match("test","/test"));
// 使用?進(jìn)行匹配, ?表示匹配一個(gè)字符
assertTrue(pathMatcher.match("t?st","test"));
assertTrue(pathMatcher.match("??st","test"));
//不匹配
assertFalse(pathMatcher.match("tes?","tes"));
assertFalse(pathMatcher.match("tes?","testt"));
//使用*進(jìn)行匹配, *匹配0? ? 更多字符
assertTrue(pathMatcher.match("*","test"));
assertTrue(pathMatcher.match("test*","test"));
assertTrue(pathMatcher.match("test*","testTest"));
assertTrue(pathMatcher.match("test/*","test/Test"));
assertTrue(pathMatcher.match("test/*","test/t"));
assertTrue(pathMatcher.match("*.*","test."));
assertTrue(pathMatcher.match("*.*","test.test.test"));
//以下不匹配
assertFalse(pathMatcher.match("test*","tst"));
assertFalse(pathMatcher.match("test*","tsttest"));
assertFalse(pathMatcher.match("test*","test/"));
assertFalse(pathMatcher.match("test/*","test"));
// 使用?和/一起匹配
assertTrue(pathMatcher.match("/?","/a"));
assertTrue(pathMatcher.match("/?/a","/a/a"));
assertTrue(pathMatcher.match("/a/?","/a/b"));
assertTrue(pathMatcher.match("/??/a","/aa/a"));
assertTrue(pathMatcher.match("/a/??","/a/bb"));
assertTrue(pathMatcher.match("/?","/a"));
// 使用**匹配, 匹配0個(gè)或更多目錄
assertTrue(pathMatcher.match("/**","/testing/testing"));
assertTrue(pathMatcher.match("/*/**","/testing/testing"));
assertTrue(pathMatcher.match("/**/*","/testing/testing"));
assertTrue(pathMatcher.match("/bla/**/bla","/bla/testing/testing/bla"));
assertTrue(pathMatcher.match("/bla/**/bla","/bla/testing/testing/bla/bla"));
assertTrue(pathMatcher.match("/*bla*/**/bla/**","/XXXblaXXXX/testing/testing/bla/testing/testing/"));
assertTrue(pathMatcher.match("/*bla*/**/bla/*","/XXXblaXXXX/testing/testing/bla/testing"));
assertTrue(pathMatcher.match("*bla*/**/bla/**","XXXblaXXXX/testing/testing/bla/testing/testing"));
assertFalse(pathMatcher.match("*bla*/**/bla/*","XXXblaXXXX/testing/testing/bla/testing/testing"));
assertTrue(pathMatcher.match("/foo/bar/**","/foo/bar")) ;
assertTrue(pathMatcher.match("/{bla}.*","/testing.html"));