springmvc里面的URL注册方式

springmvc在使用不同的版本的时候,注册的URL,或者说能够执行的URL是有些许不同的.下面我尝试的分析下为啥会出现这样的原因.


例如我下面的介绍的场景,就是一个活生生的例子,请各位童鞋们不要模仿.

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;
		}


例如:  pattern1="/a"  ,  pattern2 = "/a"  相同的情况下,经过这个代码处理,就会得出 "/a" 结果.[大跌眼镜]

源码说明 在类AntPathMatcher 292行,抄录如下

Pattern 1Pattern 2Result
/hotelsnull/hotels
null/hotels/hotels
/hotels/bookings/hotels/bookings
/hotelsbookings/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/*.txtIllegalArgumentException

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值