☰
JSP机票预订系统源码解析:从MVC分层到Tomcat部署的完整Java Web实战
2026/10/7 9:19:59 网站建设 项目流程

简介:JSP机票预订系统源码包面向Java Web初学者及课程设计开发者,模拟在线机票查询、预订、订单管理等核心流程,直观呈现JSP、Servlet、JavaBean、DAO及MVC分层架构在真实项目中的落地方式。压缩包共1644个文件,大小约38.59MB,除JSP页面、Java类与配置文件外,还包含大量gif/png/jpg图片、js/css前端脚本与样式、jar依赖库及SQL数据库脚本,覆盖前端展示、交互逻辑与后端数据操作所需的全部组成部分。目前已有156人学习或下载,适合用于课程设计参考、源码研读或项目二次开发。通过阅读源码可掌握用户认证、数据校验、会话管理、数据库增删改查等关键知识点,同时学习WEB-INF目录的组织方法、表现层与业务逻辑的分离思路,以及如何借助CSS、JavaScript完善界面交互体验。

1. JSP 机票预订系统源代码:适合课程设计,也适合补 Java Web 短板

这份 JSP 机票预订系统源代码,zip 包解开之后是一整套基于 JSP + Servlet + JavaBean + DAO 的经典 Java Web 项目。很多同学下载源码第一件事是点开 jsp 页面看界面长什么样,我建议反过来——先看 web.xml 和 classes 目录,因为这套项目的控制权根本不在页面,而在 Servlet 和 Filter 手里。它模拟的是在线机票预订的核心流程:注册登录、搜索航班、填写乘客信息、确认订单,整体走 MVC 分层。适合两类人:一是刚学完 Java Web 基础、想找一份能完整跑通请求到数据库全链路代码的初学者;二是课程设计需要快速交付、又想在答辩时讲清楚架构思路的学生。这份源码的价值不在页面多精致,而在于你顺着一次预订请求,能看懂业务逻辑是怎么从浏览器走到数据库、再原路返回的。

2. 先拆目录再碰代码:WEB-INF、classes 与 MVC 的真实落点

2.1 从 zip 到项目根:先认清五类目录的职责

拿到压缩包先别急着解压进 IDE,先在文件管理器里看一眼顶层结构。这类 JSP 项目通常不是 Maven 工程,没有 pom.xml,它是传统的 Web 工程目录,直接靠 Tomcat 识别。解开后你会发现几类东西:jsp 文件夹、WEB-INF 文件夹、css/js/images 资源文件夹,偶尔还有 SQL 脚本直接放在根目录。

先说 jsp 文件夹,这里面放的是页面文件,包括首页、登录页、注册页、机票搜索页、订单确认页。它们在架构里扮演 View 的角色,但你如果只盯页面,会发现里面混着不少 Java 代码片段,也就是常说的 scriptlet。这是早期 JSP 项目的典型写法,不是最佳实践,但胜在直观——每一行逻辑都能在页面上找到对应输出。

再说 WEB-INF,这是整个项目的核心,里面至少有 web.xml、classes 和 lib 三个子目录。web.xml 是部署描述符,配置 Servlet 映射、Filter 过滤器和欢迎页;classes 目录放编译后的 .class 文件,和包路径一一对应;lib 目录放第三方 jar 包,比如 MySQL 驱动。一个常见误区是以为 jsp 页面才是项目主体,实际上 Servlet 和 Filter 全压在 WEB-INF 里,页面只是前台。

css/js/images 不用多说,纯前端资源。css 控制布局和样式,js 做表单校验和交互,images 放 logo 和按钮图。这里我想提醒一句:如果页面样式和你预期差很远,优先去 css 里找,而不是去 Java 代码里找——前端问题很少出在 Servlet 里。

2.2 五个核心类各管哪一段:Controller、Model 与 Filter 的分工

压缩包里列出的类文件很有代表性,它们合起来就是一个微缩版 MVC。我按自己的理解把它们分成三组,你先有个全局印象,后面走流程时再逐个展开。

