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. ...
随机推荐
- 【git体验】git原理及基础
原理:分布式版本号控制系统像 Git,Mercurial,Bazaar 以及 Darcs 等,client并不仅仅提取最新版本号 的文件快照,而是把原始的代码仓库完整地镜像下来. 这么一来.不论什么一 ...
- Codeforces 480B Long Jumps 规律题
题目链接:点击打开链接 题意: 输出n l x y 有一根直尺长度为l 上面有n个刻度. 以下n个数字是距离开头的长度(保证第一个数字是0,最后一个数字是l) 要使得 直尺中存在某2个刻度的距离为x ...
- [IT学习]Python如何处理异常特殊字符
欢迎访问www.cnblogs.com/viphhs A byte of Python<输入与输出>一节中有一个处理回文的小例子(io_input.py).作者留了个思考题. 如何将标点去 ...
- Hackrank Kingdom Division 树形DP
题目链接:传送门 题意: 给你一棵树,n个点 每个点可以染成红色和蓝色 但是红色的点与其相邻的点中必须有红色节点,蓝色也是 问你有多少种染色的方案 题解: 树形dp 先转化为有根树,取1为根 设定dp ...
- apache使用总结
由于某些原因,经常会使用apache(有时用nginx) 现在我主要用它做反向代理,偶尔弄一下负载均衡和添加head头 apache官网 http://httpd.apache.org/ 下载地址 h ...
- vue学习1
1.<div id="app">{{message}}<input v-model="message"></div>new ...
- 设计模式-(9)中介者模式(swift)
在对象去耦合的模式中,有两种模式:中介者模式,观察者模式 一,概念 用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互. 这个 ...
- String StringBuffer StringBuilder 对比
1.StringBuffer是线程安全的,StringBuilder是非线程安全的 2.对String的修改其实是new了一个StringBuilder并调用append方法,然后调用toSt ...
- 利用JS 阻止表单提交
情景一:不存在Ajax异步操作 1 使用背景:会议室预定管理系统中,当表单提交的时候需要验证预约的时间是否符合预定规则(不需要通过访问服务器),否则提示错误信息,阻止表单提交. 2 相关技术点: fo ...
- C# QRCode 二维码
/*********************************************************************** * C# QRCode 二维码 * 说明: * 本文记 ...