Servlet 实例(长文解析)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
在 Web 开发领域,Servlet 是 Java 语言实现动态内容生成的核心技术之一。它为开发者提供了一个轻量级、高效的服务端编程模型,能够处理 HTTP 请求与响应,构建用户交互式应用。对于编程初学者而言,理解 Servlet 的基本原理与实践方法是掌握 Java Web 开发的必经之路;而对中级开发者来说,深入掌握 Servlet 的高级特性与优化技巧则能进一步提升开发效率。本文将以“Servlet 实例”为核心,通过理论结合实践的方式,系统性地讲解 Servlet 的核心概念、配置方法、生命周期管理及实际应用场景,帮助读者快速掌握这一技术。
一、Servlet 的基础概念与核心作用
1.1 什么是 Servlet?
Servlet 是运行在服务器端的 Java 类,它能够接收客户端(如浏览器)发送的 HTTP 请求,并根据需求生成动态响应内容返回给客户端。可以将其理解为“服务器端的小助手”——就像餐馆里的服务员,当顾客(浏览器)提交订单(HTTP 请求)时,Servlet 会处理订单内容、调用后端逻辑(如数据库查询或业务计算),最终将结果打包成网页或数据格式返回给顾客。
关键特性:
- 跨平台性:基于 Java 的“一次编写,到处运行”特性,Servlet 可在任何支持 JVM 的环境中运行。
- 与 HTTP 协议深度集成:直接操作请求头、请求体、响应状态码等核心元素。
- 轻量级:相比传统的 CGI 程序,Servlet 在服务器启动后保持常驻内存,减少了每次请求的初始化开销。
1.2 Servlet 在 Web 开发中的典型场景
Servlet 可以处理以下常见需求:
- 用户登录验证与会话管理(如检查用户名密码);
- 动态生成 HTML 页面(如根据用户输入显示搜索结果);
- 处理文件上传或下载;
- 调用数据库查询或更新操作;
- 实现 RESTful API 的服务端逻辑。
形象比喻:
若将整个 Web 应用比作一座桥梁,Servlet 就是桥面上的“信号接收器”——它负责接收来自客户端的“信号”(HTTP 请求),并将信号转化为后端系统的“动作指令”,最终将结果以标准化格式(如 JSON、HTML)反馈给客户端。
二、Servlet 的配置与部署
2.1 开发环境准备
要编写和运行 Servlet,需满足以下环境要求:
- Java 开发工具包(JDK):建议使用 JDK 8 或更高版本。
- Servlet 容器:如 Apache Tomcat、Jetty 等。
- 开发工具:推荐 IntelliJ IDEA 或 Eclipse,支持 Maven/Gradle 依赖管理。
示例:Maven 项目依赖配置
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
2.2 第一个 Servlet 实例:HelloWorld
步骤 1:创建 Servlet 类
继承 HttpServlet
类,并覆盖 doGet
或 doPost
方法:
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HelloWorldServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
response.setContentType("text/html"); // 设置响应内容类型
response.getWriter().println("<h1>Hello, Servlet World!</h1>");
}
}
步骤 2:配置 Servlet 映射路径
有两种方式配置 Servlet 的访问路径:
方式一:通过注解 @WebServlet
import javax.servlet.annotation.WebServlet;
@WebServlet("/hello")
public class HelloWorldServlet extends HttpServlet { ... }
方式二:通过 web.xml
文件配置
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.example.HelloWorldServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
步骤 3:启动服务器并访问
部署到 Tomcat 后,访问 http://localhost:8080/your-project/hello
,即可看到输出结果。
三、Servlet 的生命周期管理
3.1 生命周期阶段详解
Servlet 的生命周期由容器(如 Tomcat)严格管理,包含以下核心阶段:
- 加载与实例化:容器根据配置加载 Servlet 类,并创建其实例。
- 初始化:调用
init()
方法,完成资源初始化(如数据库连接池)。 - 服务请求:调用
service()
方法,根据请求类型(GET/POST 等)分发到对应的doGet()
或doPost()
方法。 - 销毁:调用
destroy()
方法,释放资源(如关闭数据库连接)。
生命周期图示:
| 阶段 | 触发条件 | 执行频率 |
|---------------|-----------------------------------|-----------------------|
| 加载与实例化 | 容器启动时或首次请求到达时 | 仅一次 |
| 初始化 | 实例化后立即执行 | 仅一次 |
| 服务请求 | 每次客户端发送请求时 | 多次 |
| 销毁 | 容器关闭或 Servlet 被卸载时 | 仅一次 |
3.2 生命周期方法的典型用法
示例:数据库连接池的初始化与释放
public class DatabaseServlet extends HttpServlet {
private Connection connection;
@Override
public void init() {
try {
// 初始化数据库连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "pass");
} catch (SQLException e) {
throw new UnavailableException("数据库连接失败", 5, true);
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 使用 connection 执行查询
}
@Override
public void destroy() {
try {
if (connection != null) connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
四、处理 HTTP 请求与响应
4.1 请求对象 HttpServletRequest
该对象封装了客户端发送的所有请求信息,包括:
- 请求头:如
User-Agent
、Accept-Language
等。 - 请求参数:通过
getParameter()
方法获取表单或 URL 参数。 - 会话对象:通过
getSession()
方法获取 HttpSession 实例,用于用户身份维护。
示例:获取表单提交的用户名
String username = request.getParameter("username");
if (username == null || username.isEmpty()) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "用户名不能为空");
}
4.2 响应对象 HttpServletResponse
用于构建返回给客户端的响应内容,核心操作包括:
- 设置响应状态码(如
404
、500
)。 - 定义响应内容类型(如
text/html
、application/json
)。 - 通过
getWriter()
或getOutputStream()
写入响应体。
示例:返回 JSON 格式的响应
response.setContentType("application/json");
response.getWriter().write("{ \"status\": \"success\", \"message\": \"操作完成\" }");
4.3 处理不同 HTTP 方法
Servlet 需根据请求方法(GET/POST 等)执行不同逻辑:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 处理 GET 请求(如查询数据)
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 处理 POST 请求(如提交表单)
}
五、Servlet 实例的进阶应用
5.1 用户登录验证案例
功能描述
实现一个简单的用户登录系统,包含以下步骤:
- 用户提交用户名和密码。
- Servlet 验证凭证是否有效(假设本地存储了用户数据)。
- 若验证成功,重定向到欢迎页面;否则返回错误提示。
代码实现
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private static final Map<String, String> users = new HashMap<>(); // 模拟用户数据库
static {
users.put("admin", "admin123");
users.put("user", "user123");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
if (users.containsKey(username) && users.get(username).equals(password)) {
// 登录成功,设置会话属性
req.getSession().setAttribute("user", username);
resp.sendRedirect("/welcome"); // 重定向到欢迎页面
} else {
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "用户名或密码错误");
}
}
}
5.2 数据库查询与结果展示
功能描述
通过 Servlet 查询数据库中的商品列表,并以 HTML 表格形式返回给客户端。
代码实现
@WebServlet("/products")
public class ProductServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
List<Product> products = new ProductDao().getAllProducts(); // 假设 ProductDao 是数据访问层
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
writer.println("<table border='1'>");
writer.println(" <tr><th>ID</th><th>Name</th><th>Price</th></tr>");
for (Product product : products) {
writer.printf(" <tr>" +
"<td>%d</td>" +
"<td>%s</td>" +
"<td>%.2f</td>" +
"</tr>",
product.getId(), product.getName(), product.getPrice());
}
writer.println("</table>");
}
}
六、常见问题与优化技巧
6.1 性能优化
- 避免在服务方法中创建大量对象:尽量将数据库连接、对象实例等资源复用。
- 使用过滤器(Filter)统一处理请求:如日志记录、权限校验。
- 启用 Tomcat 的 NIO 模式:通过配置
server.xml
提升并发性能。
6.2 典型错误及解决方案
错误现象 | 可能原因 | 解决方法 |
---|---|---|
404 Not Found | Servlet 路径配置错误 | 检查 @WebServlet 或 web.xml |
ClassCastException | 类型转换错误(如 req.getAttribute() ) | 确保对象类型与预期一致 |
Connection refused | 数据库服务未启动或配置错误 | 检查数据库连接参数与服务状态 |
结论
通过本文的讲解,读者应已掌握 Servlet 的核心概念、配置方法及实际应用技巧。从简单的“Hello World”到复杂的登录验证与数据库交互,每个实例都体现了 Servlet 在 Web 开发中的灵活性与强大功能。对于初学者而言,建议从基础案例入手,逐步理解生命周期管理与 HTTP 协议细节;中级开发者则可深入探索 Filter、Listener 等高级特性,并结合框架(如 Spring MVC)提升开发效率。
实践建议:
- 尝试将本文的代码示例部署到本地 Tomcat 服务器,观察运行效果。
- 扩展登录案例,加入注册功能与密码加密。
- 使用 Postman 工具测试不同 HTTP 方法的请求与响应。
掌握 Servlet 技术不仅能帮助开发者构建传统 Web 应用,更是理解 Java Web 生态系统的重要基石。希望本文能为读者的编程之旅提供清晰的指引与实用参考。