What is the difference between /* and /** pattern in Spring boot?
Spring normally uses Ant-style path matching patterns for URLs. If you look at the Java docs for the AntPathMatcher
you will see the explanation:
The mapping matches URLs using the following rules:
- ? matches one character
- * matches zero or more characters
- ** matches zero or more directories in a path
- {spring:[a-z]+} matches the regexp [a-z]+ as a path variable named "spring"
there is no /** in registration.addUrlPatterns as we can see in Source code
private static boolean matchFiltersURL(String testPath, String requestPath) {
if (testPath == null)
return false;
// Case 1 - Exact Match
if (testPath.equals(requestPath))
return true;
// Case 2 - Path Match ("/.../*")
if (testPath.equals("/*"))
return true;
if (testPath.endsWith("/*")) {
if (testPath.regionMatches(0, requestPath, 0,
testPath.length() - 2)) {
if (requestPath.length() == (testPath.length() - 2)) {
return true;
} else if ('/' == requestPath.charAt(testPath.length() - 2)) {
return true;
}
}
return false;
}
// Case 3 - Extension Match
if (testPath.startsWith("*.")) {
int slash = requestPath.lastIndexOf('/');
int period = requestPath.lastIndexOf('.');
if ((slash >= 0) && (period > slash)
&& (period != requestPath.length() - 1)
&& ((requestPath.length() - period)
== (testPath.length() - 1))) {
return testPath.regionMatches(2, requestPath, period + 1,
testPath.length() - 2);
}
}
// Case 4 - "Default" Match
return false; // NOTE - Not relevant for selecting filters
}
IMHO code worths 100 words in this case:
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import org.springframework.util.AntPathMatcher
class AntPathMatcherTests {
@Test
fun twoAsterisks() {
val pattern = "/api/balance/**"
val matcher = AntPathMatcher()
val matching = { path: String -> matcher.match(pattern, path) }
assertTrue(matching("/api/balance"))
assertTrue(matching("/api/balance/"))
assertTrue(matching("/api/balance/abc"))
assertTrue(matching("/api/balance/abc/"))
assertTrue(matching("/api/balance/abc/update"))
assertFalse(matching("/api/bala"))
}
@Test
fun oneAsterisk() {
val pattern = "/api/balance/*"
val matcher = AntPathMatcher()
val matching = { path: String -> matcher.match(pattern, path) }
assertTrue(matching("/api/balance/"))
assertTrue(matching("/api/balance/abc"))
assertFalse(matching("/api/bala"))
assertFalse(matching("/api/balance"))
assertFalse(matching("/api/balance/abc/"))
assertFalse(matching("/api/balance/abc/update"))
}
}