SpringMvc如何将Url 映射到 RequestMapping (一)
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 (一)的更多相关文章
- SpringMvc如何将Url 映射到 RequestMapping (二)
昨天简单分析了Springmvc 中 RequestMapping 配置的url和请求url之间的匹配规则.今天详细的跟踪一下一个请求url如何映射到Controller的对应方法上 一.入口 org ...
- SpringMVC中url映射到Controller
SpringMVC也是一种基于请求驱动的WEB框架,并且使用了前端控制器的设计模式.前端控制器就是DispatcherServlet控制器,只要满足web.xml文件中的[url-pattern]的规 ...
- SpringMvc的Url映射和传参案例(转)
Springmvc的基本使用,包括url映射.参数映射.页面跳转.ajax和文件上传 以前学习的时候写的代码案例,今天整理笔记的时候找到了,很久没有来园子了,发上来当个在线笔记用吧,免的时间长了又忘了 ...
- SpringMvc的Url映射和传参案例
Springmvc的基本使用,包括url映射.参数映射.页面跳转.ajax和文件上传 以前学习的时候写的代码案例,今天整理笔记的时候找到了,很久没有来园子了,发上来当个在线笔记用吧,免的时间长了又忘了 ...
- 关于requestMapping 进行url映射实现小小知识点 以及如何获取请求的url中的参数
requstMapping 用来处理url映射 可以作用在controller类上 也可以作用在方法上 经常使用的方式 通过接收一种映射关系 @RequestMapping("/del ...
- 应用springMVC时如果配置URL映射时如下配置
应用springMVC时如果配置URL映射时如下配置 [html] view plaincopy<servlet> <servlet-name>appServlet</s ...
- SpringMVC基础03——常用注解之@RequestMapping
1.用法 SpringMVC使用@RequestMapping注解,为控制器指定可以处理哪些URL请求,并且可以指定处理请求的类型(POST/GET),如果@RequestMapping没有指定请求的 ...
- SpringMVC的HandlerMapping(处理器映射器)
SpringMvc有四种HandlerMapping:BeanNameUrlHandlerMapping ,SimpleUrlHandlerMapping,ControllerClassNameHan ...
- springMVC三种处理器映射器
1.配置处理器映射器,springmvc默认的处理器映射器BeanNameUrlHandlerMapping <bean class="org.springframework.web. ...
随机推荐
- C#中泛型方法与泛型接口 C#泛型接口 List<IAll> arssr = new List<IAll>(); interface IPerson<T> c# List<接口>小技巧 泛型接口协变逆变的几个问题
http://blog.csdn.net/aladdinty/article/details/3486532 using System; using System.Collections.Generi ...
- 我的家乡:三河古镇已经登上央视CCTV-1新闻联播啦!
在烟雨朦胧时走在古镇的青石街上,别有一番风味!第一幅图为央视的直播车,第二副图为漂亮的三河夜景色!
- oracle多表关联多字段update
多表关联多字段update 有代码有J8: update spatial_references set( auth_name, auth_srid, falsex, falsey, xyunits, ...
- 2016/05/17 thinkphp3.2.2 ① Ajax 使用 ②前端验证
显示效果: ①Ajax使用: 注意传值的所有过程用的是小写,及时数据库列的名称中有大写字母 控制器部分: AjaxController.class.php <?php namespace H ...
- 2016/05/11 Thinkphp 3.2.2 验证码 使用 及校验
先新建一个公共控制器,用于放置验证码的实例化代码(不用新建控制器也行,任意公共控制器都可以). 例如:PublicController.class.php 4 5 6 7 8 9 10 11 12 1 ...
- [JS进阶] HTML5 之文件操作(file)
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/oscar999/article/details/37499743 前言 在 HTML 文档中 < ...
- mysql16---读写分离
读写分离(负载平衡)(读写分离肯定要用到主从复制) 如果数据库压力很大,一台机器支撑不了,那么可以用mysql复制实现多台机器同步,将数据库的压力分散. 分表不能解决并发量大的问题. Sql语句发过来 ...
- 洛谷P2943 清理——DP
题目:https://www.luogu.org/problemnew/show/P2943 一眼看去就有个 n^2 的做法:f[i] = min{ f[j] + num( i - j ) * num ...
- vue 生命周期钩子 过滤器 计算属性
每一个Vue实例在被创建之前都要经过一系列的初始化过程.例如,实例需要配置数据观测.编译模板.挂载实例到DOM,然后在数据变化时更新DOM,在这个过程中,实例也会调用一些生命周期钩子,这就给我们提供了 ...
- Extjs4 登陆界面
原文地址:http://fengxinnl.iteye.com/blog/1950585 <script src="ext4.2/bootstrap.js" type=&qu ...