• SpringMVC访问静态资源


    摘要: springMVC对静态资源的处理的三种方式
     

    在restful  风格下springMVC会进行如下配置

      <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"

    • Google App Engine:默认 Servlet 名字为 "_ah_default"

    • Resin:默认 Servlet 名字为 "resin-file"

    • WebLogic:默认 Servlet 名字为 "FileServlet"

    • WebSphere:默认 Servlet 名字为 "SimpleFileServlet"


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

    <servlet-mapping>
          <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个月,其他js,css,img资源缓存一年 -->  
        <mvc:resources mapping="/res/**" location="/res/" cache-period="2592000"/>   
        <mvc:resources mapping="/resources/**" location="/resources/" cache-period="31536000"/>   
        <mvc:resources mapping="/css/**" location="/css/" cache-period="31536000"/>  
        <mvc:resources mapping="/js/**" location="/js/" cache-period="31536000"/>  
        <mvc:resources mapping="/img/**" location="/img/" cache-period="31536000"/>  
        <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 包内静态资源的访问。 

    注意:使用该方法一定要使用<c:url />,否则无法访问静态资源:

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <link rel="stylesheet" href="<c:url value='/resources/css/bootstrap.min.css'/>">



        ◇ 方案三:使用 <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服务器只处理动态资源,这样也可以啊

  • 相关阅读:
    【安卓本卓】Android系统源码篇之(一)源码获取、源码目录结构及源码阅读工具简介
    【朝花夕拾】Android性能篇之(六)Android进程管理机制
    【烂笔头】adb命令篇
    【朝花夕拾】Android性能篇之(五)Android虚拟机
    【朝花夕拾】Android性能篇之(一)序言及JVM
    【烂笔头】git常用命令篇
    【朝花夕拾】Android性能篇之(四)Apk打包
    【朝花夕拾】Android Log篇
    从2015年百度站长的一则公告回头看百度的骚操作
    ASP.NET Core+Quartz.Net 实现web定时任务
  • 原文地址:https://www.cnblogs.com/drizzlewithwind/p/5995017.html
Copyright © 2020-2023  润新知