问题:为什么我使用“/”时 jsp没有被拦截,而其他包括css等静态资源都会被拦截而“/*”将会拦截所有资源?
准备知识:
一、url-pattern详解:
1、以”/’开头和以”/*”结尾的是用来做路径映射的。
2、以前缀”*.”开头的是用来做后缀(或称扩展)映射的。
3、“/” 是用来定义default servlet映射的。
但是 你只能选择路径或者后缀映射,而不能同时用使用这两种映射,因为这样容器无法判断!例如这样的映射“/*.action”
二、servlet 匹配规则:
当一个请求发送到servlet容器的时候,容器先会将请求的url减去当前应用上下文的路径作为servlet的映射url,
比如我访问的是 http://localhost/test/aaa.html,我的应用上下文是test,容器会将http://localhost/test去掉,
剩下的/aaa.html部分拿来做servlet的映射匹配。这个映射匹配过程是有顺序的,而且当有一个servlet匹配成功以后,
就不会去理会剩下 的servlet了.
其匹配规则和顺序如下:
1》精确路径匹配。例子:比如servletA 的url-pattern为 /test,servletB的url-pattern为 /* ,
这个时候,如果我访问的url为http://localhost/test ,
这个时候容器就会先 进行精确路径匹配,发现/test正好被servletA精确匹配,
那么就去调用servletA,也不会去理会其他的servlet了。
2》最长路径匹配。例子:servletA的url-pattern为/test/*,而servletB的url-pattern为/test/a/*,
此 时访问http://localhost/test/a时,容器会选择路径最长的servlet来匹配,也就是这里的servletB。
3》扩展匹配,如果url最后一段包含扩展,容器将会根据扩展选择合适的servlet。
例子:servletA的url-pattern:*.action
4》如果前面三条规则都没有找到一个servlet,容器会根据url选择对应的请求资源。
如果应用定义了一个default servlet,则容器会将请求丢给default servlet(什么是default servlet?就是以“default”配置的serverlet)。
总结以上规则可细化为以下便于记忆:
1:/abc/* ------1
2:/* ------2
3:/abc ------3
4:*.do ------4
5:/
三、tomcat的 “default servlet”和“jsp servlet”,摘录如下:
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
四、对问题的解释
当你的spring mvc 的“dispatcher servlet”配置为:“/” 时,
它会替换掉“default servlet”,此时“jsp servlet”先拦截,如果拦截失败 会才采用“default servlet”也即“dispatcher servlet”!
显然:此时除了jsp及jspx外,dispatch servlet将拦截所有资源!
当你使用“/*”时,显然它会拦截所有资源,包括“jsp、jspx、js、css等”
当你使用“*.action”时,
显然对于“.jsp、.jspx”会被“jsp servlet”拦截。
对于“.js、.css”会被“的“dispatcher servlet”拦截。
对于“.action”会被“dispatcher servlet”拦截。
五、当spring mvc 使用“/”或者“/*”时如何放过像“js等静态资源”?
解决办法1:在项目的web.xml加入如下代码:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
这样的话 会优先匹配“*.htm”!
解决办法2:采用<mvc:default-servlet-handler />
在springMVC-servlet.xml中配置<mvc:default-servlet-handler />后,
会在Spring MVC上下文中定义一个org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,
它会像一个检查员,对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,
就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。
一般Web应用服务器默认的Servlet名称是"default",因此DefaultServletHttpRequestHandler可以找到它。
如果你所有的Web应用服务器的默认Servlet名称不是"default",则需要通过default-servlet-name属性显示指定:
<mvc:default-servlet-handler default-servlet-name="所使用的Web服务器默认使用的Servlet名称" />
解决办法3:采用<mvc:resources />
<mvc:default-servlet-handler />将静态资源的处理经由Spring MVC框架交回Web应用服务器处理。而<mvc:resources />更进一步,
由Spring MVC框架自己处理静态资源,并添加一些有用的附加值功能。
首先,<mvc:resources />允许静态资源放在任何地方,如WEB-INF目录下、类路径下等,你甚至可以将JavaScript等静态文件打到JAR包中。
通过location属性指定静态资源的位置,由于location属性是Resources类型,因此可以使用诸如"classpath:"等的资源前缀指定资源位置。
传统Web容器的静态资源只能放在Web容器的根路径下,<mvc:resources />完全打破了这个限制。
其次,<mvc:resources />依据当前著名的Page Speed、YSlow等浏览器优化原则对静态资源提供优化。
你可以通过cacheSeconds属性指定静态资源在浏览器端的缓存时间,一般可将该时间设置为一年,以充分利用浏览器端的缓存。
在输出静态资源时,会根据配置设置好响应报文头的Expires 和 Cache-Control值。
在接收到静态资源的获取请求时,会检查请求头的Last-Modified值,如果静态资源没有发生变化,则直接返回303相应状态码,
提示客户端使用浏览器缓存的数据,而非将静态资源的内容输出到客户端,以充分节省带宽,提高程序性能。
在springMVC-servlet中添加如下配置:
<mvc:resources location="/,classpath:/META-INF/publicResources/" mapping="/resources/**"/>
以上配置将Web根路径"/"及类路径下 /META-INF/publicResources/ 的目录映射为/resources路径。
假设Web根路径下拥有images、js这两个资源目录,在images下面有bg.gif图片,在js下面有test.js文件,
则可以通过 /resources/images/bg.gif 和 /resources/js/test.js 访问这二个静态资源。
假设WebRoot还拥有images/bg1.gif 及 js/test1.js,则也可以在网页中通过 /resources/images/bg1.gif
及 /resources/js/test1.js 进行引用。