2222import jakarta .servlet .http .HttpServletResponse ;
2323import org .jspecify .annotations .Nullable ;
2424
25+ import org .springframework .http .HttpMethod ;
2526import org .springframework .http .server .PathContainer ;
2627import org .springframework .util .AntPathMatcher ;
2728import org .springframework .util .ObjectUtils ;
@@ -67,6 +68,10 @@ public final class MappedInterceptor implements HandlerInterceptor {
6768
6869 private final PatternAdapter @ Nullable [] excludePatterns ;
6970
71+ private final MethodAdapter @ Nullable [] includeHttpMethods ;
72+
73+ private final MethodAdapter @ Nullable [] excludeHttpMethods ;
74+
7075 private PathMatcher pathMatcher = defaultPathMatcher ;
7176
7277 private final HandlerInterceptor interceptor ;
@@ -78,58 +83,79 @@ public final class MappedInterceptor implements HandlerInterceptor {
7883 * @param includePatterns patterns to which requests must match, or null to
7984 * match all paths
8085 * @param excludePatterns patterns to which requests must not match
86+ * @param includeHttpMethods http methods to which request must match, or null to match all paths
87+ * @param excludeHttpMethods http methods to which request must not match
8188 * @param interceptor the target interceptor
8289 * @param parser a parser to use to pre-parse patterns into {@link PathPattern};
8390 * when not provided, {@link PathPatternParser#defaultInstance} is used.
8491 * @since 5.3
8592 */
86- public MappedInterceptor (String @ Nullable [] includePatterns , String @ Nullable [] excludePatterns ,
93+ public MappedInterceptor (String @ Nullable [] includePatterns , String @ Nullable [] excludePatterns , HttpMethod @ Nullable [] includeHttpMethods , HttpMethod @ Nullable [] excludeHttpMethods ,
8794 HandlerInterceptor interceptor , @ Nullable PathPatternParser parser ) {
8895
8996 this .includePatterns = PatternAdapter .initPatterns (includePatterns , parser );
9097 this .excludePatterns = PatternAdapter .initPatterns (excludePatterns , parser );
98+ this .includeHttpMethods = MethodAdapter .initHttpMethods (includeHttpMethods );
99+ this .excludeHttpMethods = MethodAdapter .initHttpMethods (excludeHttpMethods );
91100 this .interceptor = interceptor ;
92101 }
93102
94103
95104 /**
96105 * Variant of
97- * {@link #MappedInterceptor(String[], String[], HandlerInterceptor, PathPatternParser)}
106+ * {@link #MappedInterceptor(String[], String[], HttpMethod[], HttpMethod[], HandlerInterceptor, PathPatternParser)}
98107 * with include patterns only.
99108 */
100109 public MappedInterceptor (String @ Nullable [] includePatterns , HandlerInterceptor interceptor ) {
101- this (includePatterns , null , interceptor );
110+ this (includePatterns , null , null , null , interceptor );
102111 }
103112
104113 /**
105114 * Variant of
106- * {@link #MappedInterceptor(String[], String[], HandlerInterceptor, PathPatternParser)}
115+ * {@link #MappedInterceptor(String[], String[], HttpMethod[], HttpMethod[], HandlerInterceptor, PathPatternParser)}
116+ * with include methods only.
117+ */
118+ public MappedInterceptor (HttpMethod @ Nullable [] includeHttpMethods , HandlerInterceptor interceptor ) {
119+ this (null , null , includeHttpMethods , null , interceptor );
120+ }
121+
122+ /**
123+ * Variant of
124+ * {@link #MappedInterceptor(String[], String[], HttpMethod[], HttpMethod[], HandlerInterceptor, PathPatternParser)}
107125 * without a provided parser.
108126 */
109- public MappedInterceptor (String @ Nullable [] includePatterns , String @ Nullable [] excludePatterns ,
127+ public MappedInterceptor (String @ Nullable [] includePatterns , String @ Nullable [] excludePatterns , HttpMethod @ Nullable [] includeHttpMethods , HttpMethod @ Nullable [] excludeHttpMethods ,
110128 HandlerInterceptor interceptor ) {
111129
112- this (includePatterns , excludePatterns , interceptor , null );
130+ this (includePatterns , excludePatterns ,includeHttpMethods , excludeHttpMethods , interceptor , null );
113131 }
114132
115133 /**
116134 * Variant of
117- * {@link #MappedInterceptor(String[], String[], HandlerInterceptor, PathPatternParser)}
135+ * {@link #MappedInterceptor(String[], String[], HttpMethod[], HttpMethod[], HandlerInterceptor, PathPatternParser)}
118136 * with a {@link WebRequestInterceptor} as the target.
119137 */
120138 public MappedInterceptor (String @ Nullable [] includePatterns , WebRequestInterceptor interceptor ) {
121- this (includePatterns , null , interceptor );
139+ this (includePatterns , null ,null ,null , interceptor );
140+ }
141+ /**
142+ * Variant of
143+ * {@link #MappedInterceptor(String[], String[], HttpMethod[], HttpMethod[], HandlerInterceptor, PathPatternParser)}
144+ * with a {@link WebRequestInterceptor} as the target.
145+ */
146+ public MappedInterceptor (HttpMethod @ Nullable [] includeHttpMethods , WebRequestInterceptor interceptor ) {
147+ this (null , null ,includeHttpMethods ,null , interceptor );
122148 }
123149
124150 /**
125151 * Variant of
126- * {@link #MappedInterceptor(String[], String[], HandlerInterceptor, PathPatternParser)}
152+ * {@link #MappedInterceptor(String[], String[], HttpMethod[], HttpMethod[] , HandlerInterceptor, PathPatternParser)}
127153 * with a {@link WebRequestInterceptor} as the target.
128154 */
129- public MappedInterceptor (String @ Nullable [] includePatterns , String @ Nullable [] excludePatterns ,
155+ public MappedInterceptor (String @ Nullable [] includePatterns , String @ Nullable [] excludePatterns , HttpMethod @ Nullable [] includeHttpMethods , HttpMethod @ Nullable [] excludeHttpMethods ,
130156 WebRequestInterceptor interceptor ) {
131157
132- this (includePatterns , excludePatterns , new WebRequestHandlerInterceptorAdapter (interceptor ));
158+ this (includePatterns , excludePatterns ,includeHttpMethods , excludeHttpMethods , new WebRequestHandlerInterceptorAdapter (interceptor ));
133159 }
134160
135161
@@ -202,6 +228,7 @@ public PathMatcher getPathMatcher() {
202228 */
203229 public boolean matches (HttpServletRequest request ) {
204230 Object path = ServletRequestPathUtils .getCachedPath (request );
231+ HttpMethod method = HttpMethod .valueOf (request .getMethod ());
205232 if (this .pathMatcher != defaultPathMatcher ) {
206233 path = path .toString ();
207234 }
@@ -213,12 +240,45 @@ public boolean matches(HttpServletRequest request) {
213240 }
214241 }
215242 }
216- if (ObjectUtils .isEmpty (this .includePatterns )) {
243+ if (!ObjectUtils .isEmpty (this .excludeHttpMethods )) {
244+ for (MethodAdapter adapter : this .excludeHttpMethods ) {
245+ if (adapter .match (method )){
246+ return false ;
247+ }
248+ }
249+ }
250+ if (ObjectUtils .isEmpty (this .includePatterns ) && ObjectUtils .isEmpty (this .includeHttpMethods )) {
217251 return true ;
218252 }
219- for (PatternAdapter adapter : this .includePatterns ) {
220- if (adapter .match (path , isPathContainer , this .pathMatcher )) {
221- return true ;
253+ if (!ObjectUtils .isEmpty (this .includePatterns ) && ObjectUtils .isEmpty (this .includeHttpMethods )) {
254+ for (PatternAdapter adapter : this .includePatterns ) {
255+ if (adapter .match (path , isPathContainer , this .pathMatcher )) {
256+ return true ;
257+ }
258+ }
259+ }
260+ if (!ObjectUtils .isEmpty (this .includeHttpMethods ) && ObjectUtils .isEmpty (this .includePatterns )) {
261+ for (MethodAdapter adapter : this .includeHttpMethods ) {
262+ if (adapter .match (method )) {
263+ return true ;
264+ }
265+ }
266+ }
267+ if (!ObjectUtils .isEmpty (this .includePatterns ) && !ObjectUtils .isEmpty (this .includeHttpMethods )) {
268+ boolean match = false ;
269+ for (MethodAdapter methodAdapter : this .includeHttpMethods ) {
270+ if (methodAdapter .match (method )) {
271+ match = true ;
272+ break ;
273+ }
274+ }
275+ if (!match ) {
276+ return false ;
277+ }
278+ for (PatternAdapter pathAdapter : this .includePatterns ) {
279+ if (pathAdapter .match (path , isPathContainer , pathMatcher )) {
280+ return true ;
281+ }
222282 }
223283 }
224284 return false ;
@@ -305,4 +365,40 @@ public boolean match(Object path, boolean isPathContainer, PathMatcher pathMatch
305365 }
306366 }
307367
368+ /**
369+ * Adapts {@link HttpMethod} instances for internal matching purposes.
370+ *
371+ * <p>Encapsulates an {@link HttpMethod} and provides matching functionality.
372+ * Also provides a utility method to initialize arrays of {@code MethodAdapter}
373+ * instances from arrays of {@link HttpMethod}.</p>
374+ *
375+ * @since 7.0.x
376+ */
377+ private static class MethodAdapter {
378+
379+ private final @ Nullable HttpMethod httpMethod ;
380+
381+ public MethodAdapter (@ Nullable HttpMethod httpMethod ) {
382+ this .httpMethod = httpMethod ;
383+ }
384+
385+ public boolean match (HttpMethod method ) {
386+ return this .httpMethod == method ;
387+ }
388+
389+ public @ Nullable HttpMethod getHttpMethod () {
390+ return this .httpMethod ;
391+ }
392+
393+ private static MethodAdapter @ Nullable [] initHttpMethods (HttpMethod @ Nullable [] methods ) {
394+ if (ObjectUtils .isEmpty (methods )) {
395+ return null ;
396+ }
397+ return Arrays .stream (methods )
398+ .map (MethodAdapter ::new )
399+ .toArray (MethodAdapter []::new );
400+ }
401+
402+ }
403+
308404}
0 commit comments