RequestMappingInfoHandlerMapping 在处理http请求的时候, 如果 请求url 有后缀,如果找不到精确匹配的那个@RequestMapping方法。
那么,就把后缀去掉,然后.* 去匹配,这样,一般都可以匹配。 比如有一个@RequestMapping("/rest"), 那么精确匹配的情况下, 只会匹配/rest请求。 但如果我前端发来一个 /rest.abcdef 这样的请求, 又没有配置 @RequestMapping("/rest.abcdef") 这样映射的情况下, 那么@RequestMapping("/rest") 就会生效。

原理呢?处理链是这样的:
at org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getMatchingPattern(PatternsRequestCondition.java:254)
at org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getMatchingPatterns(PatternsRequestCondition.java:230)
at org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getMatchingCondition(PatternsRequestCondition.java:210)
at org.springframework.web.servlet.mvc.method.RequestMappingInfo.getMatchingCondition(RequestMappingInfo.java:214)
at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getMatchingMapping(RequestMappingInfoHandlerMapping.java:79)
at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getMatchingMapping(RequestMappingInfoHandlerMapping.java:56)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.addMatchingMappings(AbstractHandlerMethodMapping.java:358)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:328)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:299)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:57)
at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:299)
at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1104)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:916)

关键是PatternsRequestCondition, 具体来说是这个方法

AbstractHandlerMethodMapping 的getHandlerInternal:
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Looking up handler method for path " + lookupPath);
} HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);// 这里是关键,它去寻找,找到了就找到了,找不到就不会再去寻找了
if (this.logger.isDebugEnabled()) {
if (handlerMethod != null) {
this.logger.debug("Returning handler method [" + handlerMethod + "]");
} else {
this.logger.debug("Did not find handler method for [" + lookupPath + "]");
}
} return handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
} protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<AbstractHandlerMethodMapping<T>.Match> matches = new ArrayList();
List<T> directPathMatches = (List)this.urlMap.get(lookupPath); // directPathMatches, 直接匹配, 也可以说是 精确匹配
if (directPathMatches != null) {
this.addMatchingMappings(directPathMatches, matches, request);// 如果能够精确匹配, 就会进来这里
} if (matches.isEmpty()) {
this.addMatchingMappings(this.handlerMethods.keySet(), matches, request);// 如果无法精确匹配, 就会进来这里
} if (!matches.isEmpty()) {
Comparator<AbstractHandlerMethodMapping<T>.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
Collections.sort(matches, comparator);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
} AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (matches.size() > 1) {
AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
} this.handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
} else {
return this.handleNoMatch(this.handlerMethods.keySet(), lookupPath, request);
}
} public List<String> getMatchingPatterns(String lookupPath) {
List<String> matches = new ArrayList();
Iterator var3 = this.patterns.iterator(); while(var3.hasNext()) {
String pattern = (String)var3.next(); // pattern 是 @RequestMapping 提供的映射
String match = this.getMatchingPattern(pattern, lookupPath); // lookupPath + .* 后能够匹配pattern, 那么就不为空
if (match != null) {
matches.add(match);// 对于有后缀的情况, .* 后
}
} Collections.sort(matches, this.pathMatcher.getPatternComparator(lookupPath));
return matches;
} 最关键是这里 getMatchingPatterns :
private String getMatchingPattern(String pattern, String lookupPath) {
if (pattern.equals(lookupPath)) {
return pattern;
} else {
if (this.useSuffixPatternMatch) {
if (!this.fileExtensions.isEmpty() && lookupPath.indexOf(46) != -1) {
Iterator var5 = this.fileExtensions.iterator(); while(var5.hasNext()) {
String extension = (String)var5.next();
if (this.pathMatcher.match(pattern + extension, lookupPath)) {
return pattern + extension;
}
}
} else {
boolean hasSuffix = pattern.indexOf(46) != -1;
if (!hasSuffix && this.pathMatcher.match(pattern + ".*", lookupPath)) {
return pattern + ".*"; // 关键是这里
}
}
} if (this.pathMatcher.match(pattern, lookupPath)) {
return pattern;
} else {
return this.useTrailingSlashMatch && !pattern.endsWith("/") && this.pathMatcher.match(pattern + "/", lookupPath) ? pattern + "/" : null;
}
}
}

而对于AbstractUrlHandlerMapping ,匹配不上就是匹配不上, 不会进行 +.* 后在匹配。

关键方法是这个:

    protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.getApplicationContext().getBean(handlerName);
} this.validateHandler(handler, request);
return this.buildPathExposingHandler(handler, urlPath, urlPath, (Map)null);
} else {
List<String> matchingPatterns = new ArrayList();
Iterator var5 = this.handlerMap.keySet().iterator(); while(var5.hasNext()) {
String registeredPattern = (String)var5.next();
if (this.getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern);
}
} String bestPatternMatch = null;
Comparator<String> patternComparator = this.getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
Collections.sort(matchingPatterns, patternComparator);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
} bestPatternMatch = (String)matchingPatterns.get(0);
} if (bestPatternMatch != null) {
handler = this.handlerMap.get(bestPatternMatch);
String pathWithinMapping;
if (handler instanceof String) {
pathWithinMapping = (String)handler;
handler = this.getApplicationContext().getBean(pathWithinMapping);
} this.validateHandler(handler, request);
pathWithinMapping = this.getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);
Map<String, String> uriTemplateVariables = new LinkedHashMap();
Iterator var9 = matchingPatterns.iterator(); while(var9.hasNext()) {
String matchingPattern = (String)var9.next();
if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
Map<String, String> vars = this.getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
Map<String, String> decodedVars = this.getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
} if (this.logger.isDebugEnabled()) {
this.logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
} return this.buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
} else {
return null;
}
}
}

