Skip to content

Commit 8bb6308

Browse files
committed
Document PathPattern matching for single/multiple segments
This commit improves the reference document to better reflect the different between `*` or `{name}` on one side, and `**` or `{*path}` on the other. The former patterns only consider a single path segment and its content, while the latter variants consider zero or more path segments. This explains why `/test/{*path}` can match `/test`. Closes gh-35727
1 parent a698b1b commit 8bb6308

File tree

4 files changed

+61
-111
lines changed

4 files changed

+61
-111
lines changed

framework-docs/modules/ROOT/pages/web/webflux/controller/ann-requestmapping.adoc

Lines changed: 1 addition & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -89,60 +89,7 @@ Kotlin::
8989

9090
You can map requests by using glob patterns and wildcards:
9191

92-
[cols="2,3,5"]
93-
|===
94-
|Pattern |Description |Example
95-
96-
| `spring`
97-
| Literal pattern
98-
| `+"/spring"+` matches `+"/spring"+`
99-
100-
| `+?+`
101-
| Matches one character
102-
| `+"/pages/t?st.html"+` matches `+"/pages/test.html"+` and `+"/pages/t3st.html"+`
103-
104-
| `+*+`
105-
| Matches zero or more characters within a path segment
106-
| `+"/resources/*.png"+` matches `+"/resources/file.png"+`
107-
108-
`+"/projects/*/versions"+` matches `+"/projects/spring/versions"+` but does not match `+"/projects/spring/boot/versions"+`
109-
110-
| `+**+`
111-
| Matches zero or more path segments
112-
| `+"/resources/**"+` matches `+"/resources/file.png"+` and `+"/resources/images/file.png"+`
113-
114-
`+"/**/resources"+` matches `+"/spring/resources"+` and `+"/spring/framework/resources"+`
115-
116-
`+"/resources/**/file.png"+` is invalid as `+**+` is not allowed in the middle of the path.
117-
118-
`+"/**/{name}/resources"+` is invalid as only a literal pattern is allowed right after `+**+`.
119-
`+"/**/project/{project}/resources"+` is allowed.
120-
121-
`+"/**/spring/**"+` is not allowed, as only a single `+**+`/`+{*path}+` instance is allowed per pattern.
122-
123-
| `+{name}+`
124-
| Matches a path segment and captures it as a variable named "name"
125-
| `+"/projects/{project}/versions"+` matches `+"/projects/spring/versions"+` and captures `+project=spring+`
126-
`+"/projects/{project}/versions"+` does not match `+"/projects/spring/framework/versions"+` as it captures a single path segment.
127-
128-
| `{name:[a-z]+}`
129-
| Matches the regexp `[a-z]+` as a path variable named "name"
130-
| `/projects/{project:[a-z]+}/versions` matches `/projects/spring/versions` but not `/projects/spring1/versions`
131-
132-
| `+{*path}+`
133-
| Matches zero or more path segments and captures it as a variable named "path"
134-
| `+"/resources/{*file}"+` matches `+"/resources/images/file.png"+` and captures `+file=/images/file.png+`
135-
136-
`+"{*path}/resources"+` matches `+"/spring/framework/resources"+` and captures `+path=/spring/framework+`
137-
138-
`+"/resources/{*path}/file.png"+` is invalid as `{*path}` is not allowed in the middle of the path.
139-
140-
`+"/{*path}/{name}/resources"+` is invalid as only a literal pattern is allowed right after `{*path}`.
141-
`+"/{*path}/project/{project}/resources"+` is allowed.
142-
143-
`+"/{*path}/spring/**"+` is not allowed, as only a single `+**+`/`+{*path}+` instance is allowed per pattern.
144-
145-
|===
92+
include::partial$web/uri-patterns.adoc[leveloffset=+1]
14693

14794
Captured URI variables can be accessed with `@PathVariable`, as the following example shows:
14895

framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-requestmapping.adoc

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -105,61 +105,7 @@ customizations of path matching options.
105105

106106
You can map requests by using glob patterns and wildcards:
107107

108-
[cols="2,3,5"]
109-
|===
110-
|Pattern |Description |Example
111-
112-
| `spring`
113-
| Literal pattern
114-
| `+"/spring"+` matches `+"/spring"+`
115-
116-
| `+?+`
117-
| Matches one character
118-
| `+"/pages/t?st.html"+` matches `+"/pages/test.html"+` and `+"/pages/t3st.html"+`
119-
120-
| `+*+`
121-
| Matches zero or more characters within a path segment
122-
| `+"/resources/*.png"+` matches `+"/resources/file.png"+`
123-
124-
`+"/projects/*/versions"+` matches `+"/projects/spring/versions"+` but does not match `+"/projects/spring/boot/versions"+`
125-
126-
| `+**+`
127-
| Matches zero or more path segments
128-
| `+"/resources/**"+` matches `+"/resources/file.png"+` and `+"/resources/images/file.png"+`
129-
130-
`+"/**/resources"+` matches `+"/spring/resources"+` and `+"/spring/framework/resources"+`
131-
132-
`+"/resources/**/file.png"+` is invalid as `+**+` is not allowed in the middle of the path.
133-
134-
`+"/**/{name}/resources"+` is invalid as only a literal pattern is allowed right after `+**+`.
135-
`+"/**/project/{project}/resources"+` is allowed.
136-
137-
`+"/**/spring/**"+` is not allowed, as only a single `+**+`/`+{*path}+` instance is allowed per pattern.
138-
139-
| `+{name}+`
140-
| Matches a path segment and captures it as a variable named "name"
141-
| `+"/projects/{project}/versions"+` matches `+"/projects/spring/versions"+` and captures `+project=spring+`
142-
143-
`+"/projects/{project}/versions"+` does not match `+"/projects/spring/framework/versions"+` as it captures a single path segment.
144-
145-
| `{name:[a-z]+}`
146-
| Matches the regexp `"[a-z]+"` as a path variable named "name"
147-
| `"/projects/{project:[a-z]+}/versions"` matches `"/projects/spring/versions"` but not `"/projects/spring1/versions"`
148-
149-
| `+{*path}+`
150-
| Matches zero or more path segments and captures it as a variable named "path"
151-
| `+"/resources/{*file}"+` matches `+"/resources/images/file.png"+` and captures `+file=/images/file.png+`
152-
153-
`+"{*path}/resources"+` matches `+"/spring/framework/resources"+` and captures `+path=/spring/framework+`
154-
155-
`+"/resources/{*path}/file.png"+` is invalid as `{*path}` is not allowed in the middle of the path.
156-
157-
`+"/{*path}/{name}/resources"+` is invalid as only a literal pattern is allowed right after `{*path}`.
158-
`+"/{*path}/project/{project}/resources"+` is allowed.
159-
160-
`+"/{*path}/spring/**"+` is not allowed, as only a single `+**+`/`+{*path}+` instance is allowed per pattern.
161-
162-
|===
108+
include::partial$web/uri-patterns.adoc[leveloffset=+1]
163109

