Skip to content

Commit d4a21f1

Browse files
author
Keith Donald
committed
added back mvc:interceptors element and added interceptor matching based on path pattern; needs review
1 parent 0be6473 commit d4a21f1

File tree

13 files changed

+259
-43
lines changed

13 files changed

+259
-43
lines changed

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
6464
RootBeanDefinition annMappingDef = new RootBeanDefinition(DefaultAnnotationHandlerMapping.class);
6565
annMappingDef.setSource(source);
6666
annMappingDef.getPropertyValues().add("order", 0);
67-
annMappingDef.getPropertyValues().add("detectInterceptors", true);
6867
String annMappingName = parserContext.getReaderContext().registerWithGeneratedName(annMappingDef);
6968

7069
RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2002-2009 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.web.servlet.config;
18+
19+
import java.util.List;
20+
21+
import org.springframework.beans.factory.config.BeanDefinition;
22+
import org.springframework.beans.factory.config.BeanDefinitionHolder;
23+
import org.springframework.beans.factory.support.RootBeanDefinition;
24+
import org.springframework.beans.factory.xml.BeanDefinitionParser;
25+
import org.springframework.beans.factory.xml.ParserContext;
26+
import org.springframework.util.xml.DomUtils;
27+
import org.springframework.web.servlet.handler.MappedInterceptor;
28+
import org.w3c.dom.Element;
29+
30+
/**
31+
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses a {@code interceptors} element to register
32+
* a set of {@link MappedInterceptor} definitions.
33+
*
34+
* @author Keith Donald
35+
* @since 3.0
36+
*/
37+
class InterceptorsBeanDefinitionParser implements BeanDefinitionParser {
38+
39+
public BeanDefinition parse(Element element, ParserContext parserContext) {
40+
List<Element> interceptors = DomUtils.getChildElementsByTagName(element, "interceptor");
41+
for (Element interceptor : interceptors) {
42+
RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
43+
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, interceptor.getAttribute("path"));
44+
RootBeanDefinition interceptorDef = new RootBeanDefinition(interceptor.getAttribute("class"));
45+
BeanDefinitionHolder holder = new BeanDefinitionHolder(interceptorDef, parserContext.getReaderContext().generateBeanName(interceptorDef));
46+
holder = parserContext.getDelegate().decorateBeanDefinitionIfRequired(interceptor, holder);
47+
parserContext.getDelegate().parseConstructorArgElements(interceptor, interceptorDef);
48+
parserContext.getDelegate().parsePropertyElements(interceptor, interceptorDef);
49+
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, holder);
50+
parserContext.getReaderContext().registerWithGeneratedName(mappedInterceptorDef);
51+
}
52+
return null;
53+
}
54+
55+
}

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcNamespaceHandler.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public class MvcNamespaceHandler extends NamespaceHandlerSupport {
2929

3030
public void init() {
3131
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
32+
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
3233
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
3334
}
3435

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/ViewControllerBeanDefinitionParser.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
5353
handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
5454
handlerMappingDef.setSource(source);
5555
handlerMappingDef.getPropertyValues().add("order", "1");
56-
handlerMappingDef.getPropertyValues().add("detectInterceptors", true);
5756
this.handlerMappingBeanName = parserContext.getReaderContext().registerWithGeneratedName(handlerMappingDef);
5857
} else {
5958
handlerMappingDef = (RootBeanDefinition) parserContext.getReaderContext().getRegistry().getBeanDefinition(this.handlerMappingBeanName);

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
6060

6161
private HandlerInterceptor[] adaptedInterceptors;
6262

63-
private boolean detectInterceptors;
64-
6563
/**
6664
* Specify the order value for this HandlerMapping bean.
6765
* <p>Default value is <code>Integer.MAX_VALUE</code>, meaning that it's non-ordered.
@@ -104,16 +102,6 @@ public void setInterceptors(Object[] interceptors) {
104102
this.interceptors.addAll(Arrays.asList(interceptors));
105103
}
106104

107-
/**
108-
* Configure whether this handler mapping should detect interceptors registered in the WebApplicationContext.
109-
* If true, {@link HandlerInterceptor} and {@link WebRequestInterceptor} beans will be detected by type and added to the interceptors list.
110-
* Default is false.
111-
* @param detectInterceptors the detect interceptors flag
112-
*/
113-
public void setDetectInterceptors(boolean detectInterceptors) {
114-
this.detectInterceptors = detectInterceptors;
115-
}
116-
117105
/**
118106
* Initializes the interceptors.
119107
* @see #extendInterceptors(java.util.List)
@@ -144,21 +132,7 @@ protected void extendInterceptors(List interceptors) {
144132
* @see #adaptInterceptor
145133
*/
146134
protected void initInterceptors() {
147-
if (this.detectInterceptors) {
148-
Map<String, HandlerInterceptor> handlerInterceptors = BeanFactoryUtils.beansOfTypeIncludingAncestors(getApplicationContext(), HandlerInterceptor.class, true, false);
149-
if (!handlerInterceptors.isEmpty()) {
150-
this.interceptors.addAll(handlerInterceptors.values());
151-
}
152-
Map<String, WebRequestInterceptor> webInterceptors = BeanFactoryUtils.beansOfTypeIncludingAncestors(getApplicationContext(), WebRequestInterceptor.class, true, false);
153-
if (!webInterceptors.isEmpty()) {
154-
for (WebRequestInterceptor interceptor : webInterceptors.values()) {
155-
this.interceptors.add(new WebRequestHandlerInterceptorAdapter(interceptor));
156-
}
157-
}
158-
}
159-
160135
if (!this.interceptors.isEmpty()) {
161-
OrderComparator.sort(this.interceptors);
162136
this.adaptedInterceptors = new HandlerInterceptor[this.interceptors.size()];
163137
for (int i = 0; i < this.interceptors.size(); i++) {
164138
Object interceptor = this.interceptors.get(i);

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,24 @@
1616

1717
package org.springframework.web.servlet.handler;
1818

19+
import java.util.ArrayList;
1920
import java.util.Collections;
2021
import java.util.LinkedHashMap;
21-
import java.util.Map;
2222
import java.util.List;
23-
import java.util.ArrayList;
23+
import java.util.Map;
24+
import java.util.Set;
25+
2426
import javax.servlet.http.HttpServletRequest;
2527
import javax.servlet.http.HttpServletResponse;
2628

2729
import org.springframework.beans.BeansException;
30+
import org.springframework.beans.factory.BeanFactoryUtils;
2831
import org.springframework.util.AntPathMatcher;
2932
import org.springframework.util.Assert;
3033
import org.springframework.util.CollectionUtils;
3134
import org.springframework.util.PathMatcher;
3235
import org.springframework.web.servlet.HandlerExecutionChain;
36+
import org.springframework.web.servlet.HandlerInterceptor;
3337
import org.springframework.web.servlet.HandlerMapping;
3438
import org.springframework.web.util.UrlPathHelper;
3539

@@ -67,7 +71,8 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
6771

6872
private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();
6973

70-
74+
private MappedInterceptors mappedInterceptors;
75+
7176
/**
7277
* Set if URL lookup should always use the full path within the current servlet
7378
* context. Else, the path within the current servlet mapping is used if applicable
@@ -151,6 +156,21 @@ public void setLazyInitHandlers(boolean lazyInitHandlers) {
151156
this.lazyInitHandlers = lazyInitHandlers;
152157
}
153158

159+
public void setMappedInterceptors(MappedInterceptor[] mappedInterceptors) {
160+
this.mappedInterceptors = new MappedInterceptors(mappedInterceptors);
161+
}
162+
163+
164+
@Override
165+
protected void initInterceptors() {
166+
super.initInterceptors();
167+
168+
Map<String, MappedInterceptor> mappedInterceptors = BeanFactoryUtils.beansOfTypeIncludingAncestors(getApplicationContext(), MappedInterceptor.class, true, false);
169+
if (!mappedInterceptors.isEmpty()) {
170+
this.mappedInterceptors = new MappedInterceptors(mappedInterceptors.values().toArray(new MappedInterceptor[mappedInterceptors.size()]));
171+
}
172+
173+
}
154174

155175
/**
156176
* Look up a handler for the URL path of the given request.
@@ -181,6 +201,18 @@ protected Object getHandlerInternal(HttpServletRequest request) throws Exception
181201
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
182202
}
183203
}
204+
if (handler != null & this.mappedInterceptors != null) {
205+
Set<HandlerInterceptor> mappedInterceptors = this.mappedInterceptors.getInterceptors(lookupPath, this.pathMatcher);
206+
if (!mappedInterceptors.isEmpty()) {
207+
HandlerExecutionChain chain;
208+
if (handler instanceof HandlerExecutionChain) {
209+
chain = (HandlerExecutionChain) handler;
210+
} else {
211+
chain = new HandlerExecutionChain(handler);
212+
}
213+
chain.addInterceptors(mappedInterceptors.toArray(new HandlerInterceptor[mappedInterceptors.size()]));
214+
}
215+
}
184216
if (handler != null && logger.isDebugEnabled()) {
185217
logger.debug("Mapping [" + lookupPath + "] to handler '" + handler + "'");
186218
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2002-2009 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.web.servlet.handler;
17+
18+
import org.springframework.web.context.request.WebRequestInterceptor;
19+
import org.springframework.web.servlet.HandlerInterceptor;
20+
21+
/**
22+
* Holds information about a HandlerInterceptor mapped to a path into the application.
23+
* @author Keith Donald
24+
* @since 3.0
25+
*/
26+
public final class MappedInterceptor {
27+
28+
private final String pathPattern;
29+
30+
private final HandlerInterceptor interceptor;
31+
32+
/**
33+
* Creates a new mapped interceptor.
34+
* @param pathPattern the path pattern
35+
* @param interceptor the interceptor
36+
*/
37+
public MappedInterceptor(String pathPattern, HandlerInterceptor interceptor) {
38+
this.pathPattern = pathPattern;
39+
this.interceptor = interceptor;
40+
}
41+
42+
/**
43+
* Creates a new mapped interceptor.
44+
* @param pathPattern the path pattern
45+
* @param interceptor the interceptor
46+
*/
47+
public MappedInterceptor(String pathPattern, WebRequestInterceptor interceptor) {
48+
this.pathPattern = pathPattern;
49+
this.interceptor = new WebRequestHandlerInterceptorAdapter(interceptor);
50+
}
51+
52+
/**
53+
* The path into the application the interceptor is mapped to.
54+
*/
55+
public String getPathPattern() {
56+
return pathPattern;
57+
}
58+
59+
/**
60+
* The actual Interceptor reference.
61+
*/
62+
public HandlerInterceptor getInterceptor() {
63+
return interceptor;
64+
}
65+
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.springframework.web.servlet.handler;
2+
3+
import java.util.LinkedHashSet;
4+
import java.util.Set;
5+
6+
import org.springframework.util.PathMatcher;
7+
import org.springframework.util.StringUtils;
8+
import org.springframework.web.servlet.HandlerInterceptor;
9+
10+
class MappedInterceptors {
11+
12+
private MappedInterceptor[] mappedInterceptors;
13+
14+
public MappedInterceptors(MappedInterceptor[] mappedInterceptors) {
15+
this.mappedInterceptors = mappedInterceptors;
16+
}
17+
18+
public Set<HandlerInterceptor> getInterceptors(String lookupPath, PathMatcher pathMatcher) {
19+
Set<HandlerInterceptor> interceptors = new LinkedHashSet<HandlerInterceptor>();
20+
for (MappedInterceptor interceptor : this.mappedInterceptors) {
21+
if (matches(interceptor, lookupPath, pathMatcher)) {
22+
interceptors.add(interceptor.getInterceptor());
23+
}
24+
}
25+
return interceptors;
26+
}
27+
28+
private boolean matches(MappedInterceptor interceptor, String lookupPath, PathMatcher pathMatcher) {
29+
String pathPattern = interceptor.getPathPattern();
30+
if (StringUtils.hasText(pathPattern)) {
31+
return pathMatcher.match(pathPattern, lookupPath);
32+
} else {
33+
return true;
34+
}
35+
}
36+
37+
}

org.springframework.web.servlet/src/main/resources/org/springframework/web/servlet/config/spring-mvc-3.0.xsd

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,42 @@
5959
</xsd:annotation>
6060
<xsd:complexType>
6161
<xsd:sequence>
62-
<xsd:element ref="beans:bean" maxOccurs="unbounded" />
62+
<xsd:element name="interceptor" maxOccurs="unbounded">
63+
<xsd:annotation>
64+
<xsd:documentation source="java:org.springframework.web.servlet.handler.MappedInterceptor"><![CDATA[
65+
Registers a interceptor definition.
66+
]]></xsd:documentation>
67+
</xsd:annotation>
68+
<xsd:complexType>
69+
<xsd:choice minOccurs="0" maxOccurs="unbounded">
70+
<xsd:element ref="beans:constructor-arg"/>
71+
<xsd:element ref="beans:property"/>
72+
</xsd:choice>
73+
<xsd:attribute name="path" type="xsd:string">
74+
<xsd:annotation>
75+
<xsd:documentation><![CDATA[
76+
The path into the application intercepted by this interceptor.
77+
Exact path mapping URIs (such as "/myPath") are supported as well as Ant-stype path patterns (such as /myPath/**).
78+
If not specified, the interceptor intercepts all paths ("/**").
79+
]]></xsd:documentation>
80+
</xsd:annotation>
81+
</xsd:attribute>
82+
<xsd:attribute name="class" type="xsd:string" use="required">
83+
<xsd:annotation>
84+
<xsd:documentation source="java:java.lang.Class"><![CDATA[
85+
The interceptor class.
86+
Must implement org.springframework.web.servlet.HandlerInterceptor or org.springframework.web.context.request.WebRequestInterceptor.
87+
]]></xsd:documentation>
88+
<xsd:appinfo>
89+
<tool:annotation kind="direct">
90+
<tool:expected-type type="java.lang.Class"/>
91+
</tool:annotation>
92+
</xsd:appinfo>
93+
</xsd:annotation>
94+
</xsd:attribute>
95+
<xsd:anyAttribute namespace="##other" processContents="lax"/>
96+
</xsd:complexType>
97+
</xsd:element>
6398
</xsd:sequence>
6499
</xsd:complexType>
65100
</xsd:element>

0 commit comments

Comments
 (0)