一、什么是 Servlet?(邮局比喻)

你写了一个 Java 类,里面有一个方法能返回“Hello World”。
你想让用户通过浏览器访问 http://你的电脑/hello 时看到这句话。

但是浏览器不认识你的 Java 类,它只认识 HTTP 协议。

Servlet 就是一座桥

  • 它让你的 Java 类能被浏览器通过网址访问。

  • 你只需要在类里写“输出 Hello World”的代码,剩下的(接收请求、解析 HTTP、返回响应)都交给 Tomcat 去做。

邮局比喻:

  • 你写了一封信(要输出的内容)。

  • 邮局(Tomcat)负责把信装进信封、写地址、投递。

  • 那封信本身,就是 Servlet 里你写的那段代码。

一句话:Servlet 是一个 Java 类,它被 Tomcat 管理,专门用来接收浏览器请求并返回响应。


二、为什么需要 Servlet?(不用它有多麻烦)

不用 Servlet,你就要自己写 Java 代码做这些事:

  • 监听 8080 端口

  • 解析 HTTP 请求文本(GET /hello HTTP/1.1...)

  • 判断路径 /hello 该执行哪段逻辑

  • 拼 HTTP 响应(状态码、响应头、响应体)

  • 处理多线程并发
    …… 几百行底层代码,还容易错。

有了 Servlet

  • Tomcat 帮你做完上面所有脏活。

  • 你只需要写一个类,在里面写 out.println("Hello World")


三、Servlet 和 Tomcat 的关系

角色 负责的事
Tomcat 接收 HTTP 请求、解析报文、管理 Servlet 的生死、返回响应
Servlet 你写的 Java 类,里面是具体的业务逻辑(比如返回“Hello”)

类比:

  • Tomcat 是餐厅后厨系统(接单、传菜、洗碗)。

  • Servlet 是厨师(只负责做菜)。


四、Servlet 的生命周期(它的一生)

Tomcat 会管理 Servlet 从出生到死亡的整个过程,叫做生命周期。一共四个阶段:

阶段 什么时候发生 做了什么事 调用次数
1. 加载与实例化 用户第一次访问这个 Servlet 时(或 Tomcat 启动时如果配置了 load-on-startup) Tomcat 用 Java 反射创建这个 Servlet 的对象(也就是 new 出来) 1 次
2. 初始化 实例化之后,处理请求之前 Tomcat 调用 init() 方法。你可以在这里放一次性的准备工作(比如连接数据库) 1 次
3. 处理请求 每一次用户访问 Tomcat 调用 service() 方法,里面根据 HTTP 方法(GET/POST)自动调用 doGet() 或 doPost() 多次
4. 销毁 Tomcat 关闭或者你的应用被卸载时 Tomcat 调用 destroy() 方法。你可以在这里释放资源(比如关闭数据库连接) 1 次

生活类比

  • 实例化 = 招了一个新厨师(买工服、办健康证)。

  • 初始化 = 厨师熟悉厨房、认灶台(一次性准备)。

  • 处理请求 = 每来一个客人点菜,厨师就做一次菜。

  • 销毁 = 厨师离职,结清工资、交回工服。

你不需要写 init() 和 destroy(),除非你想做额外的事。Tomcat 会帮你调用它们。


五、doGet 和 doPost(两种最常见的请求方式)

浏览器发请求有两种最常见的方式:GET 和 POST
Servlet 用不同的方法来分别处理它们。

方法 浏览器何时使用 你在 Servlet 里写
doGet() 直接在地址栏输入网址、点击超链接、<form method="get"> 把处理 GET 请求的代码放在这里
doPost() 表单提交且 method="post"(例如登录、注册、上传文件) 把处理 POST 请求的代码放在这里

一个简单的写法

text

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        // 处理 GET 请求(比如显示登录页面)
    }
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) {
        // 处理 POST 请求(比如校验用户名密码)
    }
}

提示:大多数业务中,GET 用来“拿数据”,POST 用来“提交数据”。
如果你两种请求都想用同一段逻辑,可以重写 service() 方法,但初学分着写更清晰。

如果你只写了 doPost,而浏览器发来 GET 请求,Tomcat 会返回 405 Method Not Allowed 错误。


六、两个核心对象:request 和 response

Tomcat 调用你的 doGet() 或 doPost() 时,会给你两个现成的对象:

对象 全称 作用 你能用它做什么
request HttpServletRequest 装着浏览器发来的所有信息 获取参数、获取请求头、获取 Cookie、获取 Session
response HttpServletResponse 用来设置服务器要返回的信息 设置状态码、设置响应头、输出内容(HTML 或 JSON)、重定向

常见用法示例(不需要记住,看懂意思就行):

