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.util.ObjectUtils; 023import org.springframework.util.PathMatcher; 024import org.springframework.web.context.request.WebRequestInterceptor; 025import org.springframework.web.servlet.HandlerInterceptor; 026import org.springframework.web.servlet.ModelAndView; 027 028/** 029 * Contains and delegates calls to a {@link HandlerInterceptor} along with 030 * include (and optionally exclude) path patterns to which the interceptor should apply. 031 * Also provides matching logic to test if the interceptor applies to a given request path. 032 * 033 * <p>A MappedInterceptor can be registered directly with any 034 * {@link org.springframework.web.servlet.handler.AbstractHandlerMethodMapping}. 035 * Furthermore, beans of type {@code MappedInterceptor} are automatically detected by 036 * {@code AbstractHandlerMethodMapping} (including ancestor ApplicationContext's) which 037 * effectively means the interceptor is registered "globally" with all handler mappings. 038 * 039 * @author Keith Donald 040 * @author Rossen Stoyanchev 041 * @author Brian Clozel 042 * @since 3.0 043 */ 044public final class MappedInterceptor implements HandlerInterceptor { 045 046 private final String[] includePatterns; 047 048 private final String[] excludePatterns; 049 050 private final HandlerInterceptor interceptor; 051 052 private PathMatcher pathMatcher; 053 054 055 /** 056 * Create a new MappedInterceptor instance. 057 * @param includePatterns the path patterns to map (empty for matching to all paths) 058 * @param interceptor the HandlerInterceptor instance to map to the given patterns 059 */ 060 public MappedInterceptor(String[] includePatterns, HandlerInterceptor interceptor) { 061 this(includePatterns, null, interceptor); 062 } 063 064 /** 065 * Create a new MappedInterceptor instance. 066 * @param includePatterns the path patterns to map (empty for matching to all paths) 067 * @param excludePatterns the path patterns to exclude (empty for no specific excludes) 068 * @param interceptor the HandlerInterceptor instance to map to the given patterns 069 */ 070 public MappedInterceptor(String[] includePatterns, String[] excludePatterns, HandlerInterceptor interceptor) { 071 this.includePatterns = includePatterns; 072 this.excludePatterns = excludePatterns; 073 this.interceptor = interceptor; 074 } 075 076 077 /** 078 * Create a new MappedInterceptor instance. 079 * @param includePatterns the path patterns to map (empty for matching to all paths) 080 * @param interceptor the WebRequestInterceptor instance to map to the given patterns 081 */ 082 public MappedInterceptor(String[] includePatterns, WebRequestInterceptor interceptor) { 083 this(includePatterns, null, interceptor); 084 } 085 086 /** 087 * Create a new MappedInterceptor instance. 088 * @param includePatterns the path patterns to map (empty for matching to all paths) 089 * @param excludePatterns the path patterns to exclude (empty for no specific excludes) 090 * @param interceptor the WebRequestInterceptor instance to map to the given patterns 091 */ 092 public MappedInterceptor(String[] includePatterns, String[] excludePatterns, WebRequestInterceptor interceptor) { 093 this(includePatterns, excludePatterns, new WebRequestHandlerInterceptorAdapter(interceptor)); 094 } 095 096 097 /** 098 * Configure a PathMatcher to use with this MappedInterceptor instead of the one passed 099 * by default to the {@link #matches(String, org.springframework.util.PathMatcher)} method. 100 * <p>This is an advanced property that is only required when using custom PathMatcher 101 * implementations that support mapping metadata other than the Ant-style path patterns 102 * supported by default. 103 */ 104 public void setPathMatcher(PathMatcher pathMatcher) { 105 this.pathMatcher = pathMatcher; 106 } 107 108 /** 109 * The configured PathMatcher, or {@code null} if none. 110 */ 111 public PathMatcher getPathMatcher() { 112 return this.pathMatcher; 113 } 114 115 /** 116 * The path into the application the interceptor is mapped to. 117 */ 118 public String[] getPathPatterns() { 119 return this.includePatterns; 120 } 121 122 /** 123 * The actual {@link HandlerInterceptor} reference. 124 */ 125 public HandlerInterceptor getInterceptor() { 126 return this.interceptor; 127 } 128 129 130 /** 131 * Determine a match for the given lookup path. 132 * @param lookupPath the current request path 133 * @param pathMatcher a path matcher for path pattern matching 134 */ 135 public boolean matches(String lookupPath, PathMatcher pathMatcher) { 136 PathMatcher pathMatcherToUse = (this.pathMatcher != null ? this.pathMatcher : pathMatcher); 137 if (!ObjectUtils.isEmpty(this.excludePatterns)) { 138 for (String pattern : this.excludePatterns) { 139 if (pathMatcherToUse.match(pattern, lookupPath)) { 140 return false; 141 } 142 } 143 } 144 if (ObjectUtils.isEmpty(this.includePatterns)) { 145 return true; 146 } 147 for (String pattern : this.includePatterns) { 148 if (pathMatcherToUse.match(pattern, lookupPath)) { 149 return true; 150 } 151 } 152 return false; 153 } 154 155 @Override 156 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 157 throws Exception { 158 159 return this.interceptor.preHandle(request, response, handler); 160 } 161 162 @Override 163 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, 164 ModelAndView modelAndView) throws Exception { 165 166 this.interceptor.postHandle(request, response, handler, modelAndView); 167 } 168 169 @Override 170 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, 171 Exception ex) throws Exception { 172 173 this.interceptor.afterCompletion(request, response, handler, ex); 174 } 175 176}