Servlet
目标:
- 理解Servlet的执行流程和生命周期
- 掌握Servlet的使用和相关配置
# 简介
- Servlet是JavaWeb最为核心的内容,它是Java提供的一门动态web资源开发的技术;
- 使用Servlet可以实现根据不同的登录用户在页面上动态显示不同的内容。
- Servlet是JavaEE规范之一,与JDBC类似,它们同属于JavaEE规范的一部分,其实Servlet就是一个接口,后面我们会定义Servlet类实现Servlet接口,并由Web服务器运行Servlet。
介绍完Servlet是什么以后,接下来我们按照 快速入门 -> 执行流程 -> 生命周期 -> 体系结构 -> urlPatter配置 -> XML配置 的步骤来一步步完成对Servlet知识的学习,下面我们就通过一个入门案例来快速使用一下Servlet。
# 快速入门
目标:编写一个Servlet类,并使用IDEA中Tomcat插件进行部署,最终通过浏览器访问我们开发的Servlet程序。具体实现步骤如下:
- 创建Web项目
servlet-demo
,导入Servlet依赖坐标
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<!--
此处为什么需要添加该标签?
provided指的是在编译和测试过程中有效,最后生成的war包时不会加入
因为Tomcat的lib目录中已经有servlet-api这个jar包,如果在生成war包的时候生效就会和Tomcat中的jar包冲突,导致报错
-->
<scope>provided</scope>
</dependency>
2
3
4
5
6
7
8
9
10
11
创建一个类,实现Servlet接口,并重写接口中所有方法,并在
service
方法中输入一句话package com.itheima.servlet; import javax.servlet.*; import javax.servlet.annotation.WebServlet; import java.io.IOException; /** * Servlet快速入门 * @author sunyy * @version 0.0.1 * @since 2022.10.26 * */ @WebServlet("/hello") public class ServletDemo1 implements Servlet { public void init(ServletConfig servletConfig) throws ServletException { } public ServletConfig getServletConfig() { return null; } public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("Servlet Hello World~"); } public String getServletInfo() { return null; } public void destroy() { } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38配置:在类上使用
@WebServlet
注解,配置该Servlet的访问路径@WebServlet("/hello")
1访问:启动Tomcat,浏览器中输入URL地址访问该Servlet
http://localhost:8080/web-demo/demo1
1浏览器访问后,在控制台会打印
Servlet Hello World~
,说明Servlet程序已经成功运行。
至此,Servlet的入门案例就已经完成了,大家可以按照上面的步骤进行练习一下。练习过程中大家可以思考一下:我们并没有创建ServletDemo1
类的对象,也没有调用对象中的service
方法,为什么浏览器访问后控制台就打印了Servlet Hello World~
。
# 执行流程
上面我们开发的快速入门ServletDemo1
已经能正常运行了,同时我们还提出了一个问题,不知道大家有没有想到答案。
实际上,要回答上面的问题,我们就需要学习一下Servlet的执行流程:
- 浏览器发出
http://localhost:80/servlet-demo/hello
请求,从请求中可以解析除三部分内容,分别是:localhost:80
、servlet-demo
、hello
- 根据
loclahost:80
可以找到要访问的Tomcat 服务器 - 根据
servlet-demo
可以找到部署在Tomcat服务器上的servlet-demo
项目 - 根据
hello
可以找到要访问的是项目中的哪个Servlet类,根据@WebServlet
后面的值进行匹配
- 根据
- 找到
ServletDemo
这个类后,Tomcat Web服务器就会为ServletDemo
这个类创建一个对象,然后调用对象中的service
方法ServletDemo
实现了Servlet
接口,所以类中必然会重写service
方法供Tomcat Web服务器进行调用service
方法中有ServletRequest
和ServletResponse
两个参数,ServletRequest
封装的是请求数据,ServletResponse
封装的是响应数据,后面我们可以通过这两个参数实现前后端的数据交互
小结
介绍完Servlet的执行流程,需要大家掌握两个问题:
- Servlet由谁创建?Servlet方法由谁调用?
Servlet由web服务器创建,Servlet方法由web服务器调用
- 服务器怎么知道Servlet中一定有service方法?
因为我们自定义的Servlet,必须实现Servlet接口并实现其抽象方法,而Servlet接口中有service方法
# 生命周期
介绍完Servlet的执行流程后,我们知道Servlet是由Tomcat Web服务器帮我们创建的。随之而来又出现一个问题:Tomcat什么时候创建的Servlet对象?
要想回答上面的问题,我们就需要学习一下Servlet的生命周期。对象的生命周期是指一个对象从创建到消费的整个过程,而Servlet的生命周期就是只Web服务器从创建Servlet对象到使用、再到消费这个Servlet对象的整个过程。
Servlet运行在Servlet容器中(Web服务器,如Tomcat),其生命周期由容器来管理,分为4个阶段:
- 加载和实例化:默认情况下,当Servlet第一次被访问时,由容器创建Servlet对象
提示
默认情况下,Servlet会在第一次访问时被创建,但是如果创建Servlet比较耗时的话,那么第一个访问的人等待的时间就比较长,用户体验就比较差,那么这个时候就需要采用另外一种方式,也就是在Web服务器启动的时候来创建Servlet对象,可以通过下面的方式进行配置:
/**
* loadOnStartup的取值有两类情况:
* 1. 负整数:第一次访问时创建Servlet对象
* 2. 0或正整数:服务器启动时创建Servlet对象,数字越小优先级越高
*/
@WebServlet(urlPatterns = "/hello", loadOnStartup = 1)
2
3
4
5
6
初始化:在Servlet实例化之后,容器将调用Servlet的
init()
方法初始化这个对象,完成一些如加载配置文件、创建连接等初始化的工作,该方法只调用一次。请求处理:每次请求Servlet是,Servlet容器都会调用Servlet的
service()
方法对请求进行处理服务终止:当需要释放内存或者容器关闭时,容器会调用Servlet对象的
destroy()
方法完成资源的释放。在destroy()
方法调用之后,容器会释放这个Servlet实例,该实例随后会被Java的垃圾收集器回收。
下面咱们通过案例来演示下上述Servlet的生命周期:
package com.itheima.servlet;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
/**
* Servlet快速入门以及Servlet生命周期方法演示
* @author sunyy
* @version 0.0.1
* @since 2022.10.26
*
*/
@WebServlet(urlPatterns = "/hello", loadOnStartup = 1)
public class ServletDemo1 implements Servlet {
/**
* 初始化方法
* 1. 调用时机:默认情况下,Servlet第一次被访问时,调用
* loadOnStartup: 默认为-1,修改为0或者正整数,则会在服务器启动的时候,调用
* 2. 调用次数:1次
* @param servletConfig
* @throws ServletException
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init ...");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 提供服务
* 1. 调用时机:每一次Servlet被访问时,调用;
* 2. 调用次数:多次,与被请求次数有关
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws
ServletException, IOException {
System.out.println("Servlet Hello World~");
}
@Override
public String getServletInfo() {
return null;
}
/**
* 销毁方法
* 1. 调用时机:内存释放或者服务器关闭的时候,Servlet对象会被销毁;
* 2. 调用次数:1次
*/
@Override
public void destroy() {
System.out.println("destroy ...");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
运行结果:
注意
如果想看到Servlet中destroy()
方法的执行效果,需要再CMD命令行中,先使用mvn tomcat7:run
启动,然后再使用Ctrl + C
组合键关闭Tomcat。
小结:需要我们掌握的内容
- Servlet对象在什么时候被创建?
默认是第一次访问的时候被创建,可以使用
@WebServlet(urlPatterns = "/hello", loadOnStartup = 1)
的loadOnStartup修改成服务器启动的时候创建。
- Servlet生命周期中涉及到的三个方法,这三个方法是什么?什么时候被调用?调用几次?
涉及到3个方法,分别是
init()
、service()
、destroy()
init
方法在Servlet对象被创建的时候执行,只执行一次service
方法在Servlet被访问的时候调用,每访问1次就调用1次destroy
方法在Servlet对象被销毁时调用,只执行一次
# 方法介绍
Servlet中共有5个方法,前面已经介绍过其中的三个,接下来我们看下剩余两个有什么作用。
首先来回顾下前面讲的三个方法,分别是:
初始化方法,在Servlet被创建时执行,只执行一次
void init(ServletConfig config);
1提供服务方法,每次Servlet被访问,都会调用该方法
void service(ServletRequest req, ServletResponse res);
1销毁方法,当Servlet被销毁时,调用该方法,在内存释放或服务器关闭时销毁Servlet
void destory();
1
剩下的两个方法是:
获取Servlet信息
String getServletInfo(); // 该方法用来返回Servlet的相关信息,没有什么太大的用处,一般我们返回一个空字符串即可 public String getServletInfo() { return ""; }
1
2
3
4
5
6获取ServletConfig对象
ServletConfig getServletConfig();
1
ServletConfig
对象,在init
方法的参数中有,而Tomcat Web服务器在创建Servlet对象的时候会调用init
方法,必定会传入一个ServletConfig
对象,我们只需要将服务器传过来的ServletConfig
进行返回即可,代码如下:
package com.itheima.servlet;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
/**
* Servlet快速入门以及Servlet生命周期方法演示
* @author sunyy
* @version 0.0.1
* @since 2022.10.26
*
*/
@WebServlet(urlPatterns = "/hello", loadOnStartup = 1)
public class ServletDemo1 implements Servlet {
private ServletConfig servletConfig;
/**
* 初始化方法
* 1. 调用时机:默认情况下,Servlet第一次被访问时,调用
* loadOnStartup: 默认为-1,修改为0或者正整数,则会在服务器启动的时候,调用
* 2. 调用次数:1次
* @param servletConfig
* @throws ServletException
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig = servletConfig;
System.out.println("init ...");
}
@Override
public ServletConfig getServletConfig() {
return this.servletConfig;
}
/**
* 提供服务
* 1. 调用时机:每一次Servlet被访问时,调用;
* 2. 调用次数:多次,与被请求次数有关
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
System.out.println("Servlet Hello World~");
}
@Override
public String getServletInfo() {
return "";
}
/**
* 销毁方法
* 1. 调用时机:内存释放或者服务器关闭的时候,Servlet对象会被销毁;
* 2. 调用次数:1次
*/
@Override
public void destroy() {
System.out.println("destroy ...");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
getServletInfo()
和getServletConfig()
这两个方法使用的不是很多,大家了解一下即可。
# 体系结构
通过上面的学习,我们已经知道开发Servlet必须要实现Servlet接口,重写接口中的5个方法,这样虽然已经能完成要求,但是编写起来还是比较麻烦,因为我们开发Servlet重点关注的只有service
方法,那有没有更简单的方式来创建Servlet的呢?
解决上面的问题,我们先来了解下Servlet的体系结构,也就是继承关系:
我们后面主要开发B/S架构的Web项目,都是通过HTTP协议来通信交互的,所以我们自定义的Servlet,一般会通过继承HttpServlet
来实现
package com.itheima.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* HttpServlet演示案例
* @author sunyy
* @version 0.0.1
* @since 2022.10.26
*/
@WebServlet("/http")
public class HttpServletDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO GET 请求方式处理器
System.out.println("get ...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO POST 请求方式处理器
System.out.println("post ...");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- 怎么发送GET方式的请求来访问该Servlet?只需要通过浏览器发送
http://localhost:8080/servlet/http
,就能在控制台看到doGet
方法被执行了。 - 发送POST请求比GET请求要复杂,通过在浏览器地址栏输入访问地址是无法实现的,这个时候需要我们简单开发一个HTML页面,页面中设置一个
form
表单,通过表单提交数据给我们的Servlet方法。在webapp
目录下创建一个HttpServletTest.html
页面,内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HttpServletTest</title>
</head>
<body>
<form action="/servlet/http" method="post">
<input name="username" type="text" />
<input name="password" type="password" />
<input type="submit" value="提交" />
</form>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
在浏览器中通过访问http://localhost/servlet/HttpServletTest.html
页面,填写表单提交数据即可发送POST请求,我们在控制台也能看到响应的输出内容。
Servlet的简化别写就介绍完了,这里有两个问题需要我们思考一下:
- HttpServlet中为什么要根据请求方式的不同,调用不同的方法?
- HttpServlet中根据请求方式的不同调用不同的方法是如何实现的?
问题一:针对问题一,我们需要回顾一下之前的知识点,前端发送GET和POST请求的时候,参数的位置是不一致的,GET请求参数在请求行中,POST请求参数在请求体中,因此HttpServlet就需要根据请求方式来判断,如何获取请求携带的参数。
问题二:前面我们已经了解过Servlet的体系结构,类继承关系,普通的Servlet是通过service()
方法提供服务的,那么我们自己如果想实现类似HttpServlet
类似的效果该如何实现呢?我们来分析一下:
- 实现Servlet接口,开发一个自定义的Servlet;
- 重写
service()
方法,在该方法中通过判断请求方式,来执行不同的方法;
代码可以这样实现:
package com.itheima.servlet;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 个人自定义Servlet实现,模拟HttpServlet功能
* @author sunyy
* @version 0.0.1
* @since 2022.10.26
*/
@WebServlet("/my-servlet")
public class MyHttpServlet implements Servlet {
private ServletConfig servletConfig;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig = servletConfig;
System.out.println("My Servlet Init ...");
}
@Override
public ServletConfig getServletConfig() {
return this.servletConfig;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
// 获取请求方式,根据不同的请求方式进行不同的业务处理
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 1. 获取请求方式
String method = request.getMethod();
// 2. 判断
if ("GET".equals(method)) {
doGet(request, response);
} else if ("POST".equals(method)) {
doPost(request, response);
}
}
private void doGet(HttpServletRequest req, HttpServletResponse res) {
// TODO 处理GET请求,返回响应数据
}
private void doPost(HttpServletRequest req, HttpServletResponse res) {
// TODO 处理POST请求,返回响应数据
}
@Override
public String getServletInfo() {
return "";
}
@Override
public void destroy() {
System.out.println("My Servlet Destory ...");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
大家看下上面的代码有没有什么问题,假设我后面要开发很多各Servlet,上面的service
方法内容大体上是一样的,那我们能不能把上面的代码做成一个模板呢,再写其他Servlet的时候继承这个模板就行了,可以省去很多冗余代码:
package com.itheima.servlet;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 个人自定义Servlet实现
* 模拟HttpServlet功能
* 演变为自定义Servlet模板
* @author sunyy
* @version 0.0.1
* @since 2022.10.26
*/
public abstract class MyHttpServlet implements Servlet {
private ServletConfig servletConfig;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig = servletConfig;
System.out.println("My Servlet Init ...");
}
@Override
public ServletConfig getServletConfig() {
return this.servletConfig;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
// 获取请求方式,根据不同的请求方式进行不同的业务处理
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 1. 获取请求方式
String method = request.getMethod();
// 2. 判断
if ("GET".equals(method)) {
doGet(request, response);
} else if ("POST".equals(method)) {
doPost(request, response);
}
}
protected abstract void doGet(HttpServletRequest req, HttpServletResponse res);
protected abstract void doPost(HttpServletRequest req, HttpServletResponse res);
@Override
public String getServletInfo() {
return "";
}
@Override
public void destroy() {
System.out.println("My Servlet Destory ...");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
有了MyHttpServlet
这个模板,以后我们编写Servlet类的时候,只需要继承它,重写父类中的doGet
和doPost
方法,就可以用来处理GET和POST请求的业务逻辑了,接下来我们就继承MyHttpServlet
来开发一个Servlet看下效果:
package com.itheima.servlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 自定义HttpServlet模板演示
*
* @author sunyy
* @version 0.0.1
* @since 2022.10.26
*/
@WebServlet("/my-demo")
public class MyHttpServletDemo extends MyHttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.printf("MyHttpServletDemo 处理 GET 请求:username = %s, password = %s", username, password);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res) {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.printf("MyHttpServletDemo 处理 POST 请求:username = %s, password = %s", username, password);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
上述代码编写完成后,我们依旧使用HttpServletTest.html
页面进行测试,不过需要修改一下页面内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HttpServletTest</title>
</head>
<body>
<form action="/servlet/my-demo" method="get">
<input name="username" type="text" />
<input name="password" type="password" />
<input type="submit" value="提交" />
</form>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
修改action
和method
后,启动tomcat服务,访问页面提交数据就可以看到效果:
如上,将来页面发送的是GET请求,就会进入到doGet
方法中进行执行,如果是POST请求,则进入到doPost
方法。这样代码在编写的时候就相对来说更加简单快捷。
类似MyHttpServlet
这样的类Servlet中已经为我们提供好了,就是HttpServlet
,我们可以看下它的源码service()
,在HttpServlet
的service()
方法中,大家可以看到,HttpServlet能做的事有很多,不仅可以处理GET和POST还可以处理其他五种方式的请求。
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if (ifModifiedSince < lastModified) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
小结
通过这一节的学习,我们需要掌握:
- HttpServlet的使用步骤
- 继承HttpServlet
- 重写doGet和doPost方法
- HttpServlet原理
获取请求方式,并根据不同的请求方式,调用不同的doXxx方法
# urlPattern 配置
Servlet编写好后,如果希望被访问到,就需要配置其访问路径(urlPattern),下面咱们就来详细学习一下urlPattern该如何配置
- 一个Servlet,可以配置多个urlPattern
package com.itheima.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* HttpServlet演示案例
* @author sunyy
* @version 0.0.1
* @since 2022.10.26
*/
@WebServlet(urlPatterns = {"/http1", "/http2"})
public class HttpServletDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO GET 请求方式处理器
System.out.println("get ...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO POST 请求方式处理器
System.out.println("post ...");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
在浏览器上输入http://localhost/servlet/http2
和http://localhost/servlet/http2
这两个地址都能访问到HttpServletDemo
的doGet
方法。
urlPattern配置规则
- 精确匹配
- 配置路径:
@WebServlet("/demo/my-demo")
- 访问路径:
localhost/servlet/demo/my-demo
- 配置路径:
访问路径
http://localhost:80/servlet/demo/my-demo
- 精确匹配
目录匹配:
- 配置路径:
@WebServlet("/demo/*")
- 访问路径:
localhost:80/servlet/demo/aaa
和localhost:80/servlet/demo/bbb
package com.itheima.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * urlPattern演示 * * @author sunyy * @version 0.0.1 * @since 2022.10.27 */ @WebServlet("/demo/*") public class UrlPatternDemo extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("urlPattern 目录匹配:Get请求 ..."); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24访问路径为
http://localhost:80/servlet/demo/任意字符串
- 配置路径:
思考
- 访问路径
http://localhost:80/servlet/demo
能否访问到UrlPatternDemo
的doGet
方法? - 访问路径
http://localhost:80/servlet/demo/a/b
能否访问到UrlPatternDemo
的doGet
方法? - 访问路径
http://localhost:80/servlet/demo/my-demo
访问的是MyHttpServletDemo
还是UrlPatternDemo
?
答案是:能、能、MyHttpServletDemo
,进而我们可以得出结论/demo/*
中的/*
代表的是零或者多个层级访问目录,同时精确匹配优先级要高于目录匹配。
- 扩展名匹配
- 配置路径:
@WebServlet("*.do")
- 访问路径:
localhost:80/servlet/aaa.do
和localhost:80/servlet/bbb.do
- 配置路径:
package com.itheima.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* urlPattern扩展名匹配
* @author sunyy
* @version 0.0.1
* @since 2022.10.27
*/
@WebServlet("*.do")
public class ServletDemo10 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("扩展名匹配,Get请求...");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
访问路径http://localhost:80/servlet/任意.do
注意
- 如果路径配置的不是扩展名,那么在路径的前面就必须要加
/
,否则会报错
- 如果路径配置的是
*.do
,那么在*.do
的前面不能加/
,否则会报错
- 任意匹配
- 配置路径:
@WebServlet("/")
和@WebServlet("/*")
- 访问路径:
localhost:80/servlet/hehe
和localhost:80/servlet/haha
- 配置路径:
package com.itheima.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* urlPattern任意匹配
* @author sunyy
* @version 0.0.1
* @since 2022.10.27
*/
@WebServlet("/")
public class ServletDemo11 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("任意/匹配: Get请求");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
访问路径http://localhost:80/servlet/任意
package com.itheima.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 任意匹配: /*
* @author sunyy
* @version 0.0.1
* @since 2022.10.27
*/
@WebServlet("/*")
public class ServletDemo12 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("任意/*匹配:Get请求");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
访问路径http://localhost:80/servlet/任意
`/`和`/*`的区别?
- 当我们的项目中的
Servlet
配置了/
,会覆盖掉tomcat中的DefaultServlet
,当其他的url-pattern
都匹配不上时会走这个Servlet - 当我们的项目中配置了
/*
,意味着匹配任意访问路径 DefaultServlet
是用来处理静态资源,如果配置了/
会把默认的覆盖掉,就会引发请求静态资源的时候不走默认的而是走自定义的Servlet类,最终导致静态资源不能访问。
小结
- urlPattern总共有四种配置方式,分别是精确匹配、目录匹配、扩展名匹配、任意匹配
- 五种配置的优先级为 精确匹配 > 目录匹配 > 扩展名匹配 > /* > /,不许死计,以最终的运行结果为准即可。
# XML 配置
前面对应Servlet的配置,我们都是用的是@WebServlet
,这个是Servlet从3.0版本后开始支持注解配置,3.0版本前只支持XML配置文件的配置方法。
XML配置Servlet有两步:
- 编写Servlet类
package com.itheima.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* XML 配置
* @author sunyy
* @version 0.0.1
* @since 2022.10.27
*/
public class ServletDemo13 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Demo13 Get 请求 ...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- 在
web.xml
中配置该Servlet
<?xml version="1.0" encoding="UTF-8"?>
<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>
<!-- servlet的名称,名字任意 -->
<servlet-name>demo13</servlet-name>
<!-- servlet的全类名 -->
<servlet-class>com.itheima.servlet.ServletDemo13</servlet-class>
</servlet>
<!--
Servlet 访问路径
-->
<servlet-mapping>
<!-- servlet的名称,需和上面的名称一致 -->
<servlet-name>demo13</servlet-name>
<!-- servlet的访问路径 -->
<url-pattern>/demo13</url-pattern>
</servlet-mapping>
</web-app>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
这种配置方式和注解比起来,会麻烦很多,建议大家使用注解开发。但大家要了解上面这种配置方式,因为并不是所有项目都是基于注解开发的。