From 20fcefc6477f2f3d9aa88cc8b8c3686e5b5cf28b Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sun, 19 Nov 2017 21:16:29 +0100 Subject: [PATCH] ResourceHttpRequestHandler uses EmbeddedValueResolverAware --- .../ResourceHandlerRegistration.java | 11 +-- .../resource/ResourceHttpRequestHandler.java | 79 +++++++++++-------- 2 files changed, 47 insertions(+), 43 deletions(-) diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java index 56cd10f63a..20742cb524 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java @@ -99,9 +99,7 @@ public class ResourceHandlerRegistration { /** * Specify the {@link org.springframework.http.CacheControl} which should be used * by the resource handler. - * *

Setting a custom value here will override the configuration set with {@link #setCachePeriod}. - * * @param cacheControl the CacheControl configuration to use * @return the same {@link ResourceHandlerRegistration} instance, for chained method invocation * @since 4.2 @@ -114,11 +112,9 @@ public class ResourceHandlerRegistration { /** * Configure a chain of resource resolvers and transformers to use. This * can be useful, for example, to apply a version strategy to resource URLs. - * *

If this method is not invoked, by default only a simple * {@link PathResourceResolver} is used in order to match URL paths to * resources under the configured locations. - * * @param cacheResources whether to cache the result of resource resolution; * setting this to "true" is recommended for production (and "false" for * development, especially when applying a version strategy) @@ -133,11 +129,9 @@ public class ResourceHandlerRegistration { /** * Configure a chain of resource resolvers and transformers to use. This * can be useful, for example, to apply a version strategy to resource URLs. - * *

If this method is not invoked, by default only a simple * {@link PathResourceResolver} is used in order to match URL paths to * resources under the configured locations. - * * @param cacheResources whether to cache the result of resource resolution; * setting this to "true" is recommended for production (and "false" for * development, especially when applying a version strategy @@ -154,15 +148,16 @@ public class ResourceHandlerRegistration { return this.resourceChainRegistration; } + /** - * Returns the URL path patterns for the resource handler. + * Return the URL path patterns for the resource handler. */ protected String[] getPathPatterns() { return this.pathPatterns; } /** - * Returns a {@link ResourceHttpRequestHandler} instance. + * Return a {@link ResourceHttpRequestHandler} instance. */ protected ResourceHttpRequestHandler getRequestHandler() { ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java index 3cd0afb834..6f8e3deb72 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java @@ -31,8 +31,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.ApplicationContext; +import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; import org.springframework.http.HttpHeaders; @@ -49,6 +49,7 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.ResourceUtils; import org.springframework.util.StringUtils; +import org.springframework.util.StringValueResolver; import org.springframework.web.HttpRequestHandler; import org.springframework.web.accept.ContentNegotiationManager; import org.springframework.web.accept.PathExtensionContentNegotiationStrategy; @@ -93,19 +94,19 @@ import org.springframework.web.util.UrlPathHelper; * @since 3.0.4 */ public class ResourceHttpRequestHandler extends WebContentGenerator - implements HttpRequestHandler, InitializingBean, CorsConfigurationSource { + implements HttpRequestHandler, EmbeddedValueResolverAware, InitializingBean, CorsConfigurationSource { private static final Log logger = LogFactory.getLog(ResourceHttpRequestHandler.class); private static final String URL_RESOURCE_CHARSET_PREFIX = "[charset="; + private final List locationValues = new ArrayList<>(4); + private final List locations = new ArrayList<>(4); private final Map locationCharsets = new HashMap<>(4); - private final List locationValues = new ArrayList<>(4); - private final List resourceResolvers = new ArrayList<>(4); private final List resourceTransformers = new ArrayList<>(4); @@ -128,12 +129,29 @@ public class ResourceHttpRequestHandler extends WebContentGenerator @Nullable private UrlPathHelper urlPathHelper; + @Nullable + private StringValueResolver embeddedValueResolver; + public ResourceHttpRequestHandler() { super(HttpMethod.GET.name(), HttpMethod.HEAD.name()); } + /** + * An alternative to {@link #setLocations(List)} that accepts a list of + * String-based location values, with support for {@link UrlResource}'s + * (e.g. files or HTTP URLs) with a special prefix to indicate the charset + * to use when appending relative paths. For example + * {@code "[charset=Windows-31J]http://example.org/path"}. + * @since 4.3.13 + */ + public void setLocationValues(List locationValues) { + Assert.notNull(locationValues, "Location values list must not be null"); + this.locationValues.clear(); + this.locationValues.addAll(locationValues); + } + /** * Set the {@code List} of {@code Resource} locations to use as sources * for serving static resources. @@ -147,28 +165,16 @@ public class ResourceHttpRequestHandler extends WebContentGenerator /** * Return the configured {@code List} of {@code Resource} locations. - * Note that if {@link #setLocationValues(List) locationValues} are provided, + *

Note that if {@link #setLocationValues(List) locationValues} are provided, * instead of loaded Resource-based locations, this method will return * empty until after initialization via {@link #afterPropertiesSet()}. + * @see #setLocationValues + * @see #setLocations */ public List getLocations() { return this.locations; } - /** - * An alternative to {@link #setLocations(List)} that accepts a list of - * String-based location values, with support for {@link UrlResource}'s - * (e.g. files or HTTP URLs) with a special prefix to indicate the charset - * to use when appending relative paths. For example - * {@code "[charset=Windows-31J]http://example.org/path"}. - * @since 4.3.13 - */ - public void setLocationValues(List locationValues) { - Assert.notNull(locationValues, "Location values list must not be null"); - this.locationValues.clear(); - this.locationValues.addAll(locationValues); - } - /** * Configure the list of {@link ResourceResolver}s to use. *

By default {@link PathResourceResolver} is configured. If using this property, @@ -246,7 +252,6 @@ public class ResourceHttpRequestHandler extends WebContentGenerator * Configure a {@code ContentNegotiationManager} to help determine the * media types for resources being served. If the manager contains a path * extension strategy it will be checked for registered file extension. - * @param contentNegotiationManager the manager in use * @since 4.3 */ public void setContentNegotiationManager(@Nullable ContentNegotiationManager contentNegotiationManager) { @@ -298,11 +303,15 @@ public class ResourceHttpRequestHandler extends WebContentGenerator return this.urlPathHelper; } + @Override + public void setEmbeddedValueResolver(StringValueResolver resolver) { + this.embeddedValueResolver = resolver; + } + @Override public void afterPropertiesSet() throws Exception { - - loadResourceLocations(); + resolveResourceLocations(); if (logger.isWarnEnabled() && CollectionUtils.isEmpty(this.locations)) { logger.warn("Locations list is empty. No resources will be served unless a " + @@ -325,23 +334,23 @@ public class ResourceHttpRequestHandler extends WebContentGenerator this.contentNegotiationStrategy = initContentNegotiationStrategy(); } - private void loadResourceLocations() { - if (!CollectionUtils.isEmpty(this.locations) && !CollectionUtils.isEmpty(this.locationValues)) { - throw new IllegalArgumentException("Please set either Resource-based \"locations\" or " + - "String-based \"locationValues\", but not both."); - } + private void resolveResourceLocations() { if (CollectionUtils.isEmpty(this.locationValues)) { return; } - ApplicationContext appContext = obtainApplicationContext(); - ConfigurableBeanFactory beanFactory = null; - if (appContext.getAutowireCapableBeanFactory() instanceof ConfigurableBeanFactory) { - beanFactory = ((ConfigurableBeanFactory) appContext.getAutowireCapableBeanFactory()); + else if (!CollectionUtils.isEmpty(this.locations)) { + throw new IllegalArgumentException("Please set either Resource-based \"locations\" or " + + "String-based \"locationValues\", but not both."); } + + ApplicationContext applicationContext = obtainApplicationContext(); for (String location : this.locationValues) { - if (beanFactory != null) { - location = beanFactory.resolveEmbeddedValue(location); - Assert.notNull(location, "Null location"); + if (this.embeddedValueResolver != null) { + String resolvedLocation = this.embeddedValueResolver.resolveStringValue(location); + if (resolvedLocation == null) { + throw new IllegalArgumentException("Location resolved to null: " + location); + } + location = resolvedLocation; } Charset charset = null; location = location.trim(); @@ -354,7 +363,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator charset = Charset.forName(value); location = location.substring(endIndex + 1); } - Resource resource = appContext.getResource(location); + Resource resource = applicationContext.getResource(location); this.locations.add(resource); if (charset != null) { if (!(resource instanceof UrlResource)) {