diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java index d9d58035b17..fef35bcec8d 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -65,6 +65,11 @@ public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { this.configurers.configureAsyncSupport(configurer); } + @Override + public void configurePathMatch(PathMatchConfigurer configurer) { + this.configurers.configurePathMatch(configurer); + } + @Override protected void addViewControllers(ViewControllerRegistry registry) { this.configurers.addViewControllers(registry); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/PathMatchConfigurer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/PathMatchConfigurer.java new file mode 100644 index 00000000000..902b04ad363 --- /dev/null +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/PathMatchConfigurer.java @@ -0,0 +1,117 @@ +/* + * Copyright 2002-2014 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.config.annotation; + +import org.springframework.util.PathMatcher; +import org.springframework.web.util.UrlPathHelper; + +/** + * Helps with configuring {@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping} + * path matching options such as trailing slash match, suffix registration or path matcher/helper. + * + * @author Brian Clozel + * @since 4.0.3 + * @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping + */ +public class PathMatchConfigurer { + + private Boolean useSuffixPatternMatch; + private Boolean useTrailingSlashMatch; + private Boolean useRegisteredSuffixPatternMatch; + private UrlPathHelper urlPathHelper; + private PathMatcher pathMatcher; + + /** + * Whether to use suffix pattern match (".*") when matching patterns to + * requests. If enabled a method mapped to "/users" also matches to "/users.*". + *

The default value is {@code true}. + */ + public PathMatchConfigurer setUseSuffixPatternMatch(Boolean useSuffixPatternMatch) { + this.useSuffixPatternMatch = useSuffixPatternMatch; + return this; + } + + /** + * Whether to match to URLs irrespective of the presence of a trailing slash. + * If enabled a method mapped to "/users" also matches to "/users/". + *

The default value is {@code true}. + */ + public PathMatchConfigurer setUseTrailingSlashMatch(Boolean useTrailingSlashMatch) { + this.useTrailingSlashMatch = useTrailingSlashMatch; + return this; + } + + /** + * Whether to use suffix pattern match for registered file extensions only + * when matching patterns to requests. + *

If enabled, a controller method mapped to "/users" also matches to + * "/users.json" assuming ".json" is a file extension registered with the + * provided {@link org.springframework.web.accept.ContentNegotiationManager}.

+ *

The {@link org.springframework.web.accept.ContentNegotiationManager} can be customized + * using a {@link ContentNegotiationConfigurer}.

+ *

If enabled, this flag also enables + * {@link #setUseSuffixPatternMatch(Boolean) useSuffixPatternMatch}. The + * default value is {@code false}.

+ * @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping + * @see ContentNegotiationConfigurer + * + */ + public PathMatchConfigurer setUseRegisteredSuffixPatternMatch(Boolean useRegisteredSuffixPatternMatch) { + this.useRegisteredSuffixPatternMatch = useRegisteredSuffixPatternMatch; + return this; + } + + /** + * Set the UrlPathHelper to use for resolution of lookup paths. + *

Use this to override the default UrlPathHelper with a custom subclass, + * or to share common UrlPathHelper settings across multiple HandlerMappings + * and MethodNameResolvers. + */ + public PathMatchConfigurer setUrlPathHelper(UrlPathHelper urlPathHelper) { + this.urlPathHelper = urlPathHelper; + return this; + } + + /** + * Set the PathMatcher implementation to use for matching URL paths + * against registered URL patterns. Default is AntPathMatcher. + * @see org.springframework.util.AntPathMatcher + */ + public PathMatchConfigurer setPathMatcher(PathMatcher pathMatcher) { + this.pathMatcher = pathMatcher; + return this; + } + + public Boolean isUseSuffixPatternMatch() { + return useSuffixPatternMatch; + } + + public Boolean isUseTrailingSlashMatch() { + return useTrailingSlashMatch; + } + + public Boolean isUseRegisteredSuffixPatternMatch() { + return useRegisteredSuffixPatternMatch; + } + + public UrlPathHelper getUrlPathHelper() { + return urlPathHelper; + } + + public PathMatcher getPathMatcher() { + return pathMatcher; + } +} diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java index ccef1bef12a..706babc0d01 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java @@ -191,10 +191,27 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv */ @Bean public RequestMappingHandlerMapping requestMappingHandlerMapping() { + PathMatchConfigurer configurer = new PathMatchConfigurer(); + configurePathMatch(configurer); RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping(); handlerMapping.setOrder(0); handlerMapping.setInterceptors(getInterceptors()); handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager()); + if(configurer.isUseSuffixPatternMatch() != null) { + handlerMapping.setUseSuffixPatternMatch(configurer.isUseSuffixPatternMatch()); + } + if(configurer.isUseRegisteredSuffixPatternMatch() != null) { + handlerMapping.setUseRegisteredSuffixPatternMatch(configurer.isUseRegisteredSuffixPatternMatch()); + } + if(configurer.isUseTrailingSlashMatch() != null) { + handlerMapping.setUseTrailingSlashMatch(configurer.isUseTrailingSlashMatch()); + } + if(configurer.getPathMatcher() != null) { + handlerMapping.setPathMatcher(configurer.getPathMatcher()); + } + if(configurer.getUrlPathHelper() != null) { + handlerMapping.setUrlPathHelper(configurer.getUrlPathHelper()); + } return handlerMapping; } @@ -563,6 +580,14 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv public void configureAsyncSupport(AsyncSupportConfigurer configurer) { } + /** + * Override this method to configure path matching options. + * @see PathMatchConfigurer + * @since 4.0.3 + */ + public void configurePathMatch(PathMatchConfigurer configurer) { + } + /** * Return an instance of {@link CompositeUriComponentsContributor} for use with * {@link org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder}. diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java index c7f0a6fc9d9..a65b6326e8c 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java @@ -79,6 +79,12 @@ public interface WebMvcConfigurer { */ void configureAsyncSupport(AsyncSupportConfigurer configurer); + /** + * Configure path matching options. + * @since 4.0.3 + */ + void configurePathMatch(PathMatchConfigurer configurer); + /** * Add resolvers to support custom controller method argument types. *

This does not override the built-in support for resolving handler diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.java index 06747857550..69d43fb0156 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -76,6 +76,14 @@ public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer { public void configureAsyncSupport(AsyncSupportConfigurer configurer) { } + /** + * {@inheritDoc} + *

This implementation is empty. + */ + @Override + public void configurePathMatch(PathMatchConfigurer configurer) { + } + /** * {@inheritDoc} *

This implementation is empty. diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerComposite.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerComposite.java index 05461d50130..2cea34d6b12 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerComposite.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerComposite.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -64,6 +64,13 @@ class WebMvcConfigurerComposite implements WebMvcConfigurer { } } + @Override + public void configurePathMatch(PathMatchConfigurer configurer) { + for (WebMvcConfigurer delegate : this.delegates) { + delegate.configurePathMatch(configurer); + } + } + @Override public void configureMessageConverters(List> converters) { for (WebMvcConfigurer delegate : this.delegates) { diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java index 392cb9b9799..205ace6240f 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -30,6 +30,7 @@ import org.springframework.core.convert.ConversionService; import org.springframework.format.support.FormattingConversionService; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.util.PathMatcher; import org.springframework.validation.DefaultMessageCodesResolver; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; @@ -40,7 +41,9 @@ import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; +import org.springframework.web.util.UrlPathHelper; import static org.junit.Assert.*; import static org.mockito.BDDMockito.*; @@ -178,4 +181,35 @@ public class DelegatingWebMvcConfigurationTests { assertEquals("Only one custom converter is expected", 1, composite.getExceptionResolvers().size()); } + @Test + public void configurePathMatch() throws Exception { + final PathMatcher pathMatcher = mock(PathMatcher.class); + final UrlPathHelper pathHelper = mock(UrlPathHelper.class); + + List configurers = new ArrayList(); + configurers.add(new WebMvcConfigurerAdapter() { + @Override + public void configurePathMatch(PathMatchConfigurer configurer) { + configurer.setUseRegisteredSuffixPatternMatch(true) + .setUseTrailingSlashMatch(false) + .setUrlPathHelper(pathHelper) + .setPathMatcher(pathMatcher); + } + }); + delegatingConfig.setConfigurers(configurers); + + RequestMappingHandlerMapping handlerMapping = delegatingConfig.requestMappingHandlerMapping(); + assertNotNull(handlerMapping); + assertEquals("PathMatchConfigurer should configure RegisteredSuffixPatternMatch", + true, handlerMapping.useRegisteredSuffixPatternMatch()); + assertEquals("PathMatchConfigurer should configure SuffixPatternMatch", + true, handlerMapping.useSuffixPatternMatch()); + assertEquals("PathMatchConfigurer should configure TrailingSlashMatch", + false, handlerMapping.useTrailingSlashMatch()); + assertEquals("PathMatchConfigurer should configure UrlPathHelper", + pathHelper, handlerMapping.getUrlPathHelper()); + assertEquals("PathMatchConfigurer should configure PathMatcher", + pathMatcher, handlerMapping.getPathMatcher()); + } + }