Skip to content

Commit c172d9d

Browse files
committed
Add trailing slash support to AbstractUrlHandlerMapping
Issue: SPR-12818
1 parent b18053f commit c172d9d

File tree

3 files changed

+34
-0
lines changed

3 files changed

+34
-0
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
5454

5555
private Object rootHandler;
5656

57+
private boolean useTrailingSlashMatch = false;
58+
5759
private boolean lazyInitHandlers = false;
5860

5961
private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();
@@ -76,6 +78,22 @@ public Object getRootHandler() {
7678
return this.rootHandler;
7779
}
7880

81+
/**
82+
* Whether to match to URLs irrespective of the presence of a trailing slash.
83+
* If enabled a URL pattern such as "/users" also matches to "/users/".
84+
* <p>The default value is {@code false}.
85+
*/
86+
public void setUseTrailingSlashMatch(boolean useTrailingSlashMatch) {
87+
this.useTrailingSlashMatch = useTrailingSlashMatch;
88+
}
89+
90+
/**
91+
* Whether to match to URLs irrespective of the presence of a trailing slash.
92+
*/
93+
public boolean useTrailingSlashMatch() {
94+
return this.useTrailingSlashMatch;
95+
}
96+
7997
/**
8098
* Set whether to lazily initialize handlers. Only applicable to
8199
* singleton handlers, as prototypes are always lazily initialized.
@@ -159,6 +177,11 @@ protected Object lookupHandler(String urlPath, HttpServletRequest request) throw
159177
if (getPathMatcher().match(registeredPattern, urlPath)) {
160178
matchingPatterns.add(registeredPattern);
161179
}
180+
else if (useTrailingSlashMatch()) {
181+
if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
182+
matchingPatterns.add(registeredPattern +"/");
183+
}
184+
}
162185
}
163186
String bestPatternMatch = null;
164187
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
@@ -171,6 +194,10 @@ protected Object lookupHandler(String urlPath, HttpServletRequest request) throw
171194
}
172195
if (bestPatternMatch != null) {
173196
handler = this.handlerMap.get(bestPatternMatch);
197+
if (handler == null) {
198+
Assert.isTrue(bestPatternMatch.endsWith("/"));
199+
handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1));
200+
}
174201
// Bean name or resolved handler?
175202
if (handler instanceof String) {
176203
String handlerName = (String) handler;

spring-webmvc/src/test/java/org/springframework/web/servlet/handler/SimpleUrlHandlerMappingTests.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ private void checkMappings(String beanName) throws Exception {
110110
assertTrue("Handler is correct bean", hec != null && hec.getHandler() == otherBean);
111111
assertEquals("welcome.x", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE));
112112

113+
req = new MockHttpServletRequest("GET", "/welcome/");
114+
hec = getHandler(hm, req);
115+
assertTrue("Handler is correct bean", hec != null && hec.getHandler() == otherBean);
116+
assertEquals("welcome", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE));
117+
113118
req = new MockHttpServletRequest("GET", "/");
114119
req.setServletPath("/welcome.html");
115120
hec = getHandler(hm, req);

spring-webmvc/src/test/resources/org/springframework/web/servlet/handler/map2.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
77
<property name="defaultHandler"><ref local="starController"/></property>
88
<property name="rootHandler"><ref local="mainController"/></property>
9+
<property name="useTrailingSlashMatch" value="true"/>
910
<property name="urlMap">
1011
<map>
1112
<entry key="/welcome*"><ref local="otherController"/></entry>
@@ -22,6 +23,7 @@
2223
<bean id="urlMappingWithProps" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
2324
<property name="defaultHandler"><ref local="starController"/></property>
2425
<property name="rootHandler"><ref local="mainController"/></property>
26+
<property name="useTrailingSlashMatch" value="true"/>
2527
<property name="mappings"><ref local="propsForUrlMapping2"/></property>
2628
</bean>
2729

0 commit comments

Comments
 (0)