新建的web项目为什么默认访问index.jsp

传送门

  • idea新建maven web项目
  • 普通web项目添加servlet

环境

  • tomcat:apache-tomcat-8.5.43,tomcat官网,直接下载8.5.45
  • jdk:1.8
  • 开发工具:idea

主题:新建的web项目为什么默认访问index.jsp

  • tomcat启动时,会读取web.xml文件,项目中的web.xml以及tomcat自带的(位置:apache-tomcat-8.5.43\conf\web.xml),tomcat自带两个servlet,下面是这两个servlet的映射规则(web.xml里面写的)

<servlet-mapping>
    <servlet-name>defaultservlet-name>
    <url-pattern>/url-pattern>
servlet-mapping>
 
<servlet-mapping>
    <servlet-name>jspservlet-name>
    <url-pattern>*.jspurl-pattern>
    <url-pattern>*.jspxurl-pattern>
servlet-mapping>
  • 配置自己的web.xml,依据 普通web项目添加servlet 博客中所描述的项目(后面所说的配置都是依据这个项目),为HelloServlet和HiServlet多配置几个映射,配置如下

<servlet>
    
    <servlet-name>helloServletservlet-name>
    
    <servlet-class>xin.yangshuai.servlet.HelloServletservlet-class>
    <load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
    
    <servlet-name>helloServletservlet-name>
    
    <url-pattern>/hellourl-pattern>
