Servlet(一)

🍵 Servlet简称Server Applet(即服务器端小程序),是一种基于Java技术的Web组件,运行在服务器端。

1 Servlet简介

  • Servlet简介
    • Servlet简称 Server Applet (服务器端小程序),是一种基于Java技术的Web组件。
    • 运行在服务器端,由Servlet容器管理,用来生成动态的Web内容,具平台独立性。
    • 使用Servlet,可获取用户通过网页表单提交的数据、访问数据库,创建动态网页。
    • 严格来说,Servlet只是一套Java Web开发的技术标准,实现其规范需要编写代码。
    • 目前常见的实现了Servlet规范的产品包括Tomcat、Jetty、Jboss、WebSphere等。
    • 接口
      • 所有的Servlet功能都是通过一个名为Servlet的接口(Interface)向外暴露的。
      • Servlet规范提供了2个抽象类,分别是GenericServlet类以及HttpServlet类。
      • 和GenericServlet类比,HttpServlet类更加方便,实际开发一般继承自后者。
    • JSP
      • Servlet是第一代Java Web开发技术,那么JSP就是第二代Java Web开发技术。
      • JSP允许HTML代码和JSP代码分离,让开发能在HTML文档中直接嵌入JSP代码。
      • Servlet是JSP的基础,Servlet虽然不直接面向用户,但是依然是JSP的后台支撑。
    • Applet
      • Java Servlet是服务端小程序,运行在服务器上,用来开发动态网站。
      • Java Applet是客户端小程序,一般被嵌入到HTML页面,运行在支持Java的浏览器中。
      • Applet开发步骤繁杂,只能安装在Java虚拟机(JVM)上运行,已被JavaScript全面取代。

1-1 Servlet容器

  • Servlet容器
    • Web服务器
      • 只有Web服务器,例如Apache、Nginx、IIS等,功能单一,只能部署静态网站。
      • 想部署动态网站,必须有编程语言运行环境(Runtime)和数据库管理系统的支持。
      • 解释器是执行脚本语言的核心部件,除此还需垃圾回收器、标准库等辅助性部件。
    • Web容器
      • JRE只包含了JVM、核心类库和一些辅助性文件,不支持Servlet规范。
      • 运行Servlet代码还需Servlet容器,实现了Servlet接口的一些基础类。
      • Servlet类没有main()函数,不能独立运行,只作为一模块被载入Servlet容器。
      • 然后由Servlet容器实例化,并调用其中的方法,一动态页面对应一Servlet类。
      • 当用户请求到达时,Servlet容器就会根据配置文件(web.xml)来决定调用的类。

1-2 Tomcat安装

  • Tomcat安装
    • 官网:http://tomcat.apache.org/,不同的Java版本需要选择对应的Tomcat版本。
    • JDK8对应Tomcat版本9或10,这里选Core 64-bit Windows zip (pgp, sha512)
    • 目录
      • conf:用于存放Tomcat配置文件。
        • context.xml:配置数据源等。
        • web.xml:设置Tomcat支持的文件类型。
        • Catalina文件下可设置默认加载的项目。
        • server.xml:配置域名、IP、端口、默认加载的项目等。
        • tomcat-users.xml:配置和管理Tomcat的用户以及权限。
      • lib:用于存放Tomcat需进行加载的jar包。
      • temp:存放Tomcat运行时产生的临时文件。
      • work:存放应用程序,启动时会来加载该目录下的应用程序。
      • logs:存放Tomcat运行时产生的日志文件,Win以log结尾,Linux以out结尾。
      • webapps:存放Tomcat运行时的编译文件,清空work目录重启可以清除缓存。
      • bin:存放Tomcat命令,.sh结尾的Linux命令,.bat结尾的Windows命令。
        • startup.sh/startup.bat:双击启动Tomcat。
        • shutdown.sh/shutdown.bat:双击关闭Tomcat。
        • catalina.sh/catalina.bat:用来设置Tomcat内存。

