servlet的url映射定义为'/'表示映射全部路径

struts的过滤器是*.action,在spring mvc中设置成*.action或者*.do......也是可以的,但是spring mvc就是霸气,它就是要处理一切路径.

对于静态资源,在tomcat服务器上,必须通过servlet才能访问,除此之外别无他法.

即便是你自己不写servlet来访问静态资源,tomcat无论如何也要找到一个servlet来处理静态资源,所以别觉得用servlet处理会慢,无论如何都要用servlet来处理.

一言以蔽之,在tomcat容器中,处理资源的基本单位是servlet,进行数据操作计算的基本单位也是servlet.

前人之述备矣,天下文章一大抄.

Spring MVC 中的核心 servlet - DispatcherServlet,我们在 web.xml 文件中通常这样定义:

<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 先拦截。
    ◇ 方案二:Spring 3.0.4 以后版本提供了 <mvc:resources />

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

其中处理静态资源的类是org.springframework.web.servlet.resource.ResourceHttpRequestHandler,而且在location的描述中说明Each location must point to a valid directory. 即每个location都必须指向一个有效的目录。

下面看一下org.springframework.web.servlet.resource.ResourceHttpRequestHandler中是如何处理静态资源请求的:

首先它实现了org.springframework.web.HttpRequestHandler这个接口的handleRequest方法:

public void handleRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    // 这里根据配置来设置缓存的header
    checkAndPrepare(request, response, true);  

    // 获取要获取的资源,如果不存在,直接返回404错误
    Resource resource = getResource(request);
    if (resource == null) {
        logger.debug("No matching resource found - returning 404");
        response.sendError(HttpServletResponse.SC_NOT_FOUND);
        return;
    }  

    // 省略部分代码……
    // 返回相应的资源,即把资源文件写到响应中
    writeContent(response, resource);
}  

而getResource方法实现如下:

protected Resource getResource(HttpServletRequest request) {
    String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
    // 省略部分处理和检验路径的代码……  

    // 这里循环从配置的location下查找请求的静态资源
    for (Resource location : this.locations) {
        try {
            if (logger.isDebugEnabled()) {
                logger.debug("Trying relative path [" + path + "] against base location: " + location);
            }
            Resource resource = location.createRelative(path);
            // 判断资源存在而且能够读取
            if (resource.exists() && resource.isReadable()) {
                // 这里就是3.2.12及以后处理上的差别,在3.2.12前,不会判断该资源是否在指定的路径下,直接就返回了resource,而3.2.12及以后做了如下判断
                if (isResourceUnderLocation(resource, location)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Found matching resource: " + resource);
                    }
                    return resource;
                }
                else {
                    if (logger.isTraceEnabled()) {
                        logger.trace("resource=\"" + resource + "\" was successfully resolved " +
                                "but is not under the location=\"" + location);
                    }
                    return null;
                }
            }
            else if (logger.isTraceEnabled()) {
                logger.trace("Relative resource doesn't exist or isn't readable: " + resource);
            }
        }
        catch (IOException ex) {
            logger.debug("Failed to create relative resource - trying next resource location", ex);
        }
    }
    return null;
}  

下面看看isResourceUnderLocation的实现:

private boolean isResourceUnderLocation(Resource resource, Resource location) throws IOException {
    if (!resource.getClass().equals(location.getClass())) {
        return false;
    }
    String resourcePath;
    String locationPath;
    if (resource instanceof UrlResource) {
        resourcePath = resource.getURL().toExternalForm();
        locationPath = location.getURL().toExternalForm();
    }
    else if (resource instanceof ClassPathResource) {
        resourcePath = ((ClassPathResource) resource).getPath();
        locationPath = ((ClassPathResource) location).getPath();
    }
    else if (resource instanceof ServletContextResource) {
        resourcePath = ((ServletContextResource) resource).getPath();
        locationPath = ((ServletContextResource) location).getPath();
    }
    else {
        resourcePath = resource.getURL().getPath();
        locationPath = location.getURL().getPath();
    }
    // 这里是对路径的处理,如果我们配置的是/res/**,那么直接拼接成了/res/**/,如果请求资源为/res/jquery.js,   //那么会判断res/jquery.js是否以/res/**/开头,如果不是,则返回该location下没有该资源,导致不能404错误
    locationPath = (locationPath.endsWith("/") ||
            !StringUtils.hasLength(locationPath) ? locationPath : locationPath + "/");
    if (!resourcePath.startsWith(locationPath)) {
        return false;
    }
    if (resourcePath.contains("%")) {
        // Use URLDecoder (vs UriUtils) to preserve potentially decoded UTF-8 chars...
        if (URLDecoder.decode(resourcePath, "UTF-8").contains("../")) {
            if (logger.isTraceEnabled()) {
                logger.trace("Resolved resource path contains \"../\" after decoding: " + resourcePath);
            }
            return false;
        }
    }
    return true;
}   

'/'表示根目录,以'/'结尾的路径表示文件夹,location为'/'表示该路径下的全部文件相当于'/**','/*'表示单级目录,所以'/'=='/**'>'/*'

mvc:resource可以设置多个属性

在@RequestMapping注解中,如果没有参数,则表示这个servlet是默认的servlet,会处理一切资源.

   <!-- 对静态资源文件的访问  方案一  -->
    <mvc:default-servlet-handler/>  

    <!-- 对静态资源文件的访问  方案二 -->
<mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"/>
<mvc:resources mapping="/js/**" location="/js/" cache-period="31556926"/>
<mvc:resources mapping="/css/**" location="/css/" cache-period="31556926"/> 
<!-- 对静态资源文件的访问  方案二的简便写法--> 
 <mvc:resources location="/" mapping="/" /> 

spring mvc处理静态资源的更多相关文章

  1. Spring MVC 处理静态资源文件

    摘要: 三个方案: 1.方案一:激活Tomcat的defaultServlet来处理静态文件 2.方案二: 在spring3.0.4以后版本提供了mvc:resources (需要配置annotati ...

  2. 【Spring学习笔记-MVC-14】Spring MVC对静态资源的访问

    作者:ssslinppp       参考链接: http://www.cnblogs.com/luxh/archive/2013/03/14/2959207.html  http://www.cnb ...

  3. Spring MVC配置静态资源和资源包

    Spring MVC配置静态资源和资源包 本例映射:css目录: pom.xml <properties> <spring.version>4.3.5.RELEASE</ ...

  4. spring mvc对静态资源的访问

    如果我们的项目使用的是springmvc,在web.xml中会有一段这的配置. <servlet> <servlet-name>springMvc</servlet-na ...

  5. Spring MVC 访问静态资源

    当我们不通过控制器,想直接访问网站上的静态资源时,由于DispatcherServlet的url-patten的通配符的限制,导致系统会认为你访问的是个url映射,这时需要配置一个东西就可以解决问题了 ...

  6. Spring MVC 读取静态资源时404错误

    背景:web.xml配置时拦截策略是拦截所有请求: <servlet> <servlet-name>springmvc</servlet-name> <ser ...

  7. Spring MVC 过滤静态资源访问

    过滤的必要性 一般来说,HTTP 请求都会被映射到 DispatcherServlet,进而由具体的类来承接处理,但对于类似 js 或者 css 这样的静态资源则没必要这样,因为对资源的获取只需返回资 ...

  8. 【转】Spring MVC处理静态资源

    优雅REST风格的资源URL不希望带 .html 或 .do 等后缀.由于早期的Spring MVC不能很好地处理静态资源,所以在web.xml中配置DispatcherServlet的请求映射,往往 ...

  9. Spring MVC配置静态资源和资源包教程

    1- 介绍 这篇教程文章是基于: Spring 4 MVC 2- 创建一个项目 File/New/Other.. 输入: Group ID: com.yiibai Artifact ID: Sprin ...

随机推荐

  1. 深度学习笔记------windows系统下进行Linux-Ubuntu14.04双系统安装笔记(二)

    在上一篇文章中介绍了新手如何安装Ubuntu14.04的双系统,本文会说明Ubuntu系统下搜狗输入法的安装,并就我遇见的一些bug给出最简单的解决办法. 第一部分.搜狗输入法的安装 本身搜狗输入法的 ...

  2. linux基础-第八单元 正文处理命令及tar命令

    第八单元 正文处理命令及tar命令 使用cat命令进行文件的纵向合并 两种文件的纵向合并方法 归档文件和归档技术 归档的目的 什么是归档 tar命令的功能 tar命令的常用选项 使用tar命令创建.查 ...

  3. 网格弹簧质点系统模拟(Spring-Mass System by Verlet Integration)附源码

    模拟物体变形最简单的方法就是采用弹簧质点系统(Spring-Mass System),由于模型简单并且实用,它已被广泛应用于服饰.毛发以及弹性固体的动态模拟.对于三角网格而言,弹簧质点系统将网格中的顶 ...

  4. HTML 学习笔记 CSS(轮廓)

    轮廓(outline)是绘制于元素周围的一条线 位于边框边缘的外围 可起到突出元素的作用 CSS outline属性规定元素轮廓的样式 颜色和宽度 话不多说 来几个例子 看一看 1:在元素周围画线 & ...

  5. 装完Centos7提示Initial setup of CentOS Linux 7 (core)(转载)

    http://www.th7.cn/system/lin/201603/156762.shtml

  6. FJOI省队集训 chessboard

    (题目懒得打字了,建议到新窗口查看) 显然这玩意儿是可以按位搞的...然后就是一个裸的最小割模型? 然而这样做理论上只有30分实际上有40分. 事实上我们可以发现,每一列的取值只和上一列有关,这样我们 ...

  7. Java System.getProperty()方法获取系统信息

    用 System.getProperty()方法能获取到的系统信息: java.version Java 运行时环境版本 java.vendor Java 运行时环境供应商 java.vendor.u ...

  8. C语言 malloc()与sizeof运算的盲点

    //malloc()与sizeof运算的盲点 #include <stdio.h> #include <stdlib.h> #include <string.h> ...

  9. mac OS X Yosemite 上编译hadoop 2.6.0/2.7.0及TEZ 0.5.2/0.7.0 注意事项

    1.jdk 1.7问题 hadoop 2.7.0必须要求jdk 1.7.0,而oracle官网已经声明,jdk 1.7 以后不准备再提供更新了,所以趁现在还能下载,赶紧去down一个mac版吧 htt ...

  10. Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析

    前言 本文将分析mybatis与spring整合的MapperScannerConfigurer的底层原理,之前已经分析过java中实现动态,可以使用jdk自带api和cglib第三方库生成动态代理. ...