Make RequestMappingHandlerMapping xml config easier
Prior to this commit, it was necessary to override
the HandlerMapping definition to change properties
like useSuffixPatternMatch, useSuffixPatternMatch...
Also, one couldn't set custom pathmatcher/pathhelper
on RequestMappingHandlerMapping via XML configuration.
This commits adds a new "mvc:annotation-driven"
subelement called "mvc:path-matching" for the tag
that allows to configure such properties:
* suffix-pattern
* trailing-slash
* registered-suffixes-only
* path-matcher
* path-helper
Note: this is a new take on this issue, since
96b418cc
has been reverted by e2b99c3.
Issue: SPR-10163
This commit is contained in:
parent
8edb7a18cc
commit
eac4881809
|
@ -125,6 +125,7 @@ import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolv
|
|||
* @author Juergen Hoeller
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Brian Clozel
|
||||
* @since 3.0
|
||||
*/
|
||||
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
@ -172,6 +173,8 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
|||
handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
|
||||
}
|
||||
|
||||
configurePathMatchingProperties(handlerMappingDef, element);
|
||||
|
||||
RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
|
||||
RuntimeBeanReference validator = getValidator(element, source, parserContext);
|
||||
RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);
|
||||
|
@ -334,6 +337,33 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
|||
return contentNegotiationManagerRef;
|
||||
}
|
||||
|
||||
private void configurePathMatchingProperties(RootBeanDefinition handlerMappingDef, Element element) {
|
||||
|
||||
Element pathMatchingElement = DomUtils.getChildElementByTagName(element, "path-matching");
|
||||
if(pathMatchingElement != null) {
|
||||
if (pathMatchingElement.hasAttribute("suffix-pattern")) {
|
||||
Boolean useSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("suffix-pattern"));
|
||||
handlerMappingDef.getPropertyValues().add("useSuffixPatternMatch", useSuffixPatternMatch);
|
||||
}
|
||||
if (pathMatchingElement.hasAttribute("trailing-slash")) {
|
||||
Boolean useTrailingSlashMatch = Boolean.valueOf(pathMatchingElement.getAttribute("trailing-slash"));
|
||||
handlerMappingDef.getPropertyValues().add("useTrailingSlashMatch", useTrailingSlashMatch);
|
||||
}
|
||||
if (pathMatchingElement.hasAttribute("registered-suffixes-only")) {
|
||||
Boolean useRegisteredSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("registered-suffixes-only"));
|
||||
handlerMappingDef.getPropertyValues().add("useRegisteredSuffixPatternMatch", useRegisteredSuffixPatternMatch);
|
||||
}
|
||||
if (pathMatchingElement.hasAttribute("path-helper")) {
|
||||
RuntimeBeanReference pathHelperRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-helper"));
|
||||
handlerMappingDef.getPropertyValues().add("urlPathHelper", pathHelperRef);
|
||||
}
|
||||
if (pathMatchingElement.hasAttribute("path-matcher")) {
|
||||
RuntimeBeanReference pathMatcherRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-matcher"));
|
||||
handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Properties getDefaultMediaTypes() {
|
||||
Properties props = new Properties();
|
||||
if (romePresent) {
|
||||
|
|
|
@ -24,6 +24,63 @@
|
|||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:all minOccurs="0">
|
||||
<xsd:element name="path-matching" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Configures the path matching part of the Spring MVC Controller programming model.
|
||||
Like annotation-driven, code-based alternatives are also documented in EnableWebMvc Javadoc.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="suffix-pattern" type="xsd:boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
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 true.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="trailing-slash" type="xsd:boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
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 true.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="registered-suffixes-only" type="xsd:boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
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 ContentNegotiationManager. This can be useful for allowing only specific URL extensions to be used as well as in cases
|
||||
where a "." in the URL path can lead to ambiguous interpretation of path variable content, (e.g. given "/users/{user}" and incoming
|
||||
URLs such as "/users/john.j.joe" and "/users/john.j.joe.json").
|
||||
If enabled, this attribute also enables suffix-pattern. The default value is false.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="path-helper" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The bean name of 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.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="path-matcher" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The bean name of the PathMatcher implementation to use for matching URL paths against registered URL patterns.
|
||||
Default is AntPathMatcher.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="message-converters" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
|
|
|
@ -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.
|
||||
|
@ -15,12 +15,9 @@
|
|||
*/
|
||||
package org.springframework.web.servlet.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
|
@ -30,6 +27,7 @@ import org.springframework.core.io.ClassPathResource;
|
|||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.ResourceHttpMessageConverter;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
|
||||
import org.springframework.web.bind.support.WebArgumentResolver;
|
||||
|
@ -42,11 +40,16 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
|||
import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ServletWebArgumentResolverAdapter;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Test fixture for the configuration in mvc-config-annotation-driven.xml.
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
public class AnnotationDrivenBeanDefinitionParserTests {
|
||||
|
||||
|
@ -70,6 +73,21 @@ public class AnnotationDrivenBeanDefinitionParserTests {
|
|||
assertEquals(false, new DirectFieldAccessor(adapter).getPropertyValue("ignoreDefaultModelOnRedirect"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathMatchingConfiguration() {
|
||||
loadBeanDefinitions("mvc-config-path-matching.xml");
|
||||
RequestMappingHandlerMapping hm = appContext.getBean(RequestMappingHandlerMapping.class);
|
||||
assertNotNull(hm);
|
||||
assertTrue(hm.useSuffixPatternMatch());
|
||||
assertFalse(hm.useTrailingSlashMatch());
|
||||
assertTrue(hm.useRegisteredSuffixPatternMatch());
|
||||
assertThat(hm.getUrlPathHelper(), Matchers.instanceOf(TestPathHelper.class));
|
||||
assertThat(hm.getPathMatcher(), Matchers.instanceOf(TestPathMatcher.class));
|
||||
List<String> fileExtensions = hm.getContentNegotiationManager().getAllFileExtensions();
|
||||
assertThat(fileExtensions, Matchers.contains("xml"));
|
||||
assertThat(fileExtensions, Matchers.hasSize(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessageConverters() {
|
||||
loadBeanDefinitions("mvc-config-message-converters.xml");
|
||||
|
@ -198,3 +216,7 @@ class TestMessageCodesResolver implements MessageCodesResolver {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
class TestPathMatcher extends AntPathMatcher { }
|
||||
|
||||
class TestPathHelper extends UrlPathHelper { }
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
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.xsd">
|
||||
|
||||
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
|
||||
<mvc:path-matching
|
||||
suffix-pattern="true"
|
||||
trailing-slash="false"
|
||||
registered-suffixes-only="true"
|
||||
path-helper="pathHelper"
|
||||
path-matcher="pathMatcher" />
|
||||
</mvc:annotation-driven>
|
||||
|
||||
<bean id="pathMatcher" class="org.springframework.web.servlet.config.TestPathMatcher" />
|
||||
<bean id="pathHelper" class="org.springframework.web.servlet.config.TestPathHelper" />
|
||||
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
|
||||
<property name="mediaTypes">
|
||||
<value>
|
||||
xml=application/rss+xml
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
</beans>
|
Loading…
Reference in New Issue