Servlet 学习笔记

Servlet 简介

Servlet 是 Java EE(Java Platform, Enterprise Edition)中的一种 Java 程序组件,用于处理 Web 应用程序中的 HTTP 请求和响应。Servlet 通常运行在 Web 服务器或 Servlet 容器中,并提供了一种有效的方式来创建动态的 Web 内容。

Servlets were Java’s answer to CGI (Common Gateway Interface), and programs that run on web server acting as middle layer between HTTP request and databases or other applications.

MVC 模型

MVC(Model-View-Controller)是一种软件架构模式,用于组织和分离应用程序的不同组成部分,以提高应用程序的可维护性、可扩展性和可重用性。MVC模型将应用程序分为三个主要组件,每个组件都有不同的责任。

MVC Model

Java classes/beans —— The business logic (Model)
JSP —— The presentation logic (View)
Servlet —— Handling the HTTP protocol and coordination (Controller)

  1. 模型(Model)
    • 模型代表应用程序的数据和业务逻辑。
    • 模型负责处理数据的获取、存储、验证和操作,以确保数据的完整性和一致性。
    • 模型通常不直接与用户界面交互,而是通过控制器来处理数据的请求和响应。
  2. 视图(View)
    • 视图负责呈现数据给用户,并负责用户界面的显示。
    • 视图通常不包含应用程序的业务逻辑,它只负责显示数据和接收用户输入。
    • 视图可以是图形用户界面(GUI)、Web 页面、命令行界面或其他任何用户界面形式。
  3. 控制器(Controller)
    • 控制器充当模型和视图之间的中介,它接收来自用户界面的用户输入。
    • 控制器负责解释用户输入,并相应地调用模型的方法来执行业务逻辑。
    • 控制器还可以更新视图以反映模型的状态变化。
Servlet 优点
  • 高效性(Efficient,lower overhead)

    Servlet 在 JVM 上运行,每一个请求都使用线程而不是开启一个新的进程

  • 便利(Convenient)

    提供解析和解码 HTML 表单的基础设施。

  • 功能强大(Powerful)

    • 可以直接和 Web Server 连接
    • 多个 Servlet 可以共享数据库链接
  • 跨平台(Portable)

    • 使用 Java 编写,可移植性强。
Tomcat

Apache Tomcat(通常称为Tomcat)是一个开源的 Servlet 容器,用于实现和管理 Java Servlet 和 JSP。它是 Apache 软件基金会的一个项目,作为一个轻量级的 Web 服务器,被广泛用于运行 Java Web 应用程序。

目录结构:

Servlet 生命周期

Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

  • Servlet 初始化后调用 init() 方法。

    注:init() 方法不等同于构造方法,构造方法只会创建一个对象,只有调用完 init() 方法后对象才是一个合格的 Servlet。

  • Servlet 调用 service() 方法来处理客户端的请求。

  • Servlet 销毁前调用 destroy() 方法。

第一个 Servlet 实例

通过 IDEA 构建一个 Jakarta EE 项目,创建一个简单的 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
package com.example.Servlet_demo;

@WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet extends HttpServlet {
private String message;

public void init() {
message = "Hello World!";
}

@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
super.service(req, res);
System.out.println("Hello World!");
}

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html");

// Hello
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>" + message + "</h1>");
out.println("</body></html>");
}

public void destroy() {
System.out.println("Servlet is destroyed");
}
}

配置 web.xml 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.example.servlet_demo.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/HelloServlet</url-pattern>
</servlet-mapping>
</web-app>

Servlet 中的部署描述符(Deployment Descriptor,DD)是一个 XML 文件,通常命名为 web.xml,用于配置和管理 Web 应用程序中的 Servlet 组件。Deployment Descriptor 提供了一种在 Servlet 容器中配置 Servlet 和其他 Web 应用程序组件的方式,这样 Web 服务器可以正确地加载和运行这些组件。

以下是一些常用的 web.xml 配置标签及其功能:

  1. <web-app>web.xml 文件的根元素,用于定义整个 Web 应用程序的配置。它包含各种子元素,如 <servlet><servlet-mapping><filter><filter-mapping> 等,用于配置 Servlet、Filter、Listener 等。
1
2
3
4
5
6
<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_3_1.xsd"
version="3.1">
<!-- 配置其他元素 -->
</web-app>
  1. <servlet> :用于配置 Servlet,指定 Servlet 类名、Servlet 名称等信息。
1
2
3
4
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.example.MyServlet</servlet-class>
</servlet>
  1. <servlet-mapping> :将 Servlet 映射到 URL 模式,指定哪些 URL 请求将由哪个 Servlet 处理。
