Spring中的路徑匹配器AntPathMatcher詳解
PathMatcher接口
Spring的PathMatcher路徑匹配器接口,用于支持帶通配符的資源路徑匹配。
使用場景
PathMatcher接口在Spring的許多場景下使用,比如:
- PathMatchingResourcePatternResolver:資源掃描,啟動時掃描并加載資源
- AbstractUrlHandlerMapping:請求路徑映射到 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) | 得到模式匹配的部分值 該方法只返回路徑的實際模式匹配部分 例如:myroot/*.html 匹配 myroot/myfile.html 路徑,結(jié)果為 myfile.html |
| Map<String, String> extractUriTemplateVariables(String pattern, String path) | 提取路徑中的路徑參數(shù)值 |
| Comparator<String> getPatternComparator(String path) | 得到一個排序比較器,用于對匹配到的所有路徑進行排序 |
| String combine(String pattern1, String pattern2) | 合并兩個模式 |
AntPathMatcher類
AntPathMatcher是Spring為PathMatcher接口提供的默認實現(xiàn),支持Ant風格的路徑匹配。
匹配規(guī)則
AntPathMatcher支持的匹配規(guī)則:
| 規(guī)則 | 描述 |
| ? | 匹配一個字符 |
| * | 在一個路徑段中匹配零個、一個或多個字符 |
| ** | 匹配零個或多個路徑段,直到路徑結(jié)束 |
| {id} | 匹配一個路徑段,并將該路徑段的值作為變量id的變量值 |
| {id:[a-z]+} | 匹配一個滿足正則([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é)束符不一致 |
實際在Spring項目中使用的時候,你會發(fā)現(xiàn):就算實際請求的結(jié)束符為 / ,但還是能匹配成功。這又是為什么呢?
兩個關(guān)鍵屬性:
- useSuffixPatternMatch:設置是否使用后綴模式匹配,如“/user”是否匹配/user.*,默認是這種模式下,實際請求.后面加任何后綴,都會匹配到。如:實際請求“/user.html”能匹配上“/user”。
- useTrailingSlashMatch:設置是否使用后綴路徑模式匹配,如“/user”是否匹配“/user/”,默認是這種模式下,實際請求加、后綴,都會匹配到。如:實際請求“/user/”能匹配上“/user”。
關(guān)鍵源碼:
PatternsRequestCondition類的getMatchingPattern方法
private String getMatchingPattern(String pattern, String lookupPath) {
// 模式與路徑相等,直接返回模式
if (pattern.equals(lookupPath)) {
return pattern;
}
// 如果使用后綴模式匹配,返回的模式會拼接上合適的后綴,如.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;
}
// 如果使用后綴路徑模式匹配,返回的模式會拼接上/
if (this.useTrailingSlashMatch) {
if (!pattern.endsWith("/") && this.pathMatcher.match(pattern + "/", lookupPath)) {
return pattern + "/";
}
}
return null;
}因此,getMatchingPattern方法返回的模式再與請求路徑進行模式匹配當然能匹配上了。
主要方法
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
判斷路徑是否前綴匹配
前綴匹配的意思:路徑能與模式的前面部分匹配,但模式可能還有后面多余部分(可以理解為模式是否是以路徑開頭)
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
得到模式匹配的映射部分。找出通過*或者?匹配上的那一段路徑及其后續(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
得到一個排序比較器。
public Comparator<String> getPatternComparator(String path) {
return new AntPatternComparator(path);
}7. combine
合并兩個模式。 示例:
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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中使用SQLite數(shù)據(jù)庫的實現(xiàn)示例
SQLite是一種嵌入式數(shù)據(jù)庫引擎,可以在各種平臺上使用,本文主要介紹了Java中使用SQLite數(shù)據(jù)庫的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下2024-01-01
springboot實現(xiàn)maven多模塊和打包部署
本文主要介紹了springboot實現(xiàn)maven多模塊和打包部署,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-04-04
SpringBoot整合RabbitMQ實現(xiàn)交換機與隊列的綁定
這篇文章將通過幾個實例為大家介紹一些SpringBoot中RabbitMQ如何綁定交換機(交換器)與隊列,文中的示例代碼講解詳細,感興趣的可以了解一下2022-05-05

