18
18
19
19
import java .io .IOException ;
20
20
import java .util .Arrays ;
21
- import java .util .LinkedHashMap ;
22
21
import java .util .List ;
23
22
import java .util .Map ;
24
23
import java .util .function .Consumer ;
37
36
import org .springframework .http .HttpStatus ;
38
37
import org .springframework .http .server .RequestPath ;
39
38
import org .springframework .lang .Nullable ;
39
+ import org .springframework .util .LinkedMultiValueMap ;
40
+ import org .springframework .util .MultiValueMap ;
40
41
import org .springframework .util .StringUtils ;
41
42
import org .springframework .web .util .ServletRequestPathUtils ;
42
43
import org .springframework .web .util .pattern .PathPattern ;
43
44
import org .springframework .web .util .pattern .PathPatternParser ;
44
45
45
46
/**
46
- * {@code Filter} that can be configured to trim trailing slashes , and either
47
- * send a redirect or wrap the request and continue processing .
47
+ * {@link jakarta.servlet. Filter} that modifies the URL , and then redirects or
48
+ * wraps the request to apply the change .
48
49
*
49
- * <p>Use the static {@link #trailingSlashHandler(String...)} method to begin to
50
- * configure and build an instance. For example:
50
+ * <p>To create an instance, you can use the following:
51
51
*
52
52
* <pre>
53
53
* UrlHandlerFilter filter = UrlHandlerFilter
56
56
* .build();
57
57
* </pre>
58
58
*
59
- * <p>Note that this {@code Filter} should be ordered after
60
- * {@link ForwardedHeaderFilter} and before the Spring Security filter chain .
59
+ * <p>This {@code Filter} should be ordered after {@link ForwardedHeaderFilter}
60
+ * and before any security filters .
61
61
*
62
62
* @author Rossen Stoyanchev
63
63
* @since 6.2
@@ -67,11 +67,11 @@ public final class UrlHandlerFilter extends OncePerRequestFilter {
67
67
private static final Log logger = LogFactory .getLog (UrlHandlerFilter .class );
68
68
69
69
70
- private final Map < PathPattern , UrlHandler > handlers ;
70
+ private final MultiValueMap < UrlHandler , PathPattern > handlers ;
71
71
72
72
73
- private UrlHandlerFilter (Map < PathPattern , UrlHandler > handlers ) {
74
- this .handlers = new LinkedHashMap <>(handlers );
73
+ private UrlHandlerFilter (MultiValueMap < UrlHandler , PathPattern > handlers ) {
74
+ this .handlers = new LinkedMultiValueMap <>(handlers );
75
75
}
76
76
77
77
@@ -95,11 +95,15 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
95
95
if (path == null ) {
96
96
path = ServletRequestPathUtils .parseAndCache (request );
97
97
}
98
- for (Map .Entry <PathPattern , UrlHandler > entry : this .handlers .entrySet ()) {
99
- UrlHandler handler = entry .getValue ();
100
- if (entry .getKey ().matches (path ) && handler .canHandle (request )) {
101
- handler .handle (request , response , chain );
102
- return ;
98
+ for (Map .Entry <UrlHandler , List <PathPattern >> entry : this .handlers .entrySet ()) {
99
+ if (!entry .getKey ().canHandle (request )) {
100
+ continue ;
101
+ }
102
+ for (PathPattern pattern : entry .getValue ()) {
103
+ if (pattern .matches (path )) {
104
+ entry .getKey ().handle (request , response , chain );
105
+ return ;
106
+ }
103
107
}
104
108
}
105
109
}
@@ -114,8 +118,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
114
118
115
119
116
120
/**
117
- * Create a builder for a {@link UrlHandlerFilter} by adding a handler for
118
- * URL's with a trailing slash.
121
+ * Create a builder by adding a handler for URL's with a trailing slash.
119
122
* @param pathPatterns path patterns to map the handler to, e.g.
120
123
* <code>"/path/*"</code>, <code>"/path/**"</code>,
121
124
* <code>"/path/foo/"</code>.
@@ -153,8 +156,8 @@ public interface Builder {
153
156
interface TrailingSlashSpec {
154
157
155
158
/**
156
- * Intercept requests with a trailing slash. The callback is invoked
157
- * just before the configured trailing slash handler .
159
+ * Configure a request consumer to be called just before the handler
160
+ * is invoked when a URL with a trailing slash is matched .
158
161
*/
159
162
TrailingSlashSpec intercept (Consumer <HttpServletRequest > consumer );
160
163
@@ -185,15 +188,15 @@ private static final class DefaultBuilder implements Builder {
185
188
186
189
private final PathPatternParser patternParser = new PathPatternParser ();
187
190
188
- private final Map < PathPattern , UrlHandler > handlers = new LinkedHashMap <>();
191
+ private final MultiValueMap < UrlHandler , PathPattern > handlers = new LinkedMultiValueMap <>();
189
192
190
193
@ Override
191
194
public TrailingSlashSpec trailingSlashHandler (String ... patterns ) {
192
195
return new DefaultTrailingSlashSpec (patterns );
193
196
}
194
197
195
198
private DefaultBuilder addHandler (List <PathPattern > pathPatterns , UrlHandler handler ) {
196
- pathPatterns .forEach (pattern -> this .handlers .put ( pattern , handler ));
199
+ pathPatterns .forEach (pattern -> this .handlers .add ( handler , pattern ));
197
200
return this ;
198
201
}
199
202
0 commit comments