Browse Source

ResourceHttpRequestHandler uses EmbeddedValueResolverAware

(cherry picked from commit 20fcefc)
pull/1610/head
Juergen Hoeller 8 years ago
parent
commit
122a3fe9fd
  1. 16
      spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java
  2. 86
      spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java

16
spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2002-2017 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.
@ -38,7 +38,7 @@ public class ResourceHandlerRegistration {
private final String[] pathPatterns; private final String[] pathPatterns;
private final List<String> locationValues = new ArrayList<String>(4); private final List<String> locationValues = new ArrayList<String>();
private Integer cachePeriod; private Integer cachePeriod;
@ -56,6 +56,7 @@ public class ResourceHandlerRegistration {
this.pathPatterns = pathPatterns; this.pathPatterns = pathPatterns;
} }
/** /**
* Add one or more resource locations from which to serve static content. * Add one or more resource locations from which to serve static content.
* Each location must point to a valid directory. Multiple locations may * Each location must point to a valid directory. Multiple locations may
@ -94,9 +95,7 @@ public class ResourceHandlerRegistration {
/** /**
* Specify the {@link org.springframework.http.CacheControl} which should be used * Specify the {@link org.springframework.http.CacheControl} which should be used
* by the resource handler. * by the resource handler.
*
* <p>Setting a custom value here will override the configuration set with {@link #setCachePeriod}. * <p>Setting a custom value here will override the configuration set with {@link #setCachePeriod}.
*
* @param cacheControl the CacheControl configuration to use * @param cacheControl the CacheControl configuration to use
* @return the same {@link ResourceHandlerRegistration} instance, for chained method invocation * @return the same {@link ResourceHandlerRegistration} instance, for chained method invocation
* @since 4.2 * @since 4.2
@ -109,11 +108,9 @@ public class ResourceHandlerRegistration {
/** /**
* Configure a chain of resource resolvers and transformers to use. This * Configure a chain of resource resolvers and transformers to use. This
* can be useful, for example, to apply a version strategy to resource URLs. * can be useful, for example, to apply a version strategy to resource URLs.
*
* <p>If this method is not invoked, by default only a simple * <p>If this method is not invoked, by default only a simple
* {@link PathResourceResolver} is used in order to match URL paths to * {@link PathResourceResolver} is used in order to match URL paths to
* resources under the configured locations. * resources under the configured locations.
*
* @param cacheResources whether to cache the result of resource resolution; * @param cacheResources whether to cache the result of resource resolution;
* setting this to "true" is recommended for production (and "false" for * setting this to "true" is recommended for production (and "false" for
* development, especially when applying a version strategy) * development, especially when applying a version strategy)
@ -128,11 +125,9 @@ public class ResourceHandlerRegistration {
/** /**
* Configure a chain of resource resolvers and transformers to use. This * Configure a chain of resource resolvers and transformers to use. This
* can be useful, for example, to apply a version strategy to resource URLs. * can be useful, for example, to apply a version strategy to resource URLs.
*
* <p>If this method is not invoked, by default only a simple * <p>If this method is not invoked, by default only a simple
* {@link PathResourceResolver} is used in order to match URL paths to * {@link PathResourceResolver} is used in order to match URL paths to
* resources under the configured locations. * resources under the configured locations.
*
* @param cacheResources whether to cache the result of resource resolution; * @param cacheResources whether to cache the result of resource resolution;
* setting this to "true" is recommended for production (and "false" for * setting this to "true" is recommended for production (and "false" for
* development, especially when applying a version strategy * development, especially when applying a version strategy
@ -149,15 +144,16 @@ public class ResourceHandlerRegistration {
return this.resourceChainRegistration; return this.resourceChainRegistration;
} }
/** /**
* Returns the URL path patterns for the resource handler. * Return the URL path patterns for the resource handler.
*/ */
protected String[] getPathPatterns() { protected String[] getPathPatterns() {
return this.pathPatterns; return this.pathPatterns;
} }
/** /**
* Returns a {@link ResourceHttpRequestHandler} instance. * Return a {@link ResourceHttpRequestHandler} instance.
*/ */
protected ResourceHttpRequestHandler getRequestHandler() { protected ResourceHttpRequestHandler getRequestHandler() {
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler(); ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();

86
spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java

@ -32,8 +32,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource; import org.springframework.core.io.UrlResource;
import org.springframework.core.io.support.ResourceRegion; import org.springframework.core.io.support.ResourceRegion;
@ -51,6 +51,7 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.util.StringValueResolver;
import org.springframework.web.HttpRequestHandler; import org.springframework.web.HttpRequestHandler;
import org.springframework.web.accept.ContentNegotiationManager; import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.accept.PathExtensionContentNegotiationStrategy; import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
@ -95,7 +96,7 @@ import org.springframework.web.util.UrlPathHelper;
* @since 3.0.4 * @since 3.0.4
*/ */
public class ResourceHttpRequestHandler extends WebContentGenerator public class ResourceHttpRequestHandler extends WebContentGenerator
implements HttpRequestHandler, InitializingBean, CorsConfigurationSource { implements HttpRequestHandler, EmbeddedValueResolverAware, InitializingBean, CorsConfigurationSource {
// Servlet 3.1 setContentLengthLong(long) available? // Servlet 3.1 setContentLengthLong(long) available?
private static final boolean contentLengthLongAvailable = private static final boolean contentLengthLongAvailable =
@ -106,12 +107,12 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
private static final String URL_RESOURCE_CHARSET_PREFIX = "[charset="; private static final String URL_RESOURCE_CHARSET_PREFIX = "[charset=";
private final List<String> locationValues = new ArrayList<String>(4);
private final List<Resource> locations = new ArrayList<Resource>(4); private final List<Resource> locations = new ArrayList<Resource>(4);
private final Map<Resource, Charset> locationCharsets = new HashMap<Resource, Charset>(4); private final Map<Resource, Charset> locationCharsets = new HashMap<Resource, Charset>(4);
private final List<String> locationValues = new ArrayList<String>(4);
private final List<ResourceResolver> resourceResolvers = new ArrayList<ResourceResolver>(4); private final List<ResourceResolver> resourceResolvers = new ArrayList<ResourceResolver>(4);
private final List<ResourceTransformer> resourceTransformers = new ArrayList<ResourceTransformer>(4); private final List<ResourceTransformer> resourceTransformers = new ArrayList<ResourceTransformer>(4);
@ -128,12 +129,28 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
private UrlPathHelper urlPathHelper; private UrlPathHelper urlPathHelper;
private StringValueResolver embeddedValueResolver;
public ResourceHttpRequestHandler() { public ResourceHttpRequestHandler() {
super(HttpMethod.GET.name(), HttpMethod.HEAD.name()); 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<String> 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 * Set the {@code List} of {@code Resource} locations to use as sources
* for serving static resources. * for serving static resources.
@ -147,28 +164,16 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
/** /**
* Return the configured {@code List} of {@code Resource} locations. * Return the configured {@code List} of {@code Resource} locations.
* Note that if {@link #setLocationValues(List) locationValues} are provided, * <p>Note that if {@link #setLocationValues(List) locationValues} are provided,
* instead of loaded Resource-based locations, this method will return * instead of loaded Resource-based locations, this method will return
* empty until after initialization via {@link #afterPropertiesSet()}. * empty until after initialization via {@link #afterPropertiesSet()}.
* @see #setLocationValues
* @see #setLocations
*/ */
public List<Resource> getLocations() { public List<Resource> getLocations() {
return this.locations; 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<String> 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. * Configure the list of {@link ResourceResolver}s to use.
* <p>By default {@link PathResourceResolver} is configured. If using this property, * <p>By default {@link PathResourceResolver} is configured. If using this property,
@ -211,8 +216,8 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
* <p>By default a {@link ResourceHttpMessageConverter} will be configured. * <p>By default a {@link ResourceHttpMessageConverter} will be configured.
* @since 4.3 * @since 4.3
*/ */
public void setResourceHttpMessageConverter(ResourceHttpMessageConverter resourceHttpMessageConverter) { public void setResourceHttpMessageConverter(ResourceHttpMessageConverter messageConverter) {
this.resourceHttpMessageConverter = resourceHttpMessageConverter; this.resourceHttpMessageConverter = messageConverter;
} }
/** /**
@ -228,8 +233,8 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
* <p>By default a {@link ResourceRegionHttpMessageConverter} will be configured. * <p>By default a {@link ResourceRegionHttpMessageConverter} will be configured.
* @since 4.3 * @since 4.3
*/ */
public void setResourceRegionHttpMessageConverter(ResourceRegionHttpMessageConverter resourceRegionHttpMessageConverter) { public void setResourceRegionHttpMessageConverter(ResourceRegionHttpMessageConverter messageConverter) {
this.resourceRegionHttpMessageConverter = resourceRegionHttpMessageConverter; this.resourceRegionHttpMessageConverter = messageConverter;
} }
/** /**
@ -244,7 +249,6 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
* Configure a {@code ContentNegotiationManager} to help determine the * Configure a {@code ContentNegotiationManager} to help determine the
* media types for resources being served. If the manager contains a path * media types for resources being served. If the manager contains a path
* extension strategy it will be checked for registered file extension. * extension strategy it will be checked for registered file extension.
* @param contentNegotiationManager the manager in use
* @since 4.3 * @since 4.3
*/ */
public void setContentNegotiationManager(ContentNegotiationManager contentNegotiationManager) { public void setContentNegotiationManager(ContentNegotiationManager contentNegotiationManager) {
@ -293,11 +297,15 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
return this.urlPathHelper; return this.urlPathHelper;
} }
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.embeddedValueResolver = resolver;
}
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
resolveResourceLocations();
loadResourceLocations();
if (logger.isWarnEnabled() && CollectionUtils.isEmpty(this.locations)) { if (logger.isWarnEnabled() && CollectionUtils.isEmpty(this.locations)) {
logger.warn("Locations list is empty. No resources will be served unless a " + logger.warn("Locations list is empty. No resources will be served unless a " +
@ -320,23 +328,23 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
this.contentNegotiationStrategy = initContentNegotiationStrategy(); this.contentNegotiationStrategy = initContentNegotiationStrategy();
} }
private void loadResourceLocations() { private void resolveResourceLocations() {
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.");
}
if (CollectionUtils.isEmpty(this.locationValues)) { if (CollectionUtils.isEmpty(this.locationValues)) {
return; return;
} }
ApplicationContext appContext = getApplicationContext(); else if (!CollectionUtils.isEmpty(this.locations)) {
ConfigurableBeanFactory beanFactory = null; throw new IllegalArgumentException("Please set either Resource-based \"locations\" or " +
if (appContext.getAutowireCapableBeanFactory() instanceof ConfigurableBeanFactory) { "String-based \"locationValues\", but not both.");
beanFactory = ((ConfigurableBeanFactory) appContext.getAutowireCapableBeanFactory());
} }
ApplicationContext applicationContext = getApplicationContext();
for (String location : this.locationValues) { for (String location : this.locationValues) {
if (beanFactory != null) { if (this.embeddedValueResolver != null) {
location = beanFactory.resolveEmbeddedValue(location); String resolvedLocation = this.embeddedValueResolver.resolveStringValue(location);
Assert.notNull(location, "Null location"); if (resolvedLocation == null) {
throw new IllegalArgumentException("Location resolved to null: " + location);
}
location = resolvedLocation;
} }
Charset charset = null; Charset charset = null;
location = location.trim(); location = location.trim();
@ -349,7 +357,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
charset = Charset.forName(value); charset = Charset.forName(value);
location = location.substring(endIndex + 1); location = location.substring(endIndex + 1);
} }
Resource resource = appContext.getResource(location); Resource resource = applicationContext.getResource(location);
this.locations.add(resource); this.locations.add(resource);
if (charset != null) { if (charset != null) {
if (!(resource instanceof UrlResource)) { if (!(resource instanceof UrlResource)) {

Loading…
Cancel
Save