19
19
import java .util .ArrayList ;
20
20
import java .util .Arrays ;
21
21
import java .util .List ;
22
+ import java .util .Set ;
23
+ import java .util .stream .Collectors ;
22
24
25
+ import org .eclipse .jetty .http .HttpMethod ;
23
26
import org .jspecify .annotations .Nullable ;
24
-
25
27
import org .springframework .util .AntPathMatcher ;
26
28
import org .springframework .util .Assert ;
27
29
import org .springframework .util .PathMatcher ;
28
30
import org .springframework .util .StringUtils ;
29
31
import org .springframework .web .servlet .HandlerInterceptor ;
30
32
import org .springframework .web .servlet .handler .MappedInterceptor ;
33
+ import org .springframework .web .servlet .handler .MethodInterceptor ;
31
34
import org .springframework .web .util .ServletRequestPathUtils ;
32
35
import org .springframework .web .util .UrlPathHelper ;
33
36
import org .springframework .web .util .pattern .PathPattern ;
@@ -50,8 +53,9 @@ public class InterceptorRegistration {
50
53
51
54
private @ Nullable PathMatcher pathMatcher ;
52
55
53
- private int order = 0 ;
56
+ private @ Nullable Set < String > allowedMethods ;
54
57
58
+ private int order = 0 ;
55
59
56
60
/**
57
61
* Create an {@link InterceptorRegistration} instance.
@@ -61,10 +65,10 @@ public InterceptorRegistration(HandlerInterceptor interceptor) {
61
65
this .interceptor = interceptor ;
62
66
}
63
67
64
-
65
68
/**
66
69
* Add patterns for URLs the interceptor should be included in.
67
- * <p>For pattern syntax see {@link PathPattern} when parsed patterns
70
+ * <p>
71
+ * For pattern syntax see {@link PathPattern} when parsed patterns
68
72
* are {@link PathMatchConfigurer#setPatternParser enabled} or
69
73
* {@link AntPathMatcher} otherwise. The syntax is largely the same with
70
74
* {@link PathPattern} more tailored for web usage and more efficient.
@@ -75,18 +79,19 @@ public InterceptorRegistration addPathPatterns(String... patterns) {
75
79
76
80
/**
77
81
* List-based variant of {@link #addPathPatterns(String...)}.
82
+ *
78
83
* @since 5.0.3
79
84
*/
80
85
public InterceptorRegistration addPathPatterns (List <String > patterns ) {
81
- this .includePatterns = (this .includePatterns != null ?
82
- this .includePatterns : new ArrayList <>(patterns .size ()));
86
+ this .includePatterns = (this .includePatterns != null ? this .includePatterns : new ArrayList <>(patterns .size ()));
83
87
this .includePatterns .addAll (patterns );
84
88
return this ;
85
89
}
86
90
87
91
/**
88
92
* Add patterns for URLs the interceptor should be excluded from.
89
- * <p>For pattern syntax see {@link PathPattern} when parsed patterns
93
+ * <p>
94
+ * For pattern syntax see {@link PathPattern} when parsed patterns
90
95
* are {@link PathMatchConfigurer#setPatternParser enabled} or
91
96
* {@link AntPathMatcher} otherwise. The syntax is largely the same with
92
97
* {@link PathPattern} more tailored for web usage and more efficient.
@@ -97,28 +102,34 @@ public InterceptorRegistration excludePathPatterns(String... patterns) {
97
102
98
103
/**
99
104
* List-based variant of {@link #excludePathPatterns(String...)}.
105
+ *
100
106
* @since 5.0.3
101
107
*/
102
108
public InterceptorRegistration excludePathPatterns (List <String > patterns ) {
103
- this .excludePatterns = (this .excludePatterns != null ?
104
- this .excludePatterns : new ArrayList <>(patterns .size ()));
109
+ this .excludePatterns = (this .excludePatterns != null ? this .excludePatterns : new ArrayList <>(patterns .size ()));
105
110
this .excludePatterns .addAll (patterns );
106
111
return this ;
107
112
}
108
113
109
114
/**
110
115
* Configure the PathMatcher to use to match URL paths with against include
111
116
* and exclude patterns.
112
- * <p>This is an advanced property that should be used only when a
117
+ * <p>
118
+ * This is an advanced property that should be used only when a
113
119
* customized {@link AntPathMatcher} or a custom PathMatcher is required.
114
- * <p>By default this is {@link AntPathMatcher}.
115
- * <p><strong>Note:</strong> Setting {@code PathMatcher} enforces use of
120
+ * <p>
121
+ * By default this is {@link AntPathMatcher}.
122
+ * <p>
123
+ * <strong>Note:</strong> Setting {@code PathMatcher} enforces use of
116
124
* String pattern matching even when a
117
125
* {@link ServletRequestPathUtils#parseAndCache parsed} {@code RequestPath}
118
126
* is available.
119
- * @deprecated use of {@link PathMatcher} and {@link UrlPathHelper} is deprecated
120
- * for use at runtime in web modules in favor of parsed patterns with
121
- * {@link PathPatternParser}.
127
+ *
128
+ * @deprecated use of {@link PathMatcher} and {@link UrlPathHelper} is
129
+ * deprecated
130
+ * for use at runtime in web modules in favor of parsed patterns
131
+ * with
132
+ * {@link PathPatternParser}.
122
133
*/
123
134
@ Deprecated (since = "7.0" , forRemoval = true )
124
135
public InterceptorRegistration pathMatcher (PathMatcher pathMatcher ) {
@@ -128,9 +139,10 @@ public InterceptorRegistration pathMatcher(PathMatcher pathMatcher) {
128
139
129
140
/**
130
141
* Specify an order position to be used. Default is 0.
142
+ *
131
143
* @since 4.3.23
132
144
*/
133
- public InterceptorRegistration order (int order ){
145
+ public InterceptorRegistration order (int order ) {
134
146
this .order = order ;
135
147
return this ;
136
148
}
@@ -143,20 +155,42 @@ protected int getOrder() {
143
155
}
144
156
145
157
/**
146
- * Build the underlying interceptor. If URL patterns are provided, the returned
147
- * type is {@link MappedInterceptor}; otherwise {@link HandlerInterceptor}.
158
+ * Build and return the configured interceptor instance.
159
+ *
160
+ * <p>
161
+ * If no include or exclude path patterns are configured, this method returns
162
+ * the
163
+ * original {@link HandlerInterceptor} (or a decorated one if method filtering
164
+ * is applied).
165
+ * If path patterns are provided, a {@link MappedInterceptor} is returned with
166
+ * the patterns and optional {@link PathMatcher} applied.
167
+ *
168
+ * <p>
169
+ * If {@link #allowedMethods(HttpMethod...)} is used, the interceptor is wrapped
170
+ * with a {@link MethodInterceptor} that restricts its invocation based on HTTP
171
+ * method.
172
+ *
173
+ * @return a {@link HandlerInterceptor} or {@link MappedInterceptor} instance
174
+ * depending
175
+ * on path and method configuration
148
176
*/
149
177
@ SuppressWarnings ("removal" )
150
178
protected Object getInterceptor () {
151
179
180
+ HandlerInterceptor methodInterceptor = this .interceptor ;
181
+
182
+ if (allowedMethods != null ) {
183
+ methodInterceptor = new MethodInterceptor (methodInterceptor , allowedMethods );
184
+ }
185
+
152
186
if (this .includePatterns == null && this .excludePatterns == null ) {
153
- return this . interceptor ;
187
+ return methodInterceptor ;
154
188
}
155
189
156
190
MappedInterceptor mappedInterceptor = new MappedInterceptor (
157
191
StringUtils .toStringArray (this .includePatterns ),
158
192
StringUtils .toStringArray (this .excludePatterns ),
159
- this . interceptor );
193
+ methodInterceptor );
160
194
161
195
if (this .pathMatcher != null ) {
162
196
mappedInterceptor .setPathMatcher (this .pathMatcher );
@@ -165,4 +199,39 @@ protected Object getInterceptor() {
165
199
return mappedInterceptor ;
166
200
}
167
201
202
+ /**
203
+ * Specify the HTTP methods that the interceptor should be invoked for.
204
+ *
205
+ * <p>
206
+ * When this method is called, the underlying {@link HandlerInterceptor} will be
207
+ * wrapped in a {@link MethodInterceptor}, which conditionally delegates based
208
+ * on
209
+ * the HTTP method of the request.
210
+ *
211
+ * <p>
212
+ * This allows interceptors to be configured declaratively, e.g., to run only
213
+ * for {@code POST}, {@code PUT}, etc., without requiring manual method checks
214
+ * in the interceptor implementation.
215
+ *
216
+ * <p>
217
+ * Must specify at least one method; an {@link IllegalArgumentException} will be
218
+ * thrown otherwise.
219
+ *
220
+ * <pre class="code">
221
+ * registry.addInterceptor(new AuditInterceptor())
222
+ * .addPathPatterns("/api/**")
223
+ * .allowedMethods(HttpMethod.POST, HttpMethod.PUT);
224
+ * </pre>
225
+ *
226
+ * @param methods one or more HTTP methods to allow
227
+ * @return this registration for chained calls
228
+ * @throws IllegalArgumentException if no methods are specified
229
+ */
230
+ public InterceptorRegistration allowedMethods (HttpMethod ... methods ) {
231
+ Assert .isTrue (methods .length > 0 , "At least one HTTP method must be specified" );
232
+ this .allowedMethods = Arrays .stream (methods )
233
+ .map (HttpMethod ::name )
234
+ .collect (Collectors .toSet ());
235
+ return this ;
236
+ }
168
237
}
0 commit comments