类名角色职责
UserLoginServletController接收登录/注册请求,调用 DAO 校验用户,管理 Session
MainServletController主页面入口,加载菜单和初始数据,控制页面跳转
CoreServletController/调度处理核心业务请求分发,常见做法是统一入口再按参数路由
CommonDaoModel(DAO)封装 JDBC 操作,执行 SQL 增删改查,屏蔽数据库细节
User / FlightNumber / TicketInfoModel(JavaBean)用户、航班、票务的数据载体,字段对应数据库表
MenuServiceModel(Service)菜单和业务逻辑的组织层,Dao 之上的服务封装
SetCharacterEncodingFilterFilter统一请求和响应的字符编码,解决中文乱码

注意 SetCharacterEncodingFilter 不是 Servlet,它实现了 Filter 接口。它的作用是在请求进入 Servlet 之前强制把编码设为 UTF-8,避免表单提交的中文变成乱码。很多项目里它被配置在 web.xml 的最前面,因为 Filter 有执行顺序,放错了位置就白写。

CoreServlet.class 和 MainServlet.class 同时存在,说明这个项目不是单 Servlet 架构,而是按功能拆了多个入口。常见的做法是 MainServlet 处理主页面相关请求,CoreServlet 处理机票查询、预订这类核心业务,UserLoginServlet 单独管用户认证。这种拆分的好处是职责清晰,坏处是 web.xml 里的 Servlet-mapping 会比较多,排查问题时得先确认请求到底命中了哪个 Servlet。

2.3 把 MVC 映射到这份源码:JSP 不是全部,Servlet 才是入口

刚接触 JSP 的人容易有一个错觉:项目里 .jsp 文件最多,所以 JSP 是主体。实际上在这份源码里,JSP 只是视图层,真正的入口是 Servlet。一个典型请求的路径是:浏览器提交表单 → web.xml 里的 servlet-mapping 把 URL 映射到对应的 Servlet → Servlet 调用 DAO 操作数据库 → 把结果放进 request 或 session → forward 或 redirect 到 JSP 页面 → JSP 用 EL 表达式或 Java 片段渲染数据。

看一个登录请求就够了。登录表单的 action 指向一个以 .do 结尾的 URL,这个 URL 在 web.xml 里被映射到 UserLoginServlet。UserLoginServlet 收到请求后,先从 request 里取出用户名和密码,再调 CommonDao 的查询方法核对数据库,查到了就把 User 对象塞进 session,然后跳转到主页;没查到就返回登录页并带一个错误提示。整个过程 Controller 只做调度,不写 SQL;JSP 只负责显示,不碰数据库连接。

这就是 MVC 在这份源码里的真实落点。理解了这条链路,你再打开任何一个 jsp 文件看代码,就能分清楚哪些片段在做数据展示、哪些片段在做流程控制、哪些片段其实应该挪到 Servlet 里去。

3. 把预订流程走通:登录、查票、下单的数据流转

3.1 UserLoginServlet:登录逻辑与会话处理

用户认证是整套系统的第一道关卡,也是最容易看出代码水平的模块。入门项目的登录逻辑通常长这样:从 request 拿参数,拼 SQL,查库,比对密码,跳转。但合格的写法会多考虑几件事:密码字段是否为空、用户是否存在、登录成功后 Session 里放什么、Session 超时时间设多少。

在 UserLoginServlet 里,核心流程我一般这样组织:

// 典型 JSP 登录 Servlet 的核心逻辑(示意写法) protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); if (username == null || password == null || username.trim().isEmpty() || password.isEmpty()) { response.sendRedirect("login.jsp?error=empty"); return; } User user = commonDao.findUserByNameAndPwd(username, password); if (user != null) { HttpSession session = request.getSession(); session.setAttribute("loginUser", user); session.setMaxInactiveInterval(30 * 60); // 30 分钟无操作自动失效 response.sendRedirect("main.jsp"); } else { response.sendRedirect("login.jsp?error=badCredentials"); } }

这段代码有几个参数值得注意。request.setCharacterEncoding("UTF-8") 是保险动作,虽然项目里配了 SetCharacterEncodingFilter,但 Servlet 里再设一次不亏,尤其在 Filter 配置有误时它能兜底。session.setMaxInactiveInterval 设的是会话超时秒数,30 分钟是合理值,太短用户填个表单就被踢下线,太长有安全隐患。而用重定向而不是 forward 跳转,是为了避免用户刷新页面时重复提交表单。

这里有个新手容易踩的细节:密码比对是在 Java 代码里做的,还是在 SQL 里做的?这份项目是典型教学风格,密码直接明文存在数据库里,SQL 查询时一并比对。生产环境必须用加盐哈希(比如 BCrypt),但作为课程设计源码,这个写法能让你一眼看懂认证流程的每一步,反而不算坏事。

