Servlet 教程(超详细)

更新时间:

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

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

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

什么是 Servlet?为什么需要它?

Servlet 是 Java 语言中用于开发 Web 应用程序的核心技术之一。它可以理解为运行在服务器端的 Java 小程序,负责处理客户端(如浏览器)发送的 HTTP 请求,并生成相应的 HTTP 响应。

想象一个餐厅场景:当顾客(浏览器)发送点餐请求时,服务员(Servlet)会接收订单,处理后将餐品(响应内容)返回给顾客。Servlet 的核心作用,就是充当这个“服务员”,在 Web 应用中实现请求与响应的交互逻辑。

对于开发人员来说,Servlet 提供了以下优势:

  • 平台无关性:基于 Java 的跨平台特性,Servlet 可以在任何支持 Java 的服务器上运行。
  • 高效性:Servlet 运行在服务器内存中,生命周期由容器管理,避免了传统 CGI 程序重复加载解释器的性能损耗。
  • 扩展性:通过继承或接口实现,可以灵活定制请求处理逻辑。

开发环境搭建

必备工具清单

工具名称作用描述版本建议
Java JDKServlet 运行的基础环境1.8 或更高版本
Apache TomcatServlet 容器,负责部署和运行9.0 或更高版本
IDE(如 IntelliJ IDEA)提供代码编写和调试支持最新稳定版

环境配置步骤

  1. 安装 Java JDK
    下载并配置环境变量,确保 javacjava 命令可用。

    javac -version  # 验证 JDK 安装成功  
    
  2. 下载并启动 Tomcat
    Apache 官网 下载 Tomcat,解压后执行:

    bin/startup.sh  # Linux/Mac 系统  
    bin/startup.bat # Windows 系统  
    

    访问 http://localhost:8080,若显示 Tomcat 欢迎页,说明环境正常。

  3. 配置 IDE
    在 IntelliJ IDEA 中创建 Maven 项目,添加以下依赖到 pom.xml

    <dependency>  
      <groupId>javax.servlet</groupId>  
      <artifactId>javax.servlet-api</artifactId>  
      <version>4.0.1</version>  
      <scope>provided</scope>  
    </dependency>  
    

Servlet 的核心概念与生命周期

核心接口与类

Servlet 的功能主要通过以下接口实现:

  • Servlet 接口:定义了 Servlet 的基本方法(init(), service(), destroy())。
  • GenericServlet 抽象类:实现了 Servlet 接口,提供通用功能,适用于非 HTTP 协议场景。
  • HttpServlet 抽象类:继承自 GenericServlet,专为 HTTP 协议设计,提供了 doGet(), doPost() 等方法。

生命周期阶段

Servlet 的生命周期由容器(如 Tomcat)管理,分为三个阶段:

  1. 初始化阶段
    容器调用 init() 方法,完成资源加载(如数据库连接池、配置文件读取)。

  2. 服务阶段
    容器调用 service() 方法,根据请求类型(GET/POST)分发到对应的 doGet()doPost() 方法。

  3. 销毁阶段
    容器调用 destroy() 方法,释放资源(如关闭数据库连接)。

生命周期的比喻
将 Servlet 比作一个餐厅服务员,init() 是服务员上岗培训,service() 是接待顾客处理订单,destroy() 是下班前整理工作台。

请求与响应对象

Servlet 处理请求的核心是 HttpServletRequestHttpServletResponse 对象:

  • HttpServletRequest:封装了客户端请求的详细信息,包括请求头、请求参数、会话信息等。
  • HttpServletResponse:用于构建响应内容,设置响应头、状态码、输出流等。

示例代码:

protected void doGet(HttpServletRequest request, HttpServletResponse response)  
        throws ServletException, IOException {  
    // 设置响应编码为 UTF-8  
    response.setCharacterEncoding("UTF-8");  
    // 获取请求参数  
    String name = request.getParameter("name");  
    // 输出响应内容  
    response.getWriter().write("Hello, " + name + "!");  
}  

第一个 Servlet 程序:Hello World

代码实现

创建一个继承 HttpServlet 的类:

@WebServlet("/hello")  // 注解配置 URL 映射  
public class HelloServlet extends HttpServlet {  
    @Override  
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
            throws ServletException, IOException {  
        resp.getWriter().write("Hello Servlet World!");  
    }  
}  

部署与验证

  1. 将项目打包为 war 文件,放置到 Tomcat 的 webapps 目录。
  2. 访问 http://localhost:8080/your-project-name/hello,若显示“Hello Servlet World!”,则部署成功。

处理表单提交与数据验证

处理 POST 请求

当用户提交表单时,Servlet 需要通过 doPost() 方法接收参数:

protected void doPost(HttpServletRequest request, HttpServletResponse response)  
        throws ServletException, IOException {  
    String username = request.getParameter("username");  
    String password = request.getParameter("password");  
    // 验证逻辑  
    if (username.equals("admin") && password.equals("123456")) {  
        response.getWriter().write("登录成功");  
    } else {  
        response.sendRedirect("/login-failed.html");  // 重定向到失败页面  
    }  
}  

数据验证技巧

  • 非空验证:检查参数是否为 null 或空字符串。
  • 类型转换:使用 Integer.parseInt()Double.parseDouble() 时,需捕获 NumberFormatException
  • 正则表达式:验证邮箱格式、手机号等。
// 验证邮箱格式  
if (!email.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$")) {  
    // 处理格式错误  
}  

使用会话与 Cookie

HttpSession 的基本用法

