问题分析:
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
,发现了吗?)。
如下图:
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 访问静态资源的三种方式”,有所删改,转载请注明出处。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于