Servlet 实例(长文解析)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 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 类,并覆盖 doGetdoPost 方法:

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)严格管理,包含以下核心阶段:

  1. 加载与实例化:容器根据配置加载 Servlet 类,并创建其实例。
  2. 初始化:调用 init() 方法,完成资源初始化(如数据库连接池)。
  3. 服务请求:调用 service() 方法,根据请求类型(GET/POST 等)分发到对应的 doGet()doPost() 方法。
  4. 销毁:调用 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-AgentAccept-Language 等。
  • 请求参数:通过 getParameter() 方法获取表单或 URL 参数。
  • 会话对象:通过 getSession() 方法获取 HttpSession 实例,用于用户身份维护。

示例:获取表单提交的用户名

String username = request.getParameter("username");
if (username == null || username.isEmpty()) {
    response.sendError(HttpServletResponse.SC_BAD_REQUEST, "用户名不能为空");
}

4.2 响应对象 HttpServletResponse

用于构建返回给客户端的响应内容,核心操作包括:

  • 设置响应状态码(如 404500)。
  • 定义响应内容类型(如 text/htmlapplication/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 用户登录验证案例

功能描述

实现一个简单的用户登录系统,包含以下步骤:

  1. 用户提交用户名和密码。
  2. Servlet 验证凭证是否有效(假设本地存储了用户数据)。
  3. 若验证成功,重定向到欢迎页面;否则返回错误提示。

代码实现

@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 FoundServlet 路径配置错误检查 @WebServletweb.xml
ClassCastException类型转换错误(如 req.getAttribute()确保对象类型与预期一致
Connection refused数据库服务未启动或配置错误检查数据库连接参数与服务状态

结论

通过本文的讲解,读者应已掌握 Servlet 的核心概念、配置方法及实际应用技巧。从简单的“Hello World”到复杂的登录验证与数据库交互,每个实例都体现了 Servlet 在 Web 开发中的灵活性与强大功能。对于初学者而言,建议从基础案例入手,逐步理解生命周期管理与 HTTP 协议细节;中级开发者则可深入探索 Filter、Listener 等高级特性,并结合框架(如 Spring MVC)提升开发效率。

实践建议

  1. 尝试将本文的代码示例部署到本地 Tomcat 服务器,观察运行效果。
  2. 扩展登录案例,加入注册功能与密码加密。
  3. 使用 Postman 工具测试不同 HTTP 方法的请求与响应。

掌握 Servlet 技术不仅能帮助开发者构建传统 Web 应用,更是理解 Java Web 生态系统的重要基石。希望本文能为读者的编程之旅提供清晰的指引与实用参考。

最新发布