目录
- Servlet 是什么?
- Servlet 开发环境准备
- 创建第一个 Servlet (手动配置)
- 1 创建 Web 项目
- 2 编写 Servlet 代码
- 3 配置
web.xml(部署描述符) - 4 部署到 Tomcat 并运行
- 使用注解简化配置 (Servlet 3.0+)
- Servlet 生命周期详解
- 处理请求和响应
- 1 获取请求信息 (
HttpServletRequest) - 2 设置响应信息 (
HttpServletResponse)
- 1 获取请求信息 (
- 实战案例:用户登录
- 总结与最佳实践
Servlet 是什么?
Servlet (Server Applet) 是运行在 Web 服务器上的 Java 程序,它使用 Java 语言编写的、能够响应客户端(通常是浏览器)请求并生成动态内容的类。

你可以把它想象成一个“Web 上的 Java 程序员”,当你在浏览器中输入一个网址(http://localhost:8080/myapp/hello),Web 服务器(如 Tomcat)就会找到对应的 Servlet 程序来处理这个请求,然后把处理结果(通常是 HTML 页面)返回给你的浏览器。
核心作用:
- 接收 HTTP 请求:来自客户端的 GET、POST 等请求。
- 处理业务逻辑:比如查询数据库、计算数据、验证用户等。
- 生成动态响应:将处理结果生成 HTML、JSON、XML 等格式,返回给客户端。
Servlet API 是 Java EE(现为 Jakarta EE)规范的一部分,位于 javax.servlet 和 javax.servlet.http 包中。
Servlet 开发环境准备
在开始之前,你需要准备好以下工具:

- JDK (Java Development Kit): Java 开发工具包,建议使用 JDK 8 或更高版本。
- Web 服务器: 最常用的是 Apache Tomcat,它是 Servlet 和 JSP 规范的参考实现,你可以从 Tomcat 官网 下载并安装。
- IDE (集成开发环境): IntelliJ IDEA (社区版即可) 或 Eclipse 都非常合适,它们对 Java Web 开发有很好的支持。
- 构建工具 (可选但推荐): Maven 或 Gradle,用于管理项目依赖和构建过程。
创建第一个 Servlet (手动配置)
我们将以 IntelliJ IDEA 为例,创建一个最基础的 Servlet。
1 创建 Web 项目
- 打开 IntelliJ IDEA,选择
File->New->Project。 - 在左侧选择
Java Enterprise。 - 勾选
Web Application,并确保 Application server 选择你配置好的 Tomcat。 - 设置 Project name (
my-first-servlet) 和 Project location。 - 点击
Create。
IDEA 会自动为你创建一个标准的 Web 项目结构,其中最重要的是:
src: 存放你的 Java 源代码。web: 存放 Web 资源,如 HTML、CSS、JS 文件。web/WEB-INF: 这是一个特殊目录,里面的内容对客户端是不可见的。web/WEB-INF/web.xml: 部署描述符,用于配置 Servlet、过滤器、监听器等,这是 Servlet 2.5 及以前版本的核心配置文件。
2 编写 Servlet 代码
- 在
src目录下,创建一个包,com.example.servlet。 - 在该包下,创建一个 Java 类,命名为
HelloServlet。
package com.example.servlet;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
// 1. 继承 HttpServlet 类
public class HelloServlet extends HttpServlet {
// 2. 重写 doGet 或 doPost 方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 3. 设置响应内容类型为 HTML
resp.setContentType("text/html;charset=UTF-8");
// 4. 获取输出流,向客户端写入响应内容
resp.getWriter().println("<h1>Hello, Servlet World!</h1>");
resp.getWriter().println("<p>当前时间是: " + new java.util.Date() + "</p>");
}
}
代码解释:
extends HttpServlet: 我们编写的 Servlet 类必须继承HttpServlet,它是专门用于处理 HTTP 请求的 Servlet 基类。@Override protected void doGet(...): 当客户端发送 GET 请求时,Tomcat 会调用这个方法,同样,如果是 POST 请求,你需要重写doPost方法。HttpServletRequest req: 代表客户端的请求对象,可以从中获取请求参数、请求头、会话等信息。HttpServletResponse resp: 代表服务端的响应对象,用于向客户端返回数据。resp.setContentType(...): 设置响应的 MIME 类型,这里我们告诉浏览器,我返回的是 HTML 文本,并且使用 UTF-8 编码,避免中文乱码。resp.getWriter(): 获取一个字符输出流,通过println()方法向浏览器写入内容。
3 配置 web.xml
我们需要告诉 Tomcat,当用户访问哪个 URL 时,应该调用我们刚刚创建的 HelloServlet,这个配置就在 web.xml 文件中。

打开 web/WEB-INF/web.xml 文件,添加如下内容:
<?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>helloServlet</servlet-name>
<!-- Servlet 的全限定类名 -->
<servlet-class>com.example.servlet.HelloServlet</servlet-class>
</servlet>
<!-- Servlet 映射 -->
<servlet-mapping>
<!-- 将哪个映射指向上面定义的 Servlet -->
<servlet-name>helloServlet</servlet-name>
<!-- 访问的 URL 模式。/hello 表示上下文根路径为 /hello 的请求 -->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
配置解释:
<servlet>: 标签用来定义一个 Servlet。<servlet-name>: 给 Servlet 起一个内部名称。<servlet-class>: 指定这个 Servlet 对应的 Java 类的全名。
<servlet-mapping>: 标签用来将一个 URL 映射到一个已定义的 Servlet。<servlet-name>: 这里引用的名称必须和上面<servlet>中定义的<servlet-name>一致。<url-pattern>: 定义一个 URL 模式。/hello意味着所有以/hello结尾的请求都会由这个 Servlet 处理。
4 部署到 Tomcat 并运行
- 点击 IntelliJ IDEA 右上角的 "Add Configuration" 或 "Edit Configurations"。
- 点击 号,选择
Tomcat Server->Local。 - 在
Deployment标签页,点击 号,选择Artifact,然后选择你的my-first-servlet:war exploded。 - 设置 Application context(应用上下文),通常和项目名一致,
/my-first-servlet。 - 点击
OK保存配置。 - 点击绿色的 "Run" 按钮(或按
Shift + F10)。
如果一切顺利,Tomcat 会启动,你的项目会被部署,打开你的浏览器,访问地址:
http://localhost:8080/my-first-servlet/hello
你应该能看到浏览器中显示:
Hello, Servlet World!
当前时间是: Mon Jan 01 10:00:00 CST 2025
恭喜!你的第一个 Servlet 成功运行了!
使用注解简化配置 (Servlet 3.0+)
从 Servlet 3.0 规范开始,引入了注解来简化开发,我们不再需要手动编写繁琐的 web.xml 配置。
- 修改 Servlet 类
在 HelloServlet 类上添加 @WebServlet 注解:
package com.example.servlet;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
// 使用注解进行配置
@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().println("<h1>Hello, Annotation-based Servlet!</h1>");
}
}
注解解释:
@WebServlet: 这个注解替代了<servlet>和<servlet-mapping>的配置。name: 对应<servlet-name>。urlPatterns: 对应<url-pattern>,可以是一个字符串数组,表示支持多个 URL 模式。
- 移除或保留
web.xml
你可以删除或清空 web.xml 文件,项目依然可以正常运行。web.xml 已经不是必需的了,但如果你需要配置一些更复杂的全局设置(如欢迎页面、错误页面、过滤器等),保留它仍然是一个好习惯。
Servlet 生命周期详解
理解 Servlet 的生命周期对于编写健壮的代码至关重要,一个 Servlet 实例的生命周期由容器(如 Tomcat)管理,主要包括以下三个阶段:
-
初始化
- 何时发生:当客户端第一次请求该 Servlet 时,或者服务器启动时(在
web.xml中配置<load-on-startup>)。 - 调用方法:
init(ServletConfig config)方法。 - 特点:只执行一次,通常在这个方法中进行一些一次性的初始化操作,比如加载配置文件、建立数据库连接等。
init方法执行完毕后,Servlet 就处于“就绪”状态,可以处理请求了。
- 何时发生:当客户端第一次请求该 Servlet 时,或者服务器启动时(在
-
处理请求
- 何时发生:在 Servlet 初始化后,每次客户端请求该 Servlet 时。
- 调用方法:
service(ServletRequest req, ServletResponse res)方法,对于HttpServlet,它会根据请求的 method (GET, POST, PUT, DELETE...) 来调用相应的doGet(),doPost()等方法。 - 特点:可以被调用多次,每次请求都会在独立的线程中执行,Servlet 本身是线程不安全的,要共享数据,必须注意同步问题。
-
销毁
- 何时发生:当服务器关闭或应用被卸载时。
- 调用方法:
destroy()方法。 - 特点:只执行一次,通常在这个方法中进行资源释放操作,比如关闭数据库连接、文件流等。
示例代码:
@WebServlet("/lifecycle")
public class LifecycleServlet extends HttpServlet {
// 1. 初始化阶段
@Override
public void init() throws ServletException {
System.out.println("Servlet 初始化... (init() 方法被调用)");
}
// 2. 处理请求阶段
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("处理 GET 请求... (doGet() 方法被调用)");
resp.getWriter().println("This is a lifecycle demo.");
}
// 3. 销毁阶段
@Override
public void destroy() {
System.out.println("Servlet 销毁... (destroy() 方法被调用)");
}
}
你可以在 Tomcat 的控制台观察这三个方法的调用顺序。
处理请求和响应
1 获取请求信息 (HttpServletRequest)
这个对象封装了所有的 HTTP 请求信息。
// 在 doGet 或 doPost 方法中
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 获取请求参数
String username = req.getParameter("username"); // <input name="username">
String password = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobby"); // <input name="hobby" value="">
// 2. 获取请求头
String userAgent = req.getHeader("User-Agent");
// 3. 获取请求方法
String method = req.getMethod(); // "GET" or "POST"
// 4. 获取请求URI
String requestURI = req.getRequestURI(); // /my-first-servlet/login
// 5. 获取请求URL
StringBuffer requestURL = req.getRequestURL(); // http://localhost:8080/my-first-servlet/login
// ... 业务逻辑处理 ...
}
2 设置响应信息 (HttpServletResponse)
这个对象用于构建并返回 HTTP 响应。
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 设置响应状态码
resp.setStatus(HttpServletResponse.SC_OK); // 200 OK
// 2. 设置响应头
resp.setHeader("Cache-Control", "no-cache");
// 3. 设置响应内容类型和编码 (推荐使用此方法)
resp.setContentType("application/json;charset=UTF-8");
// 4. 获取输出流
// PrintWriter: 用于输出字符文本
PrintWriter out = resp.getWriter();
out.println("{\"status\": \"success\", \"message\": \"登录成功!\"}");
// ServletOutputStream: 用于输出二进制数据 (如下载文件)
// ServletOutputStream outputStream = resp.getOutputStream();
}
实战案例:用户登录
这是一个非常经典的 Servlet 应用。
目标:创建一个登录页面,用户输入用户名和密码,提交后由 Servlet 验证,并返回登录成功或失败的信息。
步骤:
- 创建登录页面
login.html(放在web目录下)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">用户登录</title>
</head>
<body>
<h2>用户登录</h2>
<form action="login" method="post">
用户名: <input type="text" name="username"><br>
密码: <input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
action="login": 表单提交的地址,这个login会在web.xml或注解中映射到我们的 Servlet。
- 创建
LoginServlet.java
package com.example.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;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
// 模拟一个用户数据库
private static final String CORRECT_USERNAME = "admin";
private static final String CORRECT_PASSWORD = "123456";
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 设置请求编码 (防止 POST 请求中文乱码)
req.setCharacterEncoding("UTF-8");
// 2. 设置响应编码
resp.setContentType("text/html;charset=UTF-8");
// 3. 获取表单数据
String username = req.getParameter("username");
String password = req.getParameter("password");
// 4. 业务逻辑验证
if (CORRECT_USERNAME.equals(username) && CORRECT_PASSWORD.equals(password)) {
// 登录成功
resp.getWriter().println("<h1 style='color: green;'>登录成功!欢迎, " + username + "!</h1>");
} else {
// 登录失败
resp.getWriter().println("<h1 style='color: red;'>登录失败!用户名或密码错误。</h1>");
// 提供返回登录页面的链接
resp.getWriter().println("<a href='login.html'>返回登录</a>");
}
}
}
- 运行测试
- 启动 Tomcat。
- 访问
http://localhost:8080/my-first-servlet/login.html。 - 输入正确的用户名
admin和密码123456,观察成功页面。 - 输入错误的密码,观察失败页面。
总结与最佳实践
- 职责分离:Servlet 的核心职责是接收请求、处理业务逻辑、返回响应,不要在 Servlet 中写大量的 HTML 代码,这会使代码难以维护,我们会使用 JSP (JavaServer Pages) 或现代的前端模板引擎来展示视图,Servlet 只负责准备数据并转发请求。
- 中文乱码问题:
- GET 请求乱码:Tomcat 8+ 之后已经默认使用 UTF-8 编码,通常不会乱码,如果遇到,可以手动对 URL 参数进行解码:
new String(username.getBytes("ISO-8859-1"), "UTF-8")。 - POST 请求乱码:务必在获取参数前调用
req.setCharacterEncoding("UTF-8");,或者使用一个全局的过滤器来统一处理。
- GET 请求乱码:Tomcat 8+ 之后已经默认使用 UTF-8 编码,通常不会乱码,如果遇到,可以手动对 URL 参数进行解码:
- 使用过滤器:对于通用的功能,如字符编码设置、登录验证、日志记录等,应该使用过滤器,过滤器可以对一组 Servlet 或 URL 模式进行预处理和后处理,实现代码复用。
- 拥抱现代框架:虽然 Servlet 是 Java Web 开发的基础,但在实际企业级项目中,通常会使用更高级的框架,如 Spring MVC 或 Jakarta EE (Jakarta EE),这些框架在 Servlet 的基础上进行了封装,提供了更强大的功能(如依赖注入、RESTful 支持、AOP 等),极大地简化了开发,但理解 Servlet 是学习和使用这些高级框架的基石。
希望这份详细的指南能帮助你顺利入门 Java Servlet 开发!
