使用Spring AntPathMatcher的doMatch方法

目录
  • AntPathMatcher的doMatch方法
    • 有4个步骤
  • Spring的AntPathMatcher工具类用法
    • AntPathMatcher
    • 下面是模糊匹配规则

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<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 循环, 用来判断绝对匹配的   /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 **'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;
			}
			// 不会执行到这里
			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. 两个字符串数组都从最后的下标开始匹配, 直到遇到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 = 2
			int 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 文件

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 简单了解Spring中常用工具类

    文件资源操作 Spring 定义了一个 org.springframework.core.io.Resource 接口,Resource 接口是为了统一各种类型不同的资源而定义的,Spring 提供了若干 Resource 接口的实现类,这些实现类可以轻松地加载不同类型的底层资源,并提供了获取文件名.URL 地址以及资源内容的操作方法 访问文件资源 * 通过 FileSystemResource 以文件系统绝对路径的方式进行访问: * 通过 ClassPathResource 以类路径的方式进行

  • 基于Spring概念模型:PathMatcher 路径匹配器

    目录 概述 PathMatcher接口源代码 AntPathMatcher使用例子 spring的路径匹配工具 AntPathMatcher 以下代码为本人使用过的路径匹配工具代码 核心代码是这一行 源代码版本 : spring-webmvc-5.1.4.RELEASE 概述 PathMatcher是Spring的一个概念模型接口,该接口抽象建模了概念"路径匹配器",一个"路径匹配器"是一个用于路径匹配的工具.它的使用者是 : org.springframework

  • 如何使用Spring工具类动态匹配url

    这篇文章主要介绍了如何使用Spring工具类动态匹配url,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 该方法主要是借助spring对于路径的通配符匹配的实现,来实现自己公司业务需求. package com.stylefeng.guns.gateway.modular; import org.apache.commons.lang3.StringUtils; import org.springframework.util.AntPathMa

  • 详解Spring mvc ant path的使用方法

    详解Spring mvc ant path的使用方法 概要: 任何一个WEB都需要解决URL与请求处理器之间的映射,spring MVC也是一样,但Spring MVC就像Spring所作的一切一样(灵活,可以配置各种东西,但是也造成了很多复杂性),肯定不会只有一种方法来映射URL和 Controller之间的关系,并且在实际上,允许你自己创建映射规则和实现,而不仅仅依赖URL映射. 1.Spring path match Spring MVC中的路径匹配要比标准的web.xml要灵活的多.默认

  • 使用Spring AntPathMatcher的doMatch方法

    目录 AntPathMatcher的doMatch方法 有4个步骤 Spring的AntPathMatcher工具类用法 AntPathMatcher 下面是模糊匹配规则 AntPathMatcher的doMatch方法 AntPathMatcher.doMatch(...), 是解决模式匹配的源码 有4个步骤 1. 分解模式字符串, 分解路径字符串 2. 第一个while 循环, 用来判断绝对匹配 /xxx/abc ==> /xxx/abc 3. 第二个while循环两个字符串数组都从最后的下

  • Spring spel表达式使用方法示例

    spring in action第三版读书笔记 spring3.0引入了spring expression language(spel)语言,通过spel我们可以实现 1.通过bean的id对bean进行引用 2.调用方法以及引用对象中的属性 3.计算表达式的值 4.正则表达式的匹配 5.集合的操作 spel最终的目标是得到表达式计算之后的值,这些表达式可能是列举的一些值,引用对象的某些属性,或者是类中的某些常量,复杂的spel表达式通常都是由一些简单的元素构成的.最简单的仅仅是得到一些给出元素

  • Spring框架依赖注入方法示例

    在阅读这篇文章之前,大家可以先参阅<理解Spring中的依赖注入和控制反转>一文,了解下依赖注入和控制反转的相关内容. 三种依赖注入的方式 属性注入,通过setter方法注入bean的属性值或依赖的对象 构造注入 工厂方法注入(很少使用) 例子 这里我们使用了spring-4.3.2,maven配置文件 <dependency> <groupid>org.springframework</groupid> spring-core</artifactid

  • Spring整合Quartz Job以及Spring Task的实现方法

    Spring中常用的定时任务的主要有两种 1.Spring整合Quartz Job 2.Spring 3.0以后自带的Task 一.两种定时任务的实现方式 Quartz job 1.首先编写任务类 package com.yjf.job; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author yjf */ public class ExampleJob { private static final Logge

  • Spring的实例工厂方法和静态工厂方法实例代码

    Spring的实例工厂方法和静态工厂方法都可以用来实例化bean,本文我们就来看看相关实例. 静态工厂方法:直接调用静态方法可以返回Bean的实例 package com.zhu.string.factory; import java.util.HashMap; import java.util.Map; public class StaticCarFactory { /** * 静态工厂方法:直接调用静态方法可以返回Bean的实例 * */ private static Map<String

  • spring boot aop 记录方法执行时间代码示例

    本文研究的主要是spring boot aop 记录方法执行时间的实现代码,具体如下. 为了性能调优,需要先统计出来每个方法的执行时间,直接在方法前后log输出太麻烦,可以用AOP来加入时间统计 添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency&

  • Spring MVC框架配置方法详解

    本文实例为大家分享了Spring MVC框架配置方法,供大家参考,具体内容如下 1.概述 Spring MVC 作用:用来实现前端浏览器与后面程序的交互 Spring MVC 是基于Spring 的MVC框架,所谓MVC(model,controller,view) ,整个Spring MVC 作用就是,基于Spring 将model(数据)在controller(后台程序) ,view(前端浏览器)之间交互 至于Spring MVC优点缺点,了解不深 不作评价, 2.引用的jar包 既然是基于

  • spring boot 全局异常处理方法汇总

    这篇文章主要介绍了spring boot 全局异常处理方法汇总,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 import cn.sisyphe.framework.web.exception.DataException; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.co

  • MyBatis 与 Spring 的完美整合方法

    MyBatis-Spring 项目 目前大部分的 Java 互联网项目,都是用 Spring MVC + Spring + MyBatis 搭建平台的. 使用 Spring IoC 可以有效的管理各类的 Java 资源,达到即插即拔的功能:通过 Spring AOP 框架,数据库事务可以委托给 Spring 管理,消除很大一部分的事务代码,配合 MyBatis 的高灵活.可配置.可优化 SQL 等特性,完全可以构建高性能的大型网站. 毫无疑问,MyBatis 和 Spring 两大框架已经成了

  • Maven项目改为spring boot项目的方法图解

    目录树 •新建Maven项目及步骤 •修改方法 •启动测试 新建Maven项目及步骤 我这里是从创建开始讲,使用的工具是Idea2017版本.如果是已经创建了Maven,想改为spring boot项目的请直接跳到[修改方法] 1.点击右上角的File,出来的列表选择New Object: 2.选择Maven,勾选Create from archetype,选择quickstart 3.输入GroupId与ArtifactId,Version版本号自己看着怎么顺眼怎么改:其中GroupId为包名

随机推荐