2 部署与访问

  • 部署与访问
    • 以Tomcat为例,通常会将JavaWeb应用存放到Tomcat的webapps目录下。
    • webapps下的每一个子目录都是一个独立的Web应用,子目录名即应用名。
    • Web应用名也叫Web应用的上下文根,通过其访问JavaWeb应用中的资源。
    • webapps目录结构
      • \examples:Web应用的根目录,该应用的所有资源存放位置(✔)。
      • \examples\WEB-INF:存放web.xml、lib目录、classes目录等(✔)。
      • \examples\WEB-INF\lib:存放应用所需的各种jar包。
      • \examples\WEB-INF\web.xml:web.xml中包含该应用程序的配置和部署信息(✔)。
      • \examples\WEB-INF\classes:存放class或包含class文件的目录,包括Servlet类的。

2-1 创建方式

  • 创建方式
    • Servlet规范的最顶层是一个名为javax.servlet.Servlet的接口。
    • Servlet又内置了GenericServlet和HttpServlet这两个抽象类。
    • 三种方式创建Servlet类
      • 实现javax.servlet.Servlet接口,重写其全部方法。
      • 继承javax.servlet.GenericServlet抽象类,重写service()方法。
      • 继承javax.servlet.http.HttpServlet抽象类,重写doGet()或doPost()方法。
    • 三者关系
      • GenericServlet是实现了Servlet接口的抽象类。
      • HttpServlet是GenericServlet的子类,具有其一切特性。
      • Servlet程序(MyServlet类)是实现Servlet接口的Java类。

(1) Servlet

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
39
40
41
42
43
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletException;

public class MyServlet01 implements Servlet {
// Servlet实例被创建后,调用init()方法进行初始化,该方法只能被调用一次
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}

// 返回ServletConfig对象,该对象包含了Servlet的初始化参数
@Override
public ServletConfig getServletConfig() {
return null;
}

// 每次请求,都会调用一次service()方法,用于处理客户端请求
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
// 设置字符集
servletResponse.setContentType("text/html;charset=UTF-8");
// 使用PrintWriter.write()方法向前台页面输出内容
PrintWriter writer = servletResponse.getWriter();
writer.write("欢迎访问首页【MyServlet01】!");
writer.close();
}

// 返回关于Servlet的信息,例如作者、版本、版权等
@Override
public String getServletInfo() {
return null;
}

// 服务器关闭、重启或Servlet对象被移除时,由Servlet容器调用,负责释放对象占用的资源
@Override
public void destroy() {
}
}

(2) HttpServlet

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
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// HttpServlet继承了GenericServlet抽象类,用于开发基于HTTP协议的Servlet程序
// HttpServlet针对HTTP/1.1协议中定义的7种请求方式分别定义了7种方法
// 即doGet()、doPost()、doHead()、doPut()、doDelete()、doTrace()、doOptions()
public class MyServlet02 extends HttpServlet {
// serialVersionUID是Java序列化机制中的一个版本控制标识符,用于验证类的版本兼容性
private static final long serialVersionUID = 1L;

public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 使用PrintWriter.write()方法向前台页面输出内容
resp.setContentType("text/html;charset=UTF-8");
PrintWriter writer = resp.getWriter();
writer.write("欢迎访问首页【MyServlet02】!");
writer.close();
}

public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 使用PrintWriter.write()方法gaifang向前台页面输出内容
PrintWriter writer = resp.getWriter();
writer.write("欢迎访问首页【MyServlet02】!");
writer.close();
doGet(req, resp);
}
}

(3) GenericServlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.GenericServlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletException;

// GenericServlet实现了Servlet接口并提供除service()外的其他四个方法的实现
// 通过继承GenericServlet类创建Servlet,只需重写service(),减少了创建Servlet的工作量
public class MyServlet03 extends GenericServlet {
// serialVersionUID是Java序列化机制中的一个版本控制标识符,用于验证类的版本兼容性
private static final long serialVersionUID = 1L;

@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
// 设置字符集
servletResponse.setContentType("text/html;charset=UTF-8");
// 使用PrintWriter.write()方法向前台页面输出内容
PrintWriter writer = servletResponse.getWriter();
writer.write("欢迎访问首页【MyServlet03】!");
writer.close();
}
}

