Revise charset by location support for static resources
This commit is contained in:
@@ -16,9 +16,7 @@
|
|||||||
|
|
||||||
package org.springframework.web.servlet.config;
|
package org.springframework.web.servlet.config;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
@@ -26,9 +24,6 @@ import org.springframework.beans.factory.config.RuntimeBeanReference;
|
|||||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.beans.factory.xml.ParserContext;
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.core.io.ResourceLoader;
|
|
||||||
import org.springframework.core.io.UrlResource;
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.AntPathMatcher;
|
import org.springframework.util.AntPathMatcher;
|
||||||
import org.springframework.util.PathMatcher;
|
import org.springframework.util.PathMatcher;
|
||||||
@@ -65,8 +60,6 @@ public abstract class MvcNamespaceUtils {
|
|||||||
|
|
||||||
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
|
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
|
||||||
|
|
||||||
private static final String URL_RESOURCE_CHARSET_PREFIX = "[charset=";
|
|
||||||
|
|
||||||
|
|
||||||
public static void registerDefaultComponents(ParserContext parserContext, @Nullable Object source) {
|
public static void registerDefaultComponents(ParserContext parserContext, @Nullable Object source) {
|
||||||
registerBeanNameUrlHandlerMapping(parserContext, source);
|
registerBeanNameUrlHandlerMapping(parserContext, source);
|
||||||
@@ -231,40 +224,4 @@ public abstract class MvcNamespaceUtils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the {@link Resource}'s for the given locations with the given
|
|
||||||
* {@link ResourceLoader} and add them to the output list. Also for
|
|
||||||
* {@link org.springframework.core.io.UrlResource URL-based resources} (e.g. files,
|
|
||||||
* HTTP URLs, etc) this method supports a special prefix to indicate the charset
|
|
||||||
* associated with the URL so that relative paths appended to it can be encoded
|
|
||||||
* correctly, e.g. {@code [charset=Windows-31J]http://example.org/path}.
|
|
||||||
* The charsets, if any, are added to the output map.
|
|
||||||
* @since 4.3.13
|
|
||||||
*/
|
|
||||||
public static void loadResourceLocations(String[] locations, ResourceLoader resourceLoader,
|
|
||||||
List<Resource> outputLocations, Map<Resource, Charset> outputLocationCharsets) {
|
|
||||||
|
|
||||||
for (String location : locations) {
|
|
||||||
Charset charset = null;
|
|
||||||
location = location.trim();
|
|
||||||
if (location.startsWith(URL_RESOURCE_CHARSET_PREFIX)) {
|
|
||||||
int endIndex = location.indexOf("]", URL_RESOURCE_CHARSET_PREFIX.length());
|
|
||||||
if (endIndex == -1) {
|
|
||||||
throw new IllegalArgumentException("Invalid charset syntax in location: " + location);
|
|
||||||
}
|
|
||||||
String value = location.substring(URL_RESOURCE_CHARSET_PREFIX.length(), endIndex);
|
|
||||||
charset = Charset.forName(value);
|
|
||||||
location = location.substring(endIndex + 1);
|
|
||||||
}
|
|
||||||
Resource resource = resourceLoader.getResource(location);
|
|
||||||
outputLocations.add(resource);
|
|
||||||
if (charset != null) {
|
|
||||||
if (!(resource instanceof UrlResource)) {
|
|
||||||
throw new IllegalArgumentException("Unexpected charset for non-UrlResource: " + resource);
|
|
||||||
}
|
|
||||||
outputLocationCharsets.put(resource, charset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,6 @@
|
|||||||
|
|
||||||
package org.springframework.web.servlet.config;
|
package org.springframework.web.servlet.config;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@@ -28,7 +23,6 @@ import org.w3c.dom.Element;
|
|||||||
|
|
||||||
import org.springframework.beans.MutablePropertyValues;
|
import org.springframework.beans.MutablePropertyValues;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
|
||||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||||
@@ -39,8 +33,6 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
|||||||
import org.springframework.beans.factory.xml.ParserContext;
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.core.io.ResourceLoader;
|
|
||||||
import org.springframework.http.CacheControl;
|
import org.springframework.http.CacheControl;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
@@ -172,35 +164,13 @@ class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] locationValues = StringUtils.commaDelimitedListToStringArray(locationAttr);
|
|
||||||
if (context.getRegistry() instanceof ConfigurableBeanFactory) {
|
|
||||||
ConfigurableBeanFactory cbf = ((ConfigurableBeanFactory) context.getRegistry());
|
|
||||||
for (int i = 0; i < locationValues.length; i++) {
|
|
||||||
locationValues[i] = cbf.resolveEmbeddedValue(locationValues[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ManagedList<Object> locations = new ManagedList<>();
|
|
||||||
Map<Resource, Charset> locationCharsets = new HashMap<>();
|
|
||||||
ResourceLoader resourceLoader = context.getReaderContext().getResourceLoader();
|
|
||||||
|
|
||||||
if (resourceLoader != null) {
|
|
||||||
List<Resource> resources = new ArrayList<>();
|
|
||||||
MvcNamespaceUtils.loadResourceLocations(locationValues, resourceLoader, resources, locationCharsets);
|
|
||||||
locations.addAll(resources);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
locations.addAll(Arrays.asList(locationValues));
|
|
||||||
}
|
|
||||||
|
|
||||||
RootBeanDefinition resourceHandlerDef = new RootBeanDefinition(ResourceHttpRequestHandler.class);
|
RootBeanDefinition resourceHandlerDef = new RootBeanDefinition(ResourceHttpRequestHandler.class);
|
||||||
resourceHandlerDef.setSource(source);
|
resourceHandlerDef.setSource(source);
|
||||||
resourceHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
resourceHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||||
|
|
||||||
MutablePropertyValues values = resourceHandlerDef.getPropertyValues();
|
MutablePropertyValues values = resourceHandlerDef.getPropertyValues();
|
||||||
values.add("urlPathHelper", pathHelperRef);
|
values.add("urlPathHelper", pathHelperRef);
|
||||||
values.add("locations", locations);
|
values.add("locationValues", StringUtils.commaDelimitedListToStringArray(locationAttr));
|
||||||
values.add("locationCharsets", locationCharsets);
|
|
||||||
|
|
||||||
String cacheSeconds = element.getAttribute("cache-period");
|
String cacheSeconds = element.getAttribute("cache-period");
|
||||||
if (StringUtils.hasText(cacheSeconds)) {
|
if (StringUtils.hasText(cacheSeconds)) {
|
||||||
|
|||||||
@@ -16,19 +16,14 @@
|
|||||||
|
|
||||||
package org.springframework.web.servlet.config.annotation;
|
package org.springframework.web.servlet.config.annotation;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache;
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.core.io.ResourceLoader;
|
|
||||||
import org.springframework.http.CacheControl;
|
import org.springframework.http.CacheControl;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.web.servlet.config.MvcNamespaceUtils;
|
|
||||||
import org.springframework.web.servlet.resource.PathResourceResolver;
|
import org.springframework.web.servlet.resource.PathResourceResolver;
|
||||||
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
|
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
|
||||||
|
|
||||||
@@ -42,13 +37,9 @@ import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
|
|||||||
*/
|
*/
|
||||||
public class ResourceHandlerRegistration {
|
public class ResourceHandlerRegistration {
|
||||||
|
|
||||||
private final ResourceLoader resourceLoader;
|
|
||||||
|
|
||||||
private final String[] pathPatterns;
|
private final String[] pathPatterns;
|
||||||
|
|
||||||
private final List<Resource> locations = new ArrayList<>();
|
private final List<String> locationValues = new ArrayList<>();
|
||||||
|
|
||||||
private final Map<Resource, Charset> locationCharsets = new HashMap<>();
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Integer cachePeriod;
|
private Integer cachePeriod;
|
||||||
@@ -62,12 +53,10 @@ public class ResourceHandlerRegistration {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a {@link ResourceHandlerRegistration} instance.
|
* Create a {@link ResourceHandlerRegistration} instance.
|
||||||
* @param resourceLoader a resource loader for turning a String location into a {@link Resource}
|
|
||||||
* @param pathPatterns one or more resource URL path patterns
|
* @param pathPatterns one or more resource URL path patterns
|
||||||
*/
|
*/
|
||||||
public ResourceHandlerRegistration(ResourceLoader resourceLoader, String... pathPatterns) {
|
public ResourceHandlerRegistration(String... pathPatterns) {
|
||||||
Assert.notEmpty(pathPatterns, "At least one path pattern is required for resource handling.");
|
Assert.notEmpty(pathPatterns, "At least one path pattern is required for resource handling.");
|
||||||
this.resourceLoader = resourceLoader;
|
|
||||||
this.pathPatterns = pathPatterns;
|
this.pathPatterns = pathPatterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,8 +80,7 @@ public class ResourceHandlerRegistration {
|
|||||||
* chained method invocation
|
* chained method invocation
|
||||||
*/
|
*/
|
||||||
public ResourceHandlerRegistration addResourceLocations(String... resourceLocations) {
|
public ResourceHandlerRegistration addResourceLocations(String... resourceLocations) {
|
||||||
MvcNamespaceUtils.loadResourceLocations(
|
this.locationValues.addAll(Arrays.asList(resourceLocations));
|
||||||
resourceLocations, this.resourceLoader, this.locations, this.locationCharsets);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,8 +170,7 @@ public class ResourceHandlerRegistration {
|
|||||||
handler.setResourceResolvers(this.resourceChainRegistration.getResourceResolvers());
|
handler.setResourceResolvers(this.resourceChainRegistration.getResourceResolvers());
|
||||||
handler.setResourceTransformers(this.resourceChainRegistration.getResourceTransformers());
|
handler.setResourceTransformers(this.resourceChainRegistration.getResourceTransformers());
|
||||||
}
|
}
|
||||||
handler.setLocations(this.locations);
|
handler.setLocationValues(this.locationValues);
|
||||||
handler.setLocationCharsets(this.locationCharsets);
|
|
||||||
if (this.cacheControl != null) {
|
if (this.cacheControl != null) {
|
||||||
handler.setCacheControl(this.cacheControl);
|
handler.setCacheControl(this.cacheControl);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,8 +117,7 @@ public class ResourceHandlerRegistry {
|
|||||||
* registered resource handler
|
* registered resource handler
|
||||||
*/
|
*/
|
||||||
public ResourceHandlerRegistration addResourceHandler(String... pathPatterns) {
|
public ResourceHandlerRegistration addResourceHandler(String... pathPatterns) {
|
||||||
ResourceHandlerRegistration registration =
|
ResourceHandlerRegistration registration = new ResourceHandlerRegistration(pathPatterns);
|
||||||
new ResourceHandlerRegistration(this.applicationContext, pathPatterns);
|
|
||||||
this.registrations.add(registration);
|
this.registrations.add(registration);
|
||||||
return registration;
|
return registration;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import java.io.IOException;
|
|||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -32,7 +31,10 @@ 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.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.UrlResource;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.HttpRange;
|
import org.springframework.http.HttpRange;
|
||||||
@@ -95,11 +97,15 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
|||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(ResourceHttpRequestHandler.class);
|
private static final Log logger = LogFactory.getLog(ResourceHttpRequestHandler.class);
|
||||||
|
|
||||||
|
private static final String URL_RESOURCE_CHARSET_PREFIX = "[charset=";
|
||||||
|
|
||||||
|
|
||||||
private final List<Resource> locations = new ArrayList<>(4);
|
private final List<Resource> locations = new ArrayList<>(4);
|
||||||
|
|
||||||
private final Map<Resource, Charset> locationCharsets = new HashMap<>(4);
|
private final Map<Resource, Charset> locationCharsets = new HashMap<>(4);
|
||||||
|
|
||||||
|
private final List<String> locationValues = new ArrayList<>(4);
|
||||||
|
|
||||||
private final List<ResourceResolver> resourceResolvers = new ArrayList<>(4);
|
private final List<ResourceResolver> resourceResolvers = new ArrayList<>(4);
|
||||||
|
|
||||||
private final List<ResourceTransformer> resourceTransformers = new ArrayList<>(4);
|
private final List<ResourceTransformer> resourceTransformers = new ArrayList<>(4);
|
||||||
@@ -129,9 +135,9 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the {@code List} of {@code Resource} paths to use as sources
|
* Set the {@code List} of {@code Resource} locations to use as sources
|
||||||
* for serving static resources.
|
* for serving static resources.
|
||||||
* @see #setLocationCharsets(Map)
|
* @see #setLocationValues(List)
|
||||||
*/
|
*/
|
||||||
public void setLocations(List<Resource> locations) {
|
public void setLocations(List<Resource> locations) {
|
||||||
Assert.notNull(locations, "Locations list must not be null");
|
Assert.notNull(locations, "Locations list must not be null");
|
||||||
@@ -140,35 +146,27 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the {@code List} of {@code Resource} paths to use as sources
|
* Return the configured {@code List} of {@code Resource} locations.
|
||||||
* for serving static resources.
|
* 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()}.
|
||||||
*/
|
*/
|
||||||
public List<Resource> getLocations() {
|
public List<Resource> getLocations() {
|
||||||
return this.locations;
|
return this.locations;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify charsets associated with the configured {@link #setLocations(List)
|
* An alternative to {@link #setLocations(List)} that accepts a list of
|
||||||
* locations}. This is supported for
|
* String-based location values, with support for {@link UrlResource}'s
|
||||||
* {@link org.springframework.core.io.UrlResource URL resources} such as a
|
* (e.g. files or HTTP URLs) with a special prefix to indicate the charset
|
||||||
* file or an HTTP URL location and is used in {@link PathResourceResolver}
|
* to use when appending relative paths. For example
|
||||||
* to correctly encode paths relative to the location.
|
* {@code "[charset=Windows-31J]http://example.org/path"}.
|
||||||
* <p><strong>Note:</strong> The charset is used only if the
|
|
||||||
* {@link #setUrlPathHelper urlPathHelper} property is also configured and
|
|
||||||
* its {@code urlDecode} property is set to {@code true}.
|
|
||||||
* @since 4.3.13
|
* @since 4.3.13
|
||||||
*/
|
*/
|
||||||
public void setLocationCharsets(Map<Resource, Charset> locationCharsets) {
|
public void setLocationValues(List<String> locationValues) {
|
||||||
this.locationCharsets.clear();
|
Assert.notNull(locationValues, "Location values list must not be null");
|
||||||
this.locationCharsets.putAll(locationCharsets);
|
this.locationValues.clear();
|
||||||
}
|
this.locationValues.addAll(locationValues);
|
||||||
|
|
||||||
/**
|
|
||||||
* Return charsets associated with static resource locations.
|
|
||||||
* @since 4.3.13
|
|
||||||
*/
|
|
||||||
public Map<Resource, Charset> getLocationCharsets() {
|
|
||||||
return Collections.unmodifiableMap(this.locationCharsets);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -303,6 +301,9 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
|
||||||
|
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 " +
|
||||||
"custom ResourceResolver is configured as an alternative to PathResourceResolver.");
|
"custom ResourceResolver is configured as an alternative to PathResourceResolver.");
|
||||||
@@ -311,6 +312,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
|||||||
if (this.resourceResolvers.isEmpty()) {
|
if (this.resourceResolvers.isEmpty()) {
|
||||||
this.resourceResolvers.add(new PathResourceResolver());
|
this.resourceResolvers.add(new PathResourceResolver());
|
||||||
}
|
}
|
||||||
|
|
||||||
initAllowedLocations();
|
initAllowedLocations();
|
||||||
|
|
||||||
if (this.resourceHttpMessageConverter == null) {
|
if (this.resourceHttpMessageConverter == null) {
|
||||||
@@ -323,6 +325,46 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
|||||||
this.contentNegotiationStrategy = initContentNegotiationStrategy();
|
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.");
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isEmpty(this.locationValues)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ApplicationContext appContext = obtainApplicationContext();
|
||||||
|
ConfigurableBeanFactory beanFactory = null;
|
||||||
|
if (appContext.getAutowireCapableBeanFactory() instanceof ConfigurableBeanFactory) {
|
||||||
|
beanFactory = ((ConfigurableBeanFactory) appContext.getAutowireCapableBeanFactory());
|
||||||
|
}
|
||||||
|
for (String location : this.locationValues) {
|
||||||
|
if (beanFactory != null) {
|
||||||
|
location = beanFactory.resolveEmbeddedValue(location);
|
||||||
|
Assert.notNull(location, "Null location");
|
||||||
|
}
|
||||||
|
Charset charset = null;
|
||||||
|
location = location.trim();
|
||||||
|
if (location.startsWith(URL_RESOURCE_CHARSET_PREFIX)) {
|
||||||
|
int endIndex = location.indexOf("]", URL_RESOURCE_CHARSET_PREFIX.length());
|
||||||
|
if (endIndex == -1) {
|
||||||
|
throw new IllegalArgumentException("Invalid charset syntax in location: " + location);
|
||||||
|
}
|
||||||
|
String value = location.substring(URL_RESOURCE_CHARSET_PREFIX.length(), endIndex);
|
||||||
|
charset = Charset.forName(value);
|
||||||
|
location = location.substring(endIndex + 1);
|
||||||
|
}
|
||||||
|
Resource resource = appContext.getResource(location);
|
||||||
|
this.locations.add(resource);
|
||||||
|
if (charset != null) {
|
||||||
|
if (!(resource instanceof UrlResource)) {
|
||||||
|
throw new IllegalArgumentException("Unexpected charset for non-UrlResource: " + resource);
|
||||||
|
}
|
||||||
|
this.locationCharsets.put(resource, charset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Look for a {@code PathResourceResolver} among the configured resource
|
* Look for a {@code PathResourceResolver} among the configured resource
|
||||||
* resolvers and set its {@code allowedLocations} property (if empty) to
|
* resolvers and set its {@code allowedLocations} property (if empty) to
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ import java.lang.annotation.ElementType;
|
|||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@@ -46,14 +46,13 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import org.springframework.beans.DirectFieldAccessor;
|
import org.springframework.beans.DirectFieldAccessor;
|
||||||
import org.springframework.beans.TypeMismatchException;
|
import org.springframework.beans.TypeMismatchException;
|
||||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
|
||||||
import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache;
|
||||||
import org.springframework.cache.CacheManager;
|
import org.springframework.cache.CacheManager;
|
||||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.convert.ConversionService;
|
import org.springframework.core.convert.ConversionService;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
import org.springframework.format.annotation.DateTimeFormat.ISO;
|
import org.springframework.format.annotation.DateTimeFormat.ISO;
|
||||||
import org.springframework.format.annotation.NumberFormat;
|
import org.springframework.format.annotation.NumberFormat;
|
||||||
@@ -84,7 +83,7 @@ import org.springframework.web.context.request.NativeWebRequest;
|
|||||||
import org.springframework.web.context.request.ServletWebRequest;
|
import org.springframework.web.context.request.ServletWebRequest;
|
||||||
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
|
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
|
||||||
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
|
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
|
||||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
import org.springframework.web.context.support.XmlWebApplicationContext;
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
import org.springframework.web.method.HandlerMethod;
|
import org.springframework.web.method.HandlerMethod;
|
||||||
import org.springframework.web.method.support.CompositeUriComponentsContributor;
|
import org.springframework.web.method.support.CompositeUriComponentsContributor;
|
||||||
@@ -169,7 +168,7 @@ public class MvcNamespaceTests {
|
|||||||
"org.springframework.web.servlet.config.viewControllerHandlerMapping";
|
"org.springframework.web.servlet.config.viewControllerHandlerMapping";
|
||||||
|
|
||||||
|
|
||||||
private GenericWebApplicationContext appContext;
|
private XmlWebApplicationContext appContext;
|
||||||
|
|
||||||
private TestController handler;
|
private TestController handler;
|
||||||
|
|
||||||
@@ -179,7 +178,7 @@ public class MvcNamespaceTests {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
TestMockServletContext servletContext = new TestMockServletContext();
|
TestMockServletContext servletContext = new TestMockServletContext();
|
||||||
appContext = new GenericWebApplicationContext();
|
appContext = new XmlWebApplicationContext();
|
||||||
appContext.setServletContext(servletContext);
|
appContext.setServletContext(servletContext);
|
||||||
LocaleContextHolder.setLocale(Locale.US);
|
LocaleContextHolder.setLocale(Locale.US);
|
||||||
|
|
||||||
@@ -422,8 +421,6 @@ public class MvcNamespaceTests {
|
|||||||
assertNotNull(handler);
|
assertNotNull(handler);
|
||||||
|
|
||||||
assertNotNull(handler.getUrlPathHelper());
|
assertNotNull(handler.getUrlPathHelper());
|
||||||
assertEquals(1, handler.getLocationCharsets().size());
|
|
||||||
assertEquals(StandardCharsets.ISO_8859_1, handler.getLocationCharsets().values().iterator().next());
|
|
||||||
|
|
||||||
List<ResourceResolver> resolvers = handler.getResourceResolvers();
|
List<ResourceResolver> resolvers = handler.getResourceResolvers();
|
||||||
assertThat(resolvers, Matchers.hasSize(4));
|
assertThat(resolvers, Matchers.hasSize(4));
|
||||||
@@ -443,8 +440,9 @@ public class MvcNamespaceTests {
|
|||||||
Matchers.instanceOf(ContentVersionStrategy.class));
|
Matchers.instanceOf(ContentVersionStrategy.class));
|
||||||
|
|
||||||
PathResourceResolver pathResolver = (PathResourceResolver) resolvers.get(3);
|
PathResourceResolver pathResolver = (PathResourceResolver) resolvers.get(3);
|
||||||
assertEquals(1, pathResolver.getLocationCharsets().size());
|
Map<Resource, Charset> locationCharsets = pathResolver.getLocationCharsets();
|
||||||
assertEquals(StandardCharsets.ISO_8859_1, handler.getLocationCharsets().values().iterator().next());
|
assertEquals(1, locationCharsets.size());
|
||||||
|
assertEquals(StandardCharsets.ISO_8859_1, locationCharsets.values().iterator().next());
|
||||||
|
|
||||||
List<ResourceTransformer> transformers = handler.getResourceTransformers();
|
List<ResourceTransformer> transformers = handler.getResourceTransformers();
|
||||||
assertThat(transformers, Matchers.hasSize(3));
|
assertThat(transformers, Matchers.hasSize(3));
|
||||||
@@ -942,11 +940,8 @@ public class MvcNamespaceTests {
|
|||||||
|
|
||||||
|
|
||||||
private void loadBeanDefinitions(String fileName) {
|
private void loadBeanDefinitions(String fileName) {
|
||||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
|
this.appContext.setConfigLocation("classpath:org/springframework/web/servlet/config/" + fileName);
|
||||||
ClassPathResource resource = new ClassPathResource(fileName, AnnotationDrivenBeanDefinitionParserTests.class);
|
this.appContext.refresh();
|
||||||
reader.loadBeanDefinitions(resource);
|
|
||||||
String names = Arrays.toString(this.appContext.getBeanDefinitionNames());
|
|
||||||
appContext.refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,10 @@
|
|||||||
|
|
||||||
package org.springframework.web.servlet.config.annotation;
|
package org.springframework.web.servlet.config.annotation;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -25,6 +27,7 @@ import org.junit.Test;
|
|||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.UrlResource;
|
import org.springframework.core.io.UrlResource;
|
||||||
import org.springframework.http.CacheControl;
|
import org.springframework.http.CacheControl;
|
||||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||||
@@ -69,8 +72,11 @@ public class ResourceHandlerRegistryTests {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
this.registry = new ResourceHandlerRegistry(new GenericWebApplicationContext(),
|
GenericWebApplicationContext appContext = new GenericWebApplicationContext();
|
||||||
new MockServletContext(), new ContentNegotiationManager(), new UrlPathHelper());
|
appContext.refresh();
|
||||||
|
|
||||||
|
this.registry = new ResourceHandlerRegistry(appContext, new MockServletContext(),
|
||||||
|
new ContentNegotiationManager(), new UrlPathHelper());
|
||||||
|
|
||||||
this.registration = this.registry.addResourceHandler("/resources/**");
|
this.registration = this.registry.addResourceHandler("/resources/**");
|
||||||
this.registration.addResourceLocations("classpath:org/springframework/web/servlet/config/annotation/");
|
this.registration.addResourceLocations("classpath:org/springframework/web/servlet/config/annotation/");
|
||||||
@@ -231,13 +237,12 @@ public class ResourceHandlerRegistryTests {
|
|||||||
UrlResource resource = (UrlResource) handler.getLocations().get(1);
|
UrlResource resource = (UrlResource) handler.getLocations().get(1);
|
||||||
assertEquals("file:/tmp", resource.getURL().toString());
|
assertEquals("file:/tmp", resource.getURL().toString());
|
||||||
assertNotNull(handler.getUrlPathHelper());
|
assertNotNull(handler.getUrlPathHelper());
|
||||||
assertEquals(1, handler.getLocationCharsets().size());
|
|
||||||
assertEquals(StandardCharsets.ISO_8859_1, handler.getLocationCharsets().get(resource));
|
|
||||||
|
|
||||||
List<ResourceResolver> resolvers = handler.getResourceResolvers();
|
List<ResourceResolver> resolvers = handler.getResourceResolvers();
|
||||||
PathResourceResolver resolver = (PathResourceResolver) resolvers.get(resolvers.size()-1);
|
PathResourceResolver resolver = (PathResourceResolver) resolvers.get(resolvers.size()-1);
|
||||||
assertEquals(1, resolver.getLocationCharsets().size());
|
Map<Resource, Charset> locationCharsets = resolver.getLocationCharsets();
|
||||||
assertEquals(StandardCharsets.ISO_8859_1, handler.getLocationCharsets().values().iterator().next());
|
assertEquals(1, locationCharsets.size());
|
||||||
|
assertEquals(StandardCharsets.ISO_8859_1, locationCharsets.values().iterator().next());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceHttpRequestHandler getHandler(String pathPattern) {
|
private ResourceHttpRequestHandler getHandler(String pathPattern) {
|
||||||
|
|||||||
@@ -21,7 +21,13 @@
|
|||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||||
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
|
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
|
||||||
|
|
||||||
<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/, [charset=ISO-8859-1]file:///tmp">
|
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
|
||||||
|
<property name="properties">
|
||||||
|
<value>location=file:///tmp</value>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/, [charset=ISO-8859-1]${location}">
|
||||||
<mvc:resource-chain resource-cache="true" cache-manager="resourceCache" cache-name="test-resource-cache">
|
<mvc:resource-chain resource-cache="true" cache-manager="resourceCache" cache-name="test-resource-cache">
|
||||||
<mvc:resolvers>
|
<mvc:resolvers>
|
||||||
<mvc:version-resolver>
|
<mvc:version-resolver>
|
||||||
|
|||||||
Reference in New Issue
Block a user