Ant风格路径

2025/10/1 Java

Ant风格路径是一种用于匹配文件路径的模式语言,最初源自Apache Ant构建工具,现在被广泛应用于Java生态系统中,特别是在Spring Framework中。

Ant风格路径的主要规则:

public class AntPathExample {
    public static void main(String[] args) {
        // 基本通配符:
        // ? - matches one character 匹配一个字符
        // * - matches zero or more characters 匹配零个或多个字符
        // ** - matches zero or more directories in a path 匹配零个或多个目录

        // 示例路径模式
        String[] patterns = {
            "com/t?st.jsp",          // 匹配 com/test.jsp, com/tast.jsp
            "com/*.jsp",             // 匹配 com 目录下的所有 .jsp 文件
            "com/**/test.jsp",       // 匹配 com 目录及其子目录下的 test.jsp
            "org/**/servlet/*.jsp",  // 匹配 org 目录下任意层级的 servlet 目录中的 .jsp 文件
            "com/{filename:\\w+}.jsp" // 匹配 com 目录下的所有 .jsp 文件,并捕获文件名
        };
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

使用Spring的AntPathMatcher:

import org.springframework.util.AntPathMatcher;

public class AntPathMatcherExample {
    public static void main(String[] args) {
        // The mapping matches URLs using the following rules: 
        // ? matches one character
		// * matches zero or more characters
		// ** matches zero or more directories in a path
		// {spring:[a-z]+} matches the regexp [a-z]+ as a path variable named "spring"
        
        // Examples:
        // com/ t?st. jsp — matches com/ test. jsp but also com/ tast. jsp or com/ txst. jsp
        // com/*.jsp — matches all .jsp files in the com directory
        // com/**/ test. jsp — matches all test. jsp files underneath the com path
        // org/ springframework/**/*.jsp — matches all .jsp files underneath the org/ springframework path
        // org/**/ servlet/ bla. jsp — matches org/ springframework/ servlet/ bla. jsp but also org/ springframework/ testing/ servlet/ bla. jsp and org/ servlet/ bla. jsp
        // com/{filename:\\w+}.jsp will match com/ test. jsp and assign the value test to the filename variable
        
        AntPathMatcher matcher = new AntPathMatcher();

        // 基本匹配
        boolean match1 = matcher.match("com/*.jsp", "com/test.jsp");
        System.out.println("Match1: " + match1);  // true

        // 目录匹配
        boolean match2 = matcher.match("com/**/test.jsp", "com/sub/test.jsp");
        System.out.println("Match2: " + match2);  // true

        // 提取路径变量
        String pattern = "/users/{id}/profile";
        String path = "/users/123/profile";
        boolean match3 = matcher.match(pattern, path);
        System.out.println("Match3: " + match3);  // true
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

AntPathMatcher 支持在路径变量中使用正则表达式模式,格式为 {varName:regex}。其中 varName 可以是任意有效的变量名,不限于 spring。

import org.springframework.util.AntPathMatcher;
import java.util.Map;

public class AntPathMatcherRegexDemo {
    private static final AntPathMatcher pathMatcher = new AntPathMatcher();

    public static void main(String[] args) {
        demonstrateBasicRegexUsage();
        demonstrateVariableNames();
        demonstrateComplexPatterns();
        demonstrateMultipleVariables();
    }

    // 基本正则表达式用法
    private static void demonstrateBasicRegexUsage() {
        System.out.println("=== Basic Regex Usage ===");

        // 使用不同的变量名
        String[] patterns = {
            "/user/{spring:[a-z]+}",      // 原始示例
            "/user/{name:[a-z]+}",        // 使用 name 作为变量名
            "/user/{id:[a-z]+}",          // 使用 id 作为变量名
            "/user/{param:[a-z]+}"        // 使用 param 作为变量名
        };

        String path = "/user/john";
        
        for (String pattern : patterns) {
            boolean matches = pathMatcher.match(pattern, path);
            if (matches) {
                Map<String, String> variables = 
                    pathMatcher.extractUriTemplateVariables(pattern, path);
                System.out.printf("Pattern: %-20s Variables: %s%n", 
                    pattern, variables);
            }
        }
    }

    // 演示不同变量名的使用
    private static void demonstrateVariableNames() {
        System.out.println("\n=== Variable Names ===");

        // 定义模式和路径
        String[] patterns = {
            "/files/{filename:[a-z]+\\.pdf}",
            "/files/{doc:[a-z]+\\.pdf}",
            "/files/{file:[a-z]+\\.pdf}"
        };

        String path = "/files/document.pdf";

        for (String pattern : patterns) {
            if (pathMatcher.match(pattern, path)) {
                Map<String, String> vars = 
                    pathMatcher.extractUriTemplateVariables(pattern, path);
                System.out.printf("Pattern: %-25s Variables: %s%n", 
                    pattern, vars);
            }
        }
    }

    // 演示复杂的正则表达式模式
    private static void demonstrateComplexPatterns() {
        System.out.println("\n=== Complex Patterns ===");

        // 不同的正则表达式模式
        String[] patterns = {
            "/users/{userId:[0-9]+}",                    // 数字ID
            "/users/{username:[a-zA-Z][a-zA-Z0-9]+}",   // 用户名
            "/date/{date:\\d{4}-\\d{2}-\\d{2}}",        // 日期格式
            "/items/{code:[A-Z]{2}\\d{3}}"              // 商品代码
        };

        // 测试路径
        String[] paths = {
            "/users/123",
            "/users/john123",
            "/date/2023-12-25",
            "/items/AB123"
        };

        for (String pattern : patterns) {
            for (String path : paths) {
                if (pathMatcher.match(pattern, path)) {
                    Map<String, String> vars = 
                        pathMatcher.extractUriTemplateVariables(pattern, path);
                    System.out.printf("Pattern: %-30s Path: %-15s Variables: %s%n", 
                        pattern, path, vars);
                }
            }
        }
    }

    // 演示多个变量的使用
    private static void demonstrateMultipleVariables() {
        System.out.println("\n=== Multiple Variables ===");

        // 包含多个变量的模式
        String pattern = "/api/{version:\\d+}/{resource:[a-z]+}/{id:[0-9]+}";
        String[] paths = {
            "/api/1/users/123",
            "/api/2/products/456",
            "/api/v1/orders/789"  // 这个不会匹配
        };

        for (String path : paths) {
            if (pathMatcher.match(pattern, path)) {
                Map<String, String> vars = 
                    pathMatcher.extractUriTemplateVariables(pattern, path);
                System.out.printf("Path: %-20s Variables: %s%n", path, vars);
            } else {
                System.out.printf("Path: %-20s No match%n", path);
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

总结:

  1. 变量名可以自定义,不限于"spring"
  2. 正则表达式模式需要用冒号分隔
  3. 可以在同一路径中使用多个变量
  4. 正则表达式需要正确转义
  5. 变量名应遵循Java标识符命名规则