diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/InterceptorsBeanDefinitionParser.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/InterceptorsBeanDefinitionParser.java index d755a93eb5..e0890ce750 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/InterceptorsBeanDefinitionParser.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/InterceptorsBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,7 @@ import org.w3c.dom.Element; /** * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses a {@code interceptors} element to register * a set of {@link MappedInterceptor} definitions. - * + * * @author Keith Donald * @since 3.0 */ @@ -40,37 +40,44 @@ class InterceptorsBeanDefinitionParser implements BeanDefinitionParser { public BeanDefinition parse(Element element, ParserContext parserContext) { CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); parserContext.pushContainingComponent(compDefinition); - + List interceptors = DomUtils.getChildElementsByTagName(element, new String[] { "bean", "ref", "interceptor" }); for (Element interceptor : interceptors) { RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class); mappedInterceptorDef.setSource(parserContext.extractSource(interceptor)); mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - - String[] pathPatterns; + + String[] includePatterns = null; + String[] excludePatterns = null; Object interceptorBean; if ("interceptor".equals(interceptor.getLocalName())) { - List paths = DomUtils.getChildElementsByTagName(interceptor, "mapping"); - pathPatterns = new String[paths.size()]; - for (int i = 0; i < paths.size(); i++) { - pathPatterns[i] = paths.get(i).getAttribute("path"); - } + includePatterns = getIncludePatterns(interceptor, "mapping"); + excludePatterns = getIncludePatterns(interceptor, "exclude-mapping"); Element beanElem = DomUtils.getChildElementsByTagName(interceptor, new String[] { "bean", "ref"}).get(0); interceptorBean = parserContext.getDelegate().parsePropertySubElement(beanElem, null); } else { - pathPatterns = null; interceptorBean = parserContext.getDelegate().parsePropertySubElement(interceptor, null); } - mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, pathPatterns); - mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, interceptorBean); + mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, includePatterns); + mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, excludePatterns); + mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(2, interceptorBean); String beanName = parserContext.getReaderContext().registerWithGeneratedName(mappedInterceptorDef); parserContext.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, beanName)); } - + parserContext.popAndRegisterContainingComponent(); return null; } + private String[] getIncludePatterns(Element interceptor, String elementName) { + List paths = DomUtils.getChildElementsByTagName(interceptor, elementName); + String[] patterns = new String[paths.size()]; + for (int i = 0; i < paths.size(); i++) { + patterns[i] = paths.get(i).getAttribute("path"); + } + return patterns; + } + } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistration.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistration.java index 6ef77d2ef9..f1a43d717d 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistration.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,13 +21,13 @@ import java.util.Arrays; import java.util.List; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.handler.MappedInterceptor; /** - * Encapsulates a {@link HandlerInterceptor} and an optional list of URL patterns. - * Results in the creation of a {@link MappedInterceptor} if URL patterns are provided. - * + * Assists with the creation of a {@link MappedInterceptor}. + * * @author Rossen Stoyanchev * @author Keith Donald * @since 3.1 @@ -35,8 +35,10 @@ import org.springframework.web.servlet.handler.MappedInterceptor; public class InterceptorRegistration { private final HandlerInterceptor interceptor; - - private final List pathPatterns = new ArrayList(); + + private final List includePatterns = new ArrayList(); + + private final List excludePatterns = new ArrayList(); /** * Creates an {@link InterceptorRegistration} instance. @@ -47,22 +49,39 @@ public class InterceptorRegistration { } /** - * Adds one or more URL patterns to which the registered interceptor should apply to. - * If no URL patterns are provided, the interceptor applies to all paths. + * Add URL patterns to which the registered interceptor should apply to. */ - public void addPathPatterns(String... pathPatterns) { - this.pathPatterns.addAll(Arrays.asList(pathPatterns)); + public InterceptorRegistration addPathPatterns(String... patterns) { + this.includePatterns.addAll(Arrays.asList(patterns)); + return this; } /** - * Returns the underlying interceptor. If URL patterns are provided the returned type is + * Add URL patterns to which the registered interceptor should not apply to. + */ + public InterceptorRegistration excludePathPatterns(String... patterns) { + this.excludePatterns.addAll(Arrays.asList(patterns)); + return this; + } + + /** + * Returns the underlying interceptor. If URL patterns are provided the returned type is * {@link MappedInterceptor}; otherwise {@link HandlerInterceptor}. */ protected Object getInterceptor() { - if (pathPatterns.isEmpty()) { - return interceptor; + if (this.includePatterns.isEmpty()) { + return this.interceptor; + } + return new MappedInterceptor(toArray(this.includePatterns), toArray(this.excludePatterns), interceptor); + } + + private static String[] toArray(List list) { + if (CollectionUtils.isEmpty(list)) { + return null; + } + else { + return list.toArray(new String[list.size()]); } - return new MappedInterceptor(pathPatterns.toArray(new String[pathPatterns.size()]), interceptor); } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/MappedInterceptor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/MappedInterceptor.java index 93e11d2ebb..4aa73925ee 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/MappedInterceptor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/MappedInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,30 +29,50 @@ import org.springframework.web.servlet.HandlerInterceptor; * @since 3.0 */ public final class MappedInterceptor { - - private final String[] pathPatterns; - + + private final String[] includePatterns; + + private final String[] excludePatterns; + private final HandlerInterceptor interceptor; + /** + * Create a new MappedInterceptor instance. + * @param includePatterns the path patterns to map with a {@code null} value matching to all paths + * @param interceptor the HandlerInterceptor instance to map to the given patterns + */ + public MappedInterceptor(String[] includePatterns, HandlerInterceptor interceptor) { + this(includePatterns, null, interceptor); + } + /** * Create a new MappedInterceptor instance. * @param pathPatterns the path patterns to map with a {@code null} value matching to all paths * @param interceptor the HandlerInterceptor instance to map to the given patterns */ - public MappedInterceptor(String[] pathPatterns, HandlerInterceptor interceptor) { - this.pathPatterns = pathPatterns; + public MappedInterceptor(String[] includePatterns, String[] excludePatterns, HandlerInterceptor interceptor) { + this.includePatterns = includePatterns; + this.excludePatterns = excludePatterns; this.interceptor = interceptor; } /** * Create a new MappedInterceptor instance. - * @param pathPatterns the path patterns to map with a {@code null} value matching to all paths + * @param includePatterns the path patterns to map with a {@code null} value matching to all paths * @param interceptor the WebRequestInterceptor instance to map to the given patterns */ - public MappedInterceptor(String[] pathPatterns, WebRequestInterceptor interceptor) { - this.pathPatterns = pathPatterns; - this.interceptor = new WebRequestHandlerInterceptorAdapter(interceptor); + public MappedInterceptor(String[] includePatterns, WebRequestInterceptor interceptor) { + this(includePatterns, null, interceptor); + } + + /** + * Create a new MappedInterceptor instance. + * @param includePatterns the path patterns to map with a {@code null} value matching to all paths + * @param interceptor the WebRequestInterceptor instance to map to the given patterns + */ + public MappedInterceptor(String[] includePatterns, String[] excludePatterns, WebRequestInterceptor interceptor) { + this(includePatterns, excludePatterns, new WebRequestHandlerInterceptorAdapter(interceptor)); } @@ -60,7 +80,7 @@ public final class MappedInterceptor { * The path into the application the interceptor is mapped to. */ public String[] getPathPatterns() { - return this.pathPatterns; + return this.includePatterns; } /** @@ -69,19 +89,26 @@ public final class MappedInterceptor { public HandlerInterceptor getInterceptor() { return this.interceptor; } - + /** - * Returns {@code true} if the interceptor applies to the given request path. + * Returns {@code true} if the interceptor applies to the given request path. * @param lookupPath the current request path * @param pathMatcher a path matcher for path pattern matching */ public boolean matches(String lookupPath, PathMatcher pathMatcher) { - if (pathPatterns == null) { + if (this.excludePatterns != null) { + for (String pattern : this.excludePatterns) { + if (pathMatcher.match(pattern, lookupPath)) { + return false; + } + } + } + if (this.includePatterns == null) { return true; } else { - for (String pathPattern : pathPatterns) { - if (pathMatcher.match(pathPattern, lookupPath)) { + for (String pattern : this.includePatterns) { + if (pathMatcher.match(pattern, lookupPath)) { return true; } } diff --git a/spring-webmvc/src/main/resources/org/springframework/web/servlet/config/spring-mvc-3.2.xsd b/spring-webmvc/src/main/resources/org/springframework/web/servlet/config/spring-mvc-3.2.xsd index 23d0aaf41d..54805b002c 100644 --- a/spring-webmvc/src/main/resources/org/springframework/web/servlet/config/spring-mvc-3.2.xsd +++ b/spring-webmvc/src/main/resources/org/springframework/web/servlet/config/spring-mvc-3.2.xsd @@ -273,6 +273,18 @@ + + + + + + + + + diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java index 08190d0a91..0c25d1ce93 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java @@ -80,7 +80,7 @@ import static org.junit.Assert.*; public class MvcNamespaceTests { private GenericWebApplicationContext appContext; - + private TestController handler; private HandlerMethod handlerMethod; @@ -90,7 +90,7 @@ public class MvcNamespaceTests { appContext = new GenericWebApplicationContext(); appContext.setServletContext(new TestMockServletContext()); LocaleContextHolder.setLocale(Locale.US); - + handler = new TestController(); Method method = TestController.class.getMethod("testBind", Date.class, TestBean.class, BindingResult.class); handlerMethod = new InvocableHandlerMethod(handler, method); @@ -104,11 +104,11 @@ public class MvcNamespaceTests { assertNotNull(mapping); assertEquals(0, mapping.getOrder()); mapping.setDefaultHandler(handlerMethod); - + RequestMappingHandlerAdapter adapter = appContext.getBean(RequestMappingHandlerAdapter.class); assertNotNull(adapter); assertEquals(false, new DirectFieldAccessor(adapter).getPropertyValue("ignoreDefaultModelOnRedirect")); - + List> messageConverters = adapter.getMessageConverters(); assertTrue(messageConverters.size() > 0); @@ -128,7 +128,7 @@ public class MvcNamespaceTests { ConversionServiceExposingInterceptor interceptor = (ConversionServiceExposingInterceptor) chain.getInterceptors()[0]; interceptor.preHandle(request, response, handlerMethod); assertSame(appContext.getBean(ConversionService.class), request.getAttribute(ConversionService.class.getName())); - + adapter.handle(request, response, handlerMethod); assertTrue(handler.recordedValidationError); } @@ -140,7 +140,7 @@ public class MvcNamespaceTests { RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class); assertNotNull(mapping); mapping.setDefaultHandler(handlerMethod); - + // default web binding initializer behavior test MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); request.setRequestURI("/accounts/12345"); @@ -153,7 +153,7 @@ public class MvcNamespaceTests { ConversionServiceExposingInterceptor interceptor = (ConversionServiceExposingInterceptor) chain.getInterceptors()[0]; interceptor.preHandle(request, response, handler); assertSame(appContext.getBean("conversionService"), request.getAttribute(ConversionService.class.getName())); - + RequestMappingHandlerAdapter adapter = appContext.getBean(RequestMappingHandlerAdapter.class); assertNotNull(adapter); adapter.handle(request, response, handlerMethod); @@ -176,7 +176,7 @@ public class MvcNamespaceTests { assertTrue(appContext.getBean(TestValidator.class).validatorInvoked); assertFalse(handler.recordedValidationError); } - + @Test public void testInterceptors() throws Exception { loadBeanDefinitions("mvc-config-interceptors.xml", 16); @@ -184,7 +184,7 @@ public class MvcNamespaceTests { RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class); assertNotNull(mapping); mapping.setDefaultHandler(handlerMethod); - + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); request.setRequestURI("/accounts/12345"); request.addParameter("locale", "en"); @@ -197,6 +197,10 @@ public class MvcNamespaceTests { assertTrue(chain.getInterceptors()[2] instanceof WebRequestHandlerInterceptorAdapter); assertTrue(chain.getInterceptors()[3] instanceof ThemeChangeInterceptor); + request.setRequestURI("/admin/users"); + chain = mapping.getHandler(request); + assertEquals(3, chain.getInterceptors().length); + request.setRequestURI("/logged/accounts/12345"); chain = mapping.getHandler(request); assertEquals(5, chain.getInterceptors().length); @@ -207,14 +211,14 @@ public class MvcNamespaceTests { assertEquals(5, chain.getInterceptors().length); assertTrue(chain.getInterceptors()[4] instanceof WebRequestHandlerInterceptorAdapter); } - + @Test public void testResources() throws Exception { loadBeanDefinitions("mvc-config-resources.xml", 5); HttpRequestHandlerAdapter adapter = appContext.getBean(HttpRequestHandlerAdapter.class); assertNotNull(adapter); - + ResourceHttpRequestHandler handler = appContext.getBean(ResourceHttpRequestHandler.class); assertNotNull(handler); @@ -229,7 +233,7 @@ public class MvcNamespaceTests { MockHttpServletRequest request = new MockHttpServletRequest(); request.setRequestURI("/resources/foo.css"); request.setMethod("GET"); - + HandlerExecutionChain chain = mapping.getHandler(request); assertTrue(chain.getHandler() instanceof ResourceHttpRequestHandler); @@ -240,7 +244,7 @@ public class MvcNamespaceTests { ModelAndView mv = adapter.handle(request, response, chain.getHandler()); assertNull(mv); } - + @Test public void testResourcesWithOptionalAttributes() throws Exception { loadBeanDefinitions("mvc-config-resources-optional-attrs.xml", 5); @@ -249,14 +253,14 @@ public class MvcNamespaceTests { assertNotNull(mapping); assertEquals(5, mapping.getOrder()); } - + @Test public void testDefaultServletHandler() throws Exception { loadBeanDefinitions("mvc-config-default-servlet.xml", 5); HttpRequestHandlerAdapter adapter = appContext.getBean(HttpRequestHandlerAdapter.class); assertNotNull(adapter); - + DefaultServletHttpRequestHandler handler = appContext.getBean(DefaultServletHttpRequestHandler.class); assertNotNull(handler); @@ -267,7 +271,7 @@ public class MvcNamespaceTests { MockHttpServletRequest request = new MockHttpServletRequest(); request.setRequestURI("/foo.css"); request.setMethod("GET"); - + HandlerExecutionChain chain = mapping.getHandler(request); assertTrue(chain.getHandler() instanceof DefaultServletHttpRequestHandler); @@ -275,14 +279,14 @@ public class MvcNamespaceTests { ModelAndView mv = adapter.handle(request, response, chain.getHandler()); assertNull(mv); } - + @Test public void testDefaultServletHandlerWithOptionalAttributes() throws Exception { loadBeanDefinitions("mvc-config-default-servlet-optional-attrs.xml", 5); HttpRequestHandlerAdapter adapter = appContext.getBean(HttpRequestHandlerAdapter.class); assertNotNull(adapter); - + DefaultServletHttpRequestHandler handler = appContext.getBean(DefaultServletHttpRequestHandler.class); assertNotNull(handler); @@ -293,7 +297,7 @@ public class MvcNamespaceTests { MockHttpServletRequest request = new MockHttpServletRequest(); request.setRequestURI("/foo.css"); request.setMethod("GET"); - + HandlerExecutionChain chain = mapping.getHandler(request); assertTrue(chain.getHandler() instanceof DefaultServletHttpRequestHandler); @@ -308,7 +312,7 @@ public class MvcNamespaceTests { RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class); assertNotNull(mapping); - mapping.setDefaultHandler(handlerMethod); + mapping.setDefaultHandler(handlerMethod); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); @@ -316,20 +320,20 @@ public class MvcNamespaceTests { assertEquals(3, chain.getInterceptors().length); assertTrue(chain.getInterceptors()[0] instanceof ConversionServiceExposingInterceptor); assertTrue(chain.getInterceptors()[1] instanceof LocaleChangeInterceptor); - assertTrue(chain.getInterceptors()[2] instanceof ThemeChangeInterceptor); + assertTrue(chain.getInterceptors()[2] instanceof ThemeChangeInterceptor); LocaleChangeInterceptor interceptor = (LocaleChangeInterceptor) chain.getInterceptors()[1]; assertEquals("lang", interceptor.getParamName()); ThemeChangeInterceptor interceptor2 = (ThemeChangeInterceptor) chain.getInterceptors()[2]; assertEquals("style", interceptor2.getParamName()); } - + @Test public void testViewControllers() throws Exception { loadBeanDefinitions("mvc-config-view-controllers.xml", 14); RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class); assertNotNull(mapping); - mapping.setDefaultHandler(handlerMethod); + mapping.setDefaultHandler(handlerMethod); BeanNameUrlHandlerMapping beanNameMapping = appContext.getBean(BeanNameUrlHandlerMapping.class); assertNotNull(beanNameMapping); @@ -349,7 +353,7 @@ public class MvcNamespaceTests { SimpleControllerHandlerAdapter adapter = appContext.getBean(SimpleControllerHandlerAdapter.class); assertNotNull(adapter); - + request.setRequestURI("/foo"); chain = mapping2.getHandler(request); assertEquals(4, chain.getInterceptors().length); @@ -435,7 +439,7 @@ public class MvcNamespaceTests { assertNotNull(beanNameMapping); assertEquals(2, beanNameMapping.getOrder()); } - + private void loadBeanDefinitions(String fileName, int expectedBeanCount) { XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext); ClassPathResource resource = new ClassPathResource(fileName, AnnotationDrivenBeanDefinitionParserTests.class); @@ -446,19 +450,19 @@ public class MvcNamespaceTests { @Controller public static class TestController { - + private boolean recordedValidationError; - + @RequestMapping public void testBind(@RequestParam @DateTimeFormat(iso=ISO.DATE) Date date, @Validated(MyGroup.class) TestBean bean, BindingResult result) { this.recordedValidationError = (result.getErrorCount() == 1); } } - + public static class TestValidator implements Validator { boolean validatorInvoked; - + public boolean supports(Class clazz) { return true; } @@ -467,13 +471,13 @@ public class MvcNamespaceTests { this.validatorInvoked = true; } } - + @Retention(RetentionPolicy.RUNTIME) public @interface MyGroup { } private static class TestBean { - + @NotNull(groups=MyGroup.class) private String field; @@ -487,7 +491,7 @@ public class MvcNamespaceTests { this.field = field; } } - + private static class TestMockServletContext extends MockServletContext { @Override diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/InterceptorRegistryTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/InterceptorRegistryTests.java index a0c8fa442f..2b54cced05 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/InterceptorRegistryTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/InterceptorRegistryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.junit.Before; @@ -72,7 +73,7 @@ public class InterceptorRegistryTests { public void addInterceptor() { registry.addInterceptor(interceptor1); List interceptors = getInterceptorsForPath(null); - + assertEquals(Arrays.asList(interceptor1), interceptors); } @@ -81,24 +82,25 @@ public class InterceptorRegistryTests { registry.addInterceptor(interceptor1); registry.addInterceptor(interceptor2); List interceptors = getInterceptorsForPath(null); - + assertEquals(Arrays.asList(interceptor1, interceptor2), interceptors); } @Test public void addInterceptorsWithUrlPatterns() { - registry.addInterceptor(interceptor1).addPathPatterns("/path1"); + registry.addInterceptor(interceptor1).addPathPatterns("/path1/**").excludePathPatterns("/path1/secret"); registry.addInterceptor(interceptor2).addPathPatterns("/path2"); - + assertEquals(Arrays.asList(interceptor1), getInterceptorsForPath("/path1")); assertEquals(Arrays.asList(interceptor2), getInterceptorsForPath("/path2")); + assertEquals(Collections.emptyList(), getInterceptorsForPath("/path1/secret")); } @Test public void addWebRequestInterceptor() throws Exception { registry.addWebRequestInterceptor(webRequestInterceptor1); List interceptors = getInterceptorsForPath(null); - + assertEquals(1, interceptors.size()); verifyAdaptedInterceptor(interceptors.get(0), webRequestInterceptor1); } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/MappedInterceptorTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/MappedInterceptorTests.java new file mode 100644 index 0000000000..3f71c09786 --- /dev/null +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/MappedInterceptorTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.web.servlet.handler; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.util.AntPathMatcher; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; + +/** + * Test fixture for {@link MappedInterceptor} tests. + * + * @author Rossen Stoyanchev + */ +public class MappedInterceptorTests { + + private LocaleChangeInterceptor interceptor; + + private final AntPathMatcher pathMatcher = new AntPathMatcher(); + + @Before + public void setup() { + this.interceptor = new LocaleChangeInterceptor(); + } + + @Test + public void noPatterns() { + MappedInterceptor mappedInterceptor = new MappedInterceptor(null, null, this.interceptor); + assertTrue(mappedInterceptor.matches("/foo", pathMatcher)); + } + + @Test + public void includePatternOnly() { + MappedInterceptor mappedInterceptor = new MappedInterceptor(new String[] { "/foo/*" }, this.interceptor); + + assertTrue(mappedInterceptor.matches("/foo/bar", pathMatcher)); + assertFalse(mappedInterceptor.matches("/bar/foo", pathMatcher)); + } + + @Test + public void excludePatternOnly() { + MappedInterceptor mappedInterceptor = new MappedInterceptor(null, new String[] { "/admin/**" }, this.interceptor); + + assertTrue(mappedInterceptor.matches("/foo", pathMatcher)); + assertFalse(mappedInterceptor.matches("/admin/foo", pathMatcher)); + } + + @Test + public void includeAndExcludePatterns() { + MappedInterceptor mappedInterceptor = new MappedInterceptor( + new String[] { "/**" }, new String[] { "/admin/**" }, this.interceptor); + + assertTrue(mappedInterceptor.matches("/foo", pathMatcher)); + assertFalse(mappedInterceptor.matches("/admin/foo", pathMatcher)); + } + +} diff --git a/spring-webmvc/src/test/resources/org/springframework/web/servlet/config/mvc-config-interceptors.xml b/spring-webmvc/src/test/resources/org/springframework/web/servlet/config/mvc-config-interceptors.xml index bc74d9b974..780d9c379e 100644 --- a/spring-webmvc/src/test/resources/org/springframework/web/servlet/config/mvc-config-interceptors.xml +++ b/spring-webmvc/src/test/resources/org/springframework/web/servlet/config/mvc-config-interceptors.xml @@ -3,7 +3,7 @@ xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd - http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd"> + http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"> @@ -12,6 +12,8 @@ + + diff --git a/src/dist/changelog.txt b/src/dist/changelog.txt index 67b7c30e66..794374a173 100644 --- a/src/dist/changelog.txt +++ b/src/dist/changelog.txt @@ -25,6 +25,7 @@ Changes in version 3.2 M2 (2012-08-xx) * parameterize DeferredResult type * use reflection to instantiate StandardServletAsyncWebRequest * fix issue with forward before async request processing +* add exclude patterns for mapped interceptors in MVC namespace and MVC Java config Changes in version 3.2 M1 (2012-05-28) diff --git a/src/reference/docbook/mvc.xml b/src/reference/docbook/mvc.xml index 7c482a7ba9..eb8e1aeba1 100644 --- a/src/reference/docbook/mvc.xml +++ b/src/reference/docbook/mvc.xml @@ -4453,7 +4453,8 @@ public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(new LocalInterceptor()); + registry.addInterceptor(new LocaleInterceptor()); + registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**"); registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*"); } @@ -4463,6 +4464,11 @@ public class WebConfig extends WebMvcConfigurerAdapter { <mvc:interceptors> <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" /> + <mvc:interceptor> + <mapping path="/**"/> + <exclude-mapping path="/admin/**"/> + <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor" /> + </mvc:interceptor> <mvc:interceptor> <mapping path="/secure/*"/> <bean class="org.example.SecurityInterceptor" />