2-2 部署访问

  • 部署访问
    • Tomcat中最快部署应用方式,即直接将应用的所有文件复制到/webapps目录下。
    • 默认情况会自动加载webapps目录下的JavaWeb应用,并将其发布到虚拟主机中。
    • Tomcat可运行开放式的目录结构(只编译不打包),也可运行打包文件(War文件)。
    • 开放式的目录结构:Win+R输入cmd,进入DOS命令窗口,引入javax.servlet包。
    • 临时环境变量:set classpath=E:\Software\Tomcat.9.0.111\lib\servlet-api.jar。
    • 编译Servlet,MyServletX.java目录:javac -encoding UTF-8 MyServletX.java。
    • 创建目录结构
      • \servletDemo
      • \servletDemo\WEB-INF
      • \servletDemo\WEB-INF\web.xml
      • \servletDemo\WEB-INF\classes\MyServletX.class
    • 双击startup.bat启动Tomcat,访问:http://localhost:8080/servletDemo/MyServletX
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?xml version="1.0" encoding="UTF-8"?>
<!-- 根元素 -->
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
id="WebApp_ID" version="4.0">
<display-name>servletDemo</display-name>

<!-- MyServlet01,用于注册Servlet,给Servlet起名 -->
<servlet>
<!-- 指定Servlet的名称和完整限定名(包名+类名) -->
<servlet-name>MyServlet01</servlet-name>
<!-- 无包名时,直接写类名 -->
<servlet-class>MyServlet01</servlet-class>
</servlet>
<!-- 定义Servlet与URL之间的映射 -->
<servlet-mapping>
<!-- 指定Servlet的名称和虚拟路径 -->
<servlet-name>MyServlet01</servlet-name>
<url-pattern>/MyServlet01</url-pattern>
</servlet-mapping>

<!-- MyServlet02 -->
<servlet>
<servlet-name>MyServlet02</servlet-name>
<servlet-class>MyServlet02</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet02</servlet-name>
<url-pattern>/MyServlet02</url-pattern>
</servlet-mapping>

<!-- MyServlet03 -->
<servlet>
<servlet-name>MyServlet03</servlet-name>
<servlet-class>MyServlet03</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet03</servlet-name>
<url-pattern>/MyServlet03</url-pattern>
</servlet-mapping>

<!-- MyServlet04,Eclipse快速创建,很奇怪,使用Eclipse访问时只有该地址链接正确 -->
<servlet>
<servlet-name>MyServlet04</servlet-name>
<servlet-class>MyServlet04</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet04</servlet-name>
<url-pattern>/MyServlet04</url-pattern>
</servlet-mapping>
</web-app>

2-3 快速创建

  • 快速创建
    • File -> New -> Dynamic Web Project -> Project name设为servletDemo。
    • 点击New Runtime新建一个运行时环境 -> 选择本地已安装好的Tomcat版本。
    • 勾选Creat a new local servlet,创建新的本地服务器 -> 点击Next(下一步)。
    • 选择Tomcat服务器名称和安装目录并指定JDK版本 -> Finish返回工程对话框。
    • 勾选Generate web.xml deployment descriptor,生成web.xml文件 -> Finish。
    • 创建Servlet
      • 右键点击项目名 -> New -> Servlet -> 填写包名、类名 -> Next。
      • 保持默认选项 -> Next -> 根据需要勾选继承的方法 -> 点击Finish。
      • 修改代码,配置web.xml -> 部署项目并启动服务器Run As -> Run on server。
      • 弹出的对话框中选一个Tomcat服务器 -> Next ->选要运行的项目 -> Finish。
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
39
40
41
42
43
44
45
46
47
48
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* Servlet implementation class MyServlet
*/
@WebServlet("/MyServlet04")
public class MyServlet04 extends HttpServlet {
private static final long serialVersionUID = 1L;

/**
* @see HttpServlet#HttpServlet()
*/
public MyServlet04() {
super();
// TODO Auto-generated constructor stub
}

/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
// response.getWriter().append("Served at: ").append(request.getContextPath());
// 设置响应给页面的格式、字符集
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
writer.write("欢迎访问首页【MyServlet04】!");
writer.close();
}

/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}

3 Servlet注解

  • Servlet注解
    • Servlet中,web.xml文件十分重要,可以将所有的Servlet配置集中进行管理。
    • 但若项目中Servlet数量较多,配置将变得冗长,此时可用注解(Annotation)。
    • Servlet3.0增加了注解,如:@WebServlet、@WebFilter、@WebLitener等。
    • @WebServlet用于将一个类声明为Servlet,该注解会在部署时被容器所处理。

3-1 启用注解支持

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
id="WebApp_ID" metadata-complete="false" version="4.0">
<!-- metadata-complete取值true,表示关闭注解支持 -->
<!-- metadata-complete取值false,表示启用注解支持,默认属性,不必创建web.xml文件 -->
</web-app>

