现在的位置: 首页 > 综合 > 正文

Spring MVC 中处理静态资源

2019年05月08日 ⁄ 综合 ⁄ 共 3117字 ⁄ 字号 评论关闭

 Spring MVC 中的核心 servlet - DispatcherServlet,我们在 web.xml 文件中通常这样定义: 
Xml代码  
  1. <servlet>  
  2.   <servlet-name>mvc</servlet-name>  
  3.   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  4.   <init-param>  
  5.     <param-name>contextConfigLocation</param-name>  
  6.     <param-value>/WEB-INF/classes/conf/spring/mvc-*.xml</param-value>  
  7.   </init-param>  
  8.   <load-on-startup>1</load-on-startup>  
  9. </servlet>  
  10.   
  11. <servlet-mapping>  
  12.   <servlet-name>mvc</servlet-name>  
  13.   <url-pattern>/</url-pattern>  
  14. </servlet-mapping>  

        很明显,该 servlet 对应的 url-pattern 定义成 /,因此该 servlet 会匹配上诸如 /images/a.jpg, /css/hello.css 等这些静态资源,甚至包括 /jsp/stock/index.jsp 这些 jsp 也会匹配。但是并没有定义相应的 Controller 来处理这些资源,因此这些请求通常是无法完成的。 

        很麻烦?没有 Struts 方便?此言差矣,因此你在 Struts 定义其核心 filter 的 url-pattern 是 *.action,当然不会对处理 jsp 和静态资源操作影响了。Spring MVC 若也定义类似的 url-pattern,同样不存在问题。 

        说到这里,我们应该想一个问题。Tomcat 中,只有 servlet 能够处理请求,即使是 jsp,也会被编译成 servlet。我们即便使用 Struts,定义 *.action 的url-pattern,那 .css, *.gfi 等这些静态资源到底是谁来处理了???你可不要想当然的认为我不是输入了图片的路径了吗?如,/images/a/b/c.gif。请注意,servlet 容器中,只有 servlet 采用处理资源! 

        由 servlet 处理这些资源那是一定了。不过,不同的 servlet 容器/应用服务器,处理这些静态资源的 servlet 的名字不大一样: 

  • Tomcat, Jetty, JBoss, and GlassFish:默认 Servlet 名字为 "default"
  • Google App Engine:默认 Servlet 名字为 "_ah_default"
  • Resin:默认 Servlet 名字为 "resin-file"
  • WebLogic:默认 Servlet 名字为 "FileServlet"
  • WebSphere:默认 Servlet 名字为 "SimpleFileServlet"

    ◇ 方案一:激活 Tomcat 的 defaultServlet 来处理静态资源 

Xml代码  
  1. <servlet-mapping>  
  2.   <servlet-name>default</servlet-name>  
  3.   <url-pattern>*.jpg</url-pattern>  
  4. </servlet-mapping>  
  5. <servlet-mapping>  
  6.   <servlet-name>default</servlet-name>  
  7.   <url-pattern>*.js</url-pattern>  
  8. </servlet-mapping>  
  9. <servlet-mapping>  
  10.   <servlet-name>default</servlet-name>  
  11.   <url-pattern>*.css</url-pattern>  
  12. </servlet-mapping>  

        每种类型的静态资源需要分别配置一个 servlet-mapping,同时,要写在 DispatcherServlet 的前面, 让 defaultServlet 先拦截。 

    ◇ 方案二:Spring 3.0.4 以后版本提供了 <mvc:resources /> 

Xml代码  
  1. <mvc:resources location="/resources/" mapping="/resources/**"/>  

        /resources/** 映射到 ResourceHttpRequestHandler 进行处理,location 指定静态资源的位置,可以是 web application 根目录下、jar 包里面,这样可以把静态资源压缩到 jar 包中。cache-period 可以使得静态资源进行 web cache。 

        使用 <mvc:resources /> 元素,会把 mapping 的 URI 注册到 SimpleUrlHandlerMapping 的 urlMap 中,key 为 mapping 的 URI pattern 值,而 value 为 ResourceHttpRequestHandler,这样就巧妙的把对静态资源的访问由 HandlerMapping 转到 ResourceHttpRequestHandler 处理并返回,所以就支持
classpath 目录, jar 包内静态资源的访问。
 

    ◇ 方案三:使用 <mvc:default-servlet-handler /> 
        <mvc:default-servlet-handler /> 会把 "/**" url 注册到 SimpleUrlHandlerMapping 的 urlMap 中,把对静态资源的访问由 HandlerMapping 转到 org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler 处理并返回。DefaultServletHttpRequestHandler
使用就是各个 Servlet 容器自己的默认 Servlet。
 

        补充说明下以上提到的 HandlerMapping 的 order 的默认值: 

  • DefaultAnnotationHandlerMapping:0
  • <mvc:resources /> 自动注册的 SimpleUrlHandlerMapping:2147483646
  • <mvc:default-servlet-handler/> 自动注册的 SimpleUrlHandlerMapping:2147483647

        Spring 会先执行 order 值比较小的。当访问一个 a.jpg 图片文件时,先通过 DefaultAnnotationHandlerMapping 来找处理器,一定是找不到的,我们没有叫 a.jpg 的 Controller。再按 order 值升序找,由于最后一个 SimpleUrlHandlerMapping 是匹配 "/**" 的,所以一定会匹配上,再响应图片。 

        Spring MVC 中,访问一个图片,还要走层层匹配。性能肯定好不到哪里去。不仅仅是 Spring MVC,即便 Struts,它们毕竟存活于 servlet 容器,只要由 servlet 容器处理这些静态资源,必然要将这些资源读入 JVM 的内存区中。所以,处理静态资源,我们通常会在前端加 apache 或 nginx。

 
来自:KILLKISS > 《spring》

抱歉!评论已关闭.