text

// 从 request 里拿参数
String username = request.getParameter("username");
String password = request.getParameter("password");

// 从 request 里拿请求头
String userAgent = request.getHeader("User-Agent");

// 用 response 输出内容
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<h1>欢迎你," + username + "</h1>");

// 用 response 重定向(让浏览器去另一个地址)
response.sendRedirect("/home");

类比

  • request = 客人给你的点菜单(上面写着“要一份宫保鸡丁,少辣”)。

  • response = 你做完菜后装盘的盘子(里面是宫保鸡丁,上面还贴了标签“少辣”)。


七、转发(forward)与重定向(redirect)

当 Servlet 处理完请求后,有时需要跳到另一个页面(比如登录成功后跳到首页)。有两种方式:转发 和 重定向

7.1 转发(Forward)

  • 代码:request.getRequestDispatcher("/home.jsp").forward(request, response);

  • 浏览器地址栏:不变(还是原来的 URL)

  • 请求次数:1 次(服务器内部跳转)

  • request 对象:可以共享数据(用 request.setAttribute 存,目标页面能取到)

  • 只能跳转本站内部的页面

7.2 重定向(Redirect)

  • 代码:response.sendRedirect("/home.jsp");

  • 浏览器地址栏:变成新 URL

  • 请求次数:2 次(第一次返回 302,浏览器再发第二次请求)

  • request 对象:不共享(两次请求是完全独立的)

  • 可以跳转到任何 URL(包括其他网站)

7.3 对比表格

对比点 转发 (Forward) 重定向 (Redirect)
地址栏 不变 变成新地址
请求次数 1 次 2 次
request 对象 共享 不共享
跳转范围 仅本站内部 任何 URL(站内/站外)
典型使用场景 Servlet → JSP 展示数据 登录成功后跳转、防止表单重复提交

生活类比

  • 转发 = 你在公司内部找同事办事,外人是看不到这个内部流程的。

  • 重定向 = 你打客服电话,客服说“这事不归我管,你打 12345678”,你挂了电话重新拨号。

初学建议

  • 如果你想返回一个页面并带数据过去(比如用户信息),用 转发

  • 如果你想完成操作后让浏览器刷新一个新页面(比如登录成功),用 重定向(防止刷新页面重复提交表单)。


八、一个完整的用户访问流程(整合所有概念)

  1. 用户在浏览器输入 http://localhost:8080/myapp/login

  2. 浏览器发送 GET 请求

  3. Tomcat 解析请求,根据 @WebServlet("/login") 找到 LoginServlet

  4. Tomcat 检查这个 Servlet 是否已经实例化:

    • 第一次访问 → 创建对象 → 调用 init()

    • 后续访问 → 直接用已有对象

  5. Tomcat 调用 service() 方法,发现是 GET 请求,于是调用你写的 doGet()

  6. 在 doGet() 中:

    • 你用 request.getParameter(...) 拿到用户名等参数

    • 你调用业务逻辑(比如查数据库)

    • 你用 request.setAttribute(...) 存入结果

    • 你用 request.getRequestDispatcher("/welcome.jsp").forward(request, response) 转发到 JSP

  7. Tomcat 执行 JSP,JSP 从 request 里取出数据,生成 HTML

  8. Tomcat 把 HTML 拼成 HTTP 响应,发回浏览器

  9. 浏览器显示页面

如果使用了重定向,第 6 步最后会用 response.sendRedirect(...),浏览器会收到 302 状态码,然后自动发起第二次请求。


九、动手实验(配合你的 Tomcat 环境)

实验1:观察生命周期

  • 在一个 Servlet 的 init()doGet()destroy() 中都加上 System.out.println("...")

  • 启动 Tomcat,第一次访问该 Servlet,观察控制台输出(你会看到 init 打印一次,每次访问都打印 doGet)。

  • 关闭 Tomcat,看到 destroy 打印。

实验2:观察 GET 和 POST

  • 写一个 Servlet,同时在 doGet() 和 doPost() 里输出不同文字。

  • 用浏览器地址栏直接访问 → 触发 doGet()

  • 写一个简单的 HTML 表单,method="post",提交后触发 doPost()

实验3:体验转发和重定向的区别

  • 写两个 Servlet:ForwardServlet 和 RedirectServlet

  • 分别在它们里面用 forward 和 sendRedirect 跳转到同一个 JSP 页面。

  • 观察浏览器地址栏的变化,以及刷新页面时是否有重复提交的提示。

分别访问转发和重定向的 Servlet,截图地址栏对比,然后刷新转发后的页面,浏览器会提示“是否重新提交表单”(因为刷新会重复上一次请求),而重定向后刷新不会重复提交。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