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";
}