SpringMVC学习笔记-06 url-pattern、静态资源处理

1. url-pattern解析

url-pattern用于配置处理请求的servlet,Tomcat会根据url-pattern的配置选择将请求交给哪个实体类。

    <!--注册DispatcherServlet,配置Tomcat启动后就创建-->
    <servlet>
        <!--SpringMVC容器创建时,读取的配置文件默认为<servlet-name>-servlet.xml-->
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <init-param>
            <!--自定义SpringMVC读取的配置文件的位置-->
            <param-name>contextConfigLocation</param-name>
            <!--类路径下的springmvc.xml文件(resources目录就是类路径)-->
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>

        <!--Tomcat启动后,创建对象的顺序-->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!--配置DispatcherServlet拦截哪些请求-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <!--
            使用框架时,url-pattern可以使用两种
            1. 扩展名  *代表通配符,匹配任意长度的路径  只看扩展名  *.do *.action 等
            2. 使用 "/"
        -->
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

我们在首页中加入静态资源,看看访问效果:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    这是一个静态页面
</body>
</html>

在index.jsp中引用静态资源

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-3.5.1.js"></script>
    <script type="text/javascript">
        $(function () {
            $("button").click(function () {
                $.ajax({
                    url:"test/returnStringAjax.do", // 请求路径
                    data:{ // 请求的数据
                        name:"zzt",
                        age:21
                    },
                    type:"post", // 请求方式
                    dataType:"text",
                    success:function (resp) { // resp结果数据解析后的结果
                        alert("返回文本数据:" + resp);
                    }
                })
            })
        })
    </script>
</head>
<body>
    <button id="btn">发起Ajax请求</button>
    <br>
    <img src="images/0.jpg" alt="图片无法正常显示"/>
</body>
</html>

访问index.jsp:

访问静态html页面:

问题1:访问项目首页index.jsp的请求是由谁负责处理的--Tomcat,Tomcat会将JSP页面翻译成对应的Servlet对象