Servlet 提供 HttpSession 对象来维护用户会话状态:

// 获取当前会话,若不存在则创建新会话  
HttpSession session = request.getSession();  
// 存储用户信息  
session.setAttribute("user", user);  
// 移除属性  
session.removeAttribute("user");  
// 销毁会话  
session.invalidate();  

Cookie 的读写操作

通过 Cookie 类可以操作客户端的 Cookie:

// 写入 Cookie  
Cookie cookie = new Cookie("theme", "dark");  
cookie.setMaxAge(60 * 60 * 24);  // 1 天后过期  
response.addCookie(cookie);  

// 读取 Cookie  
Cookie[] cookies = request.getCookies();  
if (cookies != null) {  
    for (Cookie cookie : cookies) {  
        if ("theme".equals(cookie.getName())) {  
            String theme = cookie.getValue();  
            // 处理主题逻辑  
        }  
    }  
}  

异常处理与日志记录

异常处理机制

Servlet 可通过 @WebServlet 注解的 loadOnStartup 属性控制初始化顺序,或通过 Filter 统一处理异常:

// 自定义异常处理器  
public class ErrorHandler extends HttpServlet {  
    @Override  
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
            throws ServletException, IOException {  
        Throwable throwable = (Throwable) req.getAttribute("javax.servlet.error.exception");  
        resp.getWriter().write("系统发生错误: " + throwable.getMessage());  
    }  
}  

日志记录实践

推荐使用 SLF4J 或 Logback 进行日志记录:

import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  

public class LoggerDemoServlet extends HttpServlet {  
    private static final Logger logger = LoggerFactory.getLogger(LoggerDemoServlet.class);  

    @Override  
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
            throws ServletException, IOException {  
        logger.info("请求开始处理");  
        try {  
            // 业务逻辑  
        } catch (Exception e) {  
            logger.error("处理请求时发生错误", e);  
            throw e;  
        } finally {  
            logger.info("请求处理完成");  
        }  
    }  
}  

高级主题与最佳实践

异步处理与非阻塞 I/O

Servlet 3.0 引入了异步处理能力,允许在独立线程中执行耗时操作:

@WebServlet(urlPatterns = "/async", asyncSupported = true)  
public class AsyncServlet extends HttpServlet {  
    @Override  
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
            throws ServletException, IOException {  
        AsyncContext asyncContext = req.startAsync();  
        new Thread(() -> {  
            try {  
                // 模拟耗时操作  
                Thread.sleep(2000);  
                // 构建响应  
                PrintWriter writer = asyncContext.getResponse().getWriter();  
                writer.write("异步处理完成");  
            } catch (Exception e) {  
                asyncContext.complete();  
            } finally {  
                asyncContext.complete();  
            }  
        }).start();  
    }  
}  

安全性与过滤器

通过 Filter 实现跨站脚本(XSS)防护:

@WebFilter("/*")  
public class XSSFilter implements Filter {  
    @Override  
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)  
            throws IOException, ServletException {  
        HttpServletRequest httpRequest = (HttpServletRequest) request;  
        // 清洗请求参数  
        String cleanedParam = cleanXSS(httpRequest.getParameter("input"));  
        // 继续请求链  
        chain.doFilter(request, response);  
    }  

    private String cleanXSS(String value) {  
        // 简单的 XSS 清洗逻辑  
        return value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");  
    }  
}  

性能优化建议

  1. 避免在 service() 方法中创建对象:频繁的 new 操作会增加 GC 压力。
  2. 复用数据库连接:通过连接池(如 HikariCP)管理资源。
  3. 使用缓存:对频繁查询的数据使用内存缓存(如 Redis)。

常见问题与解决方案

问题 1:Servlet 无法被 Tomcat 加载

可能原因

  • 类路径错误,未在 web.xml@WebServlet 中配置 URL。
  • Tomcat 未重启,导致新类未被检测到。

解决方案

  • 检查注解或 web.xml 中的配置:
    <servlet>  
      <servlet-name>HelloServlet</servlet-name>  
      <servlet-class>com.example.HelloServlet</servlet-class>  
    </servlet>  
    <servlet-mapping>  
      <servlet-name>HelloServlet</servlet-name>  
      <url-pattern>/hello</url-pattern>  
    </servlet-mapping>  
    

问题 2:中文乱码问题

原因:请求或响应的编码未正确设置。

解决方案
doGet()doPost() 方法开头添加编码设置:

request.setCharacterEncoding("UTF-8");  
response.setCharacterEncoding("UTF-8");  

问题 3:会话超时未处理

解决方案
web.xml 中配置全局会话超时时间:

<session-config>  
    <session-timeout>30</session-timeout>  <!-- 30 分钟超时 -->  
</session-config>  

总结与展望

通过本文的学习,读者已经掌握了从基础概念到高级应用的 Servlet 技术全貌。从简单的 Hello World 到复杂的异步处理,Servlet 的灵活性和扩展性在 Web 开发中始终占据重要地位。

对于初学者,建议从简单项目入手,逐步实践表单处理、数据库交互等场景;中级开发者则可以深入探索异步编程、安全防护等进阶主题。随着云原生和微服务架构的普及,Servlet 的核心思想依然适用于现代后端开发,例如在 Spring Framework 中,Controller 组件底层仍然基于 Servlet 技术实现。

掌握 Servlet,不仅是学习 Java Web 的基础,更是理解 HTTP 协议和服务器端编程的必经之路。希望本文能成为您通往专业 Web 开发的坚实第一步。

最新发布