SpringMvc Url 匹配规则详解

最近开始阅读Spring 源码,虽然用了很久的spring ,但是没有真正的分析过Spring时如何工作的。今天重 MVC 的Url匹配规则开始进行Spring源码的阅读。

一、Springmvc url 匹配规则

  RequestMapping中路径的定义

  1: /abc  指定具体的定义值

  2:/{type} 指定参数 即 /###

  3:/** 匹配任何值  /###/### 可以匹配任意数量

  4:/abc/*/abc 匹配中间固定值  /abc/###/abc

二、源码分析 


private static class PatternInfo {

            private final String pattern; // 匹配的url规则 例如 /abc/{type}

            private int uriVars; // url 参数

            private int singleWildcards;  // 单个*匹配符

            private int doubleWildcards;  // ** 匹配符

            private boolean catchAllPattern; // 是否完全匹配

            private boolean prefixPattern;  // 是否前缀匹配

            private Integer length;  // 匹配条件长度

            public PatternInfo(String pattern) {
this.pattern = pattern;
if (this.pattern != null) {
initCounters();
this.catchAllPattern = this.pattern.equals("/**");
this.prefixPattern = !this.catchAllPattern && this.pattern.endsWith("/**");
}
if (this.uriVars == 0) {
this.length = (this.pattern != null ? this.pattern.length() : 0);
}
} protected void initCounters() {
int pos = 0;
while (pos < this.pattern.length()) {
if (this.pattern.charAt(pos) == '{') {
this.uriVars++;
pos++;
}
else if (this.pattern.charAt(pos) == '*') {
if (pos + 1 < this.pattern.length() && this.pattern.charAt(pos + 1) == '*') {
this.doubleWildcards++;
pos += 2;
}
else if (pos > 0 && !this.pattern.substring(pos - 1).equals(".*")) {
this.singleWildcards++;
pos++;
}
else {
pos++;
}
}
else {
pos++;
}
}
} public int getUriVars() {
return this.uriVars;
} public int getSingleWildcards() {
return this.singleWildcards;
} public int getDoubleWildcards() {
return this.doubleWildcards;
} public boolean isLeastSpecific() {
return (this.pattern == null || this.catchAllPattern);
} public boolean isPrefixPattern() {
return this.prefixPattern;
} public int getTotalCount() {
return this.uriVars + this.singleWildcards + (2 * this.doubleWildcards);
} /**
* Returns the length of the given pattern, where template variables are considered to be 1 long.
*/
public int getLength() {
if (this.length == null) {
this.length = VARIABLE_PATTERN.matcher(this.pattern).replaceAll("#").length();
}
return this.length;
}
}

