What is the difference between /* and /** pattern

2020-08-16 07:41发布

问题:

I was trying to register certain URLs for a Filter when I noticed that there is a difference between /* and /** patterns.

    @Bean
    public FilterRegistrationBean tokenAuthenticationFilterBean() {
        FilterRegistrationBean registration = new FilterRegistrationBean(tokenAuthenticationFilter);
        registration.addUrlPatterns("/api/**","/ping","/api/*");
        return registration;
    }

What is the difference between these patterns?

回答1:

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"

http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/AntPathMatcher.html



回答2:

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"))
    }
}


回答3:

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

}