使用Spring|使用Spring AntPathMatcher的doMatch方法
目录
- AntPathMatcher的doMatch方法
- 有4个步骤
- Spring的AntPathMatcher工具类用法
- AntPathMatcher
- 下面是模糊匹配规则
AntPathMatcher的doMatch方法 【使用Spring|使用Spring AntPathMatcher的doMatch方法】AntPathMatcher.doMatch(...), 是解决模式匹配的源码
有4个步骤
1. 分解模式字符串, 分解路径字符串
2. 第一个while 循环, 用来判断绝对匹配 /xxx/abc ==> /xxx/abc
3. 第二个while循环两个字符串数组都从最后的下标开始匹配, 直到遇到pattDir为'**'时结束
4. 第三个while循环, 主要解决有多个'**'字符串./**/djdjdjd/**, /a/**/**/b/**/c/**/*.class等
// 解决模式匹配的函数, 返回true or false 表示是否匹配// 参数 pattern: 表示模式字符串path: 文件的路径 protected boolean doMatch(String pattern, String path, boolean fullMatch, Map 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 ~ pathIdxEndint pattIdxStart = 0; int pattIdxEnd = pattDirs.length - 1; int pathIdxStart = 0; int pathIdxEnd = pathDirs.length - 1; // Match all elements up to the first **// 2. 第一个while 循环, 用来判断绝对匹配的/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), 已经逐一的匹配到了if (pathIdxStart > pathIdxEnd) {/*// Path is exhausted, only match if rest of pattern is * or **'sif (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; }// 不会执行到这里for (int i = pattIdxStart; i <= pattIdxEnd; i++) {if (!pattDirs[i].equals("**")) {return false; }}*/// 这里返回true 一般是相等的字符串匹配(长度相同)// /abc/zzzz ==> /abc/zzzzreturn 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. 两个字符串数组都从最后的下标开始匹配, 直到遇到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 // 即只有一个**, 而且**没发挥到什么作用 // 测试// 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循环, 主要解决有多个'**'字符串. /**/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) {// '**/**' 遇到连续的/**/**就跳过, 因为这没有意义, 一个/**也可以表达多条路径pattIdxStart++; continue; }// patLength: 两个'**'之间的字符串的长度/**/a/b/** = 2// strLength: 路径还剩多少个没匹配/a/b/c/d 如果/a/b都匹配了, 就只剩下/b/c = 2int patLength = (patIdxTmp - pattIdxStart - 1); int strLength = (pathIdxEnd - pathIdxStart + 1); int foundIdx = -1; strLoop:// 因为已经确定了有 /**/a/b/**这样的模式字符串存在, 中间2长度// 如果存在/q/a/b/c/d 有5个长度, 那么就要循环3次// 第一次匹配 /a/b => /q/a// 第二次/a/b => /a/b => 这里已经匹配到了, 所以就break了///a/b => /b/c///a/b => /c/d// 当然, 如果存在更复杂的如: /**/a/b/**/a/b/**/a/b/**, 外层的while循环就会做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(); // 可根据需求做动态匹配String pattern = "/app/*.html"if (antPathMatcher.match(pattern, url)) {// 根据入参url和pattern匹配上返回ture,否则false.return true; }return false; }
下面是模糊匹配规则
也就是在响应的路径上添加* 或则 ** 对路径进行替代即可。
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 文件 |
推荐阅读
- 由浅入深理解AOP
- 【译】20个更有效地使用谷歌搜索的技巧
- Activiti(一)SpringBoot2集成Activiti6
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- MybatisPlus使用queryWrapper如何实现复杂查询
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- iOS中的Block
- Linux下面如何查看tomcat已经使用多少线程