📖前言
上一节我们学习了 Servlet 基础开发、获取请求参数。 真实业务开发不会把 JDBC 数据库代码直接写死在 Servlet 类里面,需要做分层拆分;同时业务经常需要 Servlet 之间跳转、传递数据,就需要学习请求转发 与request 作用域。
一、Servlet 整合 JDBC ------ 分层开发实战
核心思想:各司其职,把代码进行分层解耦,提高项目可维护性。 传统写法:在 Servlet 中直接写 JDBC 连接、SQL、处理结果。 ❌弊端:Servlet 代码臃肿,业务逻辑、数据库操作全部混在一起,后期修改维护非常麻烦。
整体分层结构
- 数据库层:建表
- 实体类 Entity:和数据库表一一对应,封装表数据
- DAO 层:数据访问层,接口 + 实现类,专门负责数据库 CRUD
- Service 层:业务层,接口 + 实现类,处理业务逻辑,调用 DAO
- Servlet 层:控制器,接收浏览器请求,调用 Service,处理跳转与数据展示
开发完整步骤
1. 环境准备
- 将数据库驱动 jar 包(
ojdbc.jar/mysql‑connector‑java.jar)复制到项目WEB‑INF/lib - 导入
jdbc.properties配置文件 - 导入之前写好的
JDBCUtil工具类,用于获取连接、关闭资源
2. 编码步骤
- 创建数据库表,设计字段
- 封装实体类(Entity):一张表对应一个实体类,私有属性、get/set、无参构造、toString
- 编写 DAO 层:DAO 接口 + DAO 实现类,完成数据库增删改查
✨写完 DAO 之后,建议写 JUnit 单元测试,验证数据库操作是否正常!
- 编写 Service 层:Service 接口 + Service 实现类,调用 DAO 完成业务逻辑
✨写完 Service 同样建议单元测试,确保业务逻辑没问题
- 编写 Servlet 控制器
- 继承
HttpServlet - 重写 service 方法
- 设置响应编码
- 调用 Service 获取业务数据
- 将数据交给页面 / 另一个 Servlet 展示
- 在
web.xml中配置 servlet 注册与 url‑pattern 映射
- 继承
💡分层带来的业务优势 把业务调用、数据展示进行拆分:
- ServletA:只负责接收请求,执行业务逻辑
- ServletB:专门负责数据展示渲染页面
好处:前端页面可以随时替换。例如:春节一套页面、端午节一套页面、国庆节一套页面;业务逻辑代码完全不用改动,只更换展示 Servlet 即可。
衍生两个必须解决的核心问题:
- 如何从一个 Servlet 跳转到另外一个 Servlet?👉请求转发 forward
- Servlet 之间跳转,如何传递数据?👉request 作用域
二、请求转发 forward
2.1 什么是请求转发
请求转发(forward)属于服务器内部跳转机制。 将多个 Servlet 串联起来形成工作流,一次请求内部,从 AServlet 跳转到 BServlet,多个 Servlet 协同完成一整套业务。
整个跳转动作全部发生在 Tomcat 服务器内部,浏览器完全感知不到跳转过程。
2.2 请求转发核心 API
//获取请求转发器,参数:目标跳转的Servlet访问路径,路径必须以 / 开头
RequestDispatcher dispatcher = request.getRequestDispatcher("/showAllServlet");
//执行转发
dispatcher.forward(request,response);
简化链式写法(开发常用)
request.getRequestDispatcher("/showAllServlet").forward(request,response);
2.3 请求转发五大核心特点【重点,面试常考】
- ✅浏览器地址栏 URL 不会发生变化。跳转是服务器内部行为,浏览器只发起了 1 次请求。
- ✅转发的多个 Servlet 属于同一次 HTTP 请求,共用同一个 request、response 对象。
- ✅只有转发链路上最后一个 Servlet 可以向客户端输出响应结果;前面 Servlet 不要做输出。
- ✅可以借助
request作用域在转发的 Servlet 之间传递数据。 - ❌不能转发到项目以外的资源,只能转发当前 web 项目内部的 Servlet、html。
⚠️易错坑点: 转发之前,如果前面的 Servlet 已经调用
out.write()输出数据,会抛出异常。 业务逻辑 Servlet 只做处理、存数据,不要输出页面;页面渲染交给目标 Servlet 完成。
简单流程演示
- 客户端浏览器发送请求访问
AServlet - AServlet 在服务器内部转发跳转到
BServlet - BServlet 负责输出网页返回给浏览器
- 浏览器地址栏依旧显示访问 AServlet 的地址
三、request 作用域
3.1 什么是 request 作用域
request对象本身自带一块存储空间,叫做request 作用域。
因为请求转发多个 Servlet 属于同一次请求,所以存放在 request 作用域的数据,可以在转发链路中的各个 Servlet 之间共享。
⏱生命周期:浏览器发起请求创建 request 对象;请求处理完毕,响应返回浏览器,request 对象就被销毁,里面存放的数据全部失效。
3.2 request 作用域核心 API
表格
| 方法 | 作用说明 |
|---|---|
request.setAttribute(String name,Object value) |
存数据:向 request 域存入键值对,value 可以是任意对象(字符串、实体对象、List 集合) |
Object request.getAttribute(String name) |
取数据:根据 key 取出域中保存的数据,返回 Object,需要强制类型转换 |
request.removeAttribute(String name) |
删除数据:移除作用域中指定 key 的数据 |
代码示例
AServlet(业务处理,存入数据,转发)
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.调用service查询账户集合数据
AccountService accountService = new AccountServiceImpl();
List<Account> list = accountService.queryAll();
//2.把查询到的集合存入request作用域
request.setAttribute("accountList",list);
//3.请求转发跳转到展示数据的BServlet
request.getRequestDispatcher("/showServlet").forward(request,response);
}
BServlet(接收转发,取出数据,展示页面)
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
response.setCharacterEncoding("GBK");
PrintWriter out = response.getWriter();
//从request作用域取出数据,Object强转成List集合
List<Account> list = (List<Account>) request.getAttribute("accountList");
//遍历集合输出网页表格
out.println("<table border='1'>");
for(Account acc : list){
out.println("<tr>");
out.println("<td>"+acc.getId()+"</td>");
out.println("<td>"+acc.getName()+"</td>");
out.println("</tr>");
}
out.println("</table>");
}
执行流程图解文字说明
- 浏览器请求 AServlet;Tomcat 创建本次请求的
request对象。 - AServlet 执行业务查询,调用
setAttribute(),把 List 集合存入 request 域。 - 执行 forward 转发,服务器内部跳转到 BServlet;还是同一个 request 对象。
- BServlet 调用
getAttribute()取出集合,渲染 HTML 表格输出页面。 - 响应返回浏览器,本次请求结束,request 对象销毁,域内数据全部清空。
💡重要提醒:
getAttribute(key)返回 Object,如果 key 不存在,返回null,一定要做判空,避免空指针异常。
✍课堂练习
使用 请求转发 + request 作用域,重构查询全部账户案例:
QueryAllServlet:接收请求,调用 Service 查询全部账户数据,存入 request 域,转发给ShowServlet。ShowServlet:从 request 域取出账户集合,输出 HTML 表格展示数据。
📝知识点小结
- Servlet 整合 JDBC 要分层:实体类→DAO→Service→Servlet,各司其职,提高可维护性;DAO、Service 建议单元测试。
- 请求转发 forward:服务器内部跳转,地址栏不变,属于同一次请求,只能转发本项目资源。
- request 作用域:同一次请求内共享数据;
setAttribute()存,getAttribute()取;请求结束,域对象销毁。 - 转发业务规范:源 Servlet 负责业务逻辑、存域对象,不要输出页面;目标 Servlet 负责页面渲染输出。
📢 以上为本篇 Servlet 学习笔记,若有更好的建议,欢迎评论区商讨交流,欢迎各位大佬指正、补充不同实现思路。
💡拓展思考:转发是服务器内部跳转,那如果想要浏览器地址栏发生变化,该用什么方式?下一节会学习重定向 redirect,对比转发与重定向的区别。