例如我下面的介绍的场景,就是一个活生生的例子,请各位童鞋们不要模仿.
Controller代码
@Controller
@RequestMapping("/tools")
public class ToolsController {
@RequestMapping("/tools")
public String tools() {
return "hello";
}
}
场景1 : springmvc 3.0.6
springmvc的配置就不写了.关键是看启动服务时注册的URL信息.
[org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping] - Mapped URL path [/tools] onto handler 'ToolsController' [main]
[org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping] - Mapped URL path [/tools.*] onto handler 'ToolsController' [main]
[org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping] - Mapped URL path [/tools/] onto handler 'ToolsController' [main]
[org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping] - Mapped URL path [/tools/tools.*] onto handler 'ToolsController' [main]
[org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping] - Mapped URL path [/tools/tools/] onto handler 'ToolsController' [main]
它会注册在ToolsAcontroller上面注册五个URL地址,其中有些URL没有对应的视图,会报404错误.
场景2: springmvc 3.2.6
启动服务时注册的URL信息.
[org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping] - Mapped URL path [/tools/tools] onto handler 'ToolsController' [main]
[org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping] - Mapped URL path [/tools/tools.*] onto handler 'ToolsController' [main]
[org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping] - Mapped URL path [/tools/tools/] onto handler 'ToolsController' [main]
由以上两个场景可以看出,不同版本注册的URL是有区别的,具体是什么原因引起的,大家可以先静静想下.
下面为大家解开谜团的时候了.
springmvc 3.0.6默认使用的UrlHandlerMapping 是 DefaultAnnotationHandlerMapping.
这个类里面有一个解析拼接URL的代码如下
String combinedPattern = getPathMatcher().combine(typeLevelPattern, methodLevelPattern); //129行
其中combine方法,在类AntPathMatcher.combine //292 行,抄录下部分源码
public String combine(String pattern1, String pattern2) {
if (!StringUtils.hasText(pattern1) && !StringUtils.hasText(pattern2)) {
return "";
}
else if (!StringUtils.hasText(pattern1)) {
return pattern2;
}
else if (!StringUtils.hasText(pattern2)) {
return pattern1;
}
else if (match(pattern1, pattern2)) { //这个方法就是导致问题出现的真凶
return pattern2;
}
源码说明 在类AntPathMatcher 292行,抄录如下
Pattern 1 | Pattern 2 | Result |
---|---|---|
/hotels | null | /hotels |
null | /hotels | /hotels |
/hotels | /bookings | /hotels/bookings |
/hotels | bookings | /hotels/bookings |
/hotels/* | /bookings | /hotels/bookings |
/hotels/** | /bookings | /hotels/**/bookings |
/hotels | {hotel} | /hotels/{hotel} |
/hotels/* | {hotel} | /hotels/{hotel} |
/hotels/** | {hotel} | /hotels/**/{hotel} |
/*.html | /hotels.html | /hotels.html |
/*.html | /hotels | /hotels.html |
/*.html | /*.txt | IllegalArgumentException |
springmvc 3.2.6默认使用UrlHandlerMapping 是 RequestMappingHandlerMapping
解释拼接URL源码地方
info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info); //196行
实现方式与3.0.6稍微有些不一样了,实现类PatternsRequestCondition.combine //165行
其中combine方法,在类AntPathMatcher.combine //325 行,抄录下部分源码
public String combine(String pattern1, String pattern2) {
if (!StringUtils.hasText(pattern1) && !StringUtils.hasText(pattern2)) {
return "";
}
else if (!StringUtils.hasText(pattern1)) {
return pattern2;
}
else if (!StringUtils.hasText(pattern2)) {
return pattern1;
}
/*//
这个地方将3.0.6的一个代码段干掉了
///*/
boolean pattern1ContainsUriVar = pattern1.indexOf('{') != -1;
if (!pattern1.equals(pattern2) && !pattern1ContainsUriVar && match(pattern1, pattern2)) {
// /* + /hotel -> /hotel ; "/*.*" + "/*.html" -> /*.html
// However /user + /user -> /usr/user ; /{foo} + /bar -> /{foo}/bar
return pattern2;
}
大家可以比较下,两个版本里面的AntPathMatcher.combine方法,确实做了一些调整,导致出现了不同结果.
在3.2.6版本下
例如: pattern1="/a" , pattern2 = "/a" 相同的情况下,经过这个代码处理,就会得出 "/a/a" 结果.[大吃一惊]
以上就是url为啥会出现不一致的情况,具体原因了. 坑虽然多,可不要随便跳哦.
贴出参考的文章地址:
http://jinnianshilongnian.iteye.com/blog/1682510
http://my.oschina.net/abian/blog/128028