servlet-mapping>
<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>/*url-pattern>
servlet-mapping>
<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>/url-pattern>
servlet-mapping>


<servlet>
    <servlet-name>hiServletservlet-name>
    <servlet-class>xin.yangshuai.servlet.HiServletservlet-class>
    <load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
    <servlet-name>hiServletservlet-name>
    <url-pattern>/hiurl-pattern>
servlet-mapping>
<servlet-mapping>
    <servlet-name>hiServletservlet-name>
    <url-pattern>/hi/*url-pattern>
servlet-mapping>

一、映射规则

  • 项目启动时,存储所有的映射规则(方便理解,用基本的数据结构做解释,实际数据类型为HashMap):将servlet的url-pattern做为key,servlet-name做为value,保存到map(理解为map)中。所有的url-pattern不能重复(可以与tomcat自带的两个servlet的url-pattern重复,如果重复,会覆盖tomcat自带的servlet的映射规则),具体可以看WebXml.java类的getServletMappings方法。下面是简化数据结构后,用表格描述映射规则
key value
/hi hiServlet
/hello helloServlet
/* helloServlet
/hi/* hiServlet
.jsp jsp
.jspx jsp
/ helloServlet

二、匹配规则

  • 映射规则转化为匹配规则(方便理解,用基本的数据结构做解释,实际数据类型为Mapper.MappedWrapper数组或Mapper.MappedWrapper对象),将所有的映射规则存储到四个匹配规则中,具体可以看Mapper.java类internalMapWrapper方法。下面是简化数据结构后,用表格描述匹配规则
key value 匹配规则 对象名 对象类型
/hello helloServlet 精确匹配 exactWrappers Mapper.MappedWrapper[]
/hi hiServlet 精确匹配 exactWrappers Mapper.MappedWrapper[]
(空串) helloServlet 前缀匹配 wildcardWrappers Mapper.MappedWrapper[]
/hi hiServlet 前缀匹配 wildcardWrappers Mapper.MappedWrapper[]
jsp jsp 扩展名匹配 extensionWrappers Mapper.MappedWrapper[]
jspx jsp 扩展名匹配 extensionWrappers Mapper.MappedWrapper[]
(空串) helloServlet 默认匹配 defaultWrapper Mapper.MappedWrapper

注意:这里的对象名和对象类型都是java类中使用的,可以去看源码

  • 匹配优先级如下,排在前面的优先级高
匹配规则 对象名 对象类型 映射特征(url-pattern)
精确匹配 exactWrappers 数组 具体路径,例如:/hello
前缀匹配 wildcardWrappers 数组 以/*结尾,例如:/*,/hi/*
扩展名匹配 extensionWrappers 数组 以*.开头,例如:*.jsp,*.html
默认匹配 defaultWrapper 一个对象 /,其它匹配都无法匹配时,使用默认匹配
  • tomcat自带的web.xml配置了welcome-file-list节点,该节点的子节点即为默认访问页面(welcome-file),welcome-file配置的顺序会影响到实际的默认访问,我们可以在自己的web.xml文件中配置welcome-file-list节点以覆盖tomcat自带的,tomcat自带的web.xml中配置的welcome-file-list节点如下
<welcome-file-list>
    <welcome-file>index.htmlwelcome-file>
    <welcome-file>index.htmwelcome-file>
    <welcome-file>index.jspwelcome-file>
welcome-file-list>
  • 如果是默认访问,即请求根路径(ip:port/项目名/) 时,如果我们自定义的servlet没有配置“/*”前缀匹配,那么请求路径无法依据精确匹配、前缀匹配及扩展名匹配被任何servlet匹配到,此时会增加一个资源文件(welcomeResources)匹配方式,先拼接welcome-file的值再进行如上三种匹配,具体规则如下:
    1、如果只有一个welcome-file时,直接将welcome-file的值拼接到根目录后面进行匹配
    2、如果存在多个welcome-file时,按照顺序依次尝试,如果依据精确匹配、前缀匹配方式可以找到对应的servlet或者物理真实存在该文件,则使用该welcome-file的值拼接到根目录后面进行匹配,如果不存在这样的welcome-file,则使用第一个welcome-file的值拼接到根目录后面进行匹配。
    注意:这里说的物理真实存在表示,在项目的webapp文件夹下存在这样的文件,即文件名和后缀与welcome-file的值相同

三、实例验证

仍然使用 前文提到的项目 ,servlet和项目结构都不变。项目的web.xml发生变化,覆盖tomcat自带的web.xml的welcome-file-list,现在web.xml内容如下:


<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    
    

    
    

    
    <servlet>
        
        <servlet-name>helloServletservlet-name>
        
        <servlet-class>xin.yangshuai.servlet.HelloServletservlet-class>
        <load-on-startup>1load-on-startup>
    servlet>
    
    <servlet>
        <servlet-name>hiServletservlet-name>
        <servlet-class>xin.yangshuai.servlet.HiServletservlet-class>
        <load-on-startup>1load-on-startup>
    servlet>


    
    <welcome-file-list>
        <welcome-file>index.htmlwelcome-file>
        <welcome-file>index.htmwelcome-file>
        <welcome-file>index.jspwelcome-file>
    welcome-file-list>

    


    


web-app>

  • 1、servlet配置了/*映射,则用此servlet来处理默认访问
    web.xml

<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>/index.htmlurl-pattern>
servlet-mapping>
<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>/index.jspurl-pattern>
servlet-mapping>
<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>/url-pattern>
servlet-mapping>


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

运行结果:hiServlet配置了/*映射,则由hiServlet来处理默认访问
新建的web项目为什么默认访问index.jsp_第1张图片


  • 2、servlet没有配置/*映射,只有一个welcome-file时,则直接将welcome-file的值拼接到根目录后面进行匹配
    web.xml

<welcome-file-list>
    <welcome-file>index.htmlwelcome-file>
welcome-file-list>


<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>*.htmlurl-pattern>
servlet-mapping>
<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>/index.jspurl-pattern>
servlet-mapping>
<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>/url-pattern>
servlet-mapping>


<servlet-mapping>
    <servlet-name>hiServletservlet-name>
    <url-pattern>/index.htmlurl-pattern>
servlet-mapping>

运行结果:没有servlet配置/*,只有一个welcome-file,值为index.html,则默认访问相当于:http://localhost:8080/first_page/index.html,hiServlet配置的精确匹配,所有由hiServlet来处理默认访问。
新建的web项目为什么默认访问index.jsp_第2张图片


  • 3、其实welcome-file不用写成一个页面的样子,可以随意的写,可以没有后缀,可以有层级。
    web.xml

<welcome-file-list>
    <welcome-file>hh/index.htmlwelcome-file>
welcome-file-list>



<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>*.htmlurl-pattern>
servlet-mapping>
<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>/hh/*url-pattern>
servlet-mapping>
<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>/url-pattern>
servlet-mapping>


<servlet-mapping>
    <servlet-name>hiServletservlet-name>
    <url-pattern>/hh/index.htmlurl-pattern>
servlet-mapping>

运行结果::没有servlet配置/*,只有一个welcome-file,则默认访问相当于:http://localhost:8080/first_page/hh/index.html,hiServlet配置的精确匹配,所以由hiServlet来处理默认访问。
注意:没有精确匹配时,也会寻找可以进行前缀匹配、扩展名匹配的servlet进行匹配。
新建的web项目为什么默认访问index.jsp_第3张图片


  • servlet没有配置/*映射,如果存在多个welcome-file时,按照顺序依次尝试,如果存在依据精确匹配、前缀匹配方式获取的servlet或者物理真实存在该文件,则使用该welcome-file的值拼接到根目录后面进行匹配,如果不存在这样的welcome-file,则使用第一个welcome-file的值拼接到根目录后面进行匹配。
    注意:存在多个welcome-file,默认请求尝试拼接welcome-file的值时,是不考虑扩展名匹配的。

  • 4、尝试拼接:依据物理真实存在文件
    web.xml

<welcome-file-list>
    <welcome-file>index.htmlwelcome-file>
    <welcome-file>index.htmwelcome-file>
    <welcome-file>index.jspwelcome-file>
welcome-file-list>



<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>*.htmlurl-pattern>
servlet-mapping>


<servlet-mapping>
    <servlet-name>hiServletservlet-name>
    <url-pattern>/hiurl-pattern>
servlet-mapping>

运行结果:没有servlet配置/*,存在多个welcome-file时,按照顺序依次尝试,首先尝试拼接index.html,但是index.html并非物理真实存在,并且不能精确匹配或者前缀匹配,所以index.html被舍弃,同样道理,index.htm也会被舍弃,然后尝试index.jsp,index.jsp物理真实存在,所以拼接index.jsp,默认访问相当于:http://localhost:8080/first_page/index.jsp,此路径可以由tomcat自带的名为jsp的servlet进行扩展名(*.jsp)匹配,这也就是我们新建项目默认访问的页面。
新建的web项目为什么默认访问index.jsp_第4张图片


  • 5、我们可以覆盖默认的映射规则,比如覆盖*.jsp
    web.xml

<servlet-mapping>
    <servlet-name>hiServletservlet-name>
    <url-pattern>*.jspurl-pattern>
servlet-mapping>

运行结果:与上面相同的分析过程相同,默认访问相当于:http://localhost:8080/first_page/index.jsp,由于hiServlet覆盖了*.jsp映射规则,所以由hiServlet处理默认访问。
新建的web项目为什么默认访问index.jsp_第5张图片


  • 6、尝试拼接:依据前缀匹配
    web.xml

<welcome-file-list>
    <welcome-file>hh/index.htmlwelcome-file>
    <welcome-file>index.htmwelcome-file>
    <welcome-file>index.jspwelcome-file>
welcome-file-list>



<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>*.jspurl-pattern>
servlet-mapping>


<servlet-mapping>
    <servlet-name>hiServletservlet-name>
    <url-pattern>/hh/*url-pattern>
servlet-mapping>

运行结果:没有servlet配置/*,存在多个welcome-file时,按照顺序依次尝试,首先尝试拼接hh/index.html,可以看出,hiServlet配置了/hh/*的映射规则,符合前缀匹配,所以拼接hh/index.html,默认访问相当于:http://localhost:8080/first_page/hh/index.html,所以由hiServlet处理默认访问。
注意:除了依据前缀匹配,也可以依据精确匹配。
新建的web项目为什么默认访问index.jsp_第6张图片


7、尝试拼接:不能依据扩展名匹配
web.xml


<welcome-file-list>
    <welcome-file>index.htmlwelcome-file>
    <welcome-file>index.htmwelcome-file>
    <welcome-file>index.jspwelcome-file>
welcome-file-list>



<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>*.htmlurl-pattern>
servlet-mapping>


<servlet-mapping>
    <servlet-name>hiServletservlet-name>
    <url-pattern>/hhurl-pattern>
servlet-mapping>

运行结果:没有servlet配置/*,存在多个welcome-file时,按照顺序依次尝试,此时默认访问相当于:http://localhost:8080/first_page/index.jsp,依据物理真实存在文件拼接。helloServlet虽然配置了*.html后缀匹配规则,但是并没有拼接index.html。
新建的web项目为什么默认访问index.jsp_第7张图片


  • 8、尝试拼接:无法依据精确匹配,前缀匹配和物理真实存在文件匹配,则使用第一个拼接。
    我们将项目的index.jsp删掉(改个名相当于删除了)
    新建的web项目为什么默认访问index.jsp_第8张图片
    web.xml(与上面相同)

<welcome-file-list>
    <welcome-file>index.htmlwelcome-file>
    <welcome-file>index.htmwelcome-file>
    <welcome-file>index.jspwelcome-file>
welcome-file-list>



<servlet-mapping>
    <servlet-name>helloServletservlet-name>
    <url-pattern>*.htmlurl-pattern>
servlet-mapping>


<servlet-mapping>
    <servlet-name>hiServletservlet-name>
    <url-pattern>/url-pattern>
servlet-mapping>

运行结果:没有servlet配置/*,存在多个welcome-file时,按照顺序依次尝试,此时依据精确匹配,前缀匹配和物理真实存在文件匹配都无法匹配到,所以拼接第一个,默认访问相当于:http://localhost:8080/first_page/index.html,此时只有helloServlet配置了*.html扩展名匹配,所以由helloServlet来处理默认访问。
新建的web项目为什么默认访问index.jsp_第9张图片


总结

  • 匹配优先级
    精确匹配
    前缀匹配
    扩展名匹配
    资源文件匹配(如果是默认访问)
    默认匹配
  • 默认访问拼接原则
    如果是默认访问,即请求根路径(ip:port/项目名/) 时,如果我们自定义的servlet没有配置“/*”前缀匹配,那么请求路径无法依据精确匹配、前缀匹配及扩展名匹配被任何servlet匹配到,此时会增加一个资源文件(welcomeResources)匹配方式,先拼接welcome-file的值再进行如上三种匹配,具体规则如下:
    1、如果只有一个welcome-file时,直接将welcome-file的值拼接到根目录后面进行匹配
    2、如果存在多个welcome-file时,按照顺序依次尝试,如果依据精确匹配、前缀匹配方式可以找到对应的servlet或者物理真实存在该文件,则使用该welcome-file的值拼接到根目录后面进行匹配,如果不存在这样的welcome-file,则使用第一个welcome-file的值拼接到根目录后面进行匹配。

如有错误,欢迎指正!!!


参考:https://www.cnblogs.com/fangjian0423/p/servletContainer-tomcat-urlPattern.html

你可能感兴趣的:(java,原力计划)