3.2 FlightNumber 与 TicketInfo:航班和票务的数据模型

FlightNumber 和 TicketInfo 是两个 JavaBean,我习惯叫它们"数据盒子"。JavaBean 的规矩是:私有字段 + 公有 getter/setter + 无参构造。FlightNumber 通常对应航班表,字段包括航班号、出发城市、到达城市、出发时间、到达时间、票价、余票量;TicketInfo 对应订单表,字段包括订单号、用户 ID、航班号、乘机人姓名、证件号、下单时间、订单状态。

// FlightNumber 的典型字段设计(示意) public class FlightNumber { private String flightNo; // 航班号,如 CA1234 private String fromCity; // 出发城市 private String toCity; // 到达城市 private String departTime; // 起飞时间 private String arriveTime; // 到达时间 private double price; // 经济舱票价 private int remainSeats; // 余票数量 public String getFlightNo() { return flightNo; } public void setFlightNo(String flightNo) { this.flightNo = flightNo; } // 其余 getter/setter 省略,IDE 可以一键生成 }

这段代码本身没有逻辑,但它决定了上下游的接口形态。JSP 页面要读取余票量,就得调用 getRemainSeats();CommonDao 要把数据库查询结果转成对象,就得靠 setter 逐字段赋值。所以 JavaBean 的字段设计直接影响 DAO 层的 SQL 写法和页面的 EL 表达式取值,改一个字段名,三层全要跟着动。

还有一个容易被忽略的细节:字段类型。余票量用 int,票价用 double 或 BigDecimal。用 BigDecimal 更严谨,因为价格计算涉及精度,double 在极端情况下会出现 0.1 + 0.2 != 0.3 的经典问题。课程设计里用 double 能够顺利演示,但如果你打算在这个项目上做二次开发,建议把金额字段统一改成 BigDecimal。

3.3 CommonDao:一条 SQL 如何串起前后端

CommonDao 是整个项目里最值得逐行读的类。它负责所有数据库操作,是 MVC 里的 Model 层核心。典型的 CommonDao 里会有这些方法:findUserByNameAndPwd()、searchFlights()、insertOrder()、updateSeatCount()。你注意观察它的命名习惯,基本是"动词 + 业务对象",一眼就能看出方法在干什么。

// CommonDao 中查询航班的典型 JDBC 写法(示意) public List<FlightNumber> searchFlights(String fromCity, String toCity) { List<FlightNumber> list = new ArrayList<>(); String sql = "SELECT * FROM flight WHERE from_city = ? AND to_city = ?"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, fromCity); ps.setString(2, toCity); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { FlightNumber f = new FlightNumber(); f.setFlightNo(rs.getString("flight_no")); f.setFromCity(rs.getString("from_city")); f.setToCity(rs.getString("to_city")); f.setPrice(rs.getDouble("price")); f.setRemainSeats(rs.getInt("remain_seats")); list.add(f); } } } catch (SQLException e) { e.printStackTrace(); // 实际项目应换成日志输出 } return list; }

这段代码里最值得说的是 PreparedStatement 的 ? 占位符。它比直接拼接 SQL 字符串安全,能防 SQL 注入。初学者常见的错误是写成 "SELECT * FROM flight WHERE from_city = '" + fromCity + "'",一旦用户在搜索框输入特殊字符,轻则报错,重则被注入攻击。所以你在读这份源码时,重点看它用的是 Statement 还是 PreparedStatement,这是判断代码水平的一个简单标准。

还有一处细节是 try-with-resources 写法。Connection、PreparedStatement、ResultSet 都放进 try 的括号里,Java 7 之后能自动关闭资源,不用手动 finally 关。如果源码里用的是老式写法,你可以在二次开发时顺手重构掉,这会减少大量连接泄漏问题。

3.4 MenuService 与 MainServlet:主页面菜单的动态渲染

MenuService 这个类的存在很有意思,它说明项目把"菜单渲染"当成了一项独立业务。很多入门项目会把菜单直接写成 JSP 里的静态 HTML,但这套系统用 Service 层动态加载菜单,意味着菜单数据来自数据库,想加一个菜单项不用改页面,改数据库就行。