当然, 或许我们可以设置自定义的PathMatcher ,从而到达目的。 默认的 是AntPathMatcher 。

Spring MVC 之 请求url 带后缀的情况的更多相关文章

  1. spring MVC处理请求过程及配置详解

    本文主要梳理下Spring MVC处理http请求的过程,以及配置servlet及业务application需要的常用标签,及其包含的意义. spring MVC处理请求过程 首先看一个整体图 简单说 ...

  2. spring MVC处理请求过程

    spring MVC处理请求过程 首先看一个整体图 简单说下各步骤: handlerMapping handlerMapping将请求映射到处理器,即图中的HandlerExecutionChain. ...

  3. spring mvc get请求也可以接受DTO对象

    spring mvc get请求也可以接受DTO对象,比如:url上面你还是将参数&符号连接起来,并自动封装进一个DTO对象里. 只有@RequestBody注解spring mvc才会从ht ...

  4. 使用Spring mvc接收整个url地址及参数时注意事项

    使用Spring mvc接收整个url地址及参数时注意事项:url= http://baidu?oid=9525c1f2b2cd45019b30a37bead6ebbb&td=2015-08- ...

  5. 跟踪spring MVC的请求

    当我们点击一个超链接时,spring MVC在后台都做了些什么呢,今天就来看看后台都干了啥 首先需要在web.xml里配置一下:

  6. Spring mvc源码url路由-我们到底能走多远系列(38)

    我们到底能走多远系列38 扯淡: 马航的事,挺震惊的.还是多多珍惜身边的人吧. 主题: Spring mvc 作为表现层的框架,整个流程是比较好理解的,毕竟我们做web开发的,最早也经常接触的就是一个 ...

  7. spring mvc ajax请求

    jar包中增加 jackson-annotations-2.5.0.jar jackson-core-2.5.0.jar jackson-databind-2.5.0.jar springmvx.xm ...

  8. spring mvc get请求中文乱码问题

    使用Spring MVC进行get请求时发现get请求带上中文参数,后台收到的是乱码,即使加了encoding filter也没用. 原因是,encoding filter 是针对post请求的,to ...

  9. Spring MVC 之请求参数和路径变量

    请求参数和路径变量都可以用于发送值给服务器.二者都是URL的一部分.请求参数采用key=value形式,并用“&”分隔. 例如,下面的URL带有一个名为productId的请求参数,其值为3: ...

随机推荐

  1. maven win 安装 与 IntelliJ IDEA 配置Maven【2018-11-14最新最有姿势攻略】

    [博客园cnblogs笔者m-yb原创,转载请加本文博客链接,笔者github: https://github.com/mayangbo666,公众号aandb7,QQ群927113708] http ...

  2. Java集合类框架的最佳实践有哪些?

    1.根据应用需要正确选择要使用的集合类型对性能非常重要,比如:假如知道元素的大小是固定的,那么选用Array类型而不是ArrayList类型更为合适. 2.有些集合类型允许指定初始容量.因此,如果我们 ...

  3. effective java——30使用enum

    1, 枚举太阳系八大行星 package com.enum30.www; public enum Planet {//枚举太阳系八大行星 MERCURY(3.302e+23,2.439e6), VEN ...

  4. Shell脚本的学习笔记二:字符串

    菜鸟教程提供的Shell在线编辑器 Shell 字符串 项目 功能 单引号 原样输出,变量无效.但可用成对单引号嵌套成对单引号输出变量 双引号 定义字符串中附带有变量的命令并且想将其解析后再输出的变量 ...

  5. TensorFlow 神经网络相关函数

    TensorFlow 激活函数 激活操作提供用于神经网络的不同类型的非线性.这些包括平滑的非线性(sigmoid,tanh,elu,softplus,和softsign),连续的,但不是到处可微函数( ...

  6. java面向对象编程(一)-类与对象

    1.问题的提出      张老太养了两只猫猫:一只名字叫小白,今年3岁,白色.还有一只叫小花,今年100岁,花色.请编写一个程序,当用户输入小猫的名字时,就显示该猫的名字,年龄,颜色.如果用户输入的小 ...

  7. .NET并行计算和并发8-QueueUserWorkItem异步

      QueueUserWorkItem方法将非常简单的任务排入队列 下面这个简单的代码,涉及到资源竞争问题,如果主线程先争取到资源,如果没有等待 一段时间,那么QueueUserWorkItem申请的 ...

  8. git教程: 查看文件状态与修改内容

    转载:时光机穿梭 我们已经成功地添加并提交了一个readme.txt文件,现在,是时候继续工作了,于是,我们继续修改readme.txt文件,改成如下内容: Git is a distributed ...

  9. 样本失衡会对SVM的影响

    假设正类样本远多于负类 1.线性可分的情况 假设真实数据集如下: 由于负类样本量太少,可能会出现下面这种情况 使得分隔超平面偏向负类.严格意义上,这种样本不平衡不是因为样本数量的问题,而是因为边界点发 ...

  10. C#语言与变量、数据类型

    一.计算机语言 1.计算机语言包括:C\PHP\Ruby\JAVA\C#\Basi\JS\C++ 2.计算机语言发展史:机器语言——汇编语言——高级语言 二.代码 1.程序始终:Code(编码).Co ...