3-2 @WebServlet

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
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// asyncSupported:是否支持异步处理
// name:Servlet的名称
// description:Servlet的描述信息
// loadOnStartup:数值越小优先级越高,指定Servlet启动顺序的优先级
// urlPatterns:必选,用于定义请求路径映射,可以写多个路径,逗号隔开
// initParams:定义初始化参数,类似于web.xml中的<init-param>
@WebServlet(asyncSupported = true, name = "MyServlet05", description = "描述信息",
loadOnStartup = 1, urlPatterns = {
"/MyServlet05" }, initParams = {
@WebInitParam(name = "Java", value = "Java", description = "init参数1"),
@WebInitParam(name = "Servlet", value = "Servlet", description = "init参数2")
})
public class MyServlet05 extends HttpServlet {
private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
writer.write("欢迎访问首页【MyServlet05】!");
writer.close();
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}

3-3 与web.xml比较

  • 与web.xml比较
    • @WebServlet注解配置Servlet,直接类中使用,代码量少,配置简单,适合多人开发,难管理。
    • web.xml文件配置Servlet,集中管理配置便于查找和修改,但代码繁琐,可读性不强,不易理解。

4 虚拟路径映射

  • 虚拟路径映射
    • 客户端通过URL地址访问Web服务器中的资源,Servlet程序必须被映射到URL地址上才能被访问。
    • 很多时候该URL地址和Servlet程序的物理路径(硬盘上的存储位置)并不一致,因此称为虚拟路径。
    • Servlet与虚拟路径的对应关系,叫做Servlet虚拟路径映射,可以分为单一映射和多重映射这两类。

4-1 单一映射

  • 单一映射
    • Servelt单一映射指的是一个Servlet只被映射到一个虚拟路径上。
    • 两种实现方式:使用web.xml或使用@WebServlet实现单一映射。
    • web.xml文件中,使用元素实现Servlet单一映射。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
id="WebApp_ID" metadata-complete="false" version="4.0">
<display-name>servletDemo</display-name>
<servlet>
<servlet-name>MyServlet06</servlet-name>
<servlet-class>MyServlet06</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet06</servlet-name>
<url-pattern>/MyServlet06</url-pattern>
</servlet-mapping>
</web-app>

(1) value属性

  • 在@WebServlet注解中,一般使用value属性实现Servlet单一映射。
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
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/MyServlet06")
public class MyServlet06 extends HttpServlet {
private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
writer.write("欢迎访问首页【MyServlet06】!");
writer.close();
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}

(2) urlPatterns属性

  • 在@WebServlet注解中,也可以使用urlPatterns属性实现Servlet单一映射。
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
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = "/MyServlet07")
public class MyServlet07 extends HttpServlet {
private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
writer.write("欢迎访问首页【MyServlet07】!");
writer.close();
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}

4-2 多重映射

  • 多重映射
    • Servlet的多重映射是指一个Servlet可被映射到多个虚拟路径上。
    • 此时,客户端可以通过多个路径来实现对同一个Servlet的访问。
    • 三种实现方式
      • Servlet2.5前:配置多个元素。
      • Servlet2.5后:配置多个子元素。
      • Servlet3.0后:在@WebServlet的urlPatterns属性中使用字符串数组。

(1) Servlet2.5前

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
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
id="WebApp_ID" metadata-complete="false" version="4.0">
<display-name>servletDemo</display-name>

<servlet>
<servlet-name>MyServlet01</servlet-name>
<servlet-class>MyServlet01</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

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

<servlet-mapping>
<servlet-name>MyServlet01</servlet-name>
<url-pattern>/MyServlet02</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>MyServlet01</servlet-name>
<url-pattern>/MyServlet03</url-pattern>
</servlet-mapping>
</web-app>

(2) Servlet2.5后

  • Servlet2.5规范开始,元素可以包含多个子元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
id="WebApp_ID" metadata-complete="false" version="4.0">
<display-name>servletDemo</display-name>

<servlet>
<servlet-name>MyServlet01</servlet-name>
<servlet-class>MyServlet01</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>MyServlet01</servlet-name>
<url-pattern>/MyServlet01</url-pattern>
<url-pattern>/MyServlet02</url-pattern>
<url-pattern>/MyServlet03</url-pattern>
</servlet-mapping>
</web-app>

