你真的了解DispatcherServlet的url-pattern配置吗?

https://blog.csdn.net/FarAwayWL/article/details/69527392


前言

对于springmvc中前端控制器url-pattern配置, 看了很多博客, 发现好多人理解都是错误, 并不清楚会拦截什么路径的请求, 有点小的细节并不被大家所关注.
  • 1
  • 2

DispatcherServlet常见的配置

   <servlet>
       <servlet-name>springmvc</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <!-- contextConfigLocation配置springmvc加载的配置文件(配置处理器映射器,适配器等等)
       如果不配置,默认加载的是/WEB-INF/[DispatcherServlet 的Servlet 名字]-servlet.xml(springmvc-servlet.xml) -->
       <init-param>
           <param-name>contextConfigLocation</param-name>
           <param-value>classpath:spring/springmvc.xml</param-value>
       </init-param>
       <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
       <servlet-name>springmvc</servlet-name>
       <url-pattern>/</url-pattern>
   </servlet-mapping>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

常见的url-pattern配置有以下三种:

第一种:
'*.xxx', 以指定后缀结尾的请求都交由DispatcherServlet处理
第二种:
'/' 将会 覆盖容器的default servlet, 凡是在web.xml文件中找不到匹配的URL,它们的访问请求都将交给该Servlet处理(静态资源也将会拦截). 所以web.xml没有配置其他特殊路径的servlet, 基本上 所有的请求都交由DispatcherServlet处理.
关于什么是default servlet, 可以参考 我之前的博文.
第三种:
'/*'  错误的配置,会拦截 *.jsp, *.jspx的请求, 使用这种配置最终要转发到一个JSP页面,仍然会由DispatcherServlet, 解析jsp地址, 不能根据jsp页面找到handler, 会报错

对于第一种扩展匹配, 是最简单的. 也是使用最简单的了.但是现在如此流行restful风格的URL, 这种带小尾巴的URL, 还是有点low的. 
第二种配置使用/, 通过该配置是可以实现rustful风格的URL的.

url-pattern配置为 ‘/*’, 为什么是错误的?

为了验证这种配置, 我做了一个简单的测试 
在webapp/WEB-INF/jsp下新建test.jsp, controller中只做转发.

@Controller
@RequestMapping("")
public class Test {
    @RequestMapping("/test")
    public String test() {
        return "test";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

测试请求路径: /test 
结果: 执行该请求后404 
console打印如下日志:

DispatcherServlet with name ‘taotao-sso’ processing GET request for [/test] 
RequestMappingHandlerMapping]-[DEBUG] Looking up handler method for path /test 
RequestMappingHandlerMapping]-[DEBUG] Returning handler method [public java.lang.String com.taotao.sso.controller.Test.test()] 
DispatcherServlet]-[DEBUG] Rendering view [org.springframework.web.servlet.view.InternalResourceView: name ‘test’; URL [/WEB-INF/jsp/test.jsp]] in DispatcherServlet with name ‘taotao-sso’ 
InternalResourceView]-[DEBUG] Forwarding to resource [/WEB-INF/jsp/test.jsp] in InternalResourceView ‘test’ 
DispatcherServlet]-[DEBUG] DispatcherServlet with name ‘taotao-sso’ processing GET request for [/WEB-INF/jsp/test.jsp] 
RequestMappingHandlerMapping]-[DEBUG] Looking up handler method for path /WEB-INF/jsp/test.jsp 
RequestMappingHandlerMapping]-[DEBUG] Did not find handler method for [/WEB-INF/jsp/test.jsp] 
PageNotFound]-[WARN] No mapping found for HTTP request with URI [/WEB-INF/jsp/test.jsp] in DispatcherServlet with name ‘taotao-sso’ 
DispatcherServlet]-[DEBUG] Successfully completed request

从日志可以清晰的看出, springmvc可以找到请求/test的handler, 之后springmvc转发请求’/WEB-INF/jsp/test.jsp’, 同样被DispatcherServlet处理, 之后就发出了/WEB-INF/jsp/test.jsp这样的转发请求, 自然会找不到handler, No mapping. 所以这样的请求会一直为404.

这里DispatcherServlet为什么会继续拦截/WEB-INF/jsp/test.jsp?

这里DispatcherServlet配置为: 
按照servlet的匹配规则,则路径匹配(/*)会优先于扩展匹配(*.jsp, *.jspx),导致对jsp的请求会被DispatcherServlet拦截掉。

*.jsp, *.jspx所对应的servlet为org.apache.jasper.servlet.JspServlet, 位于tomcat_home/conf/web.xml中, 下文会讲到. 
对于servlet的匹配规则和顺序不清楚的同学, 可以参看这篇博文

将url-pattern配置为 ‘/’ 看一下控制台的日志, 对比一下

请求路径为: /test 
结果: 正确找到view, 并进行渲染.

DispatcherServlet]-[DEBUG] DispatcherServlet with name ‘springmvc’ processing GET request for [/test] 
RequestMappingHandlerMapping]-[DEBUG] Looking up handler method for path /test 
RequestMappingHandlerMapping]-[DEBUG] Returning handler method [public java.lang.String com.taotao.sso.controller.Test.test()] 
DefaultListableBeanFactory]-[DEBUG] Invoking afterPropertiesSet() on bean with name ‘test’ 
DispatcherServlet]-[DEBUG] Rendering view [org.springframework.web.servlet.view.InternalResourceView: name ‘test’; URL [/WEB-INF/jsp/test.jsp]] in DispatcherServlet with name ‘springmvc’ 
InternalResourceView]-[DEBUG] Forwarding to resource [/WEB-INF/jsp/test.jsp] in InternalResourceView ‘test’ 
DispatcherServlet]-[DEBUG] Successfully completed request

看到这里的日志, 很多同学就奇怪了, 这里DispatcherServlet并不拦截转发的请求[/WEB-INF/jsp/test.jsp], 就直接找到了view.

DispatcherServlet配置为’/’, 为什么不拦截*.jsp, *.jspx.的请求?

前面说的当DispatcherServlet配置为’/’, 将会覆盖default servlet将会处理所有其他Servlet都不处理的访问请求. 所以这里不拦截拦截.jsp, .jspx.的请求, 一定有其他地方拦截了该请求, 但是仔细查找web.xml并没有发现其他的servlet啊!那一定是在容器中定义的啦~ 
果不其然, 在%TOMCAT_HOME%/conf/web.xml中继承过来的JspServlet会处理该请求.

    <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>
        <url-pattern>*.jspx</url-pattern>
    </servlet-mapping>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

从该web.xml也看到DefaultServlet的定义了(文件中总共就定义了这两个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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

这也就是为什么我们直接访问不在WEB-INF的jsp, 可以直接找到并解析的原因了. 
我们将test.jsp拷贝一份到webapp下, 直接访问/test.jsp, 访问到jsp中的内容了.并未出现404, 从而验证了我们的猜想.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值