diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlProvider.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlProvider.java index 2884ae6993..9a3b1dea0f 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlProvider.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlProvider.java @@ -18,6 +18,7 @@ package org.springframework.web.servlet.resource; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -191,6 +192,8 @@ public class ResourceUrlProvider implements ApplicationListenerIt is expected that the given path is what Spring MVC would use for * request mapping purposes, i.e. excluding context and servlet path portions. + *

If several handler mappings match, the handler used will be the one + * configured with the most specific pattern. * @param lookupPath the lookup path to check * @return the resolved public URL path, or {@code null} if unresolved */ @@ -198,25 +201,32 @@ public class ResourceUrlProvider implements ApplicationListener patternComparator = getPathMatcher().getPatternComparator(lookupPath); + Collections.sort(matchingPatterns, patternComparator); + for(String pattern : matchingPatterns) { + String pathWithinMapping = getPathMatcher().extractPathWithinPattern(pattern, lookupPath); + String pathMapping = lookupPath.substring(0, lookupPath.indexOf(pathWithinMapping)); + if (logger.isTraceEnabled()) { + logger.trace("Invoking ResourceResolverChain for URL pattern=\"" + pattern + "\""); + } + ResourceHttpRequestHandler handler = this.handlerMap.get(pattern); + ResourceResolverChain chain = new DefaultResourceResolverChain(handler.getResourceResolvers()); + String resolved = chain.resolveUrlPath(pathWithinMapping, handler.getLocations()); + if (resolved == null) { + continue; + } + if (logger.isTraceEnabled()) { + logger.trace("Resolved public resource URL path=\"" + resolved + "\""); + } + return pathMapping + resolved; } - ResourceHttpRequestHandler handler = this.handlerMap.get(pattern); - ResourceResolverChain chain = new DefaultResourceResolverChain(handler.getResourceResolvers()); - String resolved = chain.resolveUrlPath(pathWithinMapping, handler.getLocations()); - if (resolved == null) { - continue; - } - if (logger.isTraceEnabled()) { - logger.trace("Resolved public resource URL path=\"" + resolved + "\""); - } - return pathMapping + resolved; } logger.debug("No matching resource mapping"); return null; diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderTests.java index d504d6820b..98966a01f0 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderTests.java @@ -44,6 +44,8 @@ import static org.junit.Assert.*; */ public class ResourceUrlProviderTests { + private List locations; + private ResourceUrlProvider translator; private ResourceHttpRequestHandler handler; @@ -53,9 +55,9 @@ public class ResourceUrlProviderTests { @Before public void setUp() { - List locations = new ArrayList(); - locations.add(new ClassPathResource("test/", getClass())); - locations.add(new ClassPathResource("testalternatepath/", getClass())); + this.locations = new ArrayList(); + this.locations.add(new ClassPathResource("test/", getClass())); + this.locations.add(new ClassPathResource("testalternatepath/", getClass())); this.handler = new ResourceHttpRequestHandler(); this.handler.setLocations(locations); @@ -94,6 +96,28 @@ public class ResourceUrlProviderTests { this.translator.setHandlerMap(this.handlerMap); } + // SPR-12647 + @Test + public void bestPatternMatch() throws Exception { + ResourceHttpRequestHandler otherHandler = new ResourceHttpRequestHandler(); + otherHandler.setLocations(this.locations); + Map versionStrategyMap = new HashMap<>(); + versionStrategyMap.put("/**", new ContentVersionStrategy()); + VersionResourceResolver versionResolver = new VersionResourceResolver(); + versionResolver.setStrategyMap(versionStrategyMap); + + List resolvers = new ArrayList(); + resolvers.add(versionResolver); + resolvers.add(new PathResourceResolver()); + otherHandler.setResourceResolvers(resolvers); + + this.handlerMap.put("/resources/*.css", otherHandler); + initTranslator(); + + String url = this.translator.getForLookupPath("/resources/foo.css"); + assertEquals("/resources/foo-e36d2e05253c6c7085a91522ce43a0b4.css", url); + } + // SPR-12592 @Test public void initializeOnce() throws Exception {