先上总结:前端控制器URL配置/,springmvc中配置<mvc:annotation-driven />,静态资源映射两种两种方式,静态资源路径在webapp根目录下。
今天调试了两个SSM框架的项目,都出现了同一个问题,静态资源访问不到404错误。看了很多博客和问答,这里总结一下解决方案,记录下采坑记录吧。
关于静态资源访问不到,最直观的的体现就是你的页面没有任何的样式特效。浏览器控制台也会报出错误,错误代码404。
这里想起来了一句话,约定优于配置。也就是说,我们在日常开发调试的时候应该具有一些配置习惯。你可以有个性的写业务逻辑,但是对于一些配置问题,还是按照最常用的方法配置为好。
既然要做静态资源访问,我们首先需要做的事情就是一些约定俗称的配置写法:
- 资源路径配置
- springmvc.xml中的配置
- web.xml中的配置
一、资源路径配置
静态资源的路径配置一般情况下是放在webapp或webroot根目录下,WEB-INF下存放的是你项目的页面或者模板。
像这样:webapp/js、webapp/css、webapp/img..
二、springmvc.xml中的配置 springmvc版本3.0+
方案一:静态资源映射
<mvc:resources location="/css/" mapping="/css/**" />
<mvc:resources location="/js/" mapping="/js/**" />
方案二:通用配置
<mvc:default-servlet-handler/>
把"/**"的url,注册到SimpleUrlHandlerMapping的urlMap中,把对静态资源的访问由HandlerMapping转到org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler 处理并返回。
三、web.xml中的配置
约定配置:<url-pattern>/</url-pattern>使用的是/,而不是/*,如果使用/*,那么请求时可以通过DispatcherServlet转发到相应的Action或者Controller中的,但是返回的内容,如返回的jsp还会再次被拦截,这样导致404错误,即访问不到jsp。所以如果以后发现总是有404错误的时候,别忘了检查一下<url-pattern>/</url-pattern>的配置是否是/*。/表示拦截所有请求。
<!-- Spring MVC Servlet -->
<servlet>
<servlet-name>servletName</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>servletName</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
方案三:激活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>
需要注意:
1. 要配置多个,每种文件配置一个。
2. 要写在DispatcherServlet的前面, 让defaultServlet先拦截请求,这样请求就不会进入Spring了。
备注:
Tomcat, Jetty, JBoss, and GlassFish 自带的默认Servlet的名字 -- "default"
Google App Engine 自带的 默认Servlet的名字 -- "_ah_default"
Resin 自带的 默认Servlet的名字 -- "resin-file"
WebLogic 自带的 默认Servlet的名字 -- "FileServlet"
WebSphere 自带的 默认Servlet的名字 -- "SimpleFileServlet"
补充说明:多个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拦截 *.do这样的URL后缀,就不存上述问题了。这样就属于个性化配置了。
jsp文件中获取当前路径URL:
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";