1
2
3
4
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/Myservlet</url-pattern>
</servlet-mapping>
  1. <filter>:用于配置过滤器(Filter),允许对请求和响应进行处理。过滤器通常用于执行预处理、日志记录、身份验证等任务。
1
2
3
4
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.example.MyFilter</filter-class>
</filter>
  1. <filter-mapping>:将过滤器映射到 URL 模式,指定哪些请求将由哪个过滤器处理。
1
2
3
4
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/myfilter</url-pattern>
</filter-mapping>
  1. <listener>:配置监听器(Listener),用于监听 Web 应用程序的生命周期事件,如启动和销毁。
1
2
3
<listener>
<listener-class>com.example.MyListener</listener-class>
</listener>
  1. <init-param> :用于为特定的 Servlet 提供初始化参数。这些初始化参数可以在 Servlet 的初始化阶段读取,以配置和自定义 Servlet 的行为。通常情况下,<init-param> 标签是放在 <servlet> 标签内的,用于为特定的 Servlet 配置参数。以下是有关 <init-param> 的详细信息:

1
2
3
4
5
6
7
8
9
10
11
12
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.example.MyServlet</servlet-class>
<init-param>
<param-name>param1</param-name>
<param-value>value1</param-value>
</init-param>
<init-param>
<param-name>param2</param-name>
<param-value>value2</param-value>
</init-param>
</servlet>

上述示例中,我们在 <servlet> 标签内定义了两个 <init-param> 子元素,每个 <init-param> 都包含一个 <param-name> 和一个 <param-value>。这些元素的含义如下:

  • <param-name>:用于指定初始化参数的名称。这是一个字符串,用于标识参数。
  • <param-value>:用于指定初始化参数的值。这是实际的参数值,可以是字符串、数字或其他合适的数据类型。

在 Servlet 类中,您可以通过 getInitParameter(String paramName) 方法来获取这些初始化参数的值。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyServlet extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
super.init(config);

// 获取初始化参数
String param1 = getInitParameter("param1");
String param2 = getInitParameter("param2");

// 使用参数值进行初始化
// ...
}

// 其他 Servlet 方法
}

通过这种方式,您可以在部署描述符中为 Servlet 配置一些参数,以在 Servlet 初始化时使用这些参数进行定制。这对于在不同环境中部署同一个 Servlet 并根据需要进行不同的配置非常有用。

index.jsp 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>JSP - Hello World</title>
</head>
<body>
<h1><%= "Hello World!" %>
</h1>
<br/>
<a href="hello-servlet">Hello Servlet</a>
</body>
</html>

JSP (JavaServer Pages) 是一种基于 Java 的技术,用于创建动态的、数据驱动的网页。JSP 允许开发者直接在 HTML 页面中嵌入 Java 代码,这使得动态生成的内容可以轻松地与静态的 HTML 内容结合起来。

  • 基于 HTML:JSP 页面看起来很像普通的 HTML 页面。实际上,你可以直接将一个 HTML 文件的扩展名从 .html 更改为 .jsp,它仍然可以正常工作。但是,这只是 JSP 最基本的用法。
  • 动态内容:与纯 HTML 页面只能展示固定内容不同,JSP 允许开发者在 HTML 中嵌入 Java 代码片段。这些代码片段在页面请求时执行,并动态生成内容。在 JSP 中,可以使用特殊的标签(如 <%= ... %>)来插入动态内容。例如,<%= new Date() %> 会在页面上显示当前的日期和时间。
  • JSP 标签库:除了基本的 Java 代码,JSP 还支持自定义标签库,如 JSTL (JavaServer Pages Standard Tag Library)。这些标签库提供了一组可在 JSP 页面中使用的预定义功能,从而避免了直接嵌入复杂的 Java 代码。
  • 生命周期:当请求一个 JSP 页面时,它首先被转换为一个 Java Servlet,然后由 Servlet 容器(如 Apache Tomcat)编译和执行。这意味着,虽然 JSP 允许你以更声明性的方式编写动态网页,但在幕后,它实际上是一个完整的 Java Servlet。

在生成的 HTML 网页中点击超链接 "Hello Servlet" ,即调用 HelloServletdoGet() 方法,在页面打印 "Hello World!",同时每次刷新页面都会调用 service() 方法,在控制台窗口打印 "Hello World!"。

