第29课:Servlet基础
本课目标:掌握Servlet的核心概念、生命周期、配置方式,能够独立开发动态Web应用。
一、概念讲解
1.1 什么是Servlet
Servlet是Java EE规范中用于处理HTTP请求的服务器端组件。它是运行在Web服务器(如Tomcat)上的Java程序,负责接收客户端请求并生成响应。
┌─────────────┐ HTTP请求 ┌─────────────┐ 调用 ┌─────────────┐
│ 浏览器 │ ─────────────────> │ Tomcat │ ─────────────> │ Servlet │
│ (Client) │ <───────────────── │ (Server) │ <───────────── │ (Handler) │
└─────────────┘ HTTP响应 └─────────────┘ 返回 └─────────────┘
1.2 Servlet生命周期
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 加载实例 │ -> │ init()初始化 │ -> │ service()处理 │ -> │ destroy()销毁 │
│ Class.forName│ │ 仅执行一次 │ │ 每次请求调用 │ │ 仅执行一次 │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
1.3 Tomcat安装
- 下载Tomcat:https://tomcat.apache.org/download-90.cgi
- 解压到指定目录
- 配置环境变量
CATALINA_HOME - 启动:
bin\startup.bat - 访问:http://localhost:8080
二、语法格式
2.1 Servlet接口核心方法
java
public interface Servlet {
void init(ServletConfig config) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
2.2 HttpServlet常用方法
java
// doGet - 处理GET请求
protected void doGet(HttpServletRequest req, HttpServletResponse res)
// doPost - 处理POST请求
protected void doPost(HttpServletRequest req, HttpServletResponse res)
// doPut - 处理PUT请求
protected void doPut(HttpServletRequest req, HttpServletResponse res)
// doDelete - 处理DELETE请求
protected void doDelete(HttpServletRequest req, HttpServletResponse res)
三、代码案例
3.1 Hello Servlet
java
package com.example.servlet;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("HelloServlet 初始化完成");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("<h1>Hello Servlet!</h1>");
out.println("<p>当前时间: " + new java.util.Date() + "</p>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
@Override
public void destroy() {
System.out.println("HelloServlet 销毁");
}
}
▶ 运行结果:
Servlet 执行效果:
┌─────────────────────────────────────┐
│ 控制台输出: │
│ HelloServlet 初始化完成 │
│ │
│ 浏览器显示 (访问 /hello): │
│ ┌─────────────────────────────┐ │
│ │ <h1>Hello Servlet!</h1> │ │
│ │ <p>当前时间: 2026-09-02 │ │
│ │ 10:00:00</p> │ │
│ └─────────────────────────────┘ │
│ │
│ 控制台输出 (服务器关闭时): │
│ HelloServlet 销毁 │
└─────────────────────────────────────┘
3.2 表单处理器
java
package com.example.servlet;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html><head><title>登录</title></head>");
out.println("<body>");
out.println("<h2>用户登录</h2>");
out.println("<form method='post' action='login'>");
out.println("用户名: <input type='text' name='username'><br>");
out.println("密码: <input type='password' name='password'><br>");
out.println("<input type='submit' value='登录'>");
out.println("</form></body></html>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
if ("admin".equals(username) && "123456".equals(password)) {
out.println("<h1>登录成功,欢迎 " + username + "!</h1>");
} else {
out.println("<h1>用户名或密码错误!</h1>");
out.println("<a href='login'>返回登录</a>");
}
}
}
▶ 运行结果:
LoginServlet 执行效果:
┌─────────────────────────────────────┐
│ GET 请求 (访问 /login): │
│ 浏览器显示登录表单: │
│ ┌─────────────────────────────┐ │
│ │ <h2>用户登录</h2> │ │
│ │ 用户名: [ ] │ │
│ │ 密码: [ ] │ │
│ │ [登录] │ │
│ └─────────────────────────────┘ │
│ │
│ POST 请求 (输入 admin/123456): │
│ 浏览器显示: │
│ ┌─────────────────────────────┐ │
│ │ <h1>登录成功,欢迎 admin!</h1>│ │
│ └─────────────────────────────┘ │
│ │
│ POST 请求 (输入错误密码): │
│ 浏览器显示: │
│ ┌─────────────────────────────┐ │
│ │ <h1>用户名或密码错误!</h1> │ │
│ │ <a href='login'>返回登录</a> │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
3.3 计数器应用
java
package com.example.servlet;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/counter")
public class CounterServlet extends HttpServlet {
private int totalCount = 0;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 获取Session级别的计数器
HttpSession session = req.getSession();
Integer sessionCount = (Integer) session.getAttribute("sessionCount");
if (sessionCount == null) {
sessionCount = 0;
}
sessionCount++;
session.setAttribute("sessionCount", sessionCount);
// 全局计数器
totalCount++;
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("<h1>访问计数器</h1>");
out.println("<p>您的访问次数: " + sessionCount + "</p>");
out.println("<p>总访问次数: " + totalCount + "</p>");
}
}
▶ 运行结果:
CounterServlet 执行效果:
┌─────────────────────────────────────┐
│ 第一次访问: │
│ 浏览器显示: │
│ ┌─────────────────────────────┐ │
│ │ <h1>访问计数器</h1> │ │
│ │ <p>您的访问次数: 1</p> │ │
│ │ <p>总访问次数: 1</p> │ │
│ └─────────────────────────────┘ │
│ │
│ 第二次访问 (同一浏览器): │
│ 浏览器显示: │
│ ┌─────────────────────────────┐ │
│ │ <h1>访问计数器</h1> │ │
│ │ <p>您的访问次数: 2</p> │ │
│ │ <p>总访问次数: 2</p> │ │
│ └─────────────────────────────┘ │
│ │
│ 其他浏览器访问: │
│ 浏览器显示: │
│ ┌─────────────────────────────┐ │
│ │ <h1>访问计数器</h1> │ │
│ │ <p>您的访问次数: 1</p> │ │
│ │ <p>总访问次数: 3</p> │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
3.4 web.xml配置方式
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-name>HelloServlet</servlet-name>
<servlet-class>com.example.servlet.HelloServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置Servlet映射 -->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<!-- 欢迎页面 -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
四、常见错误
| 错误 | 原因 | 解决方案 |
|---|---|---|
| 404 Not Found | URL路径配置错误 | 检查@WebServlet或web.xml中的url-pattern |
| 405 Method Not Allowed | 请求方法不匹配 | 检查是否重写了doGet/doPost |
| 中文乱码 | 编码不一致 | 设置req.setCharacterEncoding("UTF-8")和resp.setContentType |
| NullPointerException | Servlet未正确初始化 | 检查load-on-startup配置 |
| ClassNotFoundException | Servlet类路径错误 | 检查servlet-class的完整包名 |
五、课后练习
- 创建一个Servlet,显示当前服务器时间
- 创建一个Servlet,接收表单提交的姓名和年龄,显示欢迎信息
- 使用web.xml配置方式注册Servlet(不用注解)
- 实现一个简单的计算器Servlet,支持加减乘除
六、本课小结
| 知识点 | 说明 |
|---|---|
| Servlet | Java EE的Web组件,处理HTTP请求 |
| 生命周期 | init() -> service() -> destroy() |
| HttpServlet | 继承GenericServlet,处理HTTP协议 |
| @WebServlet | 注解方式配置Servlet,替代web.xml |
| Tomcat | 轻量级Web服务器和Servlet容器 |
本课程持续更新中,欢迎关注!