Spring中的路徑匹配器AntPathMatcher詳解
PathMatcher接口
Spring的PathMatcher路徑匹配器接口,用于支持帶通配符的資源路徑匹配。
使用場(chǎng)景
PathMatcher接口在Spring的許多場(chǎng)景下使用,比如:
- PathMatchingResourcePatternResolver:資源掃描,啟動(dòng)時(shí)掃描并加載資源
- AbstractUrlHandlerMapping:請(qǐng)求路徑映射到 Controller
- WebContentInterceptor:攔截器攔截路徑分析
接口方法
方法 | 描述 |
boolean isPattern(String path) | 判斷路徑是否是模式 |
boolean match(String pattern, String path) | 判斷路徑是否完全匹配 |
boolean matchStart(String pattern, String path) | 判斷路徑是否前綴匹配 前綴匹配的意思:路徑能與模式的前面部分匹配,但模式可能還有后面多余部分 例如:/test能前綴匹配/test/{id}(但模式還有多余的/{id}部分未匹配) |
String extractPathWithinPattern(String pattern, String path) | 得到模式匹配的部分值 該方法只返回路徑的實(shí)際模式匹配部分 例如:myroot/*.html 匹配 myroot/myfile.html 路徑,結(jié)果為 myfile.html |
Map<String, String> extractUriTemplateVariables(String pattern, String path) | 提取路徑中的路徑參數(shù)值 |
Comparator<String> getPatternComparator(String path) | 得到一個(gè)排序比較器,用于對(duì)匹配到的所有路徑進(jìn)行排序 |
String combine(String pattern1, String pattern2) | 合并兩個(gè)模式 |
AntPathMatcher類(lèi)
AntPathMatcher是Spring為PathMatcher接口提供的默認(rèn)實(shí)現(xiàn),支持Ant風(fēng)格的路徑匹配。
匹配規(guī)則
AntPathMatcher支持的匹配規(guī)則:
規(guī)則 | 描述 |
? | 匹配一個(gè)字符 |
* | 在一個(gè)路徑段中匹配零個(gè)、一個(gè)或多個(gè)字符 |
** | 匹配零個(gè)或多個(gè)路徑段,直到路徑結(jié)束 |
{id} | 匹配一個(gè)路徑段,并將該路徑段的值作為變量id的變量值 |
{id:[a-z]+} | 匹配一個(gè)滿足正則([a-z]+)路徑段,并將該路徑段的值作為變量id的變量值 |
舉例:
public static void main(String[] args) { AntPathMatcher matcher = new AntPathMatcher(); // ? System.out.println(matcher.match("/test/a?c", "/test/abc"));// true // * System.out.println(matcher.match("/test/*", "/test/"));// true System.out.println(matcher.match("/test/*", "/test/aa"));// true System.out.println(matcher.match("/test/*.html", "/test/aa"));// false // ** System.out.println(matcher.match("/test/**", "/test/"));// true System.out.println(matcher.match("/test/**", "/test/aa"));// true System.out.println(matcher.match("/test/**", "/test/aa/bb"));// true // {id} System.out.println(matcher.match("/test/{id}", "/test/111"));// true System.out.println(matcher.match("/test/a{id}", "/test/a111"));// true System.out.println(matcher.match("/test/{id}/aa", "/test/111/aa"));// true System.out.println(matcher.match("/test/{id}-{name}/aa", "/test/111-haha/aa"));// true // {id:[a-z]+} System.out.println(matcher.match("/test/{id:[a-z]+}", "/test/111"));// false System.out.println(matcher.match("/test/{id:[a-z]+}", "/test/abc"));// true System.out.println(matcher.match("/test/{id:\\w+}", "/test/1a_"));// true System.out.println(matcher.match("/test/{id:\\w+}", "/test/--"));// false }
一些不匹配情況原因:
模式 | 路徑 | 原因 |
/user/aaa/ | /user/aaa | 結(jié)束符不一致 |
/user/*/ | /user/aaa | 結(jié)束符不一致 |
實(shí)際在Spring項(xiàng)目中使用的時(shí)候,你會(huì)發(fā)現(xiàn):就算實(shí)際請(qǐng)求的結(jié)束符為 / ,但還是能匹配成功。這又是為什么呢?
兩個(gè)關(guān)鍵屬性:
- useSuffixPatternMatch:設(shè)置是否使用后綴模式匹配,如“/user”是否匹配/user.*,默認(rèn)是這種模式下,實(shí)際請(qǐng)求.后面加任何后綴,都會(huì)匹配到。如:實(shí)際請(qǐng)求“/user.html”能匹配上“/user”。
- useTrailingSlashMatch:設(shè)置是否使用后綴路徑模式匹配,如“/user”是否匹配“/user/”,默認(rèn)是這種模式下,實(shí)際請(qǐng)求加、后綴,都會(huì)匹配到。如:實(shí)際請(qǐng)求“/user/”能匹配上“/user”。
關(guān)鍵源碼:
PatternsRequestCondition類(lèi)的getMatchingPattern方法
private String getMatchingPattern(String pattern, String lookupPath) { // 模式與路徑相等,直接返回模式 if (pattern.equals(lookupPath)) { return pattern; } // 如果使用后綴模式匹配,返回的模式會(huì)拼接上合適的后綴,如.html if (this.useSuffixPatternMatch) { if (!this.fileExtensions.isEmpty() && lookupPath.indexOf('.') != -1) { for (String extension : this.fileExtensions) { if (this.pathMatcher.match(pattern + extension, lookupPath)) { return pattern + extension; } } } else { boolean hasSuffix = pattern.indexOf('.') != -1; if (!hasSuffix && this.pathMatcher.match(pattern + ".*", lookupPath)) { return pattern + ".*"; } } } if (this.pathMatcher.match(pattern, lookupPath)) { return pattern; } // 如果使用后綴路徑模式匹配,返回的模式會(huì)拼接上/ if (this.useTrailingSlashMatch) { if (!pattern.endsWith("/") && this.pathMatcher.match(pattern + "/", lookupPath)) { return pattern + "/"; } } return null; }
因此,getMatchingPattern方法返回的模式再與請(qǐng)求路徑進(jìn)行模式匹配當(dāng)然能匹配上了。
主要方法
1. isPattern
判斷路徑是否是模式。
只要路徑中擁有 * 、 ? 、 {} ,則就是模式。
public boolean isPattern(@Nullable String path) { if (path == null) { return false; } boolean uriVar = false; for (int i = 0; i < path.length(); i++) { char c = path.charAt(i); if (c == '*' || c == '?') { return true; } if (c == '{') { uriVar = true; continue; } if (c == '}' && uriVar) { return true; } } return false; }
示例:
public static void main(String[] args) { AntPathMatcher matcher = new AntPathMatcher(); System.out.println(matcher.isPattern("/test/{id}"));// true }
2. match
判斷路徑是否完全匹配
public boolean match(String pattern, String path) { return doMatch(pattern, path, true, null); }
示例:
public static void main(String[] args) { AntPathMatcher matcher = new AntPathMatcher(); System.out.println(matcher.match("/test/*", "/test/111"));// true System.out.println(matcher.match("/test/**", "/test/111/222"));// true System.out.println(matcher.match("/test/{id}", "/test/111"));// true System.out.println(matcher.match("/test/{id}/aa", "/test/111/aa"));// true System.out.println(matcher.match("/test/{id}-{name}/aa", "/test/111-haha/aa"));// true System.out.println(matcher.match("/test/{id}-{name}/aa", "/test/111-/aa"));// true }
3. matchStart
判斷路徑是否前綴匹配
前綴匹配的意思:路徑能與模式的前面部分匹配,但模式可能還有后面多余部分(可以理解為模式是否是以路徑開(kāi)頭)
public boolean matchStart(String pattern, String path) { return doMatch(pattern, path, false, null); }
示例:
public static void main(String[] args) { AntPathMatcher matcher = new AntPathMatcher(); System.out.println(matcher.matchStart("/test/*", "/test"));// true System.out.println(matcher.matchStart("/test/aa/*", "/test"));// true System.out.println(matcher.matchStart("/test/{id}", "/test"));// true System.out.println(matcher.matchStart("/test/{id}-{name}/aa", "/test"));// true System.out.println(matcher.matchStart("/test/{id}", "/test/111/222"));// false }
4. extractPathWithinPattern
得到模式匹配的映射部分。找出通過(guò)*或者?匹配上的那一段路徑及其后續(xù)路徑。
示例:
public static void main(String[] args) { AntPathMatcher matcher = new AntPathMatcher(); System.out.println(matcher.extractPathWithinPattern("/test/*", "/test"));// System.out.println(matcher.extractPathWithinPattern("/test/*", "/test/aa"));// aa System.out.println(matcher.extractPathWithinPattern("/test/**", "/test/aa/bb"));// aa/bb System.out.println(matcher.extractPathWithinPattern("/test/a?c/aa", "/test/abc/aa"));// abc/aa System.out.println(matcher.extractPathWithinPattern("/test/aa?c/aa/cc", "/test/abc/aa"));// abc/aa }
5. extractUriTemplateVariables
路徑必須完全匹配(否則拋出異常),并提取路徑中的路徑參數(shù)值。
示例:
public static void main(String[] args) { AntPathMatcher matcher = new AntPathMatcher(); System.out.println(matcher.extractPathWithinPattern("/test/*", "/test"));// System.out.println(matcher.extractPathWithinPattern("/test/*", "/test/aa"));// aa System.out.println(matcher.extractPathWithinPattern("/test/**", "/test/aa/bb"));// aa/bb System.out.println(matcher.extractPathWithinPattern("/test/a?c/aa", "/test/abc/aa"));// abc/aa System.out.println(matcher.extractPathWithinPattern("/test/aa?c/aa/cc", "/test/abc/aa"));// abc/aa }
6. getPatternComparator
得到一個(gè)排序比較器。
public Comparator<String> getPatternComparator(String path) { return new AntPatternComparator(path); }
7. combine
合并兩個(gè)模式。 示例:
public static void main(String[] args) { AntPathMatcher matcher = new AntPathMatcher(); System.out.println(matcher.combine("/test/*", "/test/aa"));// /test/aa System.out.println(matcher.combine("/test/*", "/test/aa/bb"));// /test/test/aa/bb System.out.println(matcher.combine("/test/**", "/test/aa"));// /test/aa System.out.println(matcher.combine("/test/{id}", "/test/aa"));// /test/{id}/test/aa }
到此這篇關(guān)于Spring中的路徑匹配器AntPathMatcher詳解的文章就介紹到這了,更多相關(guān)AntPathMatcher詳解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中使用SQLite數(shù)據(jù)庫(kù)的實(shí)現(xiàn)示例
SQLite是一種嵌入式數(shù)據(jù)庫(kù)引擎,可以在各種平臺(tái)上使用,本文主要介紹了Java中使用SQLite數(shù)據(jù)庫(kù)的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01Java中獲取時(shí)間戳的三種方式對(duì)比實(shí)現(xiàn)
這篇文章主要介紹了Java中獲取時(shí)間戳的三種方式對(duì)比實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01Java中實(shí)現(xiàn)分布式定時(shí)任務(wù)的方法
這篇文章主要介紹了Java中實(shí)現(xiàn)分布式定時(shí)任務(wù),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01springboot實(shí)現(xiàn)maven多模塊和打包部署
本文主要介紹了springboot實(shí)現(xiàn)maven多模塊和打包部署,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04SpringBoot整合RabbitMQ實(shí)現(xiàn)交換機(jī)與隊(duì)列的綁定
這篇文章將通過(guò)幾個(gè)實(shí)例為大家介紹一些SpringBoot中RabbitMQ如何綁定交換機(jī)(交換器)與隊(duì)列,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-05-05