Spring中的所有路径匹配问题总结

本文探讨了Spring中如何正确匹配所有以.do结尾的请求,指出网上常见答案的错误,并提供了正确解决方案:/**/*.do。同时,文章提到了Spring中的AntMatcher规则,解释了其与正则和通配符的区别,以及AntPathMatcher类在路径匹配中的作用,包括路径分隔符的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于Spring的路径, 问的最多的问题就是如何拦截所有以.do结尾的请求.
大家都是在猜, 网上给出的答案五花八门, 比如: *do, /*do, /**do, /** 等..然而这些都是错的.
正确答案是/**/*.do, 如果要拦截/api下的所有.do结尾的请求, 那么应该使用/api/**/*.do, 以此类推.
我觉得这是一个很恶心的东西. 关于字符串匹配, 存在三个常用的规则: 正则, AntMatcher和通配符. 恶心的是这三者都使用了?和*, 而且意义各不同. 真是一件让程序员苦恼的事.

言归正传, Spring中无论是handler路径映射, 还是interceptor路径匹配, 还是sping.xml中加载配置文件时使用的”classpath*”, 都使用的是AntMathcer规则( 见PathMatcher文档), 实现类是org.springframework.util.AntPathMatcher. 这里是这个类的官方文档AntPathMatcher文档
里面有这样的说明

匹配符规则
?匹配一个字符
*匹配0或更多字符
**匹配path路径中的0个或更多目录
{spring:[a-z]+}匹配正则[a-z]+并作为一个路径变量, 赋值给变量spring

注意在AntPathMatcher中, 有个路径分隔符的概念, 路径分隔符是不能被 ? 或单个 * 匹配的, 路径分隔符默认是 / , 在匹配类全限定名时, 设置成 . 其他规则不变.

以下是简单的介绍: (注意**可以匹配0个或更多的目录)

规则简介匹配不匹配
/goods/t?st.jsp/goods路径下只相差一个字符的路径/good/test.jsp /goods/text.jsp /goods/tast.jsp等/goods/taast.jsp /google/tast.jsp等
/**/test.jsp匹配任何以test.jsp结尾的路径/test.jsp/goods/test.jsp /my/goods/test.jsp /my/favorite/goods/test.jsp等/goods/abc.jsp等
/**/*.jsp任何以jsp结尾的路径/test.jsp /goods/test.jsp /my/goods/test.jsp等/hello.html /my/hello.html等
/goods/**匹配goods下的所有路径/goods /goods/a.html /goods/a.jsp /goods/test/a.jsp等非/goods/下的路径
/或/goods只匹配/或/goods这一个路径,千万不要误认为是所有路径只有/和/goods其他任何路径
/**匹配所有路径/test/goods/test /test.html /test.jsp /goods/test.jsp /my/goods/test.jsp等

完整用法可见Sping的托管在github的测试代码AntPathMatcherTests.java

以下是我从中摘取的一部分. 可以不用看这个.

// 完全匹配
        assertTrue(pathMatcher.match("test", "test"));
        assertTrue(pathMatcher.match("/test", "/test"));
        //不匹配
        assertFalse(pathMatcher.match("/test.jpg", "test.jpg"));
        assertFalse(pathMatcher.match("test", "/test"));
// 使用?进行匹配, ?表示匹配一个字符
        assertTrue(pathMatcher.match("t?st", "test"));
        assertTrue(pathMatcher.match("??st", "test"));
        //不匹配
        assertFalse(pathMatcher.match("tes?", "tes"));
        assertFalse(pathMatcher.match("tes?", "testt"));
//使用*进行匹配, *匹配0    更多字符
        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."));
        assertTrue(pathMatcher.match("*.*", "test.test.test"));
        //以下不匹配
        assertFalse(pathMatcher.match("test*", "tst"));
        assertFalse(pathMatcher.match("test*", "tsttest"));
        assertFalse(pathMatcher.match("test*", "test/"));
        assertFalse(pathMatcher.match("test/*", "test"));
// 使用?和/一起匹配
        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"));

// 使用**匹配, 匹配0个或更多目录
        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("/*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"));

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

        assertTrue(pathMatcher.match("/{bla}.*", "/testing.html"));
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值