使用Spring AntPathMatcher的doMatch方法
AntPathMatcher的doMatch方法
AntPathMatcher.doMatch(...), 是解決模式匹配的源碼
有4個步驟
1. 分解模式字符串, 分解路徑字符串
2. 第一個while 循環(huán), 用來判斷絕對匹配 /xxx/abc ==> /xxx/abc
3. 第二個while循環(huán)兩個字符串數(shù)組都從最后的下標開始匹配, 直到遇到pattDir為'**'時結束
4. 第三個while循環(huán), 主要解決有多個'**'字符串./**/djdjdjd/**, /a/**/**/b/**/c/**/*.class等
// 解決模式匹配的函數(shù), 返回true or false 表示是否匹配
// 參數(shù) pattern: 表示模式字符串
path: 文件的路徑
protected boolean doMatch(String pattern, String path, boolean fullMatch, Map<String, String> uriTemplateVariables) {
if (path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) {
return false;
}
1.1. 分解模式字符串
String[] pattDirs = tokenizePattern(pattern);
if (fullMatch && this.caseSensitive && !isPotentialMatch(path, pattDirs)) {
return false;
}
1.2 分解路徑字符串
String[] pathDirs = tokenizePath(path);
// pattern的可分配下標 pattIdxStart ~ pattIdxEnd
// path的可分配下標 pathIdxStart ~ pathIdxEnd
int pattIdxStart = 0;
int pattIdxEnd = pattDirs.length - 1;
int pathIdxStart = 0;
int pathIdxEnd = pathDirs.length - 1;
// Match all elements up to the first **
// 2. 第一個while 循環(huán), 用來判斷絕對匹配的 /xxx/abc ==> /xxx/abc
// 兩個字符串都從下標0開始, 直到模式字符串遇到**結束
while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
String pattDir = pattDirs[pattIdxStart];
if ("**".equals(pattDir)) {
break;
}
if (!matchStrings(pattDir, pathDirs[pathIdxStart], uriTemplateVariables)) {
return false;
}
pattIdxStart++;
pathIdxStart++;
}
// pathIdxStart > pathIdEnd, 表示文件路徑(path), 已經(jīng)逐一的匹配到了
if (pathIdxStart > pathIdxEnd) {
/*
// Path is exhausted, only match if rest of pattern is * or **'s
if (pattIdxStart > pattIdxEnd) {
// 判斷最后一個字符是否為'/'
return (pattern.endsWith(this.pathSeparator) == path.endsWith(this.pathSeparator));
}
if (!fullMatch) {
return true;
}
if (pattIdxStart == pattIdxEnd && pattDirs[pattIdxStart].equals("*") && path.endsWith(this.pathSeparator)) {
return true;
}
// 不會執(zhí)行到這里
for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
if (!pattDirs[i].equals("**")) {
return false;
}
}
*/
// 這里返回true 一般是相等的字符串匹配(長度相同)
// /abc/zzzz ==> /abc/zzzz
return true;
}
/*
else if (pattIdxStart > pattIdxEnd) {
// String not exhausted, but pattern is. Failure.
return false;
}
else if (!fullMatch && "**".equals(pattDirs[pattIdxStart])) {
// Path start definitely matches due to "**" part in pattern.
return true;
}*/
// 3. 兩個字符串數(shù)組都從最后的下標開始匹配, 直到遇到pattDir為'**'時結束
while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
String pattDir = pattDirs[pattIdxEnd];
if (pattDir.equals("**")) {
break;
}
if (!matchStrings(pattDir, pathDirs[pathIdxEnd], uriTemplateVariables)) {
return false;
}
pattIdxEnd--;
pathIdxEnd--;
}
if (pathIdxStart > pathIdxEnd) {
for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
if (!pattDirs[i].equals("**")) {
return false;
}
}
// 這里返回true 一般字符串為
// /xxxx/abcd/**/*.class => /xxxx/abcd /xxx.class
// 即只有一個**, 而且**沒發(fā)揮到什么作用
// 測試
// AntPathMatcher ant = new AntPathMatcher("/");
//String pattern = "/abc/**/*.class";
//String path = "/abc/ddd.class";
//System.out.println(ant.match(pattern, path));
return true;
}
// 4. 第3個while循環(huán), 主要解決有多個'**'字符串. /**/djdjdjd/**, /a/**/**/b/**/c/**/*.class等
// 每次下標又從pattIdxStart+1開始
while (pattIdxStart != pattIdxEnd && pathIdxStart <= pathIdxEnd) {
int patIdxTmp = -1; // 這個用來指向**的位置
for (int i = pattIdxStart + 1; i <= pattIdxEnd; i++) {
if (pattDirs[i].equals("**")) {
patIdxTmp = i;
break;
}
}
if (patIdxTmp == pattIdxStart + 1) {
// '**/**' 遇到連續(xù)的/**/**就跳過, 因為這沒有意義, 一個/**也可以表達多條路徑
pattIdxStart++;
continue;
}
// patLength: 兩個'**'之間的字符串的長度 /**/a/b/** = 2
// strLength: 路徑還剩多少個沒匹配 /a/b/c/d 如果/a/b都匹配了, 就只剩下/b/c = 2
int patLength = (patIdxTmp - pattIdxStart - 1);
int strLength = (pathIdxEnd - pathIdxStart + 1);
int foundIdx = -1;
strLoop:
// 因為已經(jīng)確定了有 /**/a/b/**這樣的模式字符串存在, 中間2長度
// 如果存在/q/a/b/c/d 有5個長度, 那么就要循環(huán)3次
// 第一次匹配 /a/b => /q/a
// 第二次 /a/b => /a/b => 這里已經(jīng)匹配到了, 所以就break了
// /a/b => /b/c
// /a/b => /c/d
// 當然, 如果存在更復雜的如: /**/a/b/**/a/b/**/a/b/**, 外層的while循環(huán)就會做3次判斷,
//String pattern = "/**/a/b/**/a/b/**/a/b/**";
//String path = "/q/q/q/a/b/q/q/q/a/b/q/q/q/a/b/q/q/q/a/b";
for (int i = 0; i <= strLength - patLength; i++) {
for (int j = 0; j < patLength; j++) {
String subPat = pattDirs[pattIdxStart + j + 1];
String subStr = pathDirs[pathIdxStart + i + j];
if (!matchStrings(subPat, subStr, uriTemplateVariables)) {
continue strLoop;
}
}
foundIdx = pathIdxStart + i;
break;
}
if (foundIdx == -1) {
return false;
}
pattIdxStart = patIdxTmp;
pathIdxStart = foundIdx + patLength;
}
for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
if (!pattDirs[i].equals("**")) {
return false;
}
}
//如果上面的都沒有返回值 /** => /sdjdd/djkd/.....就會在此處返回
// 當然還有更多的
return true;
}
Spring的AntPathMatcher工具類用法
AntPathMatcher
是org.springframework.util工具包下的方法。
/**
* A convenient, alternative constructor to use with a custom path separator.
* @param pathSeparator the path separator to use, must not be {@code null}.
* @since 4.1
*/
public AntPathMatcher(String pathSeparator) {
Assert.notNull(pathSeparator, "'pathSeparator' is required");
this.pathSeparator = pathSeparator;
this.pathSeparatorPatternCache = new PathSeparatorPatternCache(pathSeparator);
}
public boolean hasUrl(String url) {
if (url == null || "".equals(url)) {
return false;
}
AntPathMatcher antPathMatcher = new AntPathMatcher();
// 可根據(jù)需求做動態(tài)匹配
String pattern = "/app/*.html"
if (antPathMatcher.match(pattern, url)) {
// 根據(jù)入?yún)rl和pattern匹配上返回ture,否則false.
return true;
}
return false;
}
下面是模糊匹配規(guī)則
也就是在響應的路徑上添加* 或則 ** 對路徑進行替代即可。
| URL路徑 | 說明 |
| /app/*.x | 匹配(Matches)所有在app路徑下的.x文件 |
| /app/p?ttern | 匹配(Matches) /app/pattern 和 /app/pXttern,但是不包括/app/pttern |
| /**/example | 匹配(Matches) /app/example, /app/foo/example, 和 /example |
| /app/**/dir/file. | 匹配(Matches) /app/dir/file.jsp, /app/foo/dir/file.html,/app/foo/bar/dir/file.pdf, 和 /app/dir/file.java |
| /**/*.jsp | 匹配(Matches)任何的.jsp 文件 |
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
java接口返回參數(shù)按照請求參數(shù)進行排序方式
這篇文章主要介紹了java接口返回參數(shù)按照請求參數(shù)進行排序方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
java集合Collection實現(xiàn)類解析ArrayList?LinkedList及Vector
這篇文章主要為大家介紹了java集合Collection實現(xiàn)類解析ArrayList?LinkedList及Vector,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-03-03
SpringBoot WebSocket實時監(jiān)控異常的詳細流程
最近做了一個需求,消防的設備巡檢,如果巡檢發(fā)現(xiàn)異常,通過手機端提交,后臺的實時監(jiān)控頁面實時獲取到該設備的信息及位置,然后安排員工去處理。這篇文章主要介紹了SpringBoot WebSocket實時監(jiān)控異常的全過程,感興趣的朋友一起看看吧2021-10-10
解決Java調(diào)用BAT批處理不彈出cmd窗口的方法分析
本篇文章是對Java調(diào)用BAT批處理不彈出cmd窗口的方法進行了詳細的分析介紹,需要的朋友參考下2013-05-05
Spring-data-redis操作redis cluster的示例代碼
這篇文章主要介紹了Spring-data-redis操作redis cluster的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-10-10