MainServlet 的工作方式是:接收主页请求,调 MenuService 拉取菜单列表和基础数据,塞进 request 作用域,然后 forward 到 main.jsp。JSP 页面上用 JSTL 或 EL 表达式遍历列表生成菜单。

这种设计的好处在你做课程设计答辩时特别明显——老师问"你的菜单是怎么来的",你可以回答"菜单由 MenuService 从数据库加载,MainServlet 负责装配数据,JSP 只做展示"。这一句话就把三层职责讲清楚了。

但这里也有一个容易翻车的点:如果 main.jsp 里的菜单是硬编码的,而 MenuService 只是空壳,那这个"动态菜单"就是假的。你拿到源码后建议搜索一下 main.jsp 里有没有 forEach 循环或 Java for 循环,确认数据到底是写死的还是从数据库读的,这决定了你答辩时能不能把话说满。

4. 本地部署复现:Tomcat、MySQL 与 web.xml 的配置顺序

4.1 环境版本怎么选:JDK 8 + Tomcat 8/9 + MySQL 5.7 的经典组合

我见过太多人在部署老项目时倒在版本上。这套 JSP 项目没有 Maven 依赖管理,用的是传统 WAR 目录结构,所以环境版本必须贴合项目年代。我最稳妥的建议是:JDK 1.8、Tomcat 8.5 或 9.0、MySQL 5.7。这三个版本组合经过最多项目验证,兼容性最好。

JDK 版本尤其关键。如果你机器上装的是 JDK 17,直接跑 Tomcat 8.5 会报错,因为高版本 JDK 移除了部分安全模块。这时候两条路:要么装一个 JDK 8 并切换,要么升到 Tomcat 10 并把项目里的 javax.* 包改成 jakarta.*——后者的改动量对新手不友好。所以别较劲,直接用 JDK 8 最省事。

MySQL 方面,5.7 是稳妥选择。8.0 也能跑,但你需要注意驱动版本和连接 URL 的变化:8.0 的驱动类名是 com.mysql.cj.jdbc.Driver,且 URL 末尾建议加 serverTimezone=Asia/Shanghai,否则时区报错会浪费你半小时。如果项目源码里的 DBUtil 用的是旧驱动名 com.mysql.jdbc.Driver,在 MySQL 8.0 下会直接 ClassNotFoundException。

4.2 导入数据库脚本:先建库再导表

zip 包里通常会带一个 .sql 文件,这是整个项目能跑起来的前提。导入顺序有讲究:先建库,再指定库,最后导表。注意不要一上来就双击执行,MySQL 命令行或 Navicat 都可以,关键是确认当前选中的是目标库。

-- 数据库初始化,按顺序执行 CREATE DATABASE IF NOT EXISTS flight_booking DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE flight_booking; -- 航班表结构(示意,以压缩包内 SQL 为准) CREATE TABLE IF NOT EXISTS flight ( id INT PRIMARY KEY AUTO_INCREMENT, flight_no VARCHAR(20) NOT NULL, from_city VARCHAR(50) NOT NULL, to_city VARCHAR(50) NOT NULL, depart_time DATETIME NOT NULL, arrive_time DATETIME NOT NULL, price DECIMAL(10,2) NOT NULL, remain_seats INT NOT NULL DEFAULT 60 );

这里有两个参数值得你留意。第一是 DEFAULT CHARACTER SET utf8mb4,它比 utf8 多了对 emoji 表情和生僻字的支持,而且兼容 utf8 的所有字符,直接用它就行。第二是 DECIMAL(10,2) 表示总位数 10 位、小数 2 位的定点数,用它可以避免前面提到的 double 精度问题。

导入完成后,务必打开项目里的 DBUtil.java 或数据库配置文件,核对连接串。最常见的差异是数据库名、用户名、密码对不上。一个我反复说的小技巧:连接 URL 写成 jdbc:mysql://localhost:3306/flight_booking?useUnicode=true&characterEncoding=UTF-8,这个写法能让你少踩两个坑——数据库乱码和连接失败。

4.3 部署到 Tomcat:war 还是目录拷贝

传统的 Eclipse/MyEclipse 项目会直接生成 war 包,但课程设计源码经常是整个文件夹给你。部署方式取决于你手上的东西:如果是解压好的项目目录,直接拷贝到 Tomcat 的 webapps 目录下即可。

