Servlet核心技术

目录

Servlet

快速入门

[Servlet 执行流程](#Servlet 执行流程)

[Servlet 的生命周期](#Servlet 的生命周期)

[Servlet 核心方法说明](#Servlet 核心方法说明)

[Servlet 体系结构](#Servlet 体系结构)

[Servlet 的 URL 映射配置](#Servlet 的 URL 映射配置)

[XML 配置方式编写 Servlet](#XML 配置方式编写 Servlet)

Request

[Request 体系结构](#Request 体系结构)

[Request 获取请求数据](#Request 获取请求数据)

[Request 请求转发](#Request 请求转发)

Response

[Response 体系结构](#Response 体系结构)

[Response 设置响应数据](#Response 设置响应数据)

[Response 完成重定向](#Response 完成重定向)

路径问题

[Response 响应字符数据](#Response 响应字符数据)

[Response 响应字节数据](#Response 响应字节数据)


Servlet

servlet是Java提供的一种开发动态web资源技术


快速入门


Servlet 执行流程

Web服务器创建Servlet对象,并调用Servlet对象中的Service方法


Servlet 的生命周期

Servlet 运行在 Servlet 容器(如 Web 服务器)中,其生命周期由容器管理,分为以下 4 个阶段

  1. 加载和实例化
  • 默认情况下,当 Servlet 第一次被访问时,由容器创建 Servlet 对象。

  1. 初始化

    • 在 Servlet 实例化之后,容器会调用 init() 方法进行初始化。

    • 该方法用于完成加载配置文件、创建连接等初始化工作。

    • init() 方法在整个生命周期中只调用一次

  2. 请求处理

    • 每次客户端请求该 Servlet 时,容器都会调用 service() 方法来处理请求

    • service() 方法根据请求类型(GET、POST 等)自动调用相应的 doGet()doPost() 等方法。

  3. 服务终止

    • 当需要释放内存或容器关闭时,容器会调用 destroy() 方法

    • 该方法用于释放资源(如数据库连接、文件句柄等)。

    • destroy() 执行完毕后,容器会释放 Servlet 实例,随后由 Java 垃圾回收器回收。


总结: Servlet 生命周期的核心方法是:

  • init() → 初始化

  • service() → 处理请求

  • destroy() → 销毁资源

这些方法均由 Servlet 容器自动调用。


Servlet 核心方法说明

  1. 初始化方法(init)

    • 作用:在 Servlet 被创建时执行,用于初始化操作。

    • 特点:只执行一次

    • 方法签名:

      复制代码
      void init(ServletConfig config)
  2. 提供服务方法(service)

    • 作用:每次 Servlet 被访问时,容器都会调用该方法来处理请求。

    • 特点:每次请求都调用

    • 方法签名:

      复制代码
      void service(HttpServletRequest req, HttpServletResponse res)
  3. 销毁方法(destroy)

    • 作用:当 Servlet 被销毁时调用,用于释放资源。

    • 触发时机:内存释放或服务器关闭时。

    • 方法签名:

      复制代码
      void destroy()
  4. 获取 ServletConfig 对象

    • 作用:获取 Servlet 的配置信息(如初始化参数)。

    • 方法签名:

      复制代码
      ServletConfig getServletConfig()
  5. 获取 Servlet 信息

    • 作用:返回 Servlet 的描述信息(通常用于版本、作者等)。

    • 方法签名:

      复制代码
      String getServletInfo()

Servlet 体系结构

1. HttpServlet 中为什么要根据请求方式的不同,调用不同方法?

原因: HTTP 协议支持多种请求方法(如 GET、POST、PUT、DELETE 等),每种方法的语义和用途不同:

  • GET:用于获取资源,通常不携带请求体,参数在 URL 中。

  • POST:用于提交数据,请求体中可包含大量数据,适合表单提交。

  • PUT / DELETE:用于更新或删除资源。

由于这些请求方式的行为差异很大,为了实现更清晰、更安全、更易维护的代码结构HttpServlet 类会根据请求方法自动调用对应的方法(如 doGet()doPost() 等)。

✅ 这样做的好处是:

  • 逻辑分离:不同请求方式的处理逻辑独立,便于开发和调试。

  • 安全性:避免误操作(例如,用 POST 处理本该用 GET 的请求)。

  • 可读性强:代码职责明确,易于理解。

2. 如何调用?

调用流程如下:

  1. 客户端发送一个 HTTP 请求(如 GET 或 POST)到服务器。

  2. Servlet 容器接收到请求后,将请求封装为 HttpServletRequest 对象,并创建 HttpServletResponse 对象。

  3. 容器调用 HttpServletservice() 方法:

    复制代码
    protected void service(HttpServletRequest req, HttpServletResponse res)
  4. service() 方法内部,容器会检查请求的方法(通过 req.getMethod() 获取)。

  5. 根据请求方法,自动调用对应的 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);
}

Web请求参数乱码,可参考 Web请求乱码解决方案

Request 请求转发

✅ 定义:

请求转发是一种在服务器内部进行资源跳转的方式。

  • 客户端发起请求到某个资源(如资源A),

  • 服务器将请求转发给另一个资源(如资源B)处理,

  • 最终由资源B生成响应并返回给客户端。

⚠️ 特点:

  • 浏览器地址栏不变URL 仍显示最初请求的路径

  • 仅一次请求客户端只发送一个请求,服务器内部完成跳转

  • 共享请求对象requestresponse 对象在整个转发过程中保持一致。

代码实现

复制代码
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);
相关推荐
靠沿6 小时前
Java数据结构初阶——LinkedList
java·开发语言·数据结构
qq_12498707536 小时前
基于springboot的建筑业数据管理系统的设计与实现(源码+论文+部署+安装)
java·spring boot·后端·毕业设计
一 乐6 小时前
宠物管理|宠物共享|基于Java+vue的宠物共享管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·springboot·宠物
a crazy day7 小时前
Spring相关知识点【详细版】
java·spring·rpc
白露与泡影7 小时前
MySQL中的12个良好SQL编写习惯
java·数据库·面试
foundbug9997 小时前
配置Spring框架以连接SQL Server数据库
java·数据库·spring
凯酱7 小时前
@JsonSerialize
java
悦悦子a啊7 小时前
项目案例作业(选做):使用文件改造已有信息系统
java·开发语言·算法
lkbhua莱克瓦247 小时前
Java项目——斗地主小游戏(控制台版)
java·开发语言·windows·斗地主项目