SpringMVC 中的静态资源映射

本贴最后更新于 2185 天前,其中的信息可能已经时移世改

问题分析:

1、当我们的 SpringMVC 核心拦截器 DispatcherServlet 拦截 “/” 时,所有的请求都会经过拦截器进行匹配,此时静态资源,例如 *.css、*.js、*.jpg…… 就会被拦截器拦下来,导致不能访问,出现 404 问题。

问题的关键就在于我们设置的是 /

<!-- 注册SpringMVC核心控制器 -->
<servlet>
	<servlet-name>DispatcherServlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:springMVC.xml</param-value>
	</init-param>
</servlet>
<servlet-mapping>
	<servlet-name>DispatcherServlet</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>

那么这是为什么呢?为什么 / 就不能访问静态资源呢?因为:
/ 将所有 url 请求都交给 spring 去处理,但是 spring 认可的 url 请求都在 Controller 中,以注解的方式定义 @RequestMapping(value = "/index", method = RequestMethod.GET),这样一来,静态资源的 url 请求不被 spring 认可,就过不了拦截器,那就没法访问了。

2、如果你的 DispatcherServlet 拦截 *.action 这样的 URL,就不存在访问不到静态资源的问题,那下面的内容,基本上跟你没有关系了。

解决办法一:激活 Tomcat 的 defaultServlet 来处理静态文件

在 web.xml 里添加如下配置

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

注意:
: - 要配置多个,每种文件配置一个。

  • 要写在 DispatcherServlet 的前面, 让 defaultServlet 先拦截,这个就不会进入 Spring 了。猜测性能是最好的了。

一些其他运行环境的 defaultServlet

运行环境 默认 Servlet 名字
Tomcat, Jetty, JBoss, GlassFish default
Google App Engine _ah_default
Resin resin-file
WebLogic FileServlet
WebSphere SimpleFileServlet

解决办法二:在 spring3.0.4 以后版本提供了 <mvc:resources />

<mvc:annotation-driven />

<!-- 静态资源映射 -->
<!--<mvc:resources mapping="/layui/images/**" location="/WEB-INF/static/layui/images/"/>-->
<!--<mvc:resources mapping="/layui/css/**" location="/WEB-INF/static/layui/css/"/>-->
<!--<mvc:resources mapping="/layui/font/**" location="/WEB-INF/static/layui/font/"/>-->
<!--<mvc:resources mapping="/layui/lay/**" location="/WEB-INF/static/layui/lay/"/>-->
<mvc:resources mapping="/layui/**" location="/WEB-INF/static/layui/" />

解释:

: - mapping:映射

  • location:本地资源路径,即:从 webapp 根目录开始算起的路径 (在 WEB-INF 目录下就要加上 WEB-INF 目录)。
  • 两个*,它表示映射 resources/下所有的 URL,包括子路径(即:可以接多个/)

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

如上面代码,实际上,layui 目录存放在 WEB-INF 目录下的 static 文件夹内,但是在 jsp 中直接访问/layui/即可。

注意:

: 如果出现下面的错误,可能是没有配置 <mvc:annotation-driven /> 的原因。

报错 > WARNING: No mapping found for HTTP request with URI ??? in DispatcherServlet with name 'SpringMVC'

原理:

: 使用 <mvc:resources /> 元素,把 mapping 的 URI 注册到 SimpleUrlHandlerMapping 的 urlMap 中,key 为 mapping 的 URI pattern 值,而 value 为 ResourceHttpRequestHandler,这样就巧妙的把对静态资源的访问由 HandlerMapping 转到 ResourceHttpRequestHandler 处理并返回,所以就支持 classpath 目录, jar 包内静态资源的访问.另外需要注意的一点是,不要对 SimpleUrlHandlerMapping 设置 defaultHandler. 因为对 static uri 的 defaultHandler 就是 ResourceHttpRequestHandler,否则无法处理 static resources request.

提示:

: 配置的 location 一般是指向 webapp 根目录下,如果你将资源目录,放置到 webapp/WEB-INF 下面的话,那么实际路径也要相应地加上 WEB-INF。
使用这个资源映射的好处在于:访问地址可以缩减(隐藏),jsp 中的 http://localhost:8080/OnlineTickets/layui/css/layui.css 即可访问到 http://localhost:8080/OnlineTickets/WEB-INF/static/layui/css/layui.css。(即使静态资源放在安全目录下,访问的时候,也没有 /WEB-INF/static,发现了吗?)。
如下图:

imagepng

imagepng

imagepng

WEB-INF 目录作用:

: WEB-INF 是 Java 的 WEB 应用的安全目录。所谓安全就是客户端无法访问,只有服务端可以访问的目录。
如果想在页面中直接访问其中的文件,一般要通过 web.xml 文件对要访问的文件进行相应映射才能访问。现在使用 <mvc:resources />,配合加上 WEB-INF 的 location,也可以达到访问的目的。

解决办法三:使用 mvc:default-servlet-handler

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

补充说明,多个 HandlerMapping 的执行顺序问题:

: - DefaultAnnotationHandlerMapping 的 order 属性值是:0

  • <mvc:resources/> 自动注册的 SimpleUrlHandlerMapping 的 order 属性值是: 2147483646
  • <mvc:default-servlet-handler/> 自动注册的 SimpleUrlHandlerMapping 的 order 属性值是:2147483647

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

最后再说明一下,如何你的 DispatcherServlet 拦截 *.action 这样的 URL,静态资源不会被拦截,自然也不存在这些问题了。

文章内容整理自“# SpringMVC 访问静态资源的三种方式”,有所删改,转载请注明出处。

  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    943 引用 • 1460 回帖 • 3 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...