Add trailing slash support to AbstractUrlHandlerMapping

Issue: SPR-12818
master
Rossen Stoyanchev 10 years ago
parent b18053f93a
commit c172d9d745
  1. 27
      spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java
  2. 5
      spring-webmvc/src/test/java/org/springframework/web/servlet/handler/SimpleUrlHandlerMappingTests.java
  3. 2
      spring-webmvc/src/test/resources/org/springframework/web/servlet/handler/map2.xml

@ -54,6 +54,8 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
private Object rootHandler; private Object rootHandler;
private boolean useTrailingSlashMatch = false;
private boolean lazyInitHandlers = false; private boolean lazyInitHandlers = false;
private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>(); private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();
@ -76,6 +78,22 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
return this.rootHandler; return this.rootHandler;
} }
/**
* Whether to match to URLs irrespective of the presence of a trailing slash.
* If enabled a URL pattern such as "/users" also matches to "/users/".
* <p>The default value is {@code false}.
*/
public void setUseTrailingSlashMatch(boolean useTrailingSlashMatch) {
this.useTrailingSlashMatch = useTrailingSlashMatch;
}
/**
* Whether to match to URLs irrespective of the presence of a trailing slash.
*/
public boolean useTrailingSlashMatch() {
return this.useTrailingSlashMatch;
}
/** /**
* Set whether to lazily initialize handlers. Only applicable to * Set whether to lazily initialize handlers. Only applicable to
* singleton handlers, as prototypes are always lazily initialized. * singleton handlers, as prototypes are always lazily initialized.
@ -159,6 +177,11 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
if (getPathMatcher().match(registeredPattern, urlPath)) { if (getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern); matchingPatterns.add(registeredPattern);
} }
else if (useTrailingSlashMatch()) {
if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
matchingPatterns.add(registeredPattern +"/");
}
}
} }
String bestPatternMatch = null; String bestPatternMatch = null;
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath); Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
@ -171,6 +194,10 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
} }
if (bestPatternMatch != null) { if (bestPatternMatch != null) {
handler = this.handlerMap.get(bestPatternMatch); handler = this.handlerMap.get(bestPatternMatch);
if (handler == null) {
Assert.isTrue(bestPatternMatch.endsWith("/"));
handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1));
}
// Bean name or resolved handler? // Bean name or resolved handler?
if (handler instanceof String) { if (handler instanceof String) {
String handlerName = (String) handler; String handlerName = (String) handler;

@ -110,6 +110,11 @@ public class SimpleUrlHandlerMappingTests {
assertTrue("Handler is correct bean", hec != null && hec.getHandler() == otherBean); assertTrue("Handler is correct bean", hec != null && hec.getHandler() == otherBean);
assertEquals("welcome.x", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); assertEquals("welcome.x", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE));
req = new MockHttpServletRequest("GET", "/welcome/");
hec = getHandler(hm, req);
assertTrue("Handler is correct bean", hec != null && hec.getHandler() == otherBean);
assertEquals("welcome", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE));
req = new MockHttpServletRequest("GET", "/"); req = new MockHttpServletRequest("GET", "/");
req.setServletPath("/welcome.html"); req.setServletPath("/welcome.html");
hec = getHandler(hm, req); hec = getHandler(hm, req);

@ -6,6 +6,7 @@
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="defaultHandler"><ref local="starController"/></property> <property name="defaultHandler"><ref local="starController"/></property>
<property name="rootHandler"><ref local="mainController"/></property> <property name="rootHandler"><ref local="mainController"/></property>
<property name="useTrailingSlashMatch" value="true"/>
<property name="urlMap"> <property name="urlMap">
<map> <map>
<entry key="/welcome*"><ref local="otherController"/></entry> <entry key="/welcome*"><ref local="otherController"/></entry>
@ -22,6 +23,7 @@
<bean id="urlMappingWithProps" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <bean id="urlMappingWithProps" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="defaultHandler"><ref local="starController"/></property> <property name="defaultHandler"><ref local="starController"/></property>
<property name="rootHandler"><ref local="mainController"/></property> <property name="rootHandler"><ref local="mainController"/></property>
<property name="useTrailingSlashMatch" value="true"/>
<property name="mappings"><ref local="propsForUrlMapping2"/></property> <property name="mappings"><ref local="propsForUrlMapping2"/></property>
</bean> </bean>

Loading…
Cancel
Save