当我们使用 @RequestMapping 注解去标记请求接口的时候(或者使用它的类似方法如 @GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping),我们可以使用一些通配符去匹配 URL 地址,举个简单例子,假设有下面五个接口:
@GetMapping("/hello/**/hello")
public String hello() {
return "/hello/**/hello";
}
@GetMapping("/h?llo")
public String hello2() {
return "/h?llo";
}
@GetMapping("/**/*.html")
public String hello3() {
return "/**/*.html";
}
@GetMapping("/hello/{p1}/{p2}")
public String hello4(@PathVariable String p1, @PathVariable String p2) {
System.out.println("p1 = " + p1);
System.out.println("p2 = " + p2);
return "/hello/{p1}/{p2}";
}
@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}")
public void handle(@PathVariable String name, @PathVariable String version, @PathVariable String ext) {
System.out.println("name = " + name);
System.out.println("version = " + version);
System.out.println("ext = " + ext);
}
在解释接口的含义之前,先来说说这几个通配符的含义:
通配符 | 含义 |
---|---|
** | 匹配0个或者多个目录 |
* | 匹配0个或者多个字符 |
? | 匹配任意单个字符 |
了解了通配符的含义,我们再来说说各个接口都能接收哪些请求:
- 第一个接口,可以接收诸如 /hello/123/123/hello、/hello/a/hello 以及 /hello/hello 这样的请求,因为中间的 ** 代表 0 个或者多个目录。
- 第二个接口,可以接收诸如 /hallo、/hello、/hMllo 之类的请求,注意它不能接收 /haallo 或者 /hllo,因为 ? 表示一个字符。
- 第三个接口可以接收任意以 .html 为后缀的请求,例如 /aaa/bb/cc.html、/aa.html 或者 /aa/aa.html。
- 第四个接口估计大家都比较熟悉,在 RESTful 风格的接口设计中估计大家都用过,它接收的请求格式类似于 /hello/aa/bb,其中参数 p1 就对应 aa,参数 p2 对应 bb。
- 第五个接口则用到了正则,name、version 以及 ext 三个参数格式用正则表达出来,它可以接收诸如 /spring-web-3.0.5.jar 格式的请求,最终的参数 name 就是 spring-web,version 就是 3.0.5,ext 则是 .jar。
- 这是 SpringMVC 中之前就存在的功能,不管你用没用过,反正它一致存在。
那么是谁支撑了这个功能呢?那就是 AntPathMatcher。
AntPathMatcher 是一个实现了 Ant 风格的路径匹配器,Ant 风格的路径规则实际上就是我们前面给大家介绍的那三种路径匹配符,很 Easy。这种路径匹配规则源自 Apache Ant 项目(https://ant.apache.org),Apache Ant 我们现在其实已经很少会用到了,它的替代品就是大家所熟知的 Maven,如果你有幸维护一些 2010 年之前的老项目的话,有可能会接触到 Ant。
- AntPathMatcher 实际上在 SpringMVC 中有非常广泛的应用,不仅仅是在 @RequestMapping 中定义接口用到,在其他一些涉及到地址匹配的地方也会用到,例如我们在 SpringMVC 的配置文件中配置静态资源过滤时,也是 Ant 风格路径匹配:
<mvc:resources mapping="/**" location="/"/>
另外像拦截器里的拦截路径注册、跨域处理时的路径匹配等等,都会用到 Ant 风格的路径匹配符。
整体上来说,AntPathMatcher 是 Spring 中一种比较原始的路径匹配解决方案,虽然比较简单,但是它的效率很低,并且在处理 URL 编码的时候也很不方便。
因此,才有了 Spring5 中的 PathPattern