Skip to content

Commit 20fcefc

Browse files
committed
ResourceHttpRequestHandler uses EmbeddedValueResolverAware
1 parent 14a7da8 commit 20fcefc

File tree

2 files changed

+47
-43
lines changed

2 files changed

+47
-43
lines changed

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

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,7 @@ public ResourceHandlerRegistration setCachePeriod(Integer cachePeriod) {
9999
/**
100100
* Specify the {@link org.springframework.http.CacheControl} which should be used
101101
* by the resource handler.
102-
*
103102
* <p>Setting a custom value here will override the configuration set with {@link #setCachePeriod}.
104-
*
105103
* @param cacheControl the CacheControl configuration to use
106104
* @return the same {@link ResourceHandlerRegistration} instance, for chained method invocation
107105
* @since 4.2
@@ -114,11 +112,9 @@ public ResourceHandlerRegistration setCacheControl(CacheControl cacheControl) {
114112
/**
115113
* Configure a chain of resource resolvers and transformers to use. This
116114
* can be useful, for example, to apply a version strategy to resource URLs.
117-
*
118115
* <p>If this method is not invoked, by default only a simple
119116
* {@link PathResourceResolver} is used in order to match URL paths to
120117
* resources under the configured locations.
121-
*
122118
* @param cacheResources whether to cache the result of resource resolution;
123119
* setting this to "true" is recommended for production (and "false" for
124120
* development, especially when applying a version strategy)
@@ -133,11 +129,9 @@ public ResourceChainRegistration resourceChain(boolean cacheResources) {
133129
/**
134130
* Configure a chain of resource resolvers and transformers to use. This
135131
* can be useful, for example, to apply a version strategy to resource URLs.
136-
*
137132
* <p>If this method is not invoked, by default only a simple
138133
* {@link PathResourceResolver} is used in order to match URL paths to
139134
* resources under the configured locations.
140-
*
141135
* @param cacheResources whether to cache the result of resource resolution;
142136
* setting this to "true" is recommended for production (and "false" for
143137
* development, especially when applying a version strategy
@@ -154,15 +148,16 @@ public ResourceChainRegistration resourceChain(boolean cacheResources, Cache cac
154148
return this.resourceChainRegistration;
155149
}
156150

151+
157152
/**
158-
* Returns the URL path patterns for the resource handler.
153+
* Return the URL path patterns for the resource handler.
159154
*/
160155
protected String[] getPathPatterns() {
161156
return this.pathPatterns;
162157
}
163158

164159
/**
165-
* Returns a {@link ResourceHttpRequestHandler} instance.
160+
* Return a {@link ResourceHttpRequestHandler} instance.
166161
*/
167162
protected ResourceHttpRequestHandler getRequestHandler() {
168163
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();

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

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
import org.apache.commons.logging.LogFactory;
3232

3333
import org.springframework.beans.factory.InitializingBean;
34-
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
3534
import org.springframework.context.ApplicationContext;
35+
import org.springframework.context.EmbeddedValueResolverAware;
3636
import org.springframework.core.io.Resource;
3737
import org.springframework.core.io.UrlResource;
3838
import org.springframework.http.HttpHeaders;
@@ -49,6 +49,7 @@
4949
import org.springframework.util.ObjectUtils;
5050
import org.springframework.util.ResourceUtils;
5151
import org.springframework.util.StringUtils;
52+
import org.springframework.util.StringValueResolver;
5253
import org.springframework.web.HttpRequestHandler;
5354
import org.springframework.web.accept.ContentNegotiationManager;
5455
import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
@@ -93,19 +94,19 @@
9394
* @since 3.0.4
9495
*/
9596
public class ResourceHttpRequestHandler extends WebContentGenerator
96-
implements HttpRequestHandler, InitializingBean, CorsConfigurationSource {
97+
implements HttpRequestHandler, EmbeddedValueResolverAware, InitializingBean, CorsConfigurationSource {
9798

9899
private static final Log logger = LogFactory.getLog(ResourceHttpRequestHandler.class);
99100

100101
private static final String URL_RESOURCE_CHARSET_PREFIX = "[charset=";
101102

102103

104+
private final List<String> locationValues = new ArrayList<>(4);
105+
103106
private final List<Resource> locations = new ArrayList<>(4);
104107

105108
private final Map<Resource, Charset> locationCharsets = new HashMap<>(4);
106109

107-
private final List<String> locationValues = new ArrayList<>(4);
108-
109110
private final List<ResourceResolver> resourceResolvers = new ArrayList<>(4);
110111

111112
private final List<ResourceTransformer> resourceTransformers = new ArrayList<>(4);
@@ -128,12 +129,29 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
128129
@Nullable
129130
private UrlPathHelper urlPathHelper;
130131

132+
@Nullable
133+
private StringValueResolver embeddedValueResolver;
134+
131135

132136
public ResourceHttpRequestHandler() {
133137
super(HttpMethod.GET.name(), HttpMethod.HEAD.name());
134138
}
135139

136140

141+
/**
142+
* An alternative to {@link #setLocations(List)} that accepts a list of
143+
* String-based location values, with support for {@link UrlResource}'s
144+
* (e.g. files or HTTP URLs) with a special prefix to indicate the charset
145+
* to use when appending relative paths. For example
146+
* {@code "[charset=Windows-31J]http://example.org/path"}.
147+
* @since 4.3.13
148+
*/
149+
public void setLocationValues(List<String> locationValues) {
150+
Assert.notNull(locationValues, "Location values list must not be null");
151+
this.locationValues.clear();
152+
this.locationValues.addAll(locationValues);
153+
}
154+
137155
/**
138156
* Set the {@code List} of {@code Resource} locations to use as sources
139157
* for serving static resources.
@@ -147,28 +165,16 @@ public void setLocations(List<Resource> locations) {
147165

148166
/**
149167
* Return the configured {@code List} of {@code Resource} locations.
150-
* Note that if {@link #setLocationValues(List) locationValues} are provided,
168+
* <p>Note that if {@link #setLocationValues(List) locationValues} are provided,
151169
* instead of loaded Resource-based locations, this method will return
152170
* empty until after initialization via {@link #afterPropertiesSet()}.
171+
* @see #setLocationValues
172+
* @see #setLocations
153173
*/
154174
public List<Resource> getLocations() {
155175
return this.locations;
156176
}
157177

158-
/**
159-
* An alternative to {@link #setLocations(List)} that accepts a list of
160-
* String-based location values, with support for {@link UrlResource}'s
161-
* (e.g. files or HTTP URLs) with a special prefix to indicate the charset
162-
* to use when appending relative paths. For example
163-
* {@code "[charset=Windows-31J]http://example.org/path"}.
164-
* @since 4.3.13
165-
*/
166-
public void setLocationValues(List<String> locationValues) {
167-
Assert.notNull(locationValues, "Location values list must not be null");
168-
this.locationValues.clear();
169-
this.locationValues.addAll(locationValues);
170-
}
171-
172178
/**
173179
* Configure the list of {@link ResourceResolver}s to use.
174180
* <p>By default {@link PathResourceResolver} is configured. If using this property,
@@ -246,7 +252,6 @@ public ResourceRegionHttpMessageConverter getResourceRegionHttpMessageConverter(
246252
* Configure a {@code ContentNegotiationManager} to help determine the
247253
* media types for resources being served. If the manager contains a path
248254
* extension strategy it will be checked for registered file extension.
249-
* @param contentNegotiationManager the manager in use
250255
* @since 4.3
251256
*/
252257
public void setContentNegotiationManager(@Nullable ContentNegotiationManager contentNegotiationManager) {
@@ -298,11 +303,15 @@ public UrlPathHelper getUrlPathHelper() {
298303
return this.urlPathHelper;
299304
}
300305

306+
@Override
307+
public void setEmbeddedValueResolver(StringValueResolver resolver) {
308+
this.embeddedValueResolver = resolver;
309+
}
310+
301311

302312
@Override
303313
public void afterPropertiesSet() throws Exception {
304-
305-
loadResourceLocations();
314+
resolveResourceLocations();
306315

307316
if (logger.isWarnEnabled() && CollectionUtils.isEmpty(this.locations)) {
308317
logger.warn("Locations list is empty. No resources will be served unless a " +
@@ -325,23 +334,23 @@ public void afterPropertiesSet() throws Exception {
325334
this.contentNegotiationStrategy = initContentNegotiationStrategy();
326335
}
327336

328-
private void loadResourceLocations() {
329-
if (!CollectionUtils.isEmpty(this.locations) && !CollectionUtils.isEmpty(this.locationValues)) {
330-
throw new IllegalArgumentException("Please set either Resource-based \"locations\" or " +
331-
"String-based \"locationValues\", but not both.");
332-
}
337+
private void resolveResourceLocations() {
333338
if (CollectionUtils.isEmpty(this.locationValues)) {
334339
return;
335340
}
336-
ApplicationContext appContext = obtainApplicationContext();
337-
ConfigurableBeanFactory beanFactory = null;
338-
if (appContext.getAutowireCapableBeanFactory() instanceof ConfigurableBeanFactory) {
339-
beanFactory = ((ConfigurableBeanFactory) appContext.getAutowireCapableBeanFactory());
341+
else if (!CollectionUtils.isEmpty(this.locations)) {
342+
throw new IllegalArgumentException("Please set either Resource-based \"locations\" or " +
343+
"String-based \"locationValues\", but not both.");
340344
}
345+
346+
ApplicationContext applicationContext = obtainApplicationContext();
341347
for (String location : this.locationValues) {
342-
if (beanFactory != null) {
343-
location = beanFactory.resolveEmbeddedValue(location);
344-
Assert.notNull(location, "Null location");
348+
if (this.embeddedValueResolver != null) {
349+
String resolvedLocation = this.embeddedValueResolver.resolveStringValue(location);
350+
if (resolvedLocation == null) {
351+
throw new IllegalArgumentException("Location resolved to null: " + location);
352+
}
353+
location = resolvedLocation;
345354
}
346355
Charset charset = null;
347356
location = location.trim();
@@ -354,7 +363,7 @@ private void loadResourceLocations() {
354363
charset = Charset.forName(value);
355364
location = location.substring(endIndex + 1);
356365
}
357-
Resource resource = appContext.getResource(location);
366+
Resource resource = applicationContext.getResource(location);
358367
this.locations.add(resource);
359368
if (charset != null) {
360369
if (!(resource instanceof UrlResource)) {

0 commit comments

Comments
 (0)