org.springframework.util.AntPathMatcher 工具类

org.springframework.util.AntPathMatcher 工具类

2017-01-10 今天用到了 AntPathMatcher 来匹配url的路径。
AntPathMatcher 是spring中的一个工具类,通过使用通配符的方式来匹配路径。
通配符有三种:

  • ?:匹配任意单个字符
  • *:匹配任意数量的字符,不包括“/”
  • **:匹配更多的目录,包括“/”

以下是 AntPathMatcher 的核心代码:

private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{[^/]+?\\}");

/** Default path separator: "/" */
public static final String DEFAULT_PATH_SEPARATOR = "/";

private String pathSeparator = DEFAULT_PATH_SEPARATOR;

/** Set the path separator to use for pattern parsing. Default is "/", as in Ant. */
public void setPathSeparator(String pathSeparator) {
    this.pathSeparator = (pathSeparator != null ? pathSeparator : DEFAULT_PATH_SEPARATOR);
}

/**
 * Actually match the given <code>path</code> against the given <code>pattern</code>.
 * @param pattern the pattern to match against
 * @param path the path String to test
 * @param fullMatch whether a full pattern match is required (else a pattern match
 * as far as the given base path goes is sufficient)
 * @return true if the supplied path matched, false if it didn't
 */
protected boolean doMatch(String pattern, String path, boolean fullMatch,
        Map<String, String> uriTemplateVariables) {
    if (path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) {
        return false;
    }

    String[] pattDirs = StringUtils.tokenizeToStringArray(pattern, this.pathSeparator);
    String[] pathDirs = StringUtils.tokenizeToStringArray(path, this.pathSeparator);

    int pattIdxStart = 0;
    int pattIdxEnd = pattDirs.length - 1;
    int pathIdxStart = 0;
    int pathIdxEnd = pathDirs.length - 1;

    // Match all elements up to the first **
    while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
        String patDir = pattDirs[pattIdxStart];
        if ("**".equals(patDir)) {
            break;
        }
        if (!matchStrings(patDir, pathDirs[pathIdxStart], uriTemplateVariables)) {
            return false;
        }
        pattIdxStart++;
        pathIdxStart++;
    }

    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) :
                    !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;
            }
        }
        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;
    }

    // up to last '**'
    while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
        String patDir = pattDirs[pattIdxEnd];
        if (patDir.equals("**")) {
            break;
        }
        if (!matchStrings(patDir, pathDirs[pathIdxEnd], uriTemplateVariables)) {
            return false;
        }
        pattIdxEnd--;
        pathIdxEnd--;
    }
    if (pathIdxStart > pathIdxEnd) {
        // String is exhausted
        for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
            if (!pattDirs[i].equals("**")) {
                return false;
            }
        }
        return true;
    }

    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) {
            // '**/**' situation, so skip one
            pattIdxStart++;
            continue;
        }
        // Find the pattern between padIdxStart & padIdxTmp in str between
        // strIdxStart & strIdxEnd
        int patLength = (patIdxTmp - pattIdxStart - 1);
        int strLength = (pathIdxEnd - pathIdxStart + 1);
        int foundIdx = -1;

        strLoop:
        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;
        }
    }

    return true;
}

/**
 * Tests whether or not a string matches against a pattern. The pattern may contain two special characters:<br> '*'
 * means zero or more characters<br> '?' means one and only one character
 * @param pattern pattern to match against. Must not be <code>null</code>.
 * @param str string which must be matched against the pattern. Must not be <code>null</code>.
 * @return true if the string matches against the pattern, or false otherwise.
 */
private boolean matchStrings(String pattern, String str, Map<String, String> uriTemplateVariables) {
    AntPathStringMatcher matcher = new AntPathStringMatcher(pattern, str, uriTemplateVariables);
    return matcher.matchStrings();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值