# 假设 Tomcat 安装在 /opt/tomcat,项目文件夹名为 flight_booking cp -r flight_booking /opt/tomcat/webapps/ # 启动 Tomcat(Linux / macOS) /opt/tomcat/bin/startup.sh # 查看启动日志,确认没有异常 tail -f /opt/tomcat/logs/catalina.out

Windows 上是同样的逻辑,把项目文件夹拷到 apache-tomcat-x.x.x\webapps 下,双击 bin\startup.bat。启动后浏览器访问 http://localhost:8080/flight_booking/ ,注意路径必须带项目名,除非你把项目改名为 ROOT 放在 webapps 下,才能直接用根路径访问。

如果你在 IDE 里跑,比如 Eclipse 或 IntelliJ IDEA,方式略有区别:IDEA 一般是通过 Artifact 打包成 war exploded 结构再部署到本地 Tomcat。但无论哪种方式,底层都是把编译后的 classes、jsp 页面、web.xml 按目录结构交给 Tomcat 识别。遇到 404 先别怀疑代码,先看项目名和 URL 路径是否完全匹配。

4.4 web.xml 里最容易影响启动的三处配置

web.xml 是传统 JSP 项目的神经中枢,启动失败、路由不对、乱码,多半和它有关。我挑三个高频出问题的配置点讲。

Servlet 映射是第一个。每个 Servlet 必须有 servlet 和 servlet-mapping 两个标签配对,前者定义类路径,后者定义 URL 规律。常见的低级错误是写了 servlet 标签但忘了 servlet-mapping,或者映射路径写成了 /login 但页面请求的是 login.do,结果永远是 404。

<!-- web.xml 中的 Servlet 映射示例 --> <servlet> <servlet-name>UserLoginServlet</servlet-name> <servlet-class>com.example.servlet.UserLoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UserLoginServlet</servlet-name> <url-pattern>/login.do</url-pattern> </servlet-mapping>

