Polish static resource handling mechanism

- ResourceResolver and ResourceResolverChain now have a consistent API
  with regard to method names and terminology.

- ResourceResolver and ResourceResolverChain now accept
  List<? extends Resource> instead of List<Resource> for simplified
  programmatic use.

- Improved Javadoc across the package.

- Formatted code to align with standards.

- Removed all references to ResourceUrlPathTranslator.

Issue: SPR-10933
This commit is contained in:
Sam Brannen 2014-04-22 10:48:12 -04:00
parent cd13b4882c
commit 3d18cfeab6
12 changed files with 135 additions and 121 deletions

View File

@ -28,30 +28,32 @@ import org.springframework.util.Assert;
/** /**
* A default implementation of * A default implementation of {@link ResourceResolverChain} for invoking a list
* {@link org.springframework.web.servlet.resource.ResourceResolverChain ResourceResolverChain} * of {@link ResourceResolver}s.
* for invoking a list of {@link ResourceResolver}s.
* *
* @author Jeremy Grelle * @author Jeremy Grelle
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Sam Brannen
* @since 4.1 * @since 4.1
*/ */
class DefaultResourceResolverChain implements ResourceResolverChain { class DefaultResourceResolverChain implements ResourceResolverChain {
private static Log logger = LogFactory.getLog(DefaultResourceResolverChain.class); private static final Log logger = LogFactory.getLog(DefaultResourceResolverChain.class);
private final List<ResourceResolver> resolvers = new ArrayList<ResourceResolver>(); private final List<ResourceResolver> resolvers = new ArrayList<ResourceResolver>();
private int index = -1; private int index = -1;
public DefaultResourceResolverChain(List<ResourceResolver> resolvers) { public DefaultResourceResolverChain(List<? extends ResourceResolver> resolvers) {
this.resolvers.addAll((resolvers != null) ? resolvers : new ArrayList<ResourceResolver>()); if (resolvers != null) {
this.resolvers.addAll(resolvers);
}
} }
@Override @Override
public Resource resolveResource(HttpServletRequest request, String requestPath, List<Resource> locations) { public Resource resolveResource(HttpServletRequest request, String requestPath, List<? extends Resource> locations) {
ResourceResolver resolver = getNextResolver(); ResourceResolver resolver = getNextResolver();
if (resolver == null) { if (resolver == null) {
return null; return null;
@ -68,14 +70,14 @@ class DefaultResourceResolverChain implements ResourceResolverChain {
} }
@Override @Override
public String resolveUrlPath(String resourcePath, List<Resource> locations) { public String resolvePublicUrlPath(String resourcePath, List<? extends Resource> locations) {
ResourceResolver resolver = getNextResolver(); ResourceResolver resolver = getNextResolver();
if (resolver == null) { if (resolver == null) {
return null; return null;
} }
try { try {
logBefore(resolver); logBefore(resolver);
String urlPath = resolver.getPublicUrlPath(resourcePath, locations, this); String urlPath = resolver.resolvePublicUrlPath(resourcePath, locations, this);
logAfter(resolver, urlPath); logAfter(resolver, urlPath);
return urlPath; return urlPath;
} }

View File

@ -30,7 +30,6 @@ import org.springframework.util.DigestUtils;
import org.springframework.util.FileCopyUtils; import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* A {@code ResourceResolver} that resolves request paths containing an additional * A {@code ResourceResolver} that resolves request paths containing an additional
* MD5 hash in the file name. * MD5 hash in the file name.
@ -48,18 +47,19 @@ import org.springframework.util.StringUtils;
* *
* @author Jeremy Grelle * @author Jeremy Grelle
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Sam Brannen
* @since 4.1 * @since 4.1
*/ */
public class FingerprintResourceResolver implements ResourceResolver { public class FingerprintResourceResolver implements ResourceResolver {
private static final Log logger = LogFactory.getLog(FingerprintResourceResolver.class); private static final Log logger = LogFactory.getLog(FingerprintResourceResolver.class);
private final Pattern pattern = Pattern.compile("-(\\S*)\\."); private static final Pattern pattern = Pattern.compile("-(\\S*)\\.");
@Override @Override
public Resource resolveResource(HttpServletRequest request, String requestPath, public Resource resolveResource(HttpServletRequest request, String requestPath, List<? extends Resource> locations,
List<Resource> locations, ResourceResolverChain chain) { ResourceResolverChain chain) {
Resource resolved = chain.resolveResource(request, requestPath, locations); Resource resolved = chain.resolveResource(request, requestPath, locations);
if (resolved != null) { if (resolved != null) {
@ -82,13 +82,13 @@ public class FingerprintResourceResolver implements ResourceResolver {
return baseResource; return baseResource;
} }
else { else {
logger.debug("Potential resource found for ["+requestPath+"], but fingerprint doesn't match."); logger.debug("Potential resource found for [" + requestPath + "], but fingerprint doesn't match.");
return null; return null;
} }
} }
private String extractHash(String path) { private String extractHash(String path) {
Matcher matcher = this.pattern.matcher(path); Matcher matcher = pattern.matcher(path);
if (matcher.find()) { if (matcher.find()) {
String match = matcher.group(1); String match = matcher.group(1);
return match.contains("-") ? match.substring(match.lastIndexOf("-") + 1) : match; return match.contains("-") ? match.substring(match.lastIndexOf("-") + 1) : match;
@ -104,19 +104,20 @@ public class FingerprintResourceResolver implements ResourceResolver {
return DigestUtils.md5DigestAsHex(content); return DigestUtils.md5DigestAsHex(content);
} }
catch (IOException e) { catch (IOException e) {
logger.error("Failed to calculate hash on resource [" + resource.toString()+"]"); logger.error("Failed to calculate hash for resource [" + resource + "]");
return ""; return "";
} }
} }
@Override @Override
public String getPublicUrlPath(String resourceUrlPath, List<Resource> locations, ResourceResolverChain chain) { public String resolvePublicUrlPath(String resourceUrlPath, List<? extends Resource> locations,
String baseUrl = chain.resolveUrlPath(resourceUrlPath, locations); ResourceResolverChain chain) {
String baseUrl = chain.resolvePublicUrlPath(resourceUrlPath, locations);
if (StringUtils.hasText(baseUrl)) { if (StringUtils.hasText(baseUrl)) {
Resource original = chain.resolveResource(null, resourceUrlPath, locations); Resource original = chain.resolveResource(null, resourceUrlPath, locations);
String hash = calculateHash(original); String hash = calculateHash(original);
return StringUtils.stripFilenameExtension(baseUrl) return StringUtils.stripFilenameExtension(baseUrl) + "-" + hash + "."
+ "-" + hash + "." + StringUtils.getFilenameExtension(baseUrl); + StringUtils.getFilenameExtension(baseUrl);
} }
return baseUrl; return baseUrl;
} }

View File

@ -40,6 +40,7 @@ import org.springframework.core.io.Resource;
* *
* @author Jeremy Grelle * @author Jeremy Grelle
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Sam Brannen
* @since 4.1 * @since 4.1
*/ */
public class GzipResourceResolver implements ResourceResolver { public class GzipResourceResolver implements ResourceResolver {
@ -48,8 +49,8 @@ public class GzipResourceResolver implements ResourceResolver {
@Override @Override
public Resource resolveResource(HttpServletRequest request, String requestPath, public Resource resolveResource(HttpServletRequest request, String requestPath, List<? extends Resource> locations,
List<Resource> locations, ResourceResolverChain chain) { ResourceResolverChain chain) {
Resource resource = chain.resolveResource(request, requestPath, locations); Resource resource = chain.resolveResource(request, requestPath, locations);
if ((resource == null) || !isGzipAccepted(request)) { if ((resource == null) || !isGzipAccepted(request)) {
@ -75,8 +76,9 @@ public class GzipResourceResolver implements ResourceResolver {
} }
@Override @Override
public String getPublicUrlPath(String resourceUrlPath, List<Resource> locations, ResourceResolverChain chain) { public String resolvePublicUrlPath(String resourceUrlPath, List<? extends Resource> locations,
return chain.resolveUrlPath(resourceUrlPath, locations); ResourceResolverChain chain) {
return chain.resolvePublicUrlPath(resourceUrlPath, locations);
} }

View File

@ -25,7 +25,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
/** /**
* A simple {@code ResourceResolver} that tries to find a resource under the given * A simple {@code ResourceResolver} that tries to find a resource under the given
* locations matching to the request path. * locations matching to the request path.
@ -35,6 +34,7 @@ import org.springframework.core.io.Resource;
* *
* @author Jeremy Grelle * @author Jeremy Grelle
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Sam Brannen
* @since 4.1 * @since 4.1
*/ */
public class PathResourceResolver implements ResourceResolver { public class PathResourceResolver implements ResourceResolver {
@ -43,18 +43,18 @@ public class PathResourceResolver implements ResourceResolver {
@Override @Override
public Resource resolveResource(HttpServletRequest request, public Resource resolveResource(HttpServletRequest request, String requestPath, List<? extends Resource> locations,
String requestPath, List<Resource> locations, ResourceResolverChain chain) { ResourceResolverChain chain) {
return getResource(requestPath, locations); return getResource(requestPath, locations);
} }
@Override @Override
public String getPublicUrlPath(String resourceUrlPath, List<Resource> locations, ResourceResolverChain chain) { public String resolvePublicUrlPath(String resourceUrlPath, List<? extends Resource> locations,
ResourceResolverChain chain) {
return (getResource(resourceUrlPath, locations) != null) ? resourceUrlPath : null; return (getResource(resourceUrlPath, locations) != null) ? resourceUrlPath : null;
} }
private Resource getResource(String path, List<Resource> locations) { private Resource getResource(String path, List<? extends Resource> locations) {
for (Resource location : locations) { for (Resource location : locations) {
try { try {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.web.servlet.resource; package org.springframework.web.servlet.resource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
@ -35,22 +36,24 @@ import java.util.List;
* it causes only actually modified resources to be reloaded. * it causes only actually modified resources to be reloaded.
* *
* @author Brian Clozel * @author Brian Clozel
* @author Sam Brannen
* @since 4.1 * @since 4.1
*/ */
public class PrefixResourceResolver implements ResourceResolver { public class PrefixResourceResolver implements ResourceResolver {
private final String prefix; private final String prefix;
public PrefixResourceResolver(String prefix) { public PrefixResourceResolver(String prefix) {
Assert.hasText(prefix, "resource path prefix should not be null"); Assert.hasText(prefix, "prefix must not be null or empty");
this.prefix = prefix.startsWith("/") ? prefix : "/" + prefix; this.prefix = prefix.startsWith("/") ? prefix : "/" + prefix;
} }
@Override @Override
public Resource resolveResource(HttpServletRequest request, public Resource resolveResource(HttpServletRequest request, String requestPath, List<? extends Resource> locations,
String requestPath, List<Resource> locations, ResourceResolverChain chain) { ResourceResolverChain chain) {
if(requestPath.startsWith(this.prefix)) { if (requestPath.startsWith(this.prefix)) {
requestPath = requestPath.substring(this.prefix.length()); requestPath = requestPath.substring(this.prefix.length());
} }
@ -58,8 +61,10 @@ public class PrefixResourceResolver implements ResourceResolver {
} }
@Override @Override
public String getPublicUrlPath(String resourceUrlPath, List<Resource> locations, ResourceResolverChain chain) { public String resolvePublicUrlPath(String resourceUrlPath, List<? extends Resource> locations,
String baseUrl = chain.resolveUrlPath(resourceUrlPath, locations); ResourceResolverChain chain) {
String baseUrl = chain.resolvePublicUrlPath(resourceUrlPath, locations);
return this.prefix + (baseUrl.startsWith("/") ? baseUrl : "/" + baseUrl); return this.prefix + (baseUrl.startsWith("/") ? baseUrl : "/" + baseUrl);
} }
} }

View File

@ -34,9 +34,9 @@ import java.util.Map;
/** /**
* A central component aware of Spring MVC handler mappings for serving static * A central component for serving static resources that is aware of Spring MVC
* resources that provides methods to determine the public URL path clients * handler mappings and provides methods to determine the public URL path that
* should to access static resource. * a client should use to access a static resource.
* *
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @since 4.1 * @since 4.1
@ -45,7 +45,6 @@ public class PublicResourceUrlProvider implements ApplicationListener<ContextRef
protected final Log logger = LogFactory.getLog(getClass()); protected final Log logger = LogFactory.getLog(getClass());
private UrlPathHelper pathHelper = new UrlPathHelper(); private UrlPathHelper pathHelper = new UrlPathHelper();
private PathMatcher pathMatcher = new AntPathMatcher(); private PathMatcher pathMatcher = new AntPathMatcher();
@ -154,8 +153,8 @@ public class PublicResourceUrlProvider implements ApplicationListener<ContextRef
* URL path to expose for public use. * URL path to expose for public use.
* *
* @param request the current request * @param request the current request
* @param requestUrl the request URL path to translate * @param requestUrl the request URL path to resolve
* @return the translated resource URL path or {@code null} * @return the resolved public URL path or {@code null} if unresolved
*/ */
public final String getForRequestUrl(HttpServletRequest request, String requestUrl) { public final String getForRequestUrl(HttpServletRequest request, String requestUrl) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
@ -181,19 +180,18 @@ public class PublicResourceUrlProvider implements ApplicationListener<ContextRef
/** /**
* Compare the given path against configured resource handler mappings and * Compare the given path against configured resource handler mappings and
* if a match is found use the {@code ResourceResolver} chain of the matched * if a match is found use the {@code ResourceResolver} chain of the matched
* {@code ResourceHttpRequestHandler} to determine the URL path to expose for * {@code ResourceHttpRequestHandler} to resolve the URL path to expose for
* public use. * public use.
* *
* <p>It is expected the given path is what Spring MVC would use for request * <p>It is expected the given path is what Spring MVC would use for request
* mapping purposes, i.e. excluding context and servlet path portions. * mapping purposes, i.e. excluding context and servlet path portions.
* *
* @param lookupPath the look path to check * @param lookupPath the lookup path to check
* * @return the resolved public URL path or {@code null} if unresolved
* @return the resolved URL path or {@code null} if unresolved
*/ */
public final String getForLookupPath(String lookupPath) { public final String getForLookupPath(String lookupPath) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Checking lookup path=" + lookupPath); logger.debug("Checking lookup path: " + lookupPath);
} }
for (String pattern : this.handlerMap.keySet()) { for (String pattern : this.handlerMap.keySet()) {
if (!getPathMatcher().match(pattern, lookupPath)) { if (!getPathMatcher().match(pattern, lookupPath)) {
@ -207,7 +205,7 @@ public class PublicResourceUrlProvider implements ApplicationListener<ContextRef
} }
ResourceHttpRequestHandler handler = this.handlerMap.get(pattern); ResourceHttpRequestHandler handler = this.handlerMap.get(pattern);
ResourceResolverChain chain = handler.createResourceResolverChain(); ResourceResolverChain chain = handler.createResourceResolverChain();
String resolved = chain.resolveUrlPath(pathWithinMapping, handler.getLocations()); String resolved = chain.resolvePublicUrlPath(pathWithinMapping, handler.getLocations());
if (resolved == null) { if (resolved == null) {
throw new IllegalStateException("Failed to get public resource URL path for " + pathWithinMapping); throw new IllegalStateException("Failed to get public resource URL path for " + pathWithinMapping);
} }

View File

@ -23,9 +23,8 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
/** /**
* An interceptor that exposes the * An interceptor that exposes the {@link PublicResourceUrlProvider} instance it
* {@link PublicResourceUrlProvider ResourceUrlPathTranslator} * is configured with as a request attribute.
* instance it is configured with as a request attribute.
* *
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @since 4.1 * @since 4.1
@ -33,8 +32,7 @@ import javax.servlet.http.HttpServletResponse;
public class PublicResourceUrlProviderExposingInterceptor extends HandlerInterceptorAdapter { public class PublicResourceUrlProviderExposingInterceptor extends HandlerInterceptorAdapter {
/** /**
* Name of request attribute that holds * Name of the request attribute that holds the {@link PublicResourceUrlProvider}.
* {@link PublicResourceUrlProvider ResourceUrlPathTranslator}.
*/ */
public static final String RESOURCE_URL_PROVIDER_ATTR = PublicResourceUrlProvider.class.getName().toString(); public static final String RESOURCE_URL_PROVIDER_ATTR = PublicResourceUrlProvider.class.getName().toString();

View File

@ -22,45 +22,46 @@ import javax.servlet.http.HttpServletRequest;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
/** /**
* A strategy for matching a request to a server-side resource. Provides a mechanism * A strategy for resolving a request to a server-side resource.
* for resolving an incoming request to an actual *
* {@link org.springframework.core.io.Resource} and also for obtaining the public * <p>Provides mechanisms for resolving an incoming request to an actual
* URL path clients should use when requesting the resource. * {@link org.springframework.core.io.Resource} and for obtaining the public
* URL path that clients should use when requesting the resource.
* *
* @author Jeremy Grelle * @author Jeremy Grelle
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Sam Brannen
* @since 4.1 * @since 4.1
*
* @see org.springframework.web.servlet.resource.ResourceResolverChain * @see org.springframework.web.servlet.resource.ResourceResolverChain
*/ */
public interface ResourceResolver { public interface ResourceResolver {
/** /**
* Resolve the input request and request path to a {@link Resource} that * Resolve the supplied request and request path to a {@link Resource} that
* exists under one of the given resource locations. * exists under one of the given resource locations.
* *
* @param request the current request * @param request the current request
* @param requestPath the portion of the request path to use * @param requestPath the portion of the request path to use
* @param locations locations where to look for resources * @param locations the locations to search in when looking up resources
* @param chain a chain with other resolvers to delegate to * @param chain the chain of resolvers to delegate to
*
* @return the resolved resource or {@code null} if unresolved * @return the resolved resource or {@code null} if unresolved
*/ */
Resource resolveResource(HttpServletRequest request, String requestPath, Resource resolveResource(HttpServletRequest request, String requestPath, List<? extends Resource> locations,
List<Resource> locations, ResourceResolverChain chain); ResourceResolverChain chain);
/** /**
* Get the externally facing public URL path for clients to use to access the * Resolve the externally facing <em>public</em> URL path for clients to use
* resource located at the resource URL path. * to access the resource that is located at the given <em>internal</em>
* resource path.
* *
* @param resourceUrlPath the candidate resource URL path * <p>This is useful when rendering URL links to clients.
* @param locations the configured locations where to look up resources
* @param chain the chain with remaining resolvers to delegate to
* *
* @return the resolved URL path or {@code null} if unresolved * @param resourcePath the internal resource path
* @param locations the locations to search in when looking up resources
* @param chain the chain of resolvers to delegate to
* @return the resolved public URL path or {@code null} if unresolved
*/ */
String getPublicUrlPath(String resourceUrlPath, List<Resource> locations, ResourceResolverChain chain); String resolvePublicUrlPath(String resourcePath, List<? extends Resource> locations, ResourceResolverChain chain);
} }

View File

@ -22,40 +22,40 @@ import javax.servlet.http.HttpServletRequest;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
/** /**
* A contract for invoking a chain of {@link ResourceResolver}s where each resolver * A contract for invoking a chain of {@link ResourceResolver}s where each resolver
* is given a reference to the chain allowing it to delegate when necessary. * is given a reference to the chain allowing it to delegate when necessary.
* *
* @author Jeremy Grelle * @author Jeremy Grelle
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Sam Brannen
* @since 4.1 * @since 4.1
* @see ResourceResolver
*/ */
public interface ResourceResolverChain { public interface ResourceResolverChain {
/** /**
* Resolve the URL path of an incoming request to an actual {@link Resource} * Resolve the supplied request and request path to a {@link Resource} that
* to serve in the response. * exists under one of the given resource locations.
* *
* @param request the current request * @param request the current request
* @param requestPath the portion of the request path to use * @param requestPath the portion of the request path to use
* @param locations the configured locations where to look up resources * @param locations the locations to search in when looking up resources
* * @return the resolved resource or {@code null} if unresolved
* @return the resolved {@link Resource} or {@code null} if this resolver
* could not resolve the resource
*/ */
Resource resolveResource(HttpServletRequest request, String requestPath, List<Resource> locations); Resource resolveResource(HttpServletRequest request, String requestPath, List<? extends Resource> locations);
/** /**
* Resolve the given resource path to a URL path. This is useful when rendering * Resolve the externally facing <em>public</em> URL path for clients to use
* URL links to clients to determine the actual URL to use. * to access the resource that is located at the given <em>internal</em>
* resource path.
* *
* @param resourcePath the resource path * <p>This is useful when rendering URL links to clients.
* @param locations the configured locations where to look up resources
* *
* @return the resolved URL path or {@code null} if this resolver could not * @param resourcePath the internal resource path
* resolve the given resource path * @param locations the locations to search in when looking up resources
* @return the resolved public URL path or {@code null} if unresolved
*/ */
String resolveUrlPath(String resourcePath, List<Resource> locations); String resolvePublicUrlPath(String resourcePath, List<? extends Resource> locations);
} }

View File

@ -26,16 +26,18 @@ import javax.servlet.http.HttpServletResponseWrapper;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.filter.OncePerRequestFilter;
/** /**
* A filter that wraps the {@link HttpServletResponse} and overrides its * A filter that wraps the {@link HttpServletResponse} and overrides its
* {@link HttpServletResponse#encodeURL(String) encodeURL} method in order to * {@link HttpServletResponse#encodeURL(String) encodeURL} method in order to
* translate resource request URLs. * translate internal resource request URLs into public URL paths for external
* use.
* *
* @author Jeremy Grelle * @author Jeremy Grelle
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Sam Brannen
* @since 4.1 * @since 4.1
*/ */
public class ResourceUrlEncodingFilter extends OncePerRequestFilter { public class ResourceUrlEncodingFilter extends OncePerRequestFilter {
@ -44,16 +46,18 @@ public class ResourceUrlEncodingFilter extends OncePerRequestFilter {
@Override @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
FilterChain filterChain) throws ServletException, IOException { throws ServletException, IOException {
filterChain.doFilter(request, new ResourceUrlEncodingResponseWrapper(request, response)); filterChain.doFilter(request, new ResourceUrlEncodingResponseWrapper(request, response));
} }
private class ResourceUrlEncodingResponseWrapper extends HttpServletResponseWrapper {
private static class ResourceUrlEncodingResponseWrapper extends HttpServletResponseWrapper {
private HttpServletRequest request; private HttpServletRequest request;
private ResourceUrlEncodingResponseWrapper(HttpServletRequest request, HttpServletResponse wrapped) { private ResourceUrlEncodingResponseWrapper(HttpServletRequest request, HttpServletResponse wrapped) {
super(wrapped); super(wrapped);
this.request = request; this.request = request;
@ -62,15 +66,15 @@ public class ResourceUrlEncodingFilter extends OncePerRequestFilter {
@Override @Override
public String encodeURL(String url) { public String encodeURL(String url) {
String name = PublicResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR; String name = PublicResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR;
PublicResourceUrlProvider translator = (PublicResourceUrlProvider) this.request.getAttribute(name); PublicResourceUrlProvider urlProvider = (PublicResourceUrlProvider) this.request.getAttribute(name);
if (translator != null) { if (urlProvider != null) {
String translatedUrl = translator.getForRequestUrl(this.request, url); String translatedUrl = urlProvider.getForRequestUrl(this.request, url);
if (translatedUrl != null) { if (translatedUrl != null) {
return super.encodeURL(translatedUrl); return super.encodeURL(translatedUrl);
} }
} }
else { else {
logger.debug("Request attribute exposing ResourceUrlPathProvider not found"); logger.debug("Request attribute exposing PublicResourceUrlProvider not found under name: " + name);
} }
return super.encodeURL(url); return super.encodeURL(url);
} }

View File

@ -13,58 +13,61 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.web.servlet.resource; package org.springframework.web.servlet.resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import java.util.ArrayList; import static org.junit.Assert.*;
import java.util.List;
import static org.junit.Assert.assertEquals;
/** /**
* Test fixture for {@link PrefixResourceResolver} * Test fixture for {@link PrefixResourceResolver}
* *
* @author Brian Clozel * @author Brian Clozel
* @author Sam Brannen
*/ */
public class PrefixResourceResolverTests { public class PrefixResourceResolverTests {
private ResourceResolverChain resolver; private final List<? extends Resource> locations = Arrays.asList(new ClassPathResource("test/", getClass()));
private List<Resource> locations;
private final String shaPrefix = "1df341f"; private final String shaPrefix = "1df341f";
private ResourceResolverChain chain;
@Before @Before
public void setUp() { public void setUp() {
List<ResourceResolver> resolvers = new ArrayList<ResourceResolver>(); List<ResourceResolver> resolvers = new ArrayList<ResourceResolver>();
resolvers.add(new PrefixResourceResolver(this.shaPrefix)); resolvers.add(new PrefixResourceResolver(this.shaPrefix));
resolvers.add(new PathResourceResolver()); resolvers.add(new PathResourceResolver());
this.resolver = new DefaultResourceResolverChain(resolvers); this.chain = new DefaultResourceResolverChain(resolvers);
this.locations = new ArrayList<Resource>();
this.locations.add(new ClassPathResource("test/", getClass()));
} }
@Test @Test
public void testResolveResource() { public void resolveResource() {
String resourceId = "foo.css"; String resourceId = "foo.css";
Resource expected = new ClassPathResource("test/foo.css", getClass()); Resource expected = new ClassPathResource("test/foo.css", getClass());
Resource actual = this.resolver.resolveResource(null, "/" + this.shaPrefix + "/" + resourceId, this.locations); Resource actual = this.chain.resolveResource(null, "/" + this.shaPrefix + "/" + resourceId, this.locations);
assertEquals(expected, actual); assertEquals(expected, actual);
} }
@Test @Test
public void testResolveUrlPath() { public void resolvePublicUrlPath() {
String resourceId = "/foo.css"; String resourceId = "/foo.css";
String url = "/" + this.shaPrefix + resourceId; String url = "/" + this.shaPrefix + resourceId;
assertEquals(url, resolver.resolveUrlPath(resourceId, locations)); assertEquals(url, chain.resolvePublicUrlPath(resourceId, locations));
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void testFailPrefixResolverConstructor() { public void constructWithEmptyPrefix() {
PrefixResourceResolver resolver = new PrefixResourceResolver(""); new PrefixResourceResolver(" ");
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -44,25 +44,25 @@ import static org.junit.Assert.*;
*/ */
public class PublicResourceUrlProviderJavaConfigTests { public class PublicResourceUrlProviderJavaConfigTests {
private MockFilterChain filterChain; private final TestServlet servlet = new TestServlet();
private TestServlet servlet; private MockFilterChain filterChain;
private MockHttpServletRequest request; private MockHttpServletRequest request;
@Before @Before
@SuppressWarnings("resource")
public void setup() throws Exception { public void setup() throws Exception {
this.servlet = new TestServlet();
this.filterChain = new MockFilterChain(this.servlet, new ResourceUrlEncodingFilter()); this.filterChain = new MockFilterChain(this.servlet, new ResourceUrlEncodingFilter());
AnnotationConfigWebApplicationContext cxt = new AnnotationConfigWebApplicationContext(); AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
cxt.setServletContext(new MockServletContext()); ctx.setServletContext(new MockServletContext());
cxt.register(WebConfig.class); ctx.register(WebConfig.class);
cxt.refresh(); ctx.refresh();
PublicResourceUrlProvider urlProvider = cxt.getBean(PublicResourceUrlProvider.class); PublicResourceUrlProvider urlProvider = ctx.getBean(PublicResourceUrlProvider.class);
this.request = new MockHttpServletRequest("GET", "/"); this.request = new MockHttpServletRequest("GET", "/");
request.setAttribute(PublicResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, urlProvider); request.setAttribute(PublicResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, urlProvider);