SPR-6280 - PathVariable resolution does not work properly
This commit is contained in:
parent
be60908d6d
commit
ef50082cad
|
|
@ -412,7 +412,7 @@ public class AntPathMatcher implements PathMatcher {
|
|||
else if (bracketCount2 < bracketCount1) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return pattern2.length() - pattern1.length();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class AntPathStringMatcher {
|
|||
|
||||
private static final Pattern GLOB_PATTERN = Pattern.compile("\\?|\\*|\\{([^/]+?)\\}");
|
||||
|
||||
private static final String DEFAULT_VARIABLE_PATTERN = "(.*)";
|
||||
private static final String DEFAULT_VARIABLE_PATTERN = "([^\\.]*)";
|
||||
|
||||
private final Pattern pattern;
|
||||
|
||||
|
|
|
|||
|
|
@ -395,6 +395,11 @@ public class AntPathMatcherTests {
|
|||
|
||||
assertEquals(-1, comparator.compare("/hotels/*", "/hotels/*/**"));
|
||||
assertEquals(1, comparator.compare("/hotels/*/**", "/hotels/*"));
|
||||
|
||||
assertEquals(-1, comparator.compare("/hotels/new", "/hotels/new.*"));
|
||||
|
||||
// longer is better
|
||||
assertEquals(1, comparator.compare("/hotels", "/hotels2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -467,6 +472,14 @@ public class AntPathMatcherTests {
|
|||
assertEquals("/hotels/{hotel}", paths.get(1));
|
||||
assertEquals("/hotels/*", paths.get(2));
|
||||
paths.clear();
|
||||
|
||||
paths.add("/hotels/ne*");
|
||||
paths.add("/hotels/n*");
|
||||
Collections.shuffle(paths);
|
||||
Collections.sort(paths, comparator);
|
||||
assertEquals("/hotels/ne*", paths.get(0));
|
||||
assertEquals("/hotels/n*", paths.get(1));
|
||||
paths.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ package org.springframework.web.servlet.handler;
|
|||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
|
@ -214,13 +216,20 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
|
|||
return buildPathExposingHandler(handler, urlPath, null);
|
||||
}
|
||||
// Pattern match?
|
||||
String bestPathMatch = null;
|
||||
List<String> matchingPaths = new ArrayList<String>();
|
||||
for (String registeredPath : this.handlerMap.keySet()) {
|
||||
if (getPathMatcher().match(registeredPath, urlPath) &&
|
||||
(bestPathMatch == null || bestPathMatch.length() < registeredPath.length())) {
|
||||
bestPathMatch = registeredPath;
|
||||
if (getPathMatcher().match(registeredPath, urlPath)) {
|
||||
matchingPaths.add(registeredPath);
|
||||
}
|
||||
}
|
||||
String bestPathMatch = null;
|
||||
if (!matchingPaths.isEmpty()) {
|
||||
Collections.sort(matchingPaths, getPathMatcher().getPatternComparator(urlPath));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Matching path for request [" + urlPath + "] are " + matchingPaths);
|
||||
}
|
||||
bestPathMatch = matchingPaths.get(0);
|
||||
}
|
||||
if (bestPathMatch != null) {
|
||||
handler = this.handlerMap.get(bestPathMatch);
|
||||
// Bean name or resolved handler?
|
||||
|
|
|
|||
|
|
@ -221,6 +221,22 @@ public class UriTemplateServletAnnotationControllerTests {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiPaths() throws Exception {
|
||||
initServlet(MultiPathController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/category/page/5");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
servlet.service(request, response);
|
||||
assertEquals("handle4-page-5", response.getContentAsString());
|
||||
|
||||
request = new MockHttpServletRequest("GET", "/category/page/5.html");
|
||||
response = new MockHttpServletResponse();
|
||||
servlet.service(request, response);
|
||||
assertEquals("handle4-page-5", response.getContentAsString());
|
||||
}
|
||||
|
||||
|
||||
private void initServlet(final Class<?> controllerclass) throws ServletException {
|
||||
servlet = new DispatcherServlet() {
|
||||
@Override
|
||||
|
|
@ -258,6 +274,17 @@ public class UriTemplateServletAnnotationControllerTests {
|
|||
assertEquals("test-hotel.with.dot", response.getContentAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customRegex() throws Exception {
|
||||
initServlet(CustomRegexController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/42");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
servlet.service(request, response);
|
||||
assertEquals("test-42", response.getContentAsString());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Controllers
|
||||
*/
|
||||
|
|
@ -371,12 +398,24 @@ public class UriTemplateServletAnnotationControllerTests {
|
|||
@RequestMapping("hotels")
|
||||
public static class ImplicitSubPathController {
|
||||
|
||||
@RequestMapping("{hotel}")
|
||||
@RequestMapping("{hotel:.*}")
|
||||
public void handleHotel(@PathVariable String hotel, Writer writer) throws IOException {
|
||||
writer.write("test-" + hotel);
|
||||
}
|
||||
}
|
||||
|
||||
@Controller
|
||||
public static class CustomRegexController {
|
||||
|
||||
@RequestMapping("/{root:\\d+}")
|
||||
public void handle(@PathVariable("root") int root, Writer writer) throws IOException {
|
||||
assertEquals("Invalid path variable value", 42, root);
|
||||
writer.write("test-" + root);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
@RequestMapping("hotels")
|
||||
public static class CrudController {
|
||||
|
|
@ -429,4 +468,34 @@ public class UriTemplateServletAnnotationControllerTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/category")
|
||||
public static class MultiPathController {
|
||||
|
||||
@RequestMapping(value = {"/{category}/page/{page}", "/**/{category}/page/{page}"})
|
||||
public void category(@PathVariable String category, @PathVariable int page, Writer writer) throws IOException {
|
||||
writer.write("handle1-");
|
||||
writer.write("category-" + category);
|
||||
writer.write("page-" + page);
|
||||
}
|
||||
|
||||
@RequestMapping(value = {"/{category}", "/**/{category}"})
|
||||
public void category(@PathVariable String category, Writer writer) throws IOException {
|
||||
writer.write("handle2-");
|
||||
writer.write("category-" + category);
|
||||
}
|
||||
|
||||
@RequestMapping(value = {""})
|
||||
public void category(Writer writer) throws IOException {
|
||||
writer.write("handle3");
|
||||
}
|
||||
|
||||
@RequestMapping(value = {"/page/{page}"})
|
||||
public void category(@PathVariable int page, Writer writer) throws IOException {
|
||||
writer.write("handle4-");
|
||||
writer.write("page-" + page);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,10 @@ import java.lang.annotation.Target;
|
|||
* exposed by the Servlet/Portlet API.
|
||||
* <li>{@link PathVariable @PathVariable} annotated parameters for access to
|
||||
* URI template values (i.e. /hotels/{hotel}). Variable values will be
|
||||
* converted to the declared method argument type.
|
||||
* converted to the declared method argument type. By default, the URI template
|
||||
* will match against the regular expression {@code [^\.]*} (i.e. any character
|
||||
* other than period), but this can be changed by specifying another regular
|
||||
* expression, like so: /hotels/{hotel:\d+}.
|
||||
* <li>{@link RequestParam @RequestParam} annotated parameters for access to
|
||||
* specific Servlet/Portlet request parameters. Parameter values will be
|
||||
* converted to the declared method argument type. Additionally,
|
||||
|
|
|
|||
Loading…
Reference in New Issue