执行原理:

  1. 当服务器接收到客户浏览器的请求后,会解析请求 URL 路径,获取访问的 Servlet 的资源路径
  2. 查找 web.xml 文件,查找是否存在 <url-pattern> 标签体内容
  3. 如果有,则在找到对应的 <servlet-class> 全类名
  4. Tomcat 会将类的字节码文件加载进内存,并且创建其对象
  5. 调用对应方法

Servlet 基本方法详解

生命周期
init()

init() 方法是 Servlet 生命周期中的一个非常重要的方法。它主要用于执行只需要在 Servlet 启动时进行一次的初始化操作。这意味着,在 Servlet 的整个生命周期中,init() 方法只会被调用一次。

定义

1
void init(ServletConfig config) throws ServletException;

方法参数

  • ServletConfig :此对象包含 Servlet 的初始化参数,这些参数在部署描述符(通常是 web.xml 文件)中定义。你可以使用这个对象来获取 Servlet 的名称、初始化参数等。现如今在定义 init() 方法的时候已经可以不需要带该参数了,不带参数的 init() 方法内部会通过 getServletConfig() 方法获取到 ServletConfig 对象,所以你仍然可以在这个方法内访问 Servlet 的配置信息。

    1
    2
    3
    4
    5
    6
    @Override
    public void init() throws ServletException {
    // 初始化代码
    String configFile = getServletConfig().getInitParameter("configFile");
    loadConfig(configFile);
    }

service()

service() 方法是 Servlet 生命周期中的一个核心方法,负责处理来自客户端的请求并返回响应。

定义

1
void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

方法参数

  • req :代表客户端发送给服务器的请求信息。这个对象提供了读取输入流、获取参数、查询头信息等方法。
  • res :代表服务器发送回客户端的响应信息。这个对象提供了设置响应内容、设置响应状态、设置响应头等方法。

service() 方法根据请求的类型(如 GET、POST、PUT、DELETE 等)将请求分派到相应的处理方法,如 doGet(), doPost(), doPut(), doDelete() 等。

例如,当一个 HTTP GET 请求到达时,service() 方法会调用 doGet() 方法进行处理。同样地,对于 HTTP POST 请求,service() 会调用 doPost() 方法。

通常,你不需要直接重写 service() 方法。相反,你应该重写 doGet()doPost()doPut()doDelete() 等方法来处理特定类型的请求。

1
2
3
4
5
6
7
8
9
10
11
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
// 在所有请求前执行的逻辑
// ...

// 调用父类的 service 方法以确保请求被分派到 doGet(), doPost() 等方法
super.service(req, res);

// 在所有请求后执行的逻辑
// ...
}
  1. doGet(HttpServletRequest request, HttpServletResponse response)
    • 该方法用于处理 HTTP GET 请求。
    • 它通常用于获取资源或执行只读操作,不应该对服务器状态进行更改。
    • 通过request对象获取请求参数、头信息等,并通过 response 对象生成响应内容发送给客户端。
  2. doPost(HttpServletRequest request, HttpServletResponse response)
    • 该方法用于处理HTTP POST请求。
    • POST 请求通常用于提交数据,例如表单数据,用于对服务器状态进行更改。
    • 通过 request 对象获取请求参数、头信息等,并通过 response 对象生成响应内容发送给客户端。
  3. doPut(HttpServletRequest request, HttpServletResponse response)
    • 该方法用于处理 HTTP PUT 请求。
    • PUT 请求通常用于更新或替换指定的资源,客户端通常会提供完整的资源表示。
    • 通过request对象获取请求参数、头信息等,并通过 response 对象生成响应内容发送给客户端。
  4. doDelete(HttpServletRequest request, HttpServletResponse response)
    • 该方法用于处理 HTTP DELETE 请求。
    • DELETE 请求通常用于删除指定的资源。
    • 通过 request 对象获取请求参数、头信息等,并通过 response 对象生成响应内容发送给客户端。
destroy()

destroy() 方法是 Servlet 生命周期中的最后一个方法,它在 Servlet 的生命周期结束时被调用,通常用于释放资源、执行清理操作或执行其他与终止相关的任务。

定义

1
void destroy();

当 Servlet 容器(例如 Tomcat)决定从服务中移除一个 Servlet 实例时,它首先会调用该 Servlet 的 destroy() 方法。此时,Servlet 可以释放它所持有的资源,如数据库连接、线程、文件句柄等,并确保所有的清理工作都已完成。

1
2
3
4
5
@Override
public void destroy() {
// 清理代码
// 例如:关闭数据库连接、释放资源等
}

Servlet 学习笔记
https://goer17.github.io/2023/10/03/Servlet 学习笔记/
作者
Captain_Lee
发布于
2023年10月3日
许可协议