问题2:访问jquery.js的请求(Request URL:http://localhost:8080/SpringMVC_01/js/jquery-3.5.1.js)是谁负责处理的--Tomcat

原因很简单,js/jquery-3.5.1.js并不符合我们为DispatcherServlet配置的*.do模式的映射。

问题3:访问项目内部的静态资源(图片资源,Request URL :http://localhost:8080/SpringMVC_01/images/0.jpg)是有谁负责处理的--Tomcat

原因同上

问题4:直接访问一个静态页面的请求是谁负责处理的--Tomcat

原因同上

问题5:发起一个*.do的请求是谁负责处理的--DispatcherServlet

通过上述分析分析我们大概可以猜出Tomcat本身就可以处理静态资源(html、图片、js)的访问,实际上,Tomcat服务器内部就有一个默认的servlet用于处理这些请求:

  <!-- The default servlet for all web applications, that serves static     -->
  <!-- resources.  It processes all requests that are not mapped to other   -->
  <!-- servlets with servlet mappings (defined either here or in your own   -->
  <!-- web.xml file).  This servlet supports the following initialization   -->

Tomcat自带的web.xml文件中有这么一段,意思就是Tomcat内部集成了一个默认的servlet,用来处理  1.静态资源  2.那些没有配置url映射的请求。

这个默认的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>

    <!-- The mapping for the default servlet -->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

        如果我们将<url-pattern>设置成/,就表示该servlet可用于处理静态资源和没有servlet匹配的请求(或者说那些没有被其他Servlet响应的请求);如果我们将自己引入的Servlet的<url-pattern>设置为/,那么Tomcat默认的Servlet就会被替代。

        前面我们说过,对于DispatcherServlet的url-pattern确实可以用/,但是因为DispatcherServlet在默认情况下不具备处理静态资源和没有匹配的Servlet的映射的能力,所以一旦我们访问那些资源(图片、html、js、css)就会报404错。

    <servlet>
        <!--SpringMVC容器创建时,读取的配置文件默认为<servlet-name>-servlet.xml-->
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <init-param>
            <!--自定义SpringMVC读取的配置文件的位置-->
            <param-name>contextConfigLocation</param-name>
            <!--类路径下的springmvc.xml文件(resources目录就是类路径)-->
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>

        <!--Tomcat启动后,创建对象的顺序-->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!--配置DispatcherServlet拦截哪些请求-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <!--
            使用框架时,url-pattern可以使用两种
            1. 扩展名  *代表通配符,匹配任意长度的路径  只看扩展名  *.do *.action 等
            2. 使用 "/"
        -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

[注]:如果发现还可以访问,那可能是因为浏览器自带的缓存功能导致的,此时Status Code为304,只需要清理一下缓存即可。        

        但是这种情况下动态资源还是可以访问的:

2.SpringMVC静态资源访问

1. 配置<mvc:default-servlet-handler/>

        在springMVC-servlet.xml中配置<mvc:default-servlet-handler />后,会在Spring MVC的容器中定义一个DefaultServletHttpRequestHandler,它会对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。一般Web应用服务器默认的Servlet名称是"default"(上面我们也看到了,Tomcat的默认servlet正是如此),因此DefaultServletHttpRequestHandler可以找到它。如果使用的Web应用服务器的默认Servlet名称不是"default",则需要通过default-servlet-name属性显式指定:

<mvc:default-servlet-handler default-servlet-name="所使用的Web服务器默认使用的Servlet名称" />

        此时我们可以正常访问图片、js这些静态资源了,但是又会神奇地发现动态资源不支持了!这是因为<mvc:default-servlet-handler/>和@RequestingMapping之间粗存在冲突,如果我们不打开注解驱动<mvc:annotation-driven/>,那么SpringMVC就会把所有的资源统统交给服务器的默认servlet处理了,但显然,他是不能处理动态资源的,因此完整的配置应该如下 :

    <!--配置注解驱动-->
    <mvc:annotation-driven/>
    
    <!--静态资源处理 方式1-->
    <mvc:default-servlet-handler/>

2. 配置<mvc:resources>

        上述配置极其简单,但是呢,他要求服务器本身需要提供一个处理静态资源和未映射请求的servlet,如果服务器没有的话是无法使用的。SpringMVC提供了了专门用于处理静态资源访问请求的处理器ResourceHttpRequestHandler。

        在springMVC-servlet.xml中配置<mvc:resources>后,会在Spring MVC的容器中定义一个ResourceHttpRequestHandler,他会负责处理对静态资源的访问,而不依赖于服务器的默认servlet。

<mvc:resources location="静态资源目录" mapping="对该静态资源的请求路径"/>

        mapping属性可以使用通配符**表示一个文件夹下的直接文件、一级目录文件、多级目录文件。

        对于不同种的静态资源,如果不在同一个目录下,我们需要单独配置:

    <!--配置注解驱动-->
    <mvc:annotation-driven/>

    <!--静态资源处理 方式2-->
    <mvc:resources mapping="/images/**" location="/images/" />
    <mvc:resources mapping="/html/**" location="/html/" />
    <mvc:resources mapping="/js/**" location="/js/" />

[注]:<mvc:resources>和@RequestMapping注解之间依旧有冲突,因此需要打开注解驱动,否则会导致动态资源无法访问。

当然我们也可以把他们放置到一个目录下,就可以只配置一条映射。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="static/js/jquery-3.5.1.js"></script>
    <script type="text/javascript">
        $(function () {
            $("button").click(function () {
                $.ajax({
                    url:"test/returnStringAjax.do", // 请求路径
                    data:{ // 请求的数据
                        name:"zzt",
                        age:21
                    },
                    type:"post", // 请求方式
                    dataType:"text",
                    success:function (resp) { // resp结果数据解析后的结果
                        alert("返回文本数据:" + resp);
                    }
                })
            })
        })
    </script>
</head>
<body>
    <button id="btn">发起Ajax请求</button>
    <br>
    <img src="static/images/0.jpg" alt="图片无法正常显示"/>
</body>
</html>

3.小Tip

        上面我们说到,实际上/代表的是所有没有被servlet处理的请求,那么当我们为DispatcherServlet配置了/,且也配置了静态资源访问后,由于我们并没有添加其他的任何Servlet,那么整个框架也就可以处理所有的请求了,这个时候,我们也就不再需要*.do这种奇怪的路径映射了:

        $(function () {
            $("button").click(function () {
                $.ajax({
                    url:"test/returnStringAjax", // 请求路径
                    data:{ // 请求的数据
                        name:"zzt",
                        age:21
                    },
                    type:"post", // 请求方式
                    dataType:"text",
                    success:function (resp) { // resp结果数据解析后的结果
                        alert("返回文本数据:" + resp);
                    }
                })
            })
        })
    @ResponseBody
    @RequestMapping(value = "/returnStringAjax", produces = "text/plain;charset=utf-8")
    public String doReturnStringAjax(){
        return "返回的是字符串不是数据--SpringMVC";
    }

猜你喜欢

转载自blog.csdn.net/qq_39304630/article/details/112969416