你真的理解SpringMVC DispatcherServlet中的映射了吗?

 

1、Request URL 与 Servlet url-pattern匹配顺序与关系html

   当一个请求发送到servlet容器(服务器)的时候,容器先会将请求的url减去当前应用上下文的路径,就是scheme://ip:port/context url做为servlet的映射url,访问的是http://localhost:8080/test/index.html,个人应用上下文(context)是test,容器会将http://localhost:8080/test去掉,剩下的/index.html部分拿来和servleturl-pattern进行匹配。前端

1.        精确路径匹配(彻底匹配)java

”/”开始的,不包含通配符*(不以通配符结尾)的,例如:web

<servlet-mapping>

    <servlet-name>default</servlet-name>

    <url-pattern>/index.html</url-pattern>

  </servlet-mapping>

 

2.        最长路径匹配(路径匹配)spring

”/”开始的,而且以通配符*结尾的(通配符只能在结尾,不能放中间。例如,/index/te*/index.html这样的)tomcat

<servlet-mapping>

    <servlet-name>default</servlet-name>

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

 </servlet-mapping>

对于最长路径匹配,老是会匹配路径长的,例如,有2servlet-mapping以下。(本地服务器)服务器

<servlet-mapping>

    <servlet-name>A</servlet-name>

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

  </servlet-mapping>

<servlet-mapping>

    <servlet-name>B</servlet-name>

    <url-pattern>/test/a/*</url-pattern>

  </servlet-mapping>

   对于请求http://localhost/test/a虽然AB都知足,可是servlet容器就会选择B,由于B匹配到的长度更长。app

3.        扩展匹配jsp

*.开始,以扩展名结束的,例如: 测试

<servlet-mapping>

    <servlet-name>spring-dispatcher-servlet</servlet-name>

    <url-pattern>*.html</url-pattern>

  </servlet-mapping>

4.        默认servlet匹配

只有一个”/”,例如:

<servlet-mapping>

    <servlet-name>default</servlet-name>

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

  </servlet-mapping>

 

2、DispatcherServlet 的url-pattern

   在说DispatcherServlet url-pattern以前得先介绍一个比较重要的点,就是咱们的项目下的WEB-INFweb.xml中的url-pattern是不容许重复的,例如同时在项目中配置以下2个相同默认的映射路径,服务器启动就会报错。

<servlet-mapping>

    <servlet-name>default</servlet-name>

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

  </servlet-mapping>

<servlet-mapping>

    <servlet-name>spring-dispatcher-servlet</servlet-name>

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

  </servlet-mapping>

   可能会有人有疑问,在tomcat服务器的web.xml中已经定义了以下图所示的servleturl-pattern,而在咱们本身的项目中的web.xml中定义一样的默认servlet-mapping  url-pattern为何没有报错呢?

图1  tomcat默认的Servlet

               

图2 tomcat jsp Servlet

                    

图3 tomcat 默认的映射

   对于这个问题尚未仔细研究过,不过应该是default servlet是单独的最后处理的,想一下这个道理很简单,只有咱们的web.xml中没有找到映射才会到default servlet因此不存在冲突的问题。

下载再来看DispatcherServlet中下面这2servlet-mapping的区别

<servlet-mapping>

    <servlet-name>spring-dispatcher-servlet</servlet-name>

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

  </servlet-mapping>

<servlet-mapping>

    <servlet-name>spring-dispatcher-servlet</servlet-name>

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

  </servlet-mapping>

       DispatcherServlet本质上仍是一个servlet,根据上面所介绍的servlet匹配顺序和规则很容易得出”/*”是路径匹配,只不过它是匹配全部路径,就是只有是页面请求的不论是客户端来的页面请求仍是,服务器转发的页面请求都会被DispatcherServlet处理。

   如今对于把DispatcherServletservlet-mapping配置为”/*”出现的各类404错误就很是明显了。DispatcherServlet处理请求是咱们本身实现的,可是全部请求(根据最长路径匹配规则,除非有更加精确的匹配,例如,/view/*)都到了DispatcherServlet显然咱们没有实现的映射的部分就会出现404错误,例如各类静态资源的请求等。

       DispatcherServletservlet-mapping若是配置的是”/”,这个是个默认的servlet,就是在没有找到匹配的servlet的时候就使用DispatcherServlet。这个一样由于咱们使用SpringMVC一般值配置了DispatcherServlet,而没有配置其余的servlet,对于这种状况”/””/*”相差不大。

   不过有一点DispatcherServletservlet-mapping若是配置的是”/”则能够访问的<welcome-file-list>设置的页面。而”/*”访问不到,这个缘由尚未仔细研究。关于”/””/*”之间的差异在stackoverflow上有一个问题 ”/””/*” 的差异 对于这个问题的有的回答刚刚开始看以为很对,可是经过不断的测试和更加深刻的思考也会发现一些问题,能够参考测试一下,顺便想想Servlet的匹配规则。

 

3、DispatcherServlet servlet-mapping配置策略参考

   配置url-pattern的时候尽可能使用更加具体的模式,例如使用后缀匹配,例如,*.do,*.html,*.action等方式。

   若是你以为上面的方式不够优雅,能够把要按模块设置前缀,例如,使用/user/*,/shop/*这样的方式来处理。

   对于静态资源的映射能够直接经过像下面的方式直接经过default Servlet来解决,这样就避免过多的转发,提升效率。

<servlet-mapping>

    <servlet-name>default</servlet-name>

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

  </servlet-mapping>

 

 

4、其余一些问题

   常常有一些404错误很难找到缘由,由于不少状况能够引发服务器返回404错误,我没有读过tomcat的源码,因此很难知道根本缘由,不过对于使用SpringMVC若是出现了像下面这样常见的错误。

No mapping found for HTTP request with URI [/context/xxx/xxx] in DispatcherServlet with name 'spring-dispatcher-servlet'

   那么就是servlet容器已经找到了DispatcherServlet可是DispatcherServlet没有设置相应的映射的方法。

   还有就是路径前面带不带”/”的的区别,这里可使用一个小技巧帮助记忆,就是服务器端(servlet,web.xmlRequestMapping等配置中)的路径加上”/”表示的是相对于上下文环境(context),例如,

request.getRequestDispatcher("/index.html").forward(request, response);

   假如是本地服务器,端口是8080项目上下文环境是test,那么上面的就表示转发到http://localhost:8080/test/index.html这个路径。而在前端页面(jsp中编译也是这个原则)中的”/”则表示根路径,例如,在jsp中有连接是”/index.html”表示的就是http://localhost:8080/index.html这个路径。

   对于没有加上”/”的路径都是相对路径,就是当前文件所在目录的路径加上指定的连接。

相关文章
相关标签/搜索