关于 servlet 的拦截设置, 之前看了好多, 说的都不太清除, 明白.
最近明白了一些, 总的来说就是保证拦截所有用户请求的同时, 放行静态资源.
现整理如下:
一, 我们都知道在基于 Spring 的 Application 中, 需要在 web.xml 中增加下面类似的配置信息:
- <listener>
- <listener-class>
- org.springframework.Web.context.ContextLoaderListener
- </listener-class>
- </listener>
- <!-- 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>
此处需要特别强调的是 <url-pattern>/</url-pattern > 使用的是 /, 而不是 /*, 如果使用 /*, 那么请求时可以通过 DispatcherServlet 转发到相应的 Action 或者 Controller 中的, 但是返回的内容, 如返回的 jsp 还会再次被拦截, 这样导致 404 错误, 即访问不到 jsp. 所以如果以后发现总是有 404 错误的时候, 别忘了 check 一下 <url-pattern>/</url-pattern > 的配置是否是 /*.
二, 其实 Spring 的 Servlet 拦截器匹配规则 (即 <url-pattern>...</url-pattern> ) 都可以自己定义,
例: 当映射为 @RequestMapping("/user/add")时
1, 拦截 *.do,*.htm, 例如:/user/add.do
这是最传统的方式, 最简单也最实用. 不会导致静态文件 (jpg,JS,CSS) 被拦截.
2, 拦截 /, 例如:/user/add
可以实现现在很流行的 REST 风格. 很多互联网类型的应用很喜欢这种风格的 URL.
弊端: 会导致静态文件 (jpg,JS,CSS) 被拦截后不能正常显示. 想实现 REST 风格, 事情就是麻烦一些. 后面有解决办法还算简单.
3, 拦截 /*, 这是一个错误的方式, 请求可以走到 Action 中, 但转到 jsp 时再次被拦截, 不能访问到 jsp.
三, 如何访问到静态的文件, 如 jpg,JS,CSS?
如果你的 DispatcherServlet 拦截 "*.do" 这样的有后缀的 URL, 就不存在访问不到静态资源的问题.
如果你的 DispatcherServlet 拦截 "/", 为了实现 REST 风格, 拦截了所有的请求, 那么同时对 *.JS,*.jpg 等静态文件的访问也就被拦截了.
我们要解决这个问题.
目的: 可以正常访问静态文件, 不可以找不到静态文件报 404.
方案一: 激活 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 了.
3. 高性能.
备注:
Tomcat, Jetty, JBoss, and GlassFish 自带的默认 Servlet 的名字 -- "default"
Google App Engine 自带的 默认 Servlet 的名字 -- "_ah_default"
Resin 自带的 默认 Servlet 的名字 -- "resin-file"
WebLogic 自带的 默认 Servlet 的名字 -- "FileServlet"
WebSphere 自带的 默认 Servlet 的名字 -- "SimpleFileServlet"
方案二: 在 spring3.0.4 以后版本提供了 mvc:resources , 使用方法:
- <!-- 对静态资源文件的访问 -->
- <mvc:resources mapping="/images/**" location="/images/" />
images/** 映射到 ResourceHttpRequestHandler 进行处理, location 指定静态资源的位置. 可以是 Web application 根目录下, jar 包里面, 这样可以把静态资源压缩到 jar 包中. cache-period 可以使得静态资源进行 Web cache
如果出现下面的错误, 可能是没有配置 < mvc:annotation-driven />的原因.
报错 WARNING: No mapping found for HTTP request with URI [/mvc/user/findUser/lisi/770] 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.
方案三 , 使用 < 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 拦截 *.do 这样的 URL 后缀, 就不存上述问题了. 还是有后缀方便.
以上.
主要参考: https://zhidao.baidu.com/question/2055907804031398347.html
来源: https://www.cnblogs.com/CharlesKY/p/10326777.html