springmvc 3.2 @MatrixVariable bug 2

阅读更多

之前遇到过一个bug,《spring3.2 带matrix变量的URL匹配问题》(spring3.2.3已经修复该bug),今天看到问答又有人遇到一个,在此记录下,bug可真不少,测试用例看了下,写的并不是很全面。

 

问题:

http://www.iteye.com/problems/95247

 

@RequestMapping(value = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)  
    public void findPet(@MatrixVariable Map matrixVars, @MatrixVariable(pathVar = "petId") Map petMatrixVars) {  
        System.out.println(matrixVars);  
        System.out.println(petMatrixVars);  
    }  

 上面代码是spring文档中的例子,浏览器中输入:http://localhost:8080/owners/44/pets/55;q=22,33;s=23时,控制台输出:

 

{q=[22, 33], s=[23]}  
{q=[22, 33], s=[23]}  

但是当输入http://localhost:8080/owners/42;q=11;r=12/pets/55;q=22,33;s=23则findPet方法没有执行,难道spring文档有错误?还是少了什么配置?

 

目前不支持

 

分析:

1、先看下springmvc官网的单元测试用例

@Test
	public void getLookupPathWithSemicolonContent() {
		helper.setRemoveSemicolonContent(false);

		request.setContextPath("/petclinic");
		request.setServletPath("/main");
		request.setRequestURI("/petclinic;a=b/main;b=c/welcome.html;c=d");

		assertEquals("/welcome.html;c=d", helper.getLookupPathForRequest(request));
	}

	@Test
	public void getLookupPathWithSemicolonContentAndNullPathInfo() {
		helper.setRemoveSemicolonContent(false);

		request.setContextPath("/petclinic");
		request.setServletPath("/welcome.html");
		request.setRequestURI("/petclinic;a=b/welcome.html;c=d");

		assertEquals("/welcome.html;c=d", helper.getLookupPathForRequest(request));
	}

 https://github.com/SpringSource/spring-framework/blob/master/spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java

 

此处可以看到,如果请求的uri是/owners/42;q=11;r=12/pets/55;q=22,33;s=23,那么request.getServletPath()实际是/owners/42,而不是期待的/owners/42/pets/55;可以参考

https://java.net/jira/browse/SERVLET_SPEC-67?page=com.atlassian.streams.streams-jira-plugin%3Aactivity-stream-issue-tab

 

接下来看下springmvc如何进行url匹配的,假设此处使用的是RequestMappingHandlerMapping(http://jinnianshilongnian.iteye.com/blog/1682510):

1、

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		if (logger.isDebugEnabled()) {
			logger.debug("Looking up handler method for path " + lookupPath);
		}

		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);

 此处委托给UrlPathHelper去查找path

2、

public String getLookupPathForRequest(HttpServletRequest request) {
		// Always use full path within current servlet context?
		if (this.alwaysUseFullPath) {
			return getPathWithinApplication(request);
		}
		// Else, use path within current servlet mapping if applicable
		String rest = getPathWithinServletMapping(request);
		if (!"".equals(rest)) {
			return rest;
		}
		else {
			return getPathWithinApplication(request);
		}
	}

 此处因为默认不开启alwaysUseFullPath,因此会执行getPathWithinServletMapping()

3、

public String getPathWithinServletMapping(HttpServletRequest request) {
		String pathWithinApp = getPathWithinApplication(request);
		String servletPath = getServletPath(request);
		String path = getRemainingPath(pathWithinApp, servletPath, false);
		if (path != null) {
			// Normal case: URI contains servlet path.
			return path;
		}
		else {
			// Special case: URI is different from servlet path.
			// Can happen e.g. with index page: URI="/", servletPath="/index.html"
			// Use path info if available, as it indicates an index page within
			// a servlet mapping. Otherwise, use the full servlet path.
			String pathInfo = request.getPathInfo();
			return (pathInfo != null ? pathInfo : servletPath);
		}
	}

此处调用String servletPath = getServletPath(request); 出问题了,如果我们的url是 http://localhost:8080/owners/44;a=123/pets/55;q=22,33;s=23,那么获取的将是/owners/44,而不是/owners/42/pets/55,此处有说明:

https://java.net/jira/browse/SERVLET_SPEC-67?page=com.atlassian.streams.streams-jira-plugin%3Aactivity-stream-issue-tab

 

接着执行getRemainingPath则获取到剩余部分 /pets/55;q=22,33;s=23,即和之前的单元测试一样。 所以得到的path不可能匹配模式/owners/{ownerId}/pets/{petId},但是匹配/pets/{petId}(但没有意义了),所以失败了。

 

@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET)  
    public void findPet(@MatrixVariable Map matrixVars, @MatrixVariable(pathVar = "petId") Map petMatrixVars) {  
        System.out.println(matrixVars);  
        System.out.println(petMatrixVars);  
    }  

 

已提交给springsource。

https://jira.springsource.org/browse/SPR-10577

你可能感兴趣的:(springmvc 3.2 @MatrixVariable bug 2)