(3) Servlet3.0后

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
39
40
41
42
43
44
45
46
47
48
49
50
51
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = { "/MyServlet08", "/MyServlet09" })
public class MyServlet08 extends HttpServlet {
private static final long serialVersionUID = 1L;
private int initCount = 0;
private int httpCount = 0;
private int destoryCount = 0;

@Override
public void destroy() {
destoryCount++;
super.destroy();
// 向控制台输出destory方法被调用次数
System.out.println("*****destroy方法:" + destoryCount + "*****");
}

@Override
public void init() throws ServletException {
initCount++;
super.init();
// 向控制台输出init方法被调用次数
System.out.println("init方法:" + initCount);
}

public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
httpCount++;
// 控制台输出doGet方法次数
System.out.println("doGet方法:" + httpCount);
// 设置返回页面格式与字符集
resp.setContentType("text/html;charset=UTF-8");
PrintWriter writer = resp.getWriter();
// 向页面输出
writer.write(
"初始次数:" + initCount + "<br/>" + "请求次数:" +
httpCount + "<br/>" + "销毁次数:" + destoryCount
);
writer.close();
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
}

5 路径匹配规则

  • 路径匹配规则
    • web.xml优先注解次之,xml没覆盖到的路径才轮到注解处理。
    • 完全路径:以/开始,不能包含通配符*,必须完全匹配。
    • 目录匹配:以/开头并以/*结尾的字符串,用于路径匹配。
    • 扩展名匹配:以通配符*.开头的字符串,用于扩展名匹配。
    • 缺省匹配(默认匹配):映射路径为/
      • 该Servlet为当前应用的默认Servlet。
      • 默认处理无法匹配到虚拟路径的请求。
    • 注意:目录匹配和扩展名匹配无法混合使用。

5-1 匹配优先级

  • 匹配优先级
    • Servlet容器会从优先级高的虚拟路径开始匹配。
    • 成功后立刻将请求交给相应的Servlet进行处理,不再关注其他匹配。
    • 全路径匹配(精确匹配)>目录匹配>扩展名匹配>缺省匹配(默认匹配)。

(1) 创建类

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
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// 创建名为MyServlet10的Servlet类
public class MyServlet10 extends HttpServlet {
private static final long serialVersionUID = 1L;

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter writer = resp.getWriter();
// 向页面输出
writer.write("本次访问的Servlet是:" + this.getServletName());
writer.close();
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}

(2) web.xml

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
id="WebApp_ID" metadata-complete="false" version="4.0">
<display-name>servletDemo</display-name>

<!-- 同一个类MyServlet10,不同的servlet -->
<servlet>
<servlet-name>MyServlet11</servlet-name>
<servlet-class>MyServlet10</servlet-class>
</servlet>
<servlet>
<servlet-name>MyServlet12</servlet-name>
<servlet-class>MyServlet10</servlet-class>
</servlet>
<servlet>
<servlet-name>MyServlet13</servlet-name>
<servlet-class>MyServlet10</servlet-class>
</servlet>
<servlet>
<servlet-name>MyServlet14</servlet-name>
<servlet-class>MyServlet10</servlet-class>
</servlet>
<servlet>
<servlet-name>MyServlet15</servlet-name>
<servlet-class>MyServlet10</servlet-class>
</servlet>

<!-- 完全路径匹配(精确匹配) -->
<servlet-mapping>
<servlet-name>MyServlet11</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<!-- 目录匹配 -->
<servlet-mapping>
<servlet-name>MyServlet12</servlet-name>
<url-pattern>/abc/my/*</url-pattern>
</servlet-mapping>
<!-- 目录匹配 -->
<servlet-mapping>
<servlet-name>MyServlet13</servlet-name>
<url-pattern>/abc/*</url-pattern>
</servlet-mapping>
<!-- 扩展名匹配 -->
<servlet-mapping>
<servlet-name>MyServlet14</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- 缺省匹配 -->
<servlet-mapping>
<servlet-name>MyServlet15</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

5-2 缺省Servlet

  • 缺省Servlet
    • Tomcat目录的/conf/web.xml文件注册了一个DefaultServlet类的Servlet,并设为缺省Servlet。
    • 当客户端访问Tomcat服务器中某个静态HTML文件或图片时,DefaultServlet将判断其是否存在。
    • 如果存在,则Tomcat服务器将数据以流的形式返回给客户端,如果不存在,则报告一个404错误。

(1) web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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>

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

(2) 缺省匹配

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
id="WebApp_ID" metadata-complete="false" version="4.0">
<display-name>servletDemo</display-name>

<!-- 同一个类MyServlet10,不同的servlet -->
<servlet>
<servlet-name>MyServlet11</servlet-name>
<servlet-class>MyServlet10</servlet-class>
</servlet>
<servlet>
<servlet-name>MyServlet12</servlet-name>
<servlet-class>MyServlet10</servlet-class>
</servlet>
<servlet>
<servlet-name>MyServlet13</servlet-name>
<servlet-class>MyServlet10</servlet-class>
</servlet>
<servlet>
<servlet-name>MyServlet14</servlet-name>
<servlet-class>MyServlet10</servlet-class>
</servlet>
<servlet>
<servlet-name>MyServlet15</servlet-name>
<servlet-class>MyServlet10</servlet-class>
</servlet>

<!-- 完全路径匹配(精确匹配) -->
<servlet-mapping>
<servlet-name>MyServlet11</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<!-- 目录匹配 -->
<servlet-mapping>
<servlet-name>MyServlet12</servlet-name>
<url-pattern>/abc/my/*</url-pattern>
</servlet-mapping>
<!-- 目录匹配 -->
<servlet-mapping>
<servlet-name>MyServlet13</servlet-name>
<url-pattern>/abc/*</url-pattern>
</servlet-mapping>
<!-- 扩展名匹配 -->
<servlet-mapping>
<servlet-name>MyServlet14</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- 缺省匹配 -->
<!--
<servlet-mapping>
<servlet-name>MyServlet15</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
-->
</web-app>

6 load-on-startup

  • load-on-startup
    • load-on-startup是web.xml配置文件中的一个节点,是servlet元素的子元素。
    • 标记Servlet容器启动时是否初始化当前Servlet,及当前Servlet的初始化顺序。
    • 元素取值规则
      • 必须是一个整数,当值小于0或未指定时,容器在该Servlet被首次请求时才会被加载。
      • 当值大于或等于0时,容器在启动时就加载并初始化该Servlet,取值越小优先级越高。
      • 当取值相同时,容器会自行选择顺序并进行加载。
    • @WebServlet的loadOnStartup属性与web.xml文件中的load-on-startup元素取值规则相同。

6-1 创建类

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
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet16 extends HttpServlet {
private static final long serialVersionUID = 1L;

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter writer = resp.getWriter();
// 向页面输出
writer.write("本次访问的Servlet是:" + this.getServletName());
writer.close();
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}

@Override
public void destroy() {
System.out.println(this.getServletName() + ":销毁");
}

@Override
public void init() throws ServletException {
System.out.println(this.getServletName() + ":初始化完成");
}
}

6-2 web.xml

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
id="WebApp_ID" metadata-complete="false" version="4.0">
<display-name>servletDemo</display-name>

<!-- 同一个类MyServlet16,不同的servlet -->
<servlet>
<servlet-name>MyServlet16</servlet-name>
<servlet-class>MyServlet16</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet>
<servlet-name>MyServlet17</servlet-name>
<servlet-class>MyServlet16</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>MyServlet18</servlet-name>
<servlet-class>MyServlet16</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet>
<servlet-name>MyServlet19</servlet-name>
<servlet-class>MyServlet16</servlet-class>
<load-on-startup>-1</load-on-startup>
</servlet>
<servlet>
<servlet-name>MyServlet20</servlet-name>
<servlet-class>MyServlet16</servlet-class>
<!-- 不设置load-on-startup,去掉默认值 -->
</servlet>

<servlet-mapping>
<servlet-name>MyServlet16</servlet-name>
<url-pattern>/MyServlet16</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyServlet17</servlet-name>
<url-pattern>/MyServlet17</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyServlet18</servlet-name>
<url-pattern>/MyServlet18</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyServlet19</servlet-name>
<url-pattern>/MyServlet19</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyServlet20</servlet-name>
<url-pattern>/MyServlet20</url-pattern>
</servlet-mapping>
</web-app>

Servlet(一)
https://stitch-top.github.io/2025/09/17/java/java05-servlet-yi/
作者
Dr.626
发布于
2025年9月17日 21:00:21
许可协议