164110
Captured URI variables can be accessed with `@PathVariable`. For example:
165111

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
[cols="2,3,5"]
2+
|===
3+
|Pattern |Description |Example
4+
5+
| `spring`
6+
| Literal pattern
7+
| `+"/spring"+` matches `+"/spring"+`
8+
9+
| `+?+`
10+
| Matches one character
11+
| `+"/pages/t?st.html"+` matches `+"/pages/test.html"+` and `+"/pages/t3st.html"+`
12+
13+
| `+*+`
14+
| Matches zero or more characters within a path segment
15+
| `+"/resources/*.png"+` matches `+"/resources/file.png"+`
16+
17+
`+"/projects/*/versions"+` matches `+"/projects/spring/versions"+` but does not match `+"/projects/spring/boot/versions"+`.
18+
19+
`+"/projects/*"+` matches `+"/projects/spring"+` but does not match `+"/projects"+` as the path segment is not present.
20+
21+
| `+**+`
22+
| Matches zero or more path segments
23+
| `+"/resources/**"+` matches `+"/resources"+`, `+"/resources/file.png"+` and `+"/resources/images/file.png"+`
24+
25+
`+"/**/info"+` matches `+"/info"+`, `+"/spring/info"+` and `+"/spring/framework/info"+`
26+
27+
`+"/resources/**/file.png"+` is invalid as `+**+` is not allowed in the middle of the path.
28+
29+
`+"/**/{name}/resources"+` is invalid as only a literal pattern is allowed right after `+**+`.
30+
`+"/**/project/{project}/resources"+` is allowed.
31+
32+
`+"/**/spring/**"+` is not allowed, as only a single `+**+`/`+{*path}+` instance is allowed per pattern.
33+
34+
| `+{name}+`
35+
| Similar to `+*+`, but also captures the path segment as a variable named "name"
36+
| `+"/projects/{project}/versions"+` matches `+"/projects/spring/versions"+` and captures `+project=spring+`
37+
38+
`+"/projects/{project}/versions"+` does not match `+"/projects/spring/framework/versions"+` as it captures a single path segment.
39+
40+
| `{name:[a-z]+}`
41+
| Matches the regexp `"[a-z]+"` as a path variable named "name"
42+
| `"/projects/{project:[a-z]+}/versions"` matches `"/projects/spring/versions"` but not `"/projects/spring1/versions"`
43+
44+
| `+{*path}+`
45+
| Similar to `+**+`, but also captures the path segments as a variable named "path"
46+
| `+"/resources/{*file}"+` matches `+"/resources/images/file.png"+` and captures `+file=/images/file.png+`
47+
48+
`+"{*path}/resources"+` matches `+"/spring/framework/resources"+` and captures `+path=/spring/framework+`
49+
50+
`+"/resources/{*path}/file.png"+` is invalid as `{*path}` is not allowed in the middle of the path.
51+
52+
`+"/{*path}/{name}/resources"+` is invalid as only a literal pattern is allowed right after `{*path}`.
53+
`+"/{*path}/project/{project}/resources"+` is allowed.
54+
55+
`+"/{*path}/spring/**"+` is not allowed, as only a single `+**+`/`+{*path}+` instance is allowed per pattern.
56+
57+
|===

spring-web/src/test/java/org/springframework/web/util/pattern/PathPatternTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,14 +149,14 @@ void wildcards() {
149149
checkMatches("/*/bar", "/foo/bar");
150150
checkNoMatch("/*/bar", "/foo/baz");
151151
checkNoMatch("/*/bar", "//bar");
152+
checkNoMatch("/*/bar", "/bar");
152153
checkMatches("/f*/bar", "/foo/bar");
153-
checkMatches("/*/bar", "/foo/bar");
154154
checkMatches("a/*","a/");
155155
checkMatches("/*","/");
156156
checkMatches("/*/bar", "/foo/bar");
157157
checkNoMatch("/*/bar", "/foo/baz");
158+
checkNoMatch("/*/bar", "/bar");
158159
checkMatches("/f*/bar", "/foo/bar");
159-
checkMatches("/*/bar", "/foo/bar");
160160
checkMatches("/a*b*c*d/bar", "/abcd/bar");
161161
checkMatches("*a*", "testa");
162162
checkMatches("a/*", "a/");

0 commit comments

Comments
 (0)