servlet、filter、interceptor的url匹配规则

前言

在配置filter过滤器的时候过滤器竟然不起作用。然后在网上查阅了许多信息,整理而成一篇文章。在查阅信息的过程中,对路径匹配也有了更清晰的了解。参考文章真的写的很棒,链接在文章最后。另外,还有一篇关于servlet的路径匹配的源码解读:Servlet容器Tomcat中web.xml中url-pattern的配置详解,留着,以后再来学习。

[ 2018.03.19 最新更新 ] SpringMVC中interceptor拦截器的路径匹配和servlet与filter不同,参考文章最后的补充部分。

疑惑

在配合编码格式过滤器的时候,我在web.xml中是这样配的:

    <!--filter过滤器-->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/</url-pattern>
    </filter-mapping>

测试,发现没起作用。保存到数据库的数据仍旧是乱码格式的。看了书本的例子后发它配置的过滤器的url-pattern是这样的:

<url-pattern>/*</url-pattern>

试了一下,果然,编码问题就解决了。

但是我又发现DispatcherServlet的url-pattern是不带星号的:

<url-pattern>/</url-pattern>

为什么要这样写?搞不懂。我想,虽然这里把问题解决了,但是如果我不搞懂它,下次遇到类似的问题,我还是会出错。于是,开始查找相关的信息。

servlet的匹配规则

以下,是整理的信息。

url参与匹配的是哪部分

在介绍servlet的匹配规则之前,先要说明一点,匹配的时候并不是用完整的url来和<servlet-mapping>中的<url-pattern>进行匹配。而是用完整url减去当前应用的上下文的路径之后的部分来和<url-pattern>进行匹配。

举个例子,譬如,
请求的url是:
http://localhost:8080/appDemo/user/users.html
该应用是appDemo,那么当前应用的上下文路径是:
http://localhost:8080/appDemo
那么相减之后的部分就是:
/user/users.html
也就是用相减之后的这一部分与<url-pattern>进行匹配。

四种匹配规则

servlet的匹配规则有四种,分别是:
1. 精确匹配
2. 路径匹配
3. 扩展名匹配
4. 缺省匹配

下面分别举例子进行介绍。

精确匹配:

<url-pattern>中配置的项与url相应部分完全一致才能匹配上。

例如

<servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/user/users.html</url-pattern>
    <url-pattern>/index.html</url-pattern>
    <url-pattern>/user/addUser.action</url-pattern>
</servlet-mapping>

当在浏览器中输入如下几种url时,都会被匹配到该servlet

http://localhost:8080/appDemo/user/users.html
http://localhost:8080/appDemo/index.html
http://localhost:8080/appDemo/user/addUser.action

路径匹配:

/字符开头,并以/*结尾的字符串用于路径匹配。

例如

<servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/user/*</url-pattern>
</servlet-mapping>

路径以/user/开始,后面的路径可以任意。比如下面的url都会被匹配:

http://localhost:8080/appDemo/user/users.html
http://localhost:8080/appDemo/user/addUser.action
http://localhost:8080/appDemo/user/updateUser.actionl

<servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

它涵盖的范围最大,它可以匹配所有的request请求。

扩展名匹配

*.开头的字符串被用于扩展名匹配。

<servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>*.jsp</url-pattern>
    <url-pattern>*.action</url-pattern>
</servlet-mapping>

则任何扩展名为jsp或action的url请求都会匹配,比如下面的url都会被匹配

http://localhost:8080/appDemo/user/users.jsp
http://localhost:8080/appDemo/toHome.action

缺省匹配

缺省匹配的写法是唯一的,就是<url-pattern>/</url-pattern>

当其他方式都匹配不到的时候,就会使用默认的servlet。

匹配优先级别

精确匹配 > 路径匹配 > 扩展名匹配 > 缺省匹配

其中,路径匹配之间遵从最长路径优先匹配。譬如:servlet-mapping1对应的url-pattern是/user/*,而servlete2-mapping2对应的url-pattern是/*,当一个请求http://localhost:8080/appDemo/user/users.html来的时候,servlet-mapping1匹配到,不再用servlet-mapping2匹配。

路径匹配和扩展名匹配不能同时使用

servlet容器中的匹配规则既不是简单的通配,也不是正则表达式,而是特定的规则。所以不要用通配符或者正则表达式的匹配规则来看待servlet的url-pattern。

路径匹配时以/开头,并以/*结尾。而扩展名匹配是以*.开头。

以下几种都是非法的:

<url-pattern>/kata/*.jsp</url-pattern>
<url-pattern>/*.jsp</url-pattern>
<url-pattern>he*.jsp</url-pattern>
<url-pattern>/user/*.action</url-pattern>

另外注意:<url-pattern>/aa/*/bb</url-pattern>
这个是精确匹配,url必须是/aa/*/bb,这里的*不是通配的含义。

再看开头的困惑

了解了上面四种匹配规则之后,再来看看开头写的<url-pattern>

<url-pattern>/</url-pattern>属于servlet中一种特殊的匹配模式。该模式有且只有一个实例,且优先级别最低,不会覆盖其他的url-pattern,只会替换servlet容器中內建的default servlet,该模式同样会匹配所有的请求。

而servlet,通常是配成<url-pattern>/</url-pattern>,这样就只会匹配形如/login这样的路径型的url,而不会匹配到模式为*.jsp这样的后缀型url。之所以jsp页面不会命中这个servlet,是因为servlet容器內建的JSP Servlet会被调用,而这个JSP Servlet设置的匹配规则是.jsp,而由于扩展名匹配的优先级高于缺省匹配,因此轮不到缺省匹配的servlet去处理模式为*.jsp这样的后缀型url。

servlet如果配成<url-pattern>*/</url-pattern>,就很可能会出问题。因为这样的servlet会拦截所有的请求,而且请求会在此servlet中结束,也就是说轮不到其他serevlet来处理请求。模式为*.jsp*.js这样的后缀型url也会被匹配到,因此当浏览器请求一个js资源的时候,也会被该servlet拦截,最后会由于在控制器中找不到对应的处理方法,而报404这样的错误。

