目录
[Servlet 执行流程](#Servlet 执行流程)
[Servlet 的生命周期](#Servlet 的生命周期)
[Servlet 核心方法说明](#Servlet 核心方法说明)
[Servlet 体系结构](#Servlet 体系结构)
[Servlet 的 URL 映射配置](#Servlet 的 URL 映射配置)
[XML 配置方式编写 Servlet](#XML 配置方式编写 Servlet)
[Request 体系结构](#Request 体系结构)
[Request 获取请求数据](#Request 获取请求数据)
[Request 请求转发](#Request 请求转发)
[Response 体系结构](#Response 体系结构)
[Response 设置响应数据](#Response 设置响应数据)
[Response 完成重定向](#Response 完成重定向)
[Response 响应字符数据](#Response 响应字符数据)
[Response 响应字节数据](#Response 响应字节数据)
Servlet
servlet是Java提供的一种开发动态web资源技术

快速入门


Servlet 执行流程

Web服务器创建Servlet对象,并调用Servlet对象中的Service方法
Servlet 的生命周期
Servlet 运行在 Servlet 容器(如 Web 服务器)中,其生命周期由容器管理,分为以下 4 个阶段:
- 加载和实例化
-
默认情况下,当 Servlet 第一次被访问时,由容器创建 Servlet 对象。

-
初始化
-
在 Servlet 实例化之后,容器会调用
init()方法进行初始化。 -
该方法用于完成加载配置文件、创建连接等初始化工作。
-
init()方法在整个生命周期中只调用一次。
-
-
请求处理
-
每次客户端请求该 Servlet 时,容器都会调用
service()方法来处理请求。 -
service()方法根据请求类型(GET、POST 等)自动调用相应的doGet()、doPost()等方法。
-
-
服务终止
-
当需要释放内存或容器关闭时,容器会调用
destroy()方法。 -
该方法用于释放资源(如数据库连接、文件句柄等)。
-
destroy()执行完毕后,容器会释放 Servlet 实例,随后由 Java 垃圾回收器回收。
-
✅ 总结: Servlet 生命周期的核心方法是:
-
init()→ 初始化 -
service()→ 处理请求 -
destroy()→ 销毁资源
这些方法均由 Servlet 容器自动调用。
Servlet 核心方法说明
-
初始化方法(init)
-
作用:在 Servlet 被创建时执行,用于初始化操作。
-
特点:只执行一次。
-
方法签名:
void init(ServletConfig config)
-
-
提供服务方法(service)
-
作用:每次 Servlet 被访问时,容器都会调用该方法来处理请求。
-
特点:每次请求都调用。
-
方法签名:
void service(HttpServletRequest req, HttpServletResponse res)
-
-
销毁方法(destroy)
-
作用:当 Servlet 被销毁时调用,用于释放资源。
-
触发时机:内存释放或服务器关闭时。
-
方法签名:
void destroy()
-
-
获取 ServletConfig 对象
-
作用:获取 Servlet 的配置信息(如初始化参数)。
-
方法签名:
ServletConfig getServletConfig()
-
-
获取 Servlet 信息
-
作用:返回 Servlet 的描述信息(通常用于版本、作者等)。
-
方法签名:
String getServletInfo()
-
Servlet 体系结构


1. HttpServlet 中为什么要根据请求方式的不同,调用不同方法?
原因: HTTP 协议支持多种请求方法(如 GET、POST、PUT、DELETE 等),每种方法的语义和用途不同:
-
GET:用于获取资源,通常不携带请求体,参数在 URL 中。
-
POST:用于提交数据,请求体中可包含大量数据,适合表单提交。
-
PUT / DELETE:用于更新或删除资源。
由于这些请求方式的行为差异很大,为了实现更清晰、更安全、更易维护的代码结构 ,HttpServlet 类会根据请求方法自动调用对应的方法(如 doGet()、doPost() 等)。
✅ 这样做的好处是:
逻辑分离:不同请求方式的处理逻辑独立,便于开发和调试。
安全性:避免误操作(例如,用 POST 处理本该用 GET 的请求)。
可读性强:代码职责明确,易于理解。
2. 如何调用?
调用流程如下:
-
客户端发送一个 HTTP 请求(如 GET 或 POST)到服务器。
-
Servlet 容器接收到请求后,将请求封装为
HttpServletRequest对象,并创建HttpServletResponse对象。 -
容器调用
HttpServlet的service()方法:protected void service(HttpServletRequest req, HttpServletResponse res) -
在
service()方法内部,容器会检查请求的方法(通过req.getMethod()获取)。 -
根据请求方法,自动调用对应的 doXXX() 方法:
-
如果是 GET → 调用
doGet(req, res) -
如果是 POST → 调用
doPost(req, res) -
如果是 PUT → 调用
doPut(req, res) -
如果是 DELETE → 调用
doDelete(req, res) -
......
-
🔍 示例代码(简化版):
protected void service(HttpServletRequest req, HttpServletResponse res) {
String method = req.getMethod();
if ("GET".equals(method)) {
doGet(req, res);
} else if ("POST".equals(method)) {
doPost(req, res);
} else if ("PUT".equals(method)) {
doPut(req, res);
} else if ("DELETE".equals(method)) {
doDelete(req, res);
}
}
Servlet 的 URL 映射配置
1. 一个 Servlet 可以配置多个 urlPattern
-
使用
@WebServlet注解时,可以通过urlPatterns属性为一个 Servlet 配置多个访问路径。 -
示例:
@WebServlet(urlPatterns = {"/demo1", "/demo2"}) public class MyServlet extends HttpServlet { // ... } -
意义:同一个 Servlet 可以通过多个不同的 URL 被访问。
2. urlPattern 配置规则
| 类型 | 规则说明 | 示例 |
|---|---|---|
| ① 精确匹配 | 完全匹配指定路径 | /demo → 只匹配 /demo |
| ② 目录匹配 | 以斜杠开头,以斜杠结尾,匹配该目录下的所有子路径 | /user/* → 匹配 /user/abc、/user/123 等 |
| ③ 扩展名匹配 | 以星号开头,匹配特定文件扩展名的请求 | *.do → 匹配 /login.do、/register.do 等 |
| ④ 任意匹配 | 使用 /,匹配所有请求(通常用于默认 Servlet) |
/ → 匹配所有请求(如根路径) |
⚠️ 注意:
多个
urlPattern之间优先级顺序:精确匹配 > 目录匹配 > 扩展名匹配 > 任意匹配。如果有多个 Servlet 都匹配同一个请求,容器会根据优先级选择一个执行。

XML 配置方式编写 Servlet


Request
Request 体系结构

Request 获取请求数据
1. 请求行(Request Line)
| 方法 | 说明 | 返回值示例 |
|---|---|---|
String getMethod() |
获取请求方式(GET、POST 等) | GET |
String getContextPath() |
获取虚拟目录(项目访问路径) | /request-demo |
StringBuffer getRequestURL() |
获取完整的 URL(含协议、主机、端口、路径) | http://localhost:8080/request-demo/req1 |
String getRequestURI() |
获取 URI(统一资源标识符,不含查询参数) | /request-demo/req1 |
String getQueryString() |
获取请求参数(GET 方式,即问号后的部分) | username=zhangsan&password=123 |
2. 请求头(Request Headers)
| 方法 | 说明 | 示例调用 |
|---|---|---|
String getHeader(String name) |
根据请求头名称获取其值 | request.getHeader("User-Agent") |
| - | 常见请求头包括:Accept, Content-Type, User-Agent, Cookie, Referer 等。 |
- |
3. 请求体(Request Body)
| 方法 | 说明 | 用途 |
|---|---|---|
ServletInputStream getInputStream() |
获取字节输入流 | 用于读取原始字节数据(如文件上传) |
BufferedReader getReader() |
获取字符输入流 | 用于读取文本数据(如表单提交的键值对)。通常用于 POST 请求中。 |
✅ 注意:
GET 请求通常没有请求体,参数在 URL 中。
POST 请求的参数一般放在请求体中,通过
getReader()或getInputStream()读取。
-
请求行:包含了请求的基本信息,比如请求类型、目标资源等。
-
请求头:包含了关于请求和客户端的一些元数据,例如浏览器类型、可接受的内容类型等。
-
请求体:主要用于包含 POST 请求中的数据,可以通过不同的方法根据需要读取为字符或字节流。

Request 提供的通用获取参数的方法


POST 逻辑代码
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// POST 请求逻辑
this.doGet(req, resp);
}
Request 请求转发

✅ 定义:
请求转发是一种在服务器内部进行资源跳转的方式。
客户端发起请求到某个资源(如资源A),
服务器将请求转发给另一个资源(如资源B)处理,
最终由资源B生成响应并返回给客户端。
⚠️ 特点:
浏览器地址栏不变 :URL 仍显示最初请求的路径。
仅一次请求 :客户端只发送一个请求,服务器内部完成跳转。
共享请求对象 :
request和response对象在整个转发过程中保持一致。
代码实现
req.getRequestDispatcher("资源B路径").forward(req, resp);

✅ 核心方法:
| 方法 | 说明 | 示例 |
|---|---|---|
void setAttribute(String name, Object o) |
将对象存储到 request 域中,以 key-value 形式保存 | request.setAttribute("username", "zhangsan"); |
Object getAttribute(String name) |
根据 key 获取 request 域中的值 | String username = (String) request.getAttribute("username"); |
void removeAttribute(String name) |
根据 key 删除 request 域中的键值对 | request.removeAttribute("username"); |

Response
Response 体系结构

Response 设置响应数据
1.响应行(Response Line)
示例:
HTTP/1.1 200 OK
| 方法 | 说明 | 示例 |
|---|---|---|
void setStatus(int sc) |
设置响应状态码(如 200、404、500 等) | response.setStatus(200); |
✅ 常见状态码:
200:请求成功
404:资源未找到
500:服务器内部错误
2. 响应头(Response Headers)
示例:
Content-Type: text/html
| 方法 | 说明 | 示例 |
|---|---|---|
void setHeader(String name, String value) |
设置响应头键值对 | response.setHeader("Content-Type", "text/html"); |
📌 常见响应头:
Content-Type:指定响应内容类型(如text/html,application/json)
Cache-Control:控制缓存行为
Location:用于重定向(配合setStatus(302))
3.响应体(Response Body)
示例:
<html><head>head</head><body></body></html>
| 方法 | 说明 | 用途 |
|---|---|---|
PrintWriter getWriter() |
获取字符输出流 | 用于输出文本内容(如 HTML、JSON) |
ServletOutputStream getOutputStream() |
获取字节输出流 | 用于输出二进制数据(如文件、图片) |
⚠️ 注意:
不能同时使用
getWriter()和getOutputStream(),否则会抛出异常。通常选择其一即可,根据响应内容类型决定。
Response 完成重定向
资源跳转的方式

| 特点 | 说明 |
|---|---|
| 🔹 浏览器地址栏路径发生变化 | 重定向后,浏览器地址栏会显示新的 URL,用户可见跳转过程。 |
| 🔹 可以重定向到任意位置的资源 | 支持跳转到: |
-
服务器内部资源(如
/login.jsp) -
外部网站(如
https://www.baidu.com) | | 🔹 两次请求,不能在多个资源间共享 request 数据 | -
客户端发送第一次请求 → 服务器返回 302 状态码 + 新地址
-
浏览器自动发起第二次请求 → 访问新资源
-
由于是两个独立请求,request 域中的数据无法共享 |
重定向适用于:
用户登录成功后跳转到首页
页面需要刷新或避免重复提交(如 POST-REDIRECT-GET 模式)
跳转到第三方网站(如支付、分享)
⚠️ 注意:因涉及两次请求,不要依赖 request 属性传递数据,应使用 session 或 URL 参数。
// 1.设置响应状态码
resp.setStatus(302);
// 2.设置响应头 Location resp.setHeader("Location","资源B的路径");
resp.setHeader("Location","/Maven/RespDemo2");
// 简化方法 resp.sendRedirect("资源B的路径");
resp.sendRedirect("/Maven/RespDemo2");

对比提示 VS 请求转发
| 特性 | 请求转发(Forward) | 重定向(Redirect) |
|---|---|---|
| 地址栏变化 | ❌ 不变 | ✅ 变化 |
| 请求次数 | 1 次 | 2 次 |
| 资源共享 | ✅ 可通过 request 共享数据 | ❌ 不能共享 request 数据 |
| 跳转范围 | 仅限服务器内部 | 内部/外部均可 |
路径问题
| 使用场景 | 路径写法示例 | 是否包含虚拟目录 | 说明 |
|---|---|---|---|
浏览器端 (<a>、<form>) |
/项目名/资源路径 |
✅ 是 | 必须写完整路径,含上下文路径(虚拟目录) |
| 请求转发(forward) | /资源路径 |
❌ 否 | 服务器内部跳转,使用应用内相对路径 |
| 重定向(sendRedirect) | /项目名/资源路径 或完整 URL |
✅ 是 | 浏览器会发起新请求,必须包含虚拟目录或使用绝对 URL |
💡 最佳实践建议:
使用
${pageContext.request.contextPath}(JSP)或request.getContextPath()(Servlet)动态获取项目名,避免硬编码。示例:
<a href="${pageContext.request.contextPath}/login">登录</a>
💡 口诀记忆:
前端用绝对路径,后端用相对路径。
转发不改地址,重定向改地址。
Response 响应字符数据
使用 response.getWriter() 获取字符输出流,用于输出文本内容(如 HTML、JSON)。 记得先设置编码:
// 设置响应内容类型为HTML格式,字符编码为UTF-8
resp.setContentType("text/html;charset=UTF-8");
// 获取PrintWriter对象,用于向浏览器输出内容
PrintWriter out = resp.getWriter();
// 输出HTML内容
out.write("Hello World");

Response 响应字节数据
使用 response.getOutputStream() 获取字节输出流,用于输出二进制内容(如图片、文件下载)。 示例:
// 获取ServletOutputStream对象,用于输出二进制数据
ServletOutputStream respOutputStream = resp.getOutputStream();
// 将字节数组写入输出流(注:此处的fileBytes变量需要预先定义和赋值)
respOutputStream.write(fileBytes);
