SpringMVC静态资源处理

本文介绍SpringMVC中如何通过<mvc:default-servlet-handler/>配置处理静态资源请求,避免DispatcherServlet误处理静态资源导致错误。
       在SpringMVC中,如果将 DispatcherServlet 请求映射配置为 /,则 Spring MVC 将捕 获 WEB 容器的所有请求,包括静态资源的请求, SpringMVC 会将他 们当成一个普通请求处理,因找不到对应处理器将导致错误。 
       可以在 SpringMVC 的配置文件中配置 <mvc:default-servlet-handler/> 的方式解决静态资源的问题: 
        <mvc:default-servlet-handler/> 将在 SpringMVC 上下文中注册一个SimpleUrlHandlerMapping,以及注册一个
DefaultServletHttpRequestHandler,它会对进入 DispatcherServlet 的请求进行筛查,如果发现是没有经过映射的请求,就将该请求交由 WEB 应用服务器默认的 Servlet 处理,如果不是静态资源的请求,才由DispatcherServlet 继续处理。
        一般 WEB 应用服务器默认的 Servlet 的名称都是 default。若所使用的 WEB 服务器的默认 Servlet 名称不是 default,则需要通过 default-servlet-name 属性显式指定。

1)、  <mvc:default-servlet-handler/>标签处理
     <mvc:default-servlet-handler/>标签是MVC模块自定义标签,当Ioc容器解析BeanDefinition遇到<mvc:default-servlet-handler/>这个标签,将使用自定义标签解析机制处理这些标签。MvcNamespaceHandler类用于加载与Spring MVC模块相关的自定义标签解析器:
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
      registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
  //这里注册<mvc:default-servlet-handlerv>标签解析器,该标签主要用与处理静态资源
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
    //这里注册<mvc:interceptors>标签解析器
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("velocity-configurer", new VelocityConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
}

}


在注册的DefaultServletHandlerBeanDefinitionParser类中主要的方法是parse方法:
class DefaultServletHandlerBeanDefinitionParser implements BeanDefinitionParser {

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
      Object source = parserContext.extractSource(element);
//获取指定的默认 Servlet 名称
String defaultServletName = element.getAttribute("default-servlet-name");
//这里定义DefaultServletHttpRequestHandler BeanDefinition,之后将注册这个BeanDefinition到应用上下文
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));
     //这里构建一个urlMap 以便于SimpleUrlHandlerMapping使用,完成请求到Handler的映射
Map<String, String> urlMap = new ManagedMap<String, String>();
urlMap.put("/**", defaultServletHandlerName);
     //这里定义SimpleUrlHandlerMapping BeanDefinition,之后将注册这个BeanDefinition到应用上下文,用于将请求匹配"/**"静态资源的路径映射到DefaultServletHttpRequestHandler,使用默认的Servlet进行处理 
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));

// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
MvcNamespaceUtils.registerDefaultComponents(parserContext, source);

      return null;
}

}

2)、DefaultServletHttpRequestHandler
DefaultServletHttpRequestHandler实现HttpRequestHandler接口,重写handleRequest()方法实现请求处理:
public class DefaultServletHttpRequestHandler implements HttpRequestHandler, ServletContextAware {

/** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish */
private static final String COMMON_DEFAULT_SERVLET_NAME = "default";

/** Default Servlet name used by Google App Engine */
private static final String GAE_DEFAULT_SERVLET_NAME = "_ah_default";

/** Default Servlet name used by Resin */
private static final String RESIN_DEFAULT_SERVLET_NAME = "resin-file";

/** Default Servlet name used by WebLogic */
private static final String WEBLOGIC_DEFAULT_SERVLET_NAME = "FileServlet";

/** Default Servlet name used by WebSphere */
private static final String WEBSPHERE_DEFAULT_SERVLET_NAME = "SimpleFileServlet";

@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
   //通过servletContext获取默认Servlet的请求转发器
      RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName);
      if (rd == null) {
throw new IllegalStateException("A RequestDispatcher could not be located for the default servlet '" +
this.defaultServletName +"'");
}
   //将请求转发给默认的Servlet请求,以便处理静态资源等
      rd.forward(request, response);
}

}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值