而filter,因为处理编码问题的过滤器是要涵盖所有的请求的,因此要使用路径匹配中能涵盖所有请求的<url-pattern>*/</url-pattern><url-pattern>/</url-pattern>只在servlet中才会匹配所有的请求。

filter与servlet

filter的匹配顺序,是根据在web.xml上配置的先后顺序进行匹配的,且是链式匹配的,即所有的filter,只要能匹配上,就会对请求进行处理。而且是在请求被servlet处理的前后进行处理。filter匹配处理完,再到servlet进行匹配,最后又到filter处理。而servlet匹配则是遵循上面说的四个匹配规则,而且一旦被匹配上,请求就会在这个被个servlet中被处理,而不会再传到下一轮的servlet匹配。

补充

interceptor、filter、servlet的匹配比较

springmvc的DispatcherServlet通常是配为:

<url-pattern>/</url-pattern>

表示拦截除静态资源外的所有请求。

而filter过滤器通常是配为:

<url-pattern>/*</url-pattern>

表示拦截所有请求。

要注意的是,SpringMVC的interceptor拦截器的匹配规则和上面servlet的匹配规则是不一样的。如:

<mvc:mapping path="/document/*"/>
<mvc:mapping path="/rbac/**"/>

前者拦截的是/document/save或者/document/delete,而不能拦截/document/path1/save
而后者拦截的是/document/save或者/document/path1/save或者/document/path1/path2/save,即可以拦截/document/开头的所有请求。

interceptor的路径匹配参考该文章:spring mvc路径匹配原则

interceptor、filter、servlet的对比

所在位置:servlet、filter、listener是配置到web.xml中,interceptor不配置到web.xml中,struts的拦截器配置到struts.xml中,spring的拦截器配置到spring.xml中。
加载顺序:web.xml 的加载顺序是:context- param -> listener -> filter -> servlet
interceptor和filter的执行顺序:接收到http请求时先执行filter再执行interceptor,最后返回html代码前先执行interceptor再执行filter。如果把整个请求看做生产流水线,那么filter是在头部和尾部,而interceptor是在脖子部位和膝盖部位。

详情参考这篇文章:《SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系》,写的超级好。

参考文章

https://www.cnblogs.com/51kata/p/5152400.html
http://blog.csdn.net/kong_lev/article/details/72911232
http://blog.sina.com.cn/s/blog_e5fee3c30102x96x.html
http://www.cnblogs.com/fangjian0423/p/servletContainer-tomcat-urlPattern.html
http://blog.csdn.net/rj042/article/details/23278337
http://blog.csdn.net/xiaoyaotan_111/article/details/53817918

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值