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.
|
* {@link NamespaceHandler} for Spring MVC configuration namespace.
|
||||||
*
|
*
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
|
* @author Jeremy Grelle
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
|
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
|
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
|
||||||
|
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
|
||||||
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
|
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
|
||||||
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
|
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
|
||||||
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
|
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.support.RootBeanDefinition;
|
||||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||||
import org.springframework.beans.factory.xml.ParserContext;
|
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.handler.SimpleUrlHandlerMapping;
|
||||||
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
|
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
|
||||||
import org.springframework.web.servlet.resources.ResourceHttpRequestHandler;
|
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
|
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses a
|
||||||
* {@code resources} element to register a {@link ResourceHttpRequestHandler}.
|
* {@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 SimpleUrlHandlerMapping} for mapping resource requests,
|
||||||
* Will also register a {@link HttpRequestHandlerAdapter} if necessary.
|
* and a {@link HttpRequestHandlerAdapter} if necessary.
|
||||||
*
|
*
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
|
* @author Jeremy Grelle
|
||||||
* @since 3.0.4
|
* @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";
|
@Override
|
||||||
|
public void doParse(Element element, ParserContext parserContext) {
|
||||||
private static final String HANDLER_MAPPING_BEAN_NAME = "org.springframework.web.servlet.config.resourcesHandlerMapping";
|
|
||||||
|
|
||||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
|
||||||
Object source = parserContext.extractSource(element);
|
Object source = parserContext.extractSource(element);
|
||||||
|
registerResourceMappings(parserContext, element, source);
|
||||||
|
}
|
||||||
|
|
||||||
registerHandlerAdapterIfNecessary(parserContext, source);
|
private void registerResourceMappings(ParserContext parserContext, Element element, Object source) {
|
||||||
BeanDefinition handlerMappingDef = registerHandlerMappingIfNecessary(parserContext, source);
|
String resourceHandlerName = registerResourceHandler(parserContext, element, source);
|
||||||
|
if (!StringUtils.hasText(resourceHandlerName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
List<String> resourcePaths = new ManagedList<String>();
|
Map<String, String> urlMap = new ManagedMap<String, String>();
|
||||||
resourcePaths.add("/");
|
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);
|
RootBeanDefinition resourceHandlerDef = new RootBeanDefinition(ResourceHttpRequestHandler.class);
|
||||||
resourceHandlerDef.setSource(source);
|
resourceHandlerDef.setSource(source);
|
||||||
resourceHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
resourceHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||||
resourceHandlerDef.getConstructorArgumentValues().addIndexedArgumentValue(0, resourcePaths);
|
resourceHandlerDef.getConstructorArgumentValues().addIndexedArgumentValue(0, locations);
|
||||||
|
String beanName = parserContext.getReaderContext().generateBeanName(resourceHandlerDef);
|
||||||
Map<String, BeanDefinition> urlMap = getUrlMap(handlerMappingDef);
|
parserContext.getRegistry().registerBeanDefinition(beanName, resourceHandlerDef);
|
||||||
String resourceRequestPath = "/resources/**";
|
parserContext.registerComponent(new BeanComponentDefinition(resourceHandlerDef, beanName));
|
||||||
urlMap.put(resourceRequestPath, resourceHandlerDef);
|
return beanName;
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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.
|
* can be matched.
|
||||||
*
|
*
|
||||||
* <p>Requests are handled by forwarding through the {@link RequestDispatcher} obtained via the name specified through the
|
* <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
|
* 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
|
* 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
|
* @author Jeremy Grelle
|
||||||
* @since 3.0.4
|
* @since 3.0.4
|
||||||
|
|
@ -55,40 +55,40 @@ public class DefaultServletHttpRequestHandler implements InitializingBean, HttpR
|
||||||
|
|
||||||
private ServletContext servletContext;
|
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
|
* If the {@code filedServletName} property has not been explicitly set, attempts to locate the default Servlet using the
|
||||||
* known common container-specific names.
|
* known common container-specific names.
|
||||||
*/
|
*/
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
if (!StringUtils.hasText(this.fileServletName)) {
|
if (!StringUtils.hasText(this.defaultServletName)) {
|
||||||
if (this.servletContext.getNamedDispatcher(COMMON_DEFAULT_SERVLET_NAME) != null) {
|
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) {
|
} 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) {
|
} 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) {
|
} 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,
|
public void handleRequest(HttpServletRequest request,
|
||||||
HttpServletResponse response) throws ServletException, IOException {
|
HttpServletResponse response) throws ServletException, IOException {
|
||||||
RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.fileServletName);
|
RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName);
|
||||||
Assert.notNull(rd, "A RequestDispatcher could not be located for the servlet name '"+this.fileServletName+"'");
|
Assert.notNull(rd, "A RequestDispatcher could not be located for the servlet name '"+this.defaultServletName+"'");
|
||||||
rd.forward(request, response);
|
rd.forward(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the name of the default Servlet to be forwarded to for static resource requests.
|
* 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) {
|
public void setDefaultServletName(String defaultServletName) {
|
||||||
this.fileServletName = fileServletName;
|
this.defaultServletName = defaultServletName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package org.springframework.web.servlet.resources;
|
package org.springframework.web.servlet.resources;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
@ -8,18 +7,15 @@ import java.io.OutputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.zip.GZIPOutputStream;
|
|
||||||
|
|
||||||
import javax.activation.FileTypeMap;
|
import javax.activation.FileTypeMap;
|
||||||
import javax.activation.MimetypesFileTypeMap;
|
import javax.activation.MimetypesFileTypeMap;
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletOutputStream;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
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
|
* {@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
|
* (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.
|
|
||||||
*
|
*
|
||||||
* <p>TODO - expand the docs further
|
* <p>TODO - expand the docs further
|
||||||
*
|
*
|
||||||
|
|
@ -54,39 +49,14 @@ public class ResourceHttpRequestHandler implements HttpRequestHandler, ServletCo
|
||||||
|
|
||||||
private final List<Resource> resourcePaths;
|
private final List<Resource> resourcePaths;
|
||||||
|
|
||||||
private int maxAge = 31556926;
|
private final int maxAge = 31556926;
|
||||||
|
|
||||||
private static final String defaultMediaTypes = "image/*,text/css,text/javascript,text/html";
|
|
||||||
|
|
||||||
private List<MediaType> allowedMediaTypes = new ArrayList<MediaType>();
|
|
||||||
|
|
||||||
private FileMediaTypeMap fileMediaTypeMap;
|
private FileMediaTypeMap fileMediaTypeMap;
|
||||||
|
|
||||||
private boolean gzipEnabled = true;
|
|
||||||
|
|
||||||
private int minGzipSize = 150;
|
|
||||||
|
|
||||||
private int maxGzipSize = 500000;
|
|
||||||
|
|
||||||
public ResourceHttpRequestHandler(List<Resource> resourcePaths) {
|
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");
|
Assert.notNull(resourcePaths, "Resource paths must not be null");
|
||||||
validateResourcePaths(resourcePaths);
|
validateResourcePaths(resourcePaths);
|
||||||
this.resourcePaths = 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 {
|
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");
|
new String[] {"GET"}, "ResourceHttpRequestHandler only supports GET requests");
|
||||||
}
|
}
|
||||||
URLResource resource = getResource(request);
|
URLResource resource = getResource(request);
|
||||||
if (resource == null || !isResourceAllowed(resource)) {
|
if (resource == null) {
|
||||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -106,18 +76,6 @@ public class ResourceHttpRequestHandler implements HttpRequestHandler, ServletCo
|
||||||
writeResponse(resource, request, response);
|
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) {
|
public void setServletContext(ServletContext servletContext) {
|
||||||
this.fileMediaTypeMap = new DefaultFileMediaTypeMap(servletContext);
|
this.fileMediaTypeMap = new DefaultFileMediaTypeMap(servletContext);
|
||||||
}
|
}
|
||||||
|
|
@ -168,17 +126,8 @@ public class ResourceHttpRequestHandler implements HttpRequestHandler, ServletCo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
private void writeResponse(URLResource resource, HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
OutputStream out = selectOutputStream(resource, request, response);
|
OutputStream out = response.getOutputStream();
|
||||||
try {
|
try {
|
||||||
InputStream in = resource.getInputStream();
|
InputStream in = resource.getInputStream();
|
||||||
try {
|
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 {
|
private boolean isValidFile(Resource resource) throws IOException {
|
||||||
return resource.exists() && StringUtils.hasText(resource.getFilename());
|
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
|
private interface FileMediaTypeMap {
|
||||||
|
|
||||||
public interface FileMediaTypeMap {
|
|
||||||
MediaType getMediaType(String fileName);
|
MediaType getMediaType(String fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DefaultFileMediaTypeMap implements FileMediaTypeMap {
|
private static class DefaultFileMediaTypeMap implements FileMediaTypeMap {
|
||||||
|
|
||||||
private static final boolean jafPresent =
|
private static final boolean jafPresent =
|
||||||
ClassUtils.isPresent("javax.activation.FileTypeMap", ContentNegotiatingViewResolver.class.getClassLoader());
|
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 static class URLResource implements Resource {
|
||||||
|
|
||||||
private final Resource wrapped;
|
private final Resource wrapped;
|
||||||
|
|
|
||||||
|
|
@ -53,10 +53,64 @@
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation
|
<xsd:documentation
|
||||||
source="java:org.springframework.web.servlet.resources.ResourceHttpRequestHandler"><![CDATA[
|
source="java:org.springframework.web.servlet.resources.ResourceHttpRequestHandler"><![CDATA[
|
||||||
Configures support for efficiently serving static resources such as images, js, and, css files.
|
Configures a handler for serving static resources such as images, js, and, css files with cache headers optimized for efficient
|
||||||
By default, registers a handler mapped to /resources/** capable of serving all resources located in the ${webappRoot}/resources directory.
|
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:documentation>
|
||||||
</xsd:annotation>
|
</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>
|
||||||
|
|
||||||
<xsd:element name="interceptors">
|
<xsd:element name="interceptors">
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ package org.springframework.web.servlet.config;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import javax.servlet.RequestDispatcher;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
|
@ -28,6 +30,7 @@ import org.junit.Test;
|
||||||
import org.springframework.beans.TypeMismatchException;
|
import org.springframework.beans.TypeMismatchException;
|
||||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
|
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.ClassPathResource;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
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.http.converter.HttpMessageConverter;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
import org.springframework.mock.web.MockRequestDispatcher;
|
||||||
import org.springframework.mock.web.MockServletContext;
|
import org.springframework.mock.web.MockServletContext;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.validation.BindingResult;
|
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.SimpleControllerHandlerAdapter;
|
||||||
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
|
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
|
||||||
import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping;
|
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.resources.ResourceHttpRequestHandler;
|
||||||
import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
|
import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
|
* @author Jeremy Grelle
|
||||||
*/
|
*/
|
||||||
public class MvcNamespaceTests {
|
public class MvcNamespaceTests {
|
||||||
|
|
||||||
|
|
@ -70,7 +76,7 @@ public class MvcNamespaceTests {
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
appContext = new GenericWebApplicationContext();
|
appContext = new GenericWebApplicationContext();
|
||||||
appContext.setServletContext(new MockServletContext());
|
appContext.setServletContext(new TestMockServletContext());
|
||||||
LocaleContextHolder.setLocale(Locale.US);
|
LocaleContextHolder.setLocale(Locale.US);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,14 +210,18 @@ public class MvcNamespaceTests {
|
||||||
public void testResources() throws Exception {
|
public void testResources() throws Exception {
|
||||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
|
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
|
||||||
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-resources.xml", getClass()));
|
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-resources.xml", getClass()));
|
||||||
assertEquals(2, appContext.getBeanDefinitionCount());
|
assertEquals(3, appContext.getBeanDefinitionCount());
|
||||||
appContext.refresh();
|
appContext.refresh();
|
||||||
|
|
||||||
HttpRequestHandlerAdapter adapter = appContext.getBean(HttpRequestHandlerAdapter.class);
|
HttpRequestHandlerAdapter adapter = appContext.getBean(HttpRequestHandlerAdapter.class);
|
||||||
assertNotNull(adapter);
|
assertNotNull(adapter);
|
||||||
|
|
||||||
|
ResourceHttpRequestHandler handler = appContext.getBean(ResourceHttpRequestHandler.class);
|
||||||
|
assertNotNull(handler);
|
||||||
|
|
||||||
SimpleUrlHandlerMapping mapping = appContext.getBean(SimpleUrlHandlerMapping.class);
|
SimpleUrlHandlerMapping mapping = appContext.getBean(SimpleUrlHandlerMapping.class);
|
||||||
assertNotNull(mapping);
|
assertNotNull(mapping);
|
||||||
|
assertEquals(Ordered.LOWEST_PRECEDENCE - 1, mapping.getOrder());
|
||||||
|
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
request.setRequestURI("/resources/foo.css");
|
request.setRequestURI("/resources/foo.css");
|
||||||
|
|
@ -228,6 +238,76 @@ public class MvcNamespaceTests {
|
||||||
assertNull(mv);
|
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
|
@Test
|
||||||
public void testBeanDecoration() throws Exception {
|
public void testBeanDecoration() throws Exception {
|
||||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
|
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
|
||||||
|
|
@ -393,14 +473,29 @@ public class MvcNamespaceTests {
|
||||||
@NotNull
|
@NotNull
|
||||||
private String field;
|
private String field;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public String getField() {
|
public String getField() {
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public void setField(String field) {
|
public void setField(String field) {
|
||||||
this.field = 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());
|
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
|
@Test
|
||||||
public void getResourceFromAlternatePath() throws Exception {
|
public void getResourceFromAlternatePath() throws Exception {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
|
@ -193,51 +183,6 @@ public class ResourceHttpRequestHandlerTests {
|
||||||
handler = new ResourceHttpRequestHandler(resourcePaths);
|
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 {
|
private static class TestServletContext extends MockServletContext {
|
||||||
@Override
|
@Override
|
||||||
public String getMimeType(String filePath) {
|
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
|
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">
|
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>
|
</beans>
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
This shouldn't be served.
|
|
||||||
Loading…
Reference in New Issue