/* Pattern Url正则表达式排序规则 */
protected static class AntPatternComparator implements Comparator<String> {
      /** 将所有匹配的URL 进行排序 */
public int compare(String pattern1, String pattern2) {
PatternInfo info1 = new PatternInfo(pattern1);
PatternInfo info2 = new PatternInfo(pattern2);
       
        // 规则1
if (info1.isLeastSpecific() && info2.isLeastSpecific()) {
          // 如果 p1 和 p2 都是 /** 则两个地址相同
return 0;
}
else if (info1.isLeastSpecific()) {
          // 如果 p1 是 /** 则p2优先
return 1;
}
else if (info2.isLeastSpecific()) {
          // 反之 p2 是 /** 则p1优先
return -1;
}
        // 规则2
boolean pattern1EqualsPath = pattern1.equals(path);
boolean pattern2EqualsPath = pattern2.equals(path);
if (pattern1EqualsPath && pattern2EqualsPath) {
        // 请求url 和p1 、p2 完全相等
return 0;
}
else if (pattern1EqualsPath) {
        // 请求url 和 p1 相等 则 p1 优先
return -1;
}
else if (pattern2EqualsPath) {
        // 请求url 和 p2 相等 则p2 优先
return 1;
}
        
        // 规则3
if (info1.isPrefixPattern() && info2.getDoubleWildcards() == 0) {
          // 如果p1 是 前缀匹配 且 p2 不包含 /** 则 p2 优先
return 1;
}
else if (info2.isPrefixPattern() && info1.getDoubleWildcards() == 0) {
          //如果p2 是 前缀匹配 且 p1 不包含 /** 则 p1 优先
return -1;
}
        // 规则4
if (info1.getTotalCount() != info2.getTotalCount()) {
          // getTotalCount = this.uriVars + this.singleWildcards + (2 * this.doubleWildcards);
           // 参数匹配个数 + 单个匹配个数 + 多个匹配个数
return info1.getTotalCount() - info2.getTotalCount();
}
        // 规则5
if (info1.getLength() != info2.getLength()) {
          // 正则匹配个数越多 则优先级越高
return info2.getLength() - info1.getLength();
}
        // 规则6
if (info1.getSingleWildcards() < info2.getSingleWildcards()) {
return -1;
}
else if (info2.getSingleWildcards() < info1.getSingleWildcards()) {
return 1;
}
        // 规则7
if (info1.getUriVars() < info2.getUriVars()) {
return -1;
}
else if (info2.getUriVars() < info1.getUriVars()) {
return 1;
} return 0;
}
 

根据上面

规则1: /** 匹配优先级最低 即当请求url其他所有都不能匹配时 则匹配 /**

规则2:路径全匹配优先级最高

规则3:前缀匹配 和 包含/** 匹配 优先级较低

规则4:参数匹配、单个匹配、多个匹配 匹配规则数量越少 则优先级越高

规则5:正则匹配个数越多,则优先级越高 区别于4 这里是和 url进行匹配后进行比较,4中单指 规则中的匹配规则数量

规则6:单匹配 规则少则优先级高

规则7:参数匹配规则少则优先级高

综合上面7个规则

总结如下:

/** 、 abc/** 规则匹配度较低

/abc/def 匹配度最高

/{type}/def 匹配度 高于 /{type}/{name}

/{} /* /** 出现越少 匹配度越高

/{} 优先级 高于 /*

/* 优先级 高于 /**

url:/test/d_d_d/test 进行匹配 则 /test/d_d_d/test > /test/{type}/test >  /test/*/test > /test/{type}_{type}/test > /test/**/test > /test/{type}_{type}_{type}/test > /test/** > /**

SpringMvc如何将Url 映射到 RequestMapping (一)的更多相关文章

  1. SpringMvc如何将Url 映射到 RequestMapping (二)

    昨天简单分析了Springmvc 中 RequestMapping 配置的url和请求url之间的匹配规则.今天详细的跟踪一下一个请求url如何映射到Controller的对应方法上 一.入口 org ...

  2. SpringMVC中url映射到Controller

    SpringMVC也是一种基于请求驱动的WEB框架,并且使用了前端控制器的设计模式.前端控制器就是DispatcherServlet控制器,只要满足web.xml文件中的[url-pattern]的规 ...

  3. SpringMvc的Url映射和传参案例(转)

    Springmvc的基本使用,包括url映射.参数映射.页面跳转.ajax和文件上传 以前学习的时候写的代码案例,今天整理笔记的时候找到了,很久没有来园子了,发上来当个在线笔记用吧,免的时间长了又忘了 ...

  4. SpringMvc的Url映射和传参案例

    Springmvc的基本使用,包括url映射.参数映射.页面跳转.ajax和文件上传 以前学习的时候写的代码案例,今天整理笔记的时候找到了,很久没有来园子了,发上来当个在线笔记用吧,免的时间长了又忘了 ...

  5. 关于requestMapping 进行url映射实现小小知识点 以及如何获取请求的url中的参数

    requstMapping 用来处理url映射  可以作用在controller类上  也可以作用在方法上 经常使用的方式  通过接收一种映射关系 @RequestMapping("/del ...

  6. 应用springMVC时如果配置URL映射时如下配置

    应用springMVC时如果配置URL映射时如下配置 [html] view plaincopy<servlet> <servlet-name>appServlet</s ...

  7. SpringMVC基础03——常用注解之@RequestMapping

    1.用法 SpringMVC使用@RequestMapping注解,为控制器指定可以处理哪些URL请求,并且可以指定处理请求的类型(POST/GET),如果@RequestMapping没有指定请求的 ...

  8. SpringMVC的HandlerMapping(处理器映射器)

    SpringMvc有四种HandlerMapping:BeanNameUrlHandlerMapping ,SimpleUrlHandlerMapping,ControllerClassNameHan ...

  9. springMVC三种处理器映射器

    1.配置处理器映射器,springmvc默认的处理器映射器BeanNameUrlHandlerMapping <bean class="org.springframework.web. ...

随机推荐

  1. HTTP协议漫谈 C#实现图(Graph) C#实现二叉查找树 浅谈进程同步和互斥的概念 C#实现平衡多路查找树(B树)

    HTTP协议漫谈   简介 园子里已经有不少介绍HTTP的的好文章.对HTTP的一些细节介绍的比较好,所以本篇文章不会对HTTP的细节进行深究,而是从够高和更结构化的角度将HTTP协议的元素进行分类讲 ...

  2. 微博试水卖车社交电商怎样令4S“颤抖”?

        微博对社交电商的探索一直在深入,年初.微博上线了"支付"产品.从而使社交产业链实现了闭环,随后,微博又尝试售卖多种商品,不断扩大移动电商的试水范围,近期微博大规模汽车销售收 ...

  3. The type java.lang.reflect.AnnotatedElement cannot be resolved. It is indirectly referenced from required .class files

    我这个错误发生于导入项目的时候..我发现主要是jdk版本的问题.切换一下jdk.直接红叉消失就可以了.....jdk版本一致性还是很重要的

  4. 【iOS9系列】- CoreSportlight内容索引的使用

    [iOS9系列]- CoreSportlight内容索引的使用 前言 在iOS9中新增加了的CoreSportlight内容索引,这个还是比较实用的,当我们的App比较多的时候,我们会实用iOS系统的 ...

  5. 实现@using{}代码块

    前几天,我要写个插件,放在asp.net mvc的view上.这需要写一些扩展HtmlHelper功能的方法.这些方法的一个参数是一段javascript代码. 假如这个参数类型是字符型,当然很简单了 ...

  6. 从Script到Code Blocks、Code Behind到MVC、MVP、MVVM(转载)

    http://www.cnblogs.com/indream/p/3602348.html 刚过去的周五(3-14)例行地主持了技术会议,主题正好是<UI层的设计模式——从Script.Code ...

  7. 再谈HBase八大应用场景

    HBase概述 HBase是一个分布式存储.数据库引擎,可以支持千万的QPS.PB级别的存储,这些都已经在生产环境验证,并且在广大的公司已经验证.特别是阿里.小米.京东.滴滴内部都有数千.上万台的HB ...

  8. 使用css属性line-height实现文字垂直居中的问题

    使用css属性line-height实现文字垂直居中的问题 1.使用css属性line-height实现文字垂直居中 方法比较简单,但是只能实现单行文字的垂直居中. 单行垂直居中效果如下:   要是p ...

  9. mybatis批量操作数据

    批量查询语句: List<MoiraiProductResource> selectBatchInfo(List<Long> idList); <!-- 批量查询 --& ...

  10. jquery a

    <!DOCTYPE html><html><head><script src="//ajax.googleapis.com/ajax/libs/jq ...