001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.handler; 018 019import javax.servlet.http.HttpServletRequest; 020import javax.servlet.http.HttpServletResponse; 021 022import org.springframework.lang.Nullable; 023import org.springframework.util.ObjectUtils; 024import org.springframework.util.PathMatcher; 025import org.springframework.web.context.request.WebRequestInterceptor; 026import org.springframework.web.servlet.HandlerInterceptor; 027import org.springframework.web.servlet.ModelAndView; 028 029/** 030 * Contains and delegates calls to a {@link HandlerInterceptor} along with 031 * include (and optionally exclude) path patterns to which the interceptor should apply. 032 * Also provides matching logic to test if the interceptor applies to a given request path. 033 * 034 * <p>A MappedInterceptor can be registered directly with any 035 * {@link org.springframework.web.servlet.handler.AbstractHandlerMethodMapping}. 036 * Furthermore, beans of type {@code MappedInterceptor} are automatically detected by 037 * {@code AbstractHandlerMethodMapping} (including ancestor ApplicationContext's) which 038 * effectively means the interceptor is registered "globally" with all handler mappings. 039 * 040 * @author Keith Donald 041 * @author Rossen Stoyanchev 042 * @author Brian Clozel 043 * @since 3.0 044 */ 045public final class MappedInterceptor implements HandlerInterceptor { 046 047 @Nullable 048 private final String[] includePatterns; 049 050 @Nullable 051 private final String[] excludePatterns; 052 053 private final HandlerInterceptor interceptor; 054 055 @Nullable 056 private PathMatcher pathMatcher; 057 058 059 /** 060 * Create a new MappedInterceptor instance. 061 * @param includePatterns the path patterns to map (empty for matching to all paths) 062 * @param interceptor the HandlerInterceptor instance to map to the given patterns 063 */ 064 public MappedInterceptor(@Nullable String[] includePatterns, HandlerInterceptor interceptor) { 065 this(includePatterns, null, interceptor); 066 } 067 068 /** 069 * Create a new MappedInterceptor instance. 070 * @param includePatterns the path patterns to map (empty for matching to all paths) 071 * @param excludePatterns the path patterns to exclude (empty for no specific excludes) 072 * @param interceptor the HandlerInterceptor instance to map to the given patterns 073 */ 074 public MappedInterceptor(@Nullable String[] includePatterns, @Nullable String[] excludePatterns, 075 HandlerInterceptor interceptor) { 076 077 this.includePatterns = includePatterns; 078 this.excludePatterns = excludePatterns; 079 this.interceptor = interceptor; 080 } 081 082 083 /** 084 * Create a new MappedInterceptor instance. 085 * @param includePatterns the path patterns to map (empty for matching to all paths) 086 * @param interceptor the WebRequestInterceptor instance to map to the given patterns 087 */ 088 public MappedInterceptor(@Nullable String[] includePatterns, WebRequestInterceptor interceptor) { 089 this(includePatterns, null, interceptor); 090 } 091 092 /** 093 * Create a new MappedInterceptor instance. 094 * @param includePatterns the path patterns to map (empty for matching to all paths) 095 * @param excludePatterns the path patterns to exclude (empty for no specific excludes) 096 * @param interceptor the WebRequestInterceptor instance to map to the given patterns 097 */ 098 public MappedInterceptor(@Nullable String[] includePatterns, @Nullable String[] excludePatterns, 099 WebRequestInterceptor interceptor) { 100 101 this(includePatterns, excludePatterns, new WebRequestHandlerInterceptorAdapter(interceptor)); 102 } 103 104 105 /** 106 * Configure a PathMatcher to use with this MappedInterceptor instead of the one passed 107 * by default to the {@link #matches(String, org.springframework.util.PathMatcher)} method. 108 * <p>This is an advanced property that is only required when using custom PathMatcher 109 * implementations that support mapping metadata other than the Ant-style path patterns 110 * supported by default. 111 */ 112 public void setPathMatcher(@Nullable PathMatcher pathMatcher) { 113 this.pathMatcher = pathMatcher; 114 } 115 116 /** 117 * The configured PathMatcher, or {@code null} if none. 118 */ 119 @Nullable 120 public PathMatcher getPathMatcher() { 121 return this.pathMatcher; 122 } 123 124 /** 125 * The path into the application the interceptor is mapped to. 126 */ 127 @Nullable 128 public String[] getPathPatterns() { 129 return this.includePatterns; 130 } 131 132 /** 133 * The actual {@link HandlerInterceptor} reference. 134 */ 135 public HandlerInterceptor getInterceptor() { 136 return this.interceptor; 137 } 138 139 140 /** 141 * Determine a match for the given lookup path. 142 * @param lookupPath the current request path 143 * @param pathMatcher a path matcher for path pattern matching 144 * @return {@code true} if the interceptor applies to the given request path 145 */ 146 public boolean matches(String lookupPath, PathMatcher pathMatcher) { 147 PathMatcher pathMatcherToUse = (this.pathMatcher != null ? this.pathMatcher : pathMatcher); 148 if (!ObjectUtils.isEmpty(this.excludePatterns)) { 149 for (String pattern : this.excludePatterns) { 150 if (pathMatcherToUse.match(pattern, lookupPath)) { 151 return false; 152 } 153 } 154 } 155 if (ObjectUtils.isEmpty(this.includePatterns)) { 156 return true; 157 } 158 for (String pattern : this.includePatterns) { 159 if (pathMatcherToUse.match(pattern, lookupPath)) { 160 return true; 161 } 162 } 163 return false; 164 } 165 166 @Override 167 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 168 throws Exception { 169 170 return this.interceptor.preHandle(request, response, handler); 171 } 172 173 @Override 174 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, 175 @Nullable ModelAndView modelAndView) throws Exception { 176 177 this.interceptor.postHandle(request, response, handler, modelAndView); 178 } 179 180 @Override 181 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, 182 @Nullable Exception ex) throws Exception { 183 184 this.interceptor.afterCompletion(request, response, handler, ex); 185 } 186 187}