SpringMVC路径匹配规则AntPathMatcher(转)

SpringMVC的路径匹配规则是依照Ant的来的.

实际上不只是SpringMVC,整个Spring框架的路径解析都是按照Ant的风格来的.

在Spring中的具体实现,详情参见 org.springframework.util.AntPathMatcher.

具体规则如下(来自Spring AntPathMatcher源码注释):

 * {@link PathMatcher} implementation for Ant-style path patterns.
 *
 * <p>Part of this mapping code has been kindly borrowed from <a href="http://ant.apache.org">Apache Ant</a>.
 *
 * <p>The mapping matches URLs using the following rules:<br>
 * <ul>
 * <li>{@code ?} matches one character</li>
 * <li>{@code *} matches zero or more characters</li>
 * <li>{@code **} matches zero or more <em>directories</em> in a path</li>
 * <li>{@code {spring:[a-z]+}} matches the regexp {@code [a-z]+} as a path variable named "spring"</li>
 * </ul>
 *
 * <h3>Examples</h3>
 * <ul>
 * <li>{@code com/t?st.jsp} &mdash; matches {@code com/test.jsp} but also
 * {@code com/tast.jsp} or {@code com/txst.jsp}</li>
 * <li>{@code com/*.jsp} &mdash; matches all {@code .jsp} files in the
 * {@code com} directory</li>
 * <li><code>com/**/test.jsp</code> &mdash; matches all {@code test.jsp}
 * files underneath the {@code com} path</li>
 * <li><code>org/springframework/**/*.jsp</code> &mdash; matches all
 * {@code .jsp} files underneath the {@code org/springframework} path</li>
 * <li><code>org/**/servlet/bla.jsp</code> &mdash; matches
 * {@code org/springframework/servlet/bla.jsp} but also
 * {@code org/springframework/testing/servlet/bla.jsp} and {@code org/servlet/bla.jsp}</li>
 * <li>{@code com/{filename:\\w+}.jsp} will match {@code com/test.jsp} and assign the value {@code test}
 * to the {@code filename} variable</li>
 * </ul>
 *
 * <p><strong>Note:</strong> a pattern and a path must both be absolute or must
 * both be relative in order for the two to match. Therefore it is recommended
 * that users of this implementation to sanitize patterns in order to prefix
 * them with "/" as it makes sense in the context in which they‘re used.

换成人话就是:

  • ? 匹配1个字符
  • * 匹配0个或多个字符
  • ** 匹配路径中的0个或多个目录
  • {spring:[a-z]+} 将正则表达式[a-z]+匹配到的值,赋值给名为 spring 的路径变量.(PS:必须是完全匹配才行,在SpringMVC中只有完全匹配才会进入controller层的方法)

一个一个的分析.

符号 ?

和其它几个不一样的是,? 要求必须为一个字符,并且不能是代表路径分隔符的/.

@RequestMapping("/index?")
@ResponseBody
public String index(){
    System.out.println("11");
    return "11";
}

结果:

index           false 404错误(必须要有一个字符)
index/          false 404错误(不能为"/")
indexab         false 404错误(不能是多个字符)
indexa          true  输出 11

符号 *

*,虽然可以匹配多个任意的字符,但是,如果你以为 * 可以替代 ** 那就错了,* 代表的多个任意字符组成的字符串不能是个 目录 或者说 路径.也就是说,* 并不能拿来替代 **.

示例代码:

@RequestMapping("/index*")
@ResponseBody
public String index(){
    System.out.println("11");
    return "11";
}

结果:

index           true  输出 11(可以为0字符)
index/          true  输出 11(可以为"/")
indexa          true  输出 11(可以为1个字符)
indexabc        true  输出 11(可以为多个字符)
index/a         false 404错误("/a"是一个路径)

符号 **

0个或多个目录.** 代表的字符串本身不一定要包含 /

@RequestMapping("/index/**/a")
@ResponseBody
public String index(){
    System.out.println();
    return "11";
}

结果:

index/a         true  输出 11(可以为0个目录)
index/x/a       true  输出 11(可以为一个目录)
index/x/z/c/a   true  输出 11(可以为多个目录)

符号 {spring:[a-z]+}

其它的关于 AntPathMatcher 的文章里,对 {spring:[a-z]+} 的匹配大多是只字未提.这里补充下.

示例代码:

@RequestMapping("/index/{username:[a-b]+}")
@ResponseBody
public String index(@PathVariable("username") String username){
    System.out.println(username);
    return username;
}

结果:

index/ab        true  输出 ab
index/abbaaa    true  输出 abbaaa
index/a         false 404错误
index/ac        false 404错误

附录(完整测试用例)

节选自 AntPathMatcherTests.不得不说 Spring 的测试用例写的实在是太完善了.

// test exact matching
assertTrue(pathMatcher.match("test", "test"));
assertTrue(pathMatcher.match("/test", "/test"));
assertTrue(pathMatcher.match("http://example.org", "http://example.org")); // SPR-14141
assertFalse(pathMatcher.match("/test.jpg", "test.jpg"));
assertFalse(pathMatcher.match("test", "/test"));
assertFalse(pathMatcher.match("/test", "test"));

// test matching with ?‘s
assertTrue(pathMatcher.match("t?st", "test"));
assertTrue(pathMatcher.match("??st", "test"));
assertTrue(pathMatcher.match("tes?", "test"));
assertTrue(pathMatcher.match("te??", "test"));
assertTrue(pathMatcher.match("?es?", "test"));
assertFalse(pathMatcher.match("tes?", "tes"));
assertFalse(pathMatcher.match("tes?", "testt"));
assertFalse(pathMatcher.match("tes?", "tsst"));

// test matching with *‘s
assertTrue(pathMatcher.match("*", "test"));
assertTrue(pathMatcher.match("test*", "test"));
assertTrue(pathMatcher.match("test*", "testTest"));
assertTrue(pathMatcher.match("test/*", "test/Test"));
assertTrue(pathMatcher.match("test/*", "test/t"));
assertTrue(pathMatcher.match("test/*", "test/"));
assertTrue(pathMatcher.match("*test*", "AnothertestTest"));
assertTrue(pathMatcher.match("*test", "Anothertest"));
assertTrue(pathMatcher.match("*.*", "test."));
assertTrue(pathMatcher.match("*.*", "test.test"));
assertTrue(pathMatcher.match("*.*", "test.test.test"));
assertTrue(pathMatcher.match("test*aaa", "testblaaaa"));
assertFalse(pathMatcher.match("test*", "tst"));
assertFalse(pathMatcher.match("test*", "tsttest"));
assertFalse(pathMatcher.match("test*", "test/"));
assertFalse(pathMatcher.match("test*", "test/t"));
assertFalse(pathMatcher.match("test/*", "test"));
assertFalse(pathMatcher.match("*test*", "tsttst"));
assertFalse(pathMatcher.match("*test", "tsttst"));
assertFalse(pathMatcher.match("*.*", "tsttst"));
assertFalse(pathMatcher.match("test*aaa", "test"));
assertFalse(pathMatcher.match("test*aaa", "testblaaab"));

// test matching with ?‘s and /‘s
assertTrue(pathMatcher.match("/?", "/a"));
assertTrue(pathMatcher.match("/?/a", "/a/a"));
assertTrue(pathMatcher.match("/a/?", "/a/b"));
assertTrue(pathMatcher.match("/??/a", "/aa/a"));
assertTrue(pathMatcher.match("/a/??", "/a/bb"));
assertTrue(pathMatcher.match("/?", "/a"));

// test matching with **‘s
assertTrue(pathMatcher.match("/**", "/testing/testing"));
assertTrue(pathMatcher.match("/*/**", "/testing/testing"));
assertTrue(pathMatcher.match("/**/*", "/testing/testing"));
assertTrue(pathMatcher.match("/bla/**/bla", "/bla/testing/testing/bla"));
assertTrue(pathMatcher.match("/bla/**/bla", "/bla/testing/testing/bla/bla"));
assertTrue(pathMatcher.match("/**/test", "/bla/bla/test"));
assertTrue(pathMatcher.match("/bla/**/**/bla", "/bla/bla/bla/bla/bla/bla"));
assertTrue(pathMatcher.match("/bla*bla/test", "/blaXXXbla/test"));
assertTrue(pathMatcher.match("/*bla/test", "/XXXbla/test"));
assertFalse(pathMatcher.match("/bla*bla/test", "/blaXXXbl/test"));
assertFalse(pathMatcher.match("/*bla/test", "XXXblab/test"));
assertFalse(pathMatcher.match("/*bla/test", "XXXbl/test"));

assertFalse(pathMatcher.match("/????", "/bala/bla"));
assertFalse(pathMatcher.match("/**/*bla", "/bla/bla/bla/bbb"));

assertTrue(pathMatcher.match("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing/"));
assertTrue(pathMatcher.match("/*bla*/**/bla/*", "/XXXblaXXXX/testing/testing/bla/testing"));
assertTrue(pathMatcher.match("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing"));
assertTrue(pathMatcher.match("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing.jpg"));

assertTrue(pathMatcher.match("*bla*/**/bla/**", "XXXblaXXXX/testing/testing/bla/testing/testing/"));
assertTrue(pathMatcher.match("*bla*/**/bla/*", "XXXblaXXXX/testing/testing/bla/testing"));
assertTrue(pathMatcher.match("*bla*/**/bla/**", "XXXblaXXXX/testing/testing/bla/testing/testing"));
assertFalse(pathMatcher.match("*bla*/**/bla/*", "XXXblaXXXX/testing/testing/bla/testing/testing"));

assertFalse(pathMatcher.match("/x/x/**/bla", "/x/x/x/"));

assertTrue(pathMatcher.match("/foo/bar/**", "/foo/bar")) ;

assertTrue(pathMatcher.match("", ""));

assertTrue(pathMatcher.match("/{bla}.*", "/testing.html"));    
时间: 2024-10-16 11:51:11

SpringMVC路径匹配规则AntPathMatcher(转)的相关文章

SpringMVC路径匹配规则AntPathMatcher

? 匹配1个字符 * 匹配0个或多个字符 ** 匹配路径中的0个或多个目录 {spring:[a-z]+} 将正则表达式[a-z]+匹配到的值,赋值给名为 spring 的路径变量.(PS:必须是完全匹配才行,在SpringMVC中只有完全匹配才会进入controller层的方法)

SpringMVC路径匹配规则源码

package cc.zeelan.framework.interceptor.permission; /* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. *

SpringMVC HttpMessageConverter 匹配规则

以下内容,如有问题,烦请指出,谢谢! SpringMVC启动时会自动配置一些HttpMessageConverter,接收到http请求时,从这些Converters中选择一个符合条件的来进行Http序列化/反序列化.在不覆盖默认的HttpMessageConverters的情况下,我们添加的Converter可能会与默认的产生冲突,在某些场景中出现不符合预期的情况. 在上一篇文章的末尾已经列举了一个jsonConverter冲突的情况:添加一个最低优先级的FastJsonConverter后会

Spring Boot实战之定制URL匹配规则

本文首发于个人网站:Spring Boot实战之定制URL匹配规则 构建web应用程序时,并不是所有的URL请求都遵循默认的规则.有时,我们希望RESTful URL匹配的时候包含定界符".",这种情况在Spring中可以称之为"定界符定义的格式":有时,我们希望识别斜杠的存在.Spring提供了接口供开发人员按照需求定制. 在之前的几篇文章中,可以通过WebConfiguration类来定制程序中的过滤器.格式化工具等等,同样得,也可以在这个类中用类似的办法配置&

Nginx学习笔记04URL匹配规则和实际路径

1.1.1. URL匹配规则 匹配规则配置总结: location [=|~|~*|^~] /uri/ {  } 优先级 匹配方式 描述 1最高 = 精确匹配. 2 ^~ 以字符串开头,纯字符串,不支持正则表达式 3 ~* 正则表达式匹配,不区分大小写 3 ~ 正则表达式匹配,区分大小写 3 !~* 正则表达式不匹配,不区分大小写 3 !~ 正则表达式不匹配,区分大小写 4最低 / 通用匹配,匹配所有没匹配前面的条件的路径 当优先级相同的多个location结点都匹配某个请求的URL时,在配置文

Spring MVC的路径匹配

Spring MVC中的路径匹配比起标准web.xml的servlet映射要灵活得多.路径匹配的默认策略是由org.springframework.util.AntPathMatcher实现的.顾名思义,路径模式是采用Apache Ant(http://ant.apache.org)风格路径来编写的.Ant风格路径有三种类型的通配符(列于表5-2中),能相互结合以创建多样灵活的路径模式.见表5-3中的模式例子. 表5-2  Ant通配符字符 通配符描述 ?  匹配一个字符 *  匹配零个或多个字

servlet的url-pattern匹配规则详细描述

一.概述 在利用servlet或Filter进行url请求的匹配时,很关键的一点就是匹配规则,但servlet容器中的匹配规则既不是简单的通配,也不是正则表达式,而是由自己的规则,比较容易混淆.本文来详细举例介绍下.下面的说明都是在tomcat服务器中得到验证的. 先介绍一下匹配的概念,上例子代码.在一个app(如名字为myapp)的web.xml文件中,有如下信息: <servlet> <servlet-name>MyServlet</servlet-name> &l

nginx 的路径匹配

nginx 的路径匹配 = 精确匹配, 后面是文件名, 不能是文件夹 /image 精确匹配, 后面是文件夹, 如果这个匹配到了, 还可能会被正则替换掉 ^~ image 精确匹配, 后面是文件夹, 如果这个匹配到了, 不会继续匹配正则 ~ image 正则 ~* image 正则, 不区分大小写 匹配规则: 普通命中匹配命中最长的 location / { ... } location /image { ... } 正则表达式一旦匹配到就不会再匹配, 因此第二条永远不会被匹配 location

你必须弄懂的Intent Filter匹配规则

Intent简介 Android中提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作.动作涉及数据.附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用.Intent不仅可用于应用程序之间,也可用于应用程序内部的Activity/Service之间的交互.因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦.在SDK中给出了I