springMVC對靜態資源訪問的處理

在restful  風格下springMVC會進行以下配置css

  <servlet>      
      <servlet-name>mvc</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
      <init-param>        
          <param-name>contextConfigLocation</param-name>        
          <param-value>/WEB-INF/classes/conf/spring/mvc-*.xml</param-value>  
       </init-param>  
       <load-on-startup>1</load-on-startup>  
  </servlet>
  <servlet-mapping>
      <servlet-name>mvc</servlet-name>
       <url-pattern>/</url-pattern>  
   </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"java

  • Google App Engine:默認 Servlet 名字爲 "_ah_default"nginx

  • Resin:默認 Servlet 名字爲 "resin-file"web

  • WebLogic:默認 Servlet 名字爲 "FileServlet"spring

  • WebSphere:默認 Servlet 名字爲 "SimpleFileServlet"apache


    ◇ 方案一:激活 Tomcat 的 defaultServlet 來處理靜態資源 緩存

<servlet-mapping>  tomcat

      <servlet-name>default</servlet-name>  服務器

      <url-pattern>*.jpg</url-pattern>  

</servlet-mapping>  

<servlet-mapping>  

      <servlet-name>default</servlet-name>  

      <url-pattern>*.js</url-pattern>  

</servlet-mapping>  

<servlet-mapping>  

      <servlet-name>default</servlet-name>  

      <url-pattern>*.css</url-pattern>  

</servlet-mapping>  


        每種類型的靜態資源須要分別配置一個 servlet-mapping,同時,要寫在 DispatcherServlet 的前面, 讓 defaultServlet 先攔截。 

可是這樣還會有個問題,就是沒法訪問到classpath下的資源文件,看了tomcat的DefaultServlet的配置項,彷佛也沒有能夠指定目錄的地方。
    ◇ 方案二:Spring 3.0.4 之後版本提供了 <mvc:resources /> 

    

  1. <!-- 處理靜態資源 -->  

  2.     <!-- 上傳的圖片緩存1個月,其餘js,css,img資源緩存一年 -->  

  3.     <mvc:resources mapping="/res/**" location="/res/" cache-period="2592000"/>   

  4.     <mvc:resources mapping="/resources/**" location="/resources/" cache-period="31536000"/>   

  5.     <mvc:resources mapping="/css/**" location="/css/" cache-period="31536000"/>  

  6.     <mvc:resources mapping="/js/**" location="/js/" cache-period="31536000"/>  

  7.     <mvc:resources mapping="/img/**" location="/img/" cache-period="31536000"/>  

  8.     <mvc:resources mapping="/images/**" location="/images/" cache-period="31536000"/>  

       mapping 映射到 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。

另外,性能最好的應該是直接利用容器的DefaultServlet,讓它最早攔截靜態資源請求,這樣就避免了後續的轉發等操做,提升了性能,可是沒法訪問classpath下的資源文件。而經過mvc:resources標籤能夠簡單配置匹配規則和資源文件路徑,應該說是最簡單快捷的一種方式,固然這大概也是mvc命名空間設計的初衷。

另外,若想結合二者的話,本身卻是能夠嘗試寫一個Servlet或者filter來處理,不過估計有難度且麻煩。


--- add 2016-04-19

最近又想到一個辦法,在java服務器前再增長一個http服務器處理靜態資源,java服務器只處理動態資源,這樣也能夠啊

相關文章
相關標籤/搜索