In-depth understanding of the difference between configuration / and /* in web.xml

This article is so well written that I want to reprint it and keep a copy for myself

       When using SpringMVC for web development, if you configure the virtual path of DispathcerServlet external access to /, you need to configure <mvc:default-servlet-handler/> in the Spring configuration file, then why do you need to configure this item? Is it OK if the external access virtual path is configured as /*? Next, this article will take these two questions, starting from the conf/web.xml file in Tomcat, and analyze the real difference between the two configurations in simple language.

1. A note: why? Intercept why? match

       When describing the url-patten tag corresponding to a servlet, many people will use the word "intercept" to describe this relationship. In fact, the word "intercept" is very inappropriate. In daily life, the word "intercept" as the name suggests is to stop and not give it the right of way. Then it should be used in Servlet to block the request and not respond to the browser. In fact, this is obviously not the result we want. So what word would be more appropriate to describe this relationship?

write picture description here

       The above picture is taken from the description of org.apache.jasper.servlet.JspServlet (line 113) in conf/web.xml in Tomact, from which you can see that the word map is used to describe this relationship. map is translated as "mapping", but "mapping" is too specialized and difficult for beginners to understand, so using "matching" with a close meaning can better describe this relationship and be more approachable. So only if the request matches the corresponding Servelt, the server will give a response, otherwise, sorry, give 404.

2. A little note: All requested resources need to be processed by Servlet

       All requested resources need to be processed by Servlet, including but not limited to static resources (.html, .css, jpg and other files), .jsp requests and Servlet requests. When learning web for the first time, when the address bar directly accesses static resources (localhost:8080/index.html), it gives us the feeling that we do not need to go through Servlet processing, and the server will respond directly to us. In fact, the conf/web.xml in Tomcat has the following description (line 38). This description is about org.apache.catalina.servlets.DefaultServlet.

write picture description here

       It can be seen from this that DefaultServlet mainly deals with static resources. The Servlet processing rule is that requests that cannot be matched by other Servlets will be processed by it. And the path configuration of DefalutServlet (default Servlet, default Servlet) in Tomcat happens to be /.

write picture description here

       If you also configure a path / in your own web application, it will override the default Servlet in conf/web.xml in Tomcat. For this reason, configure the following in your own web.xml:

  <servlet>
    <servlet-name>DefaultServlet</servlet-name>
    <servlet-class>cn.tedu.test.DefaultServlet</servlet-class>
  </servlet>

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

  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

       I have the following code in the DefaultServlet I wrote:

        //告诉浏览器响应的是文本信息
        response.setContentType("text/html;charset=utf-8");
        //获得index.html的真实路径
        String path = this.getServletContext().getRealPath("index.html");
        //获得输入输出流,并将文件内容响应给浏览器
        FileInputStream fis = new FileInputStream(path);
        OutputStream out = response.getOutputStream();
        int i = -1;
        while((i = fis.read()) != -1){
            out.write(i);
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

       Prepare a simple html static resource and place it in the webRoot directory:

    <!DOCTYPE html>
    <html>
      <head>
        <title>index.html</title>
        <meta charset="UTF-8">
      </head>

      <body>
        This is my HTML page. <br>
      </body>
    </html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

       这个时候在浏览器输入相应的地址,浏览器会有”This is my HTML page.”显示,表明此时可以正确访问静态资源index.html。当将自己的DefalutServlet中的java代码给注释掉后,再从浏览器访问index.html静态资源,会发现浏览器不会做出任何响应。从这个结果中可以看到静态资源是由Servlet以流的形式响应给页面的,在这个Servlet中有一个重要的设置response.setContentType(“text/html;charset=utf-8”)。这个设置是告诉浏览器服务器将发送的是text/html信息,浏览器将会按照这种格式去解析浏览器所发送的内容(ig.发送的是png格式的图片则为image/png)。 
       从上我们可以看到当在自己的Servlet中配置/的时候会覆盖Tomcat中config/web.xml中的/配置,这时如果我们不对静态资源进行相应的处理的时候,将导致静态资源无法访问。可见,Tomcat中的config/web.xml中的缺省Servlet主要处理的就是静态资源的访问。 
       这也是为什么平常我们在自己的web应用中没有处理配置处理静态资源ervlet的时候,静态资源仍然可以正常访问和显示的原因。因此当我们在springMVC中将DispatcherServlet配置成/时,我们一定要在spring的配置文件中加上如下配置的原因。

    <!-- 处理静态资源被"/"所拦截的问题 -->
    <mvc:default-servlet-handler/>
  • 1
  • 2

3. /和/*区别

       其实/和/*都可以匹配所有的请求资源,但其匹配的优先顺序是不同的。/在所有的匹配路径中,优先级最低,即当别的路径都无法匹配时,/所匹配的缺省Servlet才会进行相应的请求资源处理。而 /星号 匹配的优先级是高于/路径和星号.后缀的路径的(如星号.action,星号.jsp等路径)。 
       为了更好的说明这个问题我们以一个例子来说明。相关文件如下(注意导入springMVC的jar包):

write picture description here

web.xml配置如下:

  <servlet>
      <servlet-name>springmvc</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc-servlet.xml</param-value>
    </init-param>
  </servlet>

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

  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

       springmvc-servlet.xml配置如下:

    <!-- 处理静态资源被"/"所拦截的问题 -->
    <mvc:default-servlet-handler/>
  • 1
  • 2

       index.jsp文件如下:

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE >
<html>
  <head>
    <title>My JSP 'index.jsp' starting page</title>
  </head>

  <body>
    This is my JSP page. <br>
    <img alt="图片" src="1.jpg" border="1px" width="400px" height="200px">
  </body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

       在浏览器地址栏输入localhost:8080/hello,我们发现页面文字和图片内容都可以正常显示。

write picture description here

       当将springmvc-servlet.xml中关于静态资源访问的配置给注释掉后,再次访问结果如下:

write picture description here

       这时静态的图片资源无法访问,这正如一开始论述的结论一样。这时我们再次打开springmvc-servlet.xml中关于静态资源的配置,并将web.xml中对外访问的虚拟路径配置成/*这样的形式。再次访问会抛出一个404的错误。而将地址栏改为localhost:8080/hello/index.jsp强行访问该资源的时候,会出现以下结果:

write picture description here

       即将jsp内容以文本的形式显示出来了。接着我们继续将springmvc-servlet.xml中关于静态资源的访问配置给注释掉,继续访问localhost:8080/hello/index.jsp资源,这时会抛出一个404错误,也就是说在上一次访问的时候,服务器把index.jsp当成了静态资源响应给了浏览器,所有我们才会看到这样的文本页面。 
       那么为什么在配置成/*后index.jsp就不能正常访问了?原来在Tomcat中conf/web.xml中配置了org.apache.jasper.servlet.JspServlet用来处理.jsp这样的资源了(第113行)。

write picture description here

       这段话的意思是说JspServlet是jsp页面的编译和执行的Servlet.也就是说JspServlet可以将.jsp页面转换成.java文件,最终编译成.class文件并执行。 
       至此,对/和/*的配置有一个这样的总结:两者都可以匹配任何资源,只不过两者的匹配的优先级是不一样的;当请求资源与其它Servlet都无法匹配的时候,/所配置的Servlet才会匹配。 
       在Tomcat中conf/web.xml中有关于/和.jsp页面处理的Servlet,当自己所配的web.xml文件中配置/时,会使Tomcat中的DefaultServlet无法访问,导致静态资源无法访问,因此在SpingMVC配置文件中要开启处理静态资源的开关。实际上,当将对外访问的虚拟路径配置成*.action等类似路径的时候,就可以很好的避免上述问题了。

4. 引申一:Servlet对外访问虚拟路径匹配顺序简介

       Servlet对外访问的虚拟路径的匹配顺序大致如下:

       1. Contains all or part of the specific path configuration for external access, such as /LoginServlet, /servlet/* (more specific paths are preferentially matched);  2. The configuration of /*
       ; 
       3. The configuration in the form of a suffix such as * .action , such as index.jsp, login.action (even if it is a specific path, the priority will be lower than the configuration of 1 and 2); 
       4. When other configurations cannot be matched, match/configured Servlet.

       Note: A configuration like /servlet/*.action is wrong, i.e. there should be no such configuration.

5. Extension 2: Can the external access virtual path of the filter be configured as /?

       the answer is negative. 
       In a servlet, the requested resource must be processed by the corresponding servlet, otherwise a 404 error will be thrown. But it is different in the filter. Sometimes the requested resource does not need to be processed by the filter, so when it is configured as /, the filter will not take effect. This is consistent with the conclusion of / configuration, that is, / will only match requests that cannot be processed by other request resources, and the request resources in the filter are not required to be processed.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326080528&siteId=291194637