第二个是 Filter 配置。SetCharacterEncodingFilter 的 filter-mapping 必须放在所有需要中文处理的请求路径上,且顺序要靠前。这个 filter 的配置很简单,但坑在细节:url-pattern 如果写 /* 就拦截所有请求,如果漏写某个路径,那个路径的请求就会乱码。

第三个是 welcome-file 配置。打开系统时如果直接进 404,不是代码有问题,而是欢迎页没配对。web.xml 里的 welcome-file 决定了访问项目根路径时默认打开哪个页面,一般配成 index.jsp 或 main.jsp。如果配错成 login.jsp 而登录成功后跳转又依赖 session,就会出现"打开系统直接跳到登录页"的奇怪表现。

5. 避坑记录:这份 JSP 项目最常见的五个坑

5.1 中文乱码:Filter 顺序不对,编码过滤器形同虚设

现象:登录页面输入中文用户名,提交后数据库里存的是乱码,页面显示也是问号。

原因:SetCharacterEncodingFilter 虽然配置了,但 filter-mapping 的位置放错,或者放在某些不拦截的路径上。更隐蔽的情况是 JSP 页面本身的 pageEncoding 没设 UTF-8,导致页面提交时就已编码错误。

解决:三步走。第一步确认 web.xml 里 filter 的 url-pattern 是 /*,保证拦全部请求。第二步确认每个 jsp 文件头部有 <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>。第三步确认数据库连接 URL 带 characterEncoding=UTF-8。三处都对了,乱码基本绝迹。

5.2 页面 404 而控制台没报错:WEB-INF 下的页面不能直接访问

现象:把 login.jsp 放在 WEB-INF 目录下,浏览器直接访问 http://localhost:8080/login.jsp 返回 404,但 Tomcat 日志没有任何报错。

原因:WEB-INF 目录有访问保护,它下面的资源对浏览器不可见,只能通过 Servlet 转发访问。这是 Java Servlet 规范的安全设计,不是 bug。

解决:用 forward 跳转而不是 sendRedirect。Servlet 里写 request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response),把页面渲染交给服务端。如果是页面之间的正常跳转,就通过 URL 访问 Servlet,由 Servlet 决定渲染哪个 WEB-INF 下的 JSP。

5.3 数据库连接失败:驱动 jar 没进 lib,JDBC 直接抛 ClassNotFoundException

现象:项目部署后一切正常,一点登录就报 java.lang.ClassNotFoundException: com.mysql.jdbc.Driver。

原因:mysql-connector-java 的 jar 包没有放进 WEB-INF/lib 目录,或者放进了但 IDE 没有把它加入发布路径。

解决:检查 WEB-INF/lib 下有没有 mysql-connector-java-x.x.x.jar。如果没有,去项目依赖目录或网上下载对应版本(5.1.49 或 8.0.x),拷进去后重启 Tomcat。注意重启前清理 Tomcat 的 work 目录,否则可能加载不到新 jar。

5.4 改了 Java 代码不生效:class 没重新编译,Tomcat 还在跑旧类

现象:在 User.java 里加了一个字段,重启 Tomcat 后页面依然取不到这个值,反射一看还是旧 class。

原因:IDE 没触发编译,或者直接手动部署目录时只覆盖了 .java 文件,没有编译成 .class。Tomcat 运行的是 classes 目录里的字节码,不是源码。

解决:在 IDE 里执行 clean + build(Eclipse 是 Project → Clean,IDEA 是 Build → Rebuild Project),确认 WEB-INF/classes 下的 .class 文件时间戳已经更新。如果是手工部署,先到项目根目录执行 javac 重新编译,再把整个 classes 目录完整拷贝过去。血泪经验:改完 Java 代码不重编译,等于没改。

5.5 端口被占用与 Tomcat 缓存:部署半天发现跑的是旧包

现象:Tomcat 启动报 Port 8080 was already in use,或者界面改了但访问时还是老页面。

原因:前一个 Tomcat 实例没关干净;或者 webapps 下存在相同项目的旧目录,Tomcat 解压 war 包时不会覆盖同名目录。

解决:端口占用时用命令查出进程并结束,Windows 是 netstat -ano | findstr 8080 然后 taskkill /PID 进程号 /F,Linux 是 lsof -i:8080 然后 kill。部署更新时,先停 Tomcat,删掉 webapps 下旧项目目录和 work/Catalina 下的缓存,再拷贝新代码。Tomcat 这层缓存特别容易造成"我改了代码怎么不生效"的假象,遇到诡异问题先清 work 目录。

6. 二次开发进阶:从定位页面到改功能的一小时验证法

拿到源码跑通只是第一步,你大概率还要改东西——课程设计加功能、面试前优化代码、或者单纯想拆开看看。我常用一套一小时验证法,从"改哪个文件"到"确认生效"全程可控。

先学会倒推页面定位。你在浏览器看到某个页面有问题,按 F12 看请求路径,或者直接看地址栏的 URL。如果 URL 以 .do 结尾,说明走的是 Servlet,去 web.xml 里查这个映射对应的 servlet-class,然后打开那个 Servlet 看它 forward 到哪个 JSP。如果 URL 直接是 .jsp 结尾,那页面文件就在 jsp 目录的对应路径下,逐个找即可。这套倒推法比在 IDE 里全局搜索关键词快得多。

再讲一个"我的订单"功能的加法。假设你要给登录用户加一个查看历史订单的页面。第一步,在数据库里确认有订单表 ticket_info,字段至少包含用户 ID、航班号、下单时间。第二步,打开 CommonDao,加一个方法 findOrdersByUserId(int userId),SQL 是按用户 ID 查订单表。第三步,新建一个 OrderServlet 或者在 MainServlet 里加一个分支,收到请求后调 DAO,把订单列表塞进 request。第四步,新建 order_list.jsp,用 JSTL 的 <c:forEach> 遍历订单列表渲染成表格。第五步,在 main.jsp 或用户菜单里加一个入口链接指向订单 Servlet 的映射路径。

这五步走完,功能就通了。验证时我习惯分三层:第一层看 Tomcat 控制台有没有异常堆栈;第二层直接访问 Servlet 的 URL,看返回的页面 HTML 里有没有预期的数据;第三层用 Navicat 单独执行 DAO 里的 SQL,确认数据本身是存在的。如果页面没数据,先查 SQL,再查 JSP 的 EL 表达式,最后才查 Servlet 的转发路径——这个排查顺序能帮你省大量时间。

从那以后,我每次改这类 JSP 源码都会强制走一遍固定动作:改 Java 先编译再重启,改 JSP 只刷新页面不重启,改数据库先备份再执行,改 web.xml 一定检查标签配对。老项目没有热部署,每一步都得给足耐心。这份源码作为学习样本,最大的价值就是让你在低成本的试错里把这些教训提前踩一遍,希望对你有帮助。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询