SPR-7116 - Simplified (removed gzip and white-listing) and completed XML namespace config.
This commit is contained in:
parent
061af2f25f
commit
367048c5d1
|
|
@ -0,0 +1,39 @@
|
|||
package org.springframework.web.servlet.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Abstract base class for {@link BeanDefinitonParser}s that register an {@link HttpRequestHandler}.
|
||||
*
|
||||
* @author Jeremy Grelle
|
||||
* @since 3.0.4
|
||||
*/
|
||||
public abstract class AbstractHttpRequestHandlerBeanDefinitionParser implements BeanDefinitionParser{
|
||||
|
||||
private static final String HANDLER_ADAPTER_BEAN_NAME = "org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
registerHandlerAdapterIfNecessary(parserContext, source);
|
||||
doParse(element, parserContext);
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract void doParse(Element element, ParserContext parserContext);
|
||||
|
||||
private void registerHandlerAdapterIfNecessary(ParserContext parserContext, Object source) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(HANDLER_ADAPTER_BEAN_NAME)) {
|
||||
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(HttpRequestHandlerAdapter.class);
|
||||
handlerAdapterDef.setSource(source);
|
||||
handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
parserContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package org.springframework.web.servlet.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
|
||||
import org.springframework.web.servlet.resources.DefaultServletHttpRequestHandler;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link BeanDefinitionParser} that parses a {@code default-servlet-handler} element to
|
||||
* register a {@link DefaultServletHttpRequestHandler}. Will also register a
|
||||
* {@link SimpleUrlHandlerMapping} for mapping resource requests, and a
|
||||
* {@link HttpRequestHandlerAdapter} if necessary.
|
||||
*
|
||||
* @author Jeremy Grelle
|
||||
* @since 3.0.4
|
||||
*/
|
||||
public class DefaultServletHandlerBeanDefinitionParser extends AbstractHttpRequestHandlerBeanDefinitionParser {
|
||||
|
||||
@Override
|
||||
public void doParse(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
|
||||
String defaultServletName = element.getAttribute("default-servlet-name");
|
||||
RootBeanDefinition defaultServletHandlerDef = new RootBeanDefinition(DefaultServletHttpRequestHandler.class);
|
||||
defaultServletHandlerDef.setSource(source);
|
||||
defaultServletHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
if (StringUtils.hasText(defaultServletName)) {
|
||||
defaultServletHandlerDef.getPropertyValues().add("defaultServletName", defaultServletName);
|
||||
}
|
||||
String defaultServletHandlerName = parserContext.getReaderContext().generateBeanName(defaultServletHandlerDef);
|
||||
parserContext.getRegistry().registerBeanDefinition(defaultServletHandlerName, defaultServletHandlerDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(defaultServletHandlerDef, defaultServletHandlerName));
|
||||
|
||||
Map<String, String> urlMap = new ManagedMap<String, String>();
|
||||
urlMap.put("/**", defaultServletHandlerName);
|
||||
|
||||
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
|
||||
handlerMappingDef.setSource(source);
|
||||
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
handlerMappingDef.getPropertyValues().add("urlMap", urlMap);
|
||||
|
||||
String handlerMappingBeanName = parserContext.getReaderContext().generateBeanName(handlerMappingDef);
|
||||
parserContext.getRegistry().registerBeanDefinition(handlerMappingBeanName, handlerMappingDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, handlerMappingBeanName));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -23,12 +23,14 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
|||
* {@link NamespaceHandler} for Spring MVC configuration namespace.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Jeremy Grelle
|
||||
* @since 3.0
|
||||
*/
|
||||
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import org.springframework.beans.factory.support.ManagedMap;
|
|||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
|
||||
import org.springframework.web.servlet.resources.ResourceHttpRequestHandler;
|
||||
|
|
@ -18,74 +20,66 @@ import org.w3c.dom.Element;
|
|||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses a
|
||||
* {@code resources} element to register a {@link ResourceHttpRequestHandler}.
|
||||
* Will also register a {@link SimpleUrlHandlerMapping} for mapping resource requests, if necessary.
|
||||
* Will also register a {@link HttpRequestHandlerAdapter} if necessary.
|
||||
* Will also register a {@link SimpleUrlHandlerMapping} for mapping resource requests,
|
||||
* and a {@link HttpRequestHandlerAdapter} if necessary.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Jeremy Grelle
|
||||
* @since 3.0.4
|
||||
*/
|
||||
public class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
|
||||
public class ResourcesBeanDefinitionParser extends AbstractHttpRequestHandlerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
private static final String HANDLER_ADAPTER_BEAN_NAME = "org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter";
|
||||
|
||||
private static final String HANDLER_MAPPING_BEAN_NAME = "org.springframework.web.servlet.config.resourcesHandlerMapping";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
@Override
|
||||
public void doParse(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
|
||||
registerHandlerAdapterIfNecessary(parserContext, source);
|
||||
BeanDefinition handlerMappingDef = registerHandlerMappingIfNecessary(parserContext, source);
|
||||
|
||||
List<String> resourcePaths = new ManagedList<String>();
|
||||
resourcePaths.add("/");
|
||||
registerResourceMappings(parserContext, element, source);
|
||||
}
|
||||
|
||||
private void registerResourceMappings(ParserContext parserContext, Element element, Object source) {
|
||||
String resourceHandlerName = registerResourceHandler(parserContext, element, source);
|
||||
if (!StringUtils.hasText(resourceHandlerName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, String> urlMap = new ManagedMap<String, String>();
|
||||
String resourceRequestPath = element.getAttribute("mapping");
|
||||
if (!StringUtils.hasText(resourceRequestPath)) {
|
||||
parserContext.getReaderContext().error("The 'mapping' attribute is required.", parserContext.extractSource(element));
|
||||
return;
|
||||
}
|
||||
urlMap.put(resourceRequestPath, resourceHandlerName);
|
||||
|
||||
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
|
||||
handlerMappingDef.setSource(source);
|
||||
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
handlerMappingDef.getPropertyValues().add("urlMap", urlMap);
|
||||
|
||||
String mappingOrder = element.getAttribute("mapping-order");
|
||||
handlerMappingDef.getPropertyValues().add("order", StringUtils.hasText(mappingOrder) ? mappingOrder : Ordered.LOWEST_PRECEDENCE - 1);
|
||||
|
||||
String beanName = parserContext.getReaderContext().generateBeanName(handlerMappingDef);
|
||||
parserContext.getRegistry().registerBeanDefinition(beanName, handlerMappingDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, beanName));
|
||||
}
|
||||
|
||||
private String registerResourceHandler(ParserContext parserContext, Element element, Object source) {
|
||||
String locationAttr = element.getAttribute("location");
|
||||
if (!StringUtils.hasText(locationAttr)) {
|
||||
parserContext.getReaderContext().error("The 'location' attribute is required.", parserContext.extractSource(element));
|
||||
return "";
|
||||
}
|
||||
String[] locationPatterns = locationAttr.split(",\\s*");
|
||||
List<String> locations = new ManagedList<String>();
|
||||
for (String location : locationPatterns) {
|
||||
locations.add(location);
|
||||
}
|
||||
RootBeanDefinition resourceHandlerDef = new RootBeanDefinition(ResourceHttpRequestHandler.class);
|
||||
resourceHandlerDef.setSource(source);
|
||||
resourceHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
resourceHandlerDef.getConstructorArgumentValues().addIndexedArgumentValue(0, resourcePaths);
|
||||
|
||||
Map<String, BeanDefinition> urlMap = getUrlMap(handlerMappingDef);
|
||||
String resourceRequestPath = "/resources/**";
|
||||
urlMap.put(resourceRequestPath, resourceHandlerDef);
|
||||
|
||||
return null;
|
||||
resourceHandlerDef.getConstructorArgumentValues().addIndexedArgumentValue(0, locations);
|
||||
String beanName = parserContext.getReaderContext().generateBeanName(resourceHandlerDef);
|
||||
parserContext.getRegistry().registerBeanDefinition(beanName, resourceHandlerDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(resourceHandlerDef, beanName));
|
||||
return beanName;
|
||||
}
|
||||
|
||||
private void registerHandlerAdapterIfNecessary(ParserContext parserContext, Object source) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(HANDLER_ADAPTER_BEAN_NAME)) {
|
||||
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(HttpRequestHandlerAdapter.class);
|
||||
handlerAdapterDef.setSource(source);
|
||||
handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
parserContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
private BeanDefinition registerHandlerMappingIfNecessary(ParserContext parserContext, Object source) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(HANDLER_MAPPING_BEAN_NAME)) {
|
||||
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
|
||||
handlerMappingDef.setSource(source);
|
||||
handlerMappingDef.getPropertyValues().add("order", "2");
|
||||
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
parserContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
|
||||
return handlerMappingDef;
|
||||
}
|
||||
else {
|
||||
return parserContext.getRegistry().getBeanDefinition(HANDLER_MAPPING_BEAN_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, BeanDefinition> getUrlMap(BeanDefinition handlerMappingDef) {
|
||||
Map<String, BeanDefinition> urlMap;
|
||||
if (handlerMappingDef.getPropertyValues().contains("urlMap")) {
|
||||
urlMap = (Map<String, BeanDefinition>) handlerMappingDef.getPropertyValues().getPropertyValue("urlMap").getValue();
|
||||
}
|
||||
else {
|
||||
urlMap = new ManagedMap<String, BeanDefinition>();
|
||||
handlerMappingDef.getPropertyValues().add("urlMap", urlMap);
|
||||
}
|
||||
return urlMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ import org.springframework.web.context.ServletContextAware;
|
|||
* can be matched.
|
||||
*
|
||||
* <p>Requests are handled by forwarding through the {@link RequestDispatcher} obtained via the name specified through the
|
||||
* {@code fileServletName} property. In most cases, the {@code fileServletName} does not need to be set explicitly, as the
|
||||
* {@code defaultServletName} property. In most cases, the {@code defaultServletName} does not need to be set explicitly, as the
|
||||
* handler checks at initialization time for the presence of the default Servlet of one of the known containers. However, if
|
||||
* running in a container where the default Servlet's name is not known, or where it has been customized via configuration, the
|
||||
* {@code fileServletName} will need to be set explicitly.
|
||||
* {@code defaultServletName} will need to be set explicitly.
|
||||
*
|
||||
* @author Jeremy Grelle
|
||||
* @since 3.0.4
|
||||
|
|
@ -55,40 +55,40 @@ public class DefaultServletHttpRequestHandler implements InitializingBean, HttpR
|
|||
|
||||
private ServletContext servletContext;
|
||||
|
||||
private String fileServletName;
|
||||
private String defaultServletName;
|
||||
|
||||
/**
|
||||
* If the {@code filedServletName} property has not been explicitly set, attempts to locate the default Servlet using the
|
||||
* known common container-specific names.
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (!StringUtils.hasText(this.fileServletName)) {
|
||||
if (!StringUtils.hasText(this.defaultServletName)) {
|
||||
if (this.servletContext.getNamedDispatcher(COMMON_DEFAULT_SERVLET_NAME) != null) {
|
||||
this.fileServletName = COMMON_DEFAULT_SERVLET_NAME;
|
||||
this.defaultServletName = COMMON_DEFAULT_SERVLET_NAME;
|
||||
} else if (this.servletContext.getNamedDispatcher(RESIN_DEFAULT_SERVLET_NAME) != null) {
|
||||
this.fileServletName = RESIN_DEFAULT_SERVLET_NAME;
|
||||
this.defaultServletName = RESIN_DEFAULT_SERVLET_NAME;
|
||||
} else if (this.servletContext.getNamedDispatcher(WEBLOGIC_DEFAULT_SERVLET_NAME) != null) {
|
||||
this.fileServletName = WEBLOGIC_DEFAULT_SERVLET_NAME;
|
||||
this.defaultServletName = WEBLOGIC_DEFAULT_SERVLET_NAME;
|
||||
} else if (this.servletContext.getNamedDispatcher(WEBSPHERE_DEFAULT_SERVLET_NAME) != null) {
|
||||
this.fileServletName = WEBSPHERE_DEFAULT_SERVLET_NAME;
|
||||
this.defaultServletName = WEBSPHERE_DEFAULT_SERVLET_NAME;
|
||||
}
|
||||
Assert.hasText(this.fileServletName, "Unable to locate the default servlet for serving static content. Please set the 'fileServletName' property explicitly.");
|
||||
Assert.hasText(this.defaultServletName, "Unable to locate the default servlet for serving static content. Please set the 'defaultServletName' property explicitly.");
|
||||
}
|
||||
}
|
||||
|
||||
public void handleRequest(HttpServletRequest request,
|
||||
HttpServletResponse response) throws ServletException, IOException {
|
||||
RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.fileServletName);
|
||||
Assert.notNull(rd, "A RequestDispatcher could not be located for the servlet name '"+this.fileServletName+"'");
|
||||
RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName);
|
||||
Assert.notNull(rd, "A RequestDispatcher could not be located for the servlet name '"+this.defaultServletName+"'");
|
||||
rd.forward(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the default Servlet to be forwarded to for static resource requests.
|
||||
* @param fileServletName The name of the Servlet to use for static resources.
|
||||
* @param defaultServletName The name of the Servlet to use for static resources.
|
||||
*/
|
||||
public void setDefaultServletName(String fileServletName) {
|
||||
this.fileServletName = fileServletName;
|
||||
public void setDefaultServletName(String defaultServletName) {
|
||||
this.defaultServletName = defaultServletName;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package org.springframework.web.servlet.resources;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
|
@ -8,18 +7,15 @@ import java.io.OutputStream;
|
|||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
|
@ -39,8 +35,7 @@ import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
|
|||
|
||||
/**
|
||||
* {@link HttpRequestHandler} that serves static resources optimized for superior browser performance
|
||||
* (according to the guidelines of Page Speed, YSlow, etc.) by adding far future cache expiration headers
|
||||
* and gzip compressing the resources if supported by the client.
|
||||
* (according to the guidelines of Page Speed, YSlow, etc.) by adding far future cache expiration headers.
|
||||
*
|
||||
* <p>TODO - expand the docs further
|
||||
*
|
||||
|
|
@ -54,39 +49,14 @@ public class ResourceHttpRequestHandler implements HttpRequestHandler, ServletCo
|
|||
|
||||
private final List<Resource> resourcePaths;
|
||||
|
||||
private int maxAge = 31556926;
|
||||
|
||||
private static final String defaultMediaTypes = "image/*,text/css,text/javascript,text/html";
|
||||
|
||||
private List<MediaType> allowedMediaTypes = new ArrayList<MediaType>();
|
||||
private final int maxAge = 31556926;
|
||||
|
||||
private FileMediaTypeMap fileMediaTypeMap;
|
||||
|
||||
private boolean gzipEnabled = true;
|
||||
|
||||
private int minGzipSize = 150;
|
||||
|
||||
private int maxGzipSize = 500000;
|
||||
|
||||
public ResourceHttpRequestHandler(List<Resource> resourcePaths) {
|
||||
this(resourcePaths, defaultMediaTypes);
|
||||
}
|
||||
|
||||
public ResourceHttpRequestHandler(List<Resource> resourcePaths, String allowedMediaTypes) {
|
||||
this(resourcePaths, allowedMediaTypes, false);
|
||||
}
|
||||
|
||||
public ResourceHttpRequestHandler(List<Resource> resourcePaths, String allowedMediaTypes, boolean overrideDefaultMediaTypes) {
|
||||
Assert.notNull(resourcePaths, "Resource paths must not be null");
|
||||
validateResourcePaths(resourcePaths);
|
||||
this.resourcePaths = resourcePaths;
|
||||
if (StringUtils.hasText(allowedMediaTypes)) {
|
||||
this.allowedMediaTypes.addAll(MediaType.parseMediaTypes(allowedMediaTypes));
|
||||
}
|
||||
if (!overrideDefaultMediaTypes) {
|
||||
this.allowedMediaTypes.addAll(MediaType.parseMediaTypes(defaultMediaTypes));
|
||||
}
|
||||
MediaType.sortBySpecificity(this.allowedMediaTypes);
|
||||
}
|
||||
|
||||
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
|
|
@ -95,7 +65,7 @@ public class ResourceHttpRequestHandler implements HttpRequestHandler, ServletCo
|
|||
new String[] {"GET"}, "ResourceHttpRequestHandler only supports GET requests");
|
||||
}
|
||||
URLResource resource = getResource(request);
|
||||
if (resource == null || !isResourceAllowed(resource)) {
|
||||
if (resource == null) {
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
|
@ -106,18 +76,6 @@ public class ResourceHttpRequestHandler implements HttpRequestHandler, ServletCo
|
|||
writeResponse(resource, request, response);
|
||||
}
|
||||
|
||||
public void setGzipEnabled(boolean gzipEnabled) {
|
||||
this.gzipEnabled = gzipEnabled;
|
||||
}
|
||||
|
||||
public void setMinGzipSize(int minGzipSize) {
|
||||
this.minGzipSize = minGzipSize;
|
||||
}
|
||||
|
||||
public void setMaxGzipSize(int maxGzipSize) {
|
||||
this.maxGzipSize = maxGzipSize;
|
||||
}
|
||||
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
this.fileMediaTypeMap = new DefaultFileMediaTypeMap(servletContext);
|
||||
}
|
||||
|
|
@ -167,18 +125,9 @@ public class ResourceHttpRequestHandler implements HttpRequestHandler, ServletCo
|
|||
response.setHeader("Cache-Control", "max-age=" + this.maxAge);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isResourceAllowed(URLResource resource) {
|
||||
for(MediaType allowedType : allowedMediaTypes) {
|
||||
if (allowedType.includes(resource.getMediaType())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void writeResponse(URLResource resource, HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
OutputStream out = selectOutputStream(resource, request, response);
|
||||
OutputStream out = response.getOutputStream();
|
||||
try {
|
||||
InputStream in = resource.getInputStream();
|
||||
try {
|
||||
|
|
@ -199,19 +148,6 @@ public class ResourceHttpRequestHandler implements HttpRequestHandler, ServletCo
|
|||
}
|
||||
}
|
||||
|
||||
private OutputStream selectOutputStream(URLResource resource, HttpServletRequest request,
|
||||
HttpServletResponse response) throws IOException {
|
||||
String acceptEncoding = request.getHeader("Accept-Encoding");
|
||||
boolean isGzipEligible = resource.getContentLength() >= this.minGzipSize && resource.getContentLength() <= this.maxGzipSize;
|
||||
if (this.gzipEnabled && isGzipEligible && StringUtils.hasText(acceptEncoding)
|
||||
&& acceptEncoding.indexOf("gzip") > -1
|
||||
&& response.getContentType().startsWith("text/")){
|
||||
return new GZIPResponseStream(response);
|
||||
} else {
|
||||
return response.getOutputStream();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidFile(Resource resource) throws IOException {
|
||||
return resource.exists() && StringUtils.hasText(resource.getFilename());
|
||||
}
|
||||
|
|
@ -223,13 +159,11 @@ public class ResourceHttpRequestHandler implements HttpRequestHandler, ServletCo
|
|||
}
|
||||
}
|
||||
|
||||
// TODO promote to top-level and make reusable
|
||||
|
||||
public interface FileMediaTypeMap {
|
||||
private interface FileMediaTypeMap {
|
||||
MediaType getMediaType(String fileName);
|
||||
}
|
||||
|
||||
public static class DefaultFileMediaTypeMap implements FileMediaTypeMap {
|
||||
private static class DefaultFileMediaTypeMap implements FileMediaTypeMap {
|
||||
|
||||
private static final boolean jafPresent =
|
||||
ClassUtils.isPresent("javax.activation.FileTypeMap", ContentNegotiatingViewResolver.class.getClassLoader());
|
||||
|
|
@ -314,67 +248,6 @@ public class ResourceHttpRequestHandler implements HttpRequestHandler, ServletCo
|
|||
}
|
||||
}
|
||||
|
||||
private class GZIPResponseStream extends ServletOutputStream {
|
||||
|
||||
private ByteArrayOutputStream byteStream = null;
|
||||
|
||||
private GZIPOutputStream gzipStream = null;
|
||||
|
||||
private boolean closed = false;
|
||||
|
||||
private HttpServletResponse response = null;
|
||||
|
||||
private ServletOutputStream servletStream = null;
|
||||
|
||||
public GZIPResponseStream(HttpServletResponse response) throws IOException {
|
||||
super();
|
||||
closed = false;
|
||||
this.response = response;
|
||||
this.servletStream = response.getOutputStream();
|
||||
byteStream = new ByteArrayOutputStream();
|
||||
gzipStream = new GZIPOutputStream(byteStream);
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("This output stream has already been closed");
|
||||
}
|
||||
gzipStream.finish();
|
||||
byte[] bytes = byteStream.toByteArray();
|
||||
response.setContentLength(bytes.length);
|
||||
response.addHeader("Content-Encoding", "gzip");
|
||||
servletStream.write(bytes);
|
||||
servletStream.flush();
|
||||
servletStream.close();
|
||||
closed = true;
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Cannot flush a closed output stream");
|
||||
}
|
||||
gzipStream.flush();
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Cannot write to a closed output stream");
|
||||
}
|
||||
gzipStream.write((byte) b);
|
||||
}
|
||||
|
||||
public void write(byte b[]) throws IOException {
|
||||
write(b, 0, b.length);
|
||||
}
|
||||
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Cannot write to a closed output stream");
|
||||
}
|
||||
gzipStream.write(b, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
private static class URLResource implements Resource {
|
||||
|
||||
private final Resource wrapped;
|
||||
|
|
|
|||
|
|
@ -53,10 +53,64 @@
|
|||
<xsd:annotation>
|
||||
<xsd:documentation
|
||||
source="java:org.springframework.web.servlet.resources.ResourceHttpRequestHandler"><![CDATA[
|
||||
Configures support for efficiently serving static resources such as images, js, and, css files.
|
||||
By default, registers a handler mapped to /resources/** capable of serving all resources located in the ${webappRoot}/resources directory.
|
||||
Configures a handler for serving static resources such as images, js, and, css files with cache headers optimized for efficient
|
||||
loading in a web browser. Allows resources to be served out of any path that is reachable via Spring's Resource handling.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="mapping" use="required" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The URL mapping pattern, within the current Sevlet context, to use for serving resources from this handler, such as "/resources/**"
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="location" use="required" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The resource location from which to serve static content, specified at a Spring Resource pattern. Each location must point to a valid directory.
|
||||
Multiple locations may be specified as a comma-seperated list, and the locations will be checked for a given resource in the order specified. For example,
|
||||
a value of "/, classpath:/META-INF/public-web-resources/" will allow resources to be served both from the web app root and from any JAR on the classpath
|
||||
that contains a /META-INF/public-web-resources/ directory, with resources in the web app root taking precedence.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="mapping-order" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Specifies the order of the HandlerMapping for the resource handler. The default order is Ordered.LOWEST_PRECEDENCE - 1.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="default-servlet-handler">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation
|
||||
source="java:org.springframework.web.servlet.resources.DefaultServletHttpRequestHandler"><![CDATA[
|
||||
Configures a handler for serving static resources by forwarding to the Servlet container's default Servlet. Use of this
|
||||
handler allows using a "/" mapping with the DispatcherServlet while still utilizing the Servlet container to serve static
|
||||
resources.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="default-servlet-name" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The name of the default Servlet to forward to for static resource requests. The handler will try to auto-detect the container's
|
||||
default Servlet at startup time using a list of known names. If the default Servlet cannot be detected because of using an unknown
|
||||
container or because it has been manually configured, the servlet name must be set explicitly.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="interceptors">
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ package org.springframework.web.servlet.config;
|
|||
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
|
|
@ -28,6 +30,7 @@ import org.junit.Test;
|
|||
import org.springframework.beans.TypeMismatchException;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
|
@ -36,6 +39,7 @@ import org.springframework.format.support.FormattingConversionServiceFactoryBean
|
|||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockRequestDispatcher;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.BindingResult;
|
||||
|
|
@ -56,12 +60,14 @@ import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
|
|||
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
|
||||
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
|
||||
import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping;
|
||||
import org.springframework.web.servlet.resources.DefaultServletHttpRequestHandler;
|
||||
import org.springframework.web.servlet.resources.ResourceHttpRequestHandler;
|
||||
import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
|
||||
|
||||
/**
|
||||
* @author Keith Donald
|
||||
* @author Arjen Poutsma
|
||||
* @author Jeremy Grelle
|
||||
*/
|
||||
public class MvcNamespaceTests {
|
||||
|
||||
|
|
@ -70,7 +76,7 @@ public class MvcNamespaceTests {
|
|||
@Before
|
||||
public void setUp() {
|
||||
appContext = new GenericWebApplicationContext();
|
||||
appContext.setServletContext(new MockServletContext());
|
||||
appContext.setServletContext(new TestMockServletContext());
|
||||
LocaleContextHolder.setLocale(Locale.US);
|
||||
}
|
||||
|
||||
|
|
@ -204,14 +210,18 @@ public class MvcNamespaceTests {
|
|||
public void testResources() throws Exception {
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
|
||||
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-resources.xml", getClass()));
|
||||
assertEquals(2, appContext.getBeanDefinitionCount());
|
||||
assertEquals(3, appContext.getBeanDefinitionCount());
|
||||
appContext.refresh();
|
||||
|
||||
HttpRequestHandlerAdapter adapter = appContext.getBean(HttpRequestHandlerAdapter.class);
|
||||
assertNotNull(adapter);
|
||||
|
||||
ResourceHttpRequestHandler handler = appContext.getBean(ResourceHttpRequestHandler.class);
|
||||
assertNotNull(handler);
|
||||
|
||||
SimpleUrlHandlerMapping mapping = appContext.getBean(SimpleUrlHandlerMapping.class);
|
||||
assertNotNull(mapping);
|
||||
assertEquals(Ordered.LOWEST_PRECEDENCE - 1, mapping.getOrder());
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI("/resources/foo.css");
|
||||
|
|
@ -227,6 +237,76 @@ public class MvcNamespaceTests {
|
|||
ModelAndView mv = adapter.handle(request, response, chain.getHandler());
|
||||
assertNull(mv);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourcesWithOptionalAttributes() throws Exception {
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
|
||||
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-resources-optional-attrs.xml", getClass()));
|
||||
assertEquals(3, appContext.getBeanDefinitionCount());
|
||||
appContext.refresh();
|
||||
|
||||
SimpleUrlHandlerMapping mapping = appContext.getBean(SimpleUrlHandlerMapping.class);
|
||||
assertNotNull(mapping);
|
||||
assertEquals(5, mapping.getOrder());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultServletHandler() throws Exception {
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
|
||||
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-default-servlet.xml", getClass()));
|
||||
assertEquals(3, appContext.getBeanDefinitionCount());
|
||||
appContext.refresh();
|
||||
|
||||
HttpRequestHandlerAdapter adapter = appContext.getBean(HttpRequestHandlerAdapter.class);
|
||||
assertNotNull(adapter);
|
||||
|
||||
DefaultServletHttpRequestHandler handler = appContext.getBean(DefaultServletHttpRequestHandler.class);
|
||||
assertNotNull(handler);
|
||||
|
||||
SimpleUrlHandlerMapping mapping = appContext.getBean(SimpleUrlHandlerMapping.class);
|
||||
assertNotNull(mapping);
|
||||
assertEquals(Ordered.LOWEST_PRECEDENCE, mapping.getOrder());
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI("/foo.css");
|
||||
request.setMethod("GET");
|
||||
|
||||
HandlerExecutionChain chain = mapping.getHandler(request);
|
||||
assertTrue(chain.getHandler() instanceof DefaultServletHttpRequestHandler);
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
ModelAndView mv = adapter.handle(request, response, chain.getHandler());
|
||||
assertNull(mv);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultServletHandlerWithOptionalAtrributes() throws Exception {
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
|
||||
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-default-servlet-optional-attrs.xml", getClass()));
|
||||
assertEquals(3, appContext.getBeanDefinitionCount());
|
||||
appContext.refresh();
|
||||
|
||||
HttpRequestHandlerAdapter adapter = appContext.getBean(HttpRequestHandlerAdapter.class);
|
||||
assertNotNull(adapter);
|
||||
|
||||
DefaultServletHttpRequestHandler handler = appContext.getBean(DefaultServletHttpRequestHandler.class);
|
||||
assertNotNull(handler);
|
||||
|
||||
SimpleUrlHandlerMapping mapping = appContext.getBean(SimpleUrlHandlerMapping.class);
|
||||
assertNotNull(mapping);
|
||||
assertEquals(Ordered.LOWEST_PRECEDENCE, mapping.getOrder());
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI("/foo.css");
|
||||
request.setMethod("GET");
|
||||
|
||||
HandlerExecutionChain chain = mapping.getHandler(request);
|
||||
assertTrue(chain.getHandler() instanceof DefaultServletHttpRequestHandler);
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
ModelAndView mv = adapter.handle(request, response, chain.getHandler());
|
||||
assertNull(mv);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeanDecoration() throws Exception {
|
||||
|
|
@ -393,14 +473,29 @@ public class MvcNamespaceTests {
|
|||
@NotNull
|
||||
private String field;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public String getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setField(String field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class TestMockServletContext extends MockServletContext {
|
||||
|
||||
@Override
|
||||
public RequestDispatcher getNamedDispatcher(String path) {
|
||||
if (path.equals("default") || path.equals("custom")) {
|
||||
return new MockRequestDispatcher("/");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,16 +61,6 @@ public class ResourceHttpRequestHandlerTests {
|
|||
assertEquals(response.getHeader("Last-Modified"), new ClassPathResource("test/foo.html", getClass()).getFile().lastModified());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResourceWithUnknownMediaType() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "/test.unknown");
|
||||
request.setMethod("GET");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
handler.handleRequest(request, response);
|
||||
assertEquals(404, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResourceFromAlternatePath() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
|
@ -193,51 +183,6 @@ public class ResourceHttpRequestHandlerTests {
|
|||
handler = new ResourceHttpRequestHandler(resourcePaths);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResourceOfAddedAllowedMimeType() throws Exception{
|
||||
List<Resource> resourcePaths = new ArrayList<Resource>();
|
||||
resourcePaths.add(new ClassPathResource("test/", getClass()));
|
||||
handler = new ResourceHttpRequestHandler(resourcePaths, "text/plain");
|
||||
handler.setServletContext(new TestServletContext());
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "/foo.txt");
|
||||
request.setMethod("GET");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
handler.handleRequest(request, response);
|
||||
assertEquals("text/plain", response.getContentType());
|
||||
assertTrue(((Long)response.getHeader("Expires")) > System.currentTimeMillis() + (31556926 * 1000) - 10000);
|
||||
assertEquals("max-age=31556926", response.getHeader("Cache-Control"));
|
||||
assertTrue(response.containsHeader("Last-Modified"));
|
||||
assertEquals(response.getHeader("Last-Modified"), new ClassPathResource("test/foo.txt", getClass()).getFile().lastModified());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResourceWithDefaultMimeTypesOverriden() throws Exception{
|
||||
List<Resource> resourcePaths = new ArrayList<Resource>();
|
||||
resourcePaths.add(new ClassPathResource("test/", getClass()));
|
||||
handler = new ResourceHttpRequestHandler(resourcePaths, "text/plain", true);
|
||||
handler.setServletContext(new TestServletContext());
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "/foo.txt");
|
||||
request.setMethod("GET");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
handler.handleRequest(request, response);
|
||||
assertEquals("text/plain", response.getContentType());
|
||||
assertTrue(((Long)response.getHeader("Expires")) > System.currentTimeMillis() + (31556926 * 1000) - 10000);
|
||||
assertEquals("max-age=31556926", response.getHeader("Cache-Control"));
|
||||
assertTrue(response.containsHeader("Last-Modified"));
|
||||
assertEquals(response.getHeader("Last-Modified"), new ClassPathResource("test/foo.txt", getClass()).getFile().lastModified());
|
||||
|
||||
request = new MockHttpServletRequest();
|
||||
request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "/foo.css");
|
||||
request.setMethod("GET");
|
||||
response = new MockHttpServletResponse();
|
||||
handler.handleRequest(request, response);
|
||||
assertEquals(404, response.getStatus());
|
||||
}
|
||||
|
||||
private static class TestServletContext extends MockServletContext {
|
||||
@Override
|
||||
public String getMimeType(String filePath) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
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-3.0.xsd">
|
||||
|
||||
<mvc:default-servlet-handler default-servlet-name="custom" />
|
||||
|
||||
</beans>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
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-3.0.xsd">
|
||||
|
||||
<mvc:default-servlet-handler />
|
||||
|
||||
</beans>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
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-3.0.xsd">
|
||||
|
||||
<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/" mapping-order="5"/>
|
||||
|
||||
</beans>
|
||||
|
|
@ -5,6 +5,6 @@
|
|||
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-3.0.xsd">
|
||||
|
||||
<mvc:resources />
|
||||
<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/" />
|
||||
|
||||
</beans>
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
This shouldn't be served.
|
||||
Loading…
Reference in New Issue