ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Java大作业酒店管理系统实战:JDBC+MySQL+Swing实现教程

Java大作业酒店管理系统实战:JDBC+MySQL+Swing实现教程 简介面向Java课程设计提供酒店管理系统期末大作业完整源码与设计报告适合需要完成课程设计或复习Java编程的学生。项目覆盖客房预订、入住登记、退房处理、账单结算等业务从类与对象、继承多态到JDBC数据库交互均有涉及并融入异常处理、文件输入输出、多线程同步和工厂、单例等设计模式。资源包共29个文件含11个Java源文件实现核心业务类与JavaFX界面、1份doc设计报告便于答辩与文档撰写、4张jpg/png图片界面图标与背景及若干快捷方式压缩包约9.7MB。目前已有1641人学习下载。读者可对照源码理解SQL增删改查、Swing/JavaFX组件布局、MVC分层思想也可借助设计报告中的模块划分、流程梳理和数据库表结构说明快速掌握完整项目从建模到实现的过程。整包目录按代码、报告、素材分类结构清晰能为课程答辩和同类管理系统开发提供直接参考。1. 为什么Java期末大作业清单里总出现酒店管理系统这门课真正要考的能力Java期末大作业题目里酒店管理系统出现频率高得不像巧合。任课老师喜欢出这个题不是因为它简单而是因为它能同时覆盖 Java 课程设计最在意的三件事面向对象建模、JDBC 操作数据库、Swing 界面的增删改查。你的交付物是“源代码设计报告”源代码证明你会写 Java设计报告证明你懂为什么要这么写。这个系统不追求算法难度追求的是业务闭环房间能被预订、入住、退房、结算一条完整的数据流在界面、业务对象、数据库表之间走通。适合谁做所有需要交 Java 课程设计或毕业设计管理类题目的本科生尤其是 Java 基础还没形成肌肉记忆、想靠一份能真正运行的项目把知识串起来的人。本文给的是可以直接照着落地的方案技术栈选型、建表 SQL、标准 DAO 写法、事务预订代码以及期末答辩最容易踩的五个坑。2. 把技术栈定死再动手界面选Swing还是JavaFX数据存MySQL还是SQLite2.1 界面层为什么课程作业仍然以Swing为主流期末大作业的界面层我一般直接建议用 Swing除非老师明确要求 JavaFX。原因很实际机房和大多数学生电脑上的 JDK 版本参差不齐Swing 作为 JDK 自带的组件不需要额外配置就能在任何 JDK 8 及以上的环境运行JavaFX 在 JDK 8 之后从 JDK 中剥离了需要单独下载 SDK 和配置模块路径单是这一条就够期末阶段劝退一半人。Swing 的 JFrame、JTable、JButton 三个组件覆盖了酒店管理系统的核心交互左侧导航菜单切模块中间表格展示房间或订单底部放按钮做新增、修改、删除。这种布局实现成本低而且符合老师对「管理系统」这个概念的直觉。值得注意的一个点是 JDK 版本与代码写法匹配。如果你用的是 JDK 11switch可以写成表达式String statusText switch (room.getStatus()) { case 0 - 空闲; case 1 - 已预订; case 2 - 已入住; case 3 - 维修中; default - 未知; };这段switch表达式从 Java 14 才正式稳定如果你的环境是 JDK 8就必须改回传统写法否则编译直接报错String statusText; switch (room.getStatus()) { case 0: statusText 空闲; break; case 1: statusText 已预订; break; case 2: statusText 已入住; break; case 3: statusText 维修中; break; default: statusText 未知; break; }选 Swing 时顺手确认一下 JDK 版本写符合版本的语法这是期末大作业源代码能一次运行过关的第一道门。2.2 存储层选型MySQL 的安装、建库与 JDBC 连接参数存储层选 MySQL 还是 SQLite取决于老师对课程设计的验收方式。如果验收现场要求检查数据库中的数据、看设计报告里的 ER 图或者让你演示增删改查后刷新数据MySQL 是更安全的选择SQLite 适合单机免配置场景但老师对它的接受度明显低于 MySQL。MySQL 环境的搭建课程作业场景下最省时间的配置是 MySQL 8.0 Connector/J 8.x。安装后先建库注意字符集必须显式指定CREATE DATABASE IF NOT EXISTS hotel_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE hotel_db;utf8mb4 和 utf8 的区别在于表情符号和部分生僻字的存储但更重要的是它从源头避免了一部分中文乱码问题。乱码问题会在第 5 章展开讲这里先记住结论库、表、连接 URL 三处字符集要一致。JDBC 连接配置中连接 URL 的写法有讲究String url jdbc:mysql://localhost:3306/hotel_db ?useUnicodetrue characterEncodingutf8 serverTimezoneAsia/Shanghai useSSLfalse allowPublicKeyRetrievaltrue;几个参数说明一下useUnicodetrue与characterEncodingutf8是中文传输的保障serverTimezoneAsia/Shanghai解决 MySQL 8 的时区报错allowPublicKeyRetrievaltrue配合useSSLfalse解决 MySQL 8 的 caching_sha2_password 认证时的连接失败。这些参数如果抄网上老教程经常漏掉最后一个导致本地连接报错这是很常见的翻车点。2.3 包结构设计实体类、DAO、工具类、界面层各归其位酒店管理系统虽然只有几千行代码但设计报告里要展示“分层思想”所以源代码的包结构不能乱。我建议按五个包组织这正好对应面向对象编程 Java 课程反复强调的职责单一原则com.hotel ├── entity // Room, Customer, Reservation, Bill 实体类 ├── dao // RoomDAO, CustomerDAO, ReservationDAO, BillDAO ├── util // DBUtil 数据库连接工具类 ├── ui // MainFrame, RoomPanel, ReservationPanel 等界面类 ├── service // ReservationService 业务逻辑层可选事务放这里实体类是数据库表的直接映射字段类型与数据库列类型保持对应关系比如数据库的 DECIMAL 对应 Java 的 BigDecimalDATE 对应 java.time.LocalDate如果你用 JDBC 4.2 及以上或 java.sql.Date。DAO 层只负责 SQL 交互一个方法对应一个业务动作findAll、findById、insert、updateStatus。界面层不允许写 SQL这是设计报告里“分层架构”得分的关键也是答辩老师翻代码时大概率会看的地方。service 层在期末作业里可不做独立分层但如果你想让报告上一个档次把预订的事务逻辑单独拆到 ReservationService 里是成本最低的加分项。第 4 章的事务代码就是按这个结构写的。3. 房间、客户、预订、账单四张核心表数据库设计与状态流转3.1 四张核心表的建表语句与字段说明酒店管理系统的数据库设计四张表是标配room房间、customer客户、reservation预订、bill账单。别贪多期末报告不鼓励把表拆到七八张四张表已经能把整个业务闭环说清楚而且 ER 图画出来干净、答辩追问不慌。完整建表语句如下直接在 MySQL 的 SQL 窗口中执行-- 房间表 CREATE TABLE room ( room_id INT PRIMARY KEY AUTO_INCREMENT, room_number VARCHAR(10) NOT NULL UNIQUE COMMENT 房间号如 501, room_type VARCHAR(20) NOT NULL COMMENT 单人间/双人间/套房, price DECIMAL(10,2) NOT NULL COMMENT 门市价, status TINYINT DEFAULT 0 COMMENT 0-空闲 1-已预订 2-已入住 3-维修, floor INT DEFAULT 1 COMMENT 所在楼层 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 客户表 CREATE TABLE customer ( customer_id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL COMMENT 姓名, phone VARCHAR(20) COMMENT 手机号, id_card VARCHAR(18) COMMENT 身份证号, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 预订表 CREATE TABLE reservation ( reservation_id INT PRIMARY KEY AUTO_INCREMENT, room_id INT NOT NULL, customer_id INT NOT NULL, check_in_date DATE NOT NULL, check_out_date DATE NOT NULL, total_price DECIMAL(10,2) COMMENT 按入住天数*单价计算, status VARCHAR(10) DEFAULT BOOKED COMMENT BOOKED-已预订 CHECKED_IN-已入住 CHECKED_OUT-已退房 CANCELLED-已取消, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (room_id) REFERENCES room(room_id), FOREIGN KEY (customer_id) REFERENCES customer(customer_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 账单表 CREATE TABLE bill ( bill_id INT PRIMARY KEY AUTO_INCREMENT, reservation_id INT NOT NULL, amount DECIMAL(10,2) NOT NULL COMMENT 实际结算金额, pay_method VARCHAR(10) COMMENT 现金/支付宝/微信/银行卡, pay_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (reservation_id) REFERENCES reservation(reservation_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;字段设计的几个关键决策room 表用status整数状态而不是字符串因为 TINYINT 在设计报告里更容易画状态图而且 Java 侧映射简单reservation 和 bill 之间用外键建立关联数据修改时数据库层就能拦住非法操作价格字段统一使用 DECIMAL避免 float/double 导致的精度问题这是设计报告里写“数据类型选择理由”时可以直接抄的素材。3.2 预订状态流转与“一间房不能被订两次”的实现约束酒店管理系统的业务核心是房间状态流转空闲 → 已预订 → 已入住 → 已退房中间任意时刻都可能取消取消后回到空闲或维修。设计师需要同时守住两件事界面按钮的状态切换和数据库层的状态校验。最常见的问题是“一间房被订两次”。学生实现时容易只在前端判断先查询房间状态为空闲再弹出确认对话框然后执行 INSERT。但两个用户同时操作时两个请求都可能通过查询各自认为房间空闲然后插入两条预订。这在课程演示时不容易暴露但答辩老师一定会追问“并发怎么办”。数据库层面需要做三件事reservation 表建(room_id, check_in_date, check_out_date)的索引用于查询预订时用事务加行锁更新房间状态时用带条件的 UPDATE。具体实现放在第 4 章这里先把原理记清楚事务保证“查询状态 → 写入预订 → 更新房间状态”这三步是一个原子操作SELECT ... FOR UPDATE在事务中锁定该房间记录让并发的第二个请求必须等第一个提交后才能读到状态。3.3 设计报告怎么写ER 图、数据流图、功能模块说明的编排设计报告不是代码的复述它要回答“为什么这么设计”。期末报告相对通用的结构是七部分摘要、需求分析、总体设计、详细设计、测试、总结体会、参考文献。需求分析部分不要写“系统要实现酒店管理”而要写角色和用例比如“前台的角色可以完成开房登记、退房结算管理员可以查询营业报表”。总体设计部分放系统架构图和功能模块划分——把界面层、DAO 层、数据库层画成三层配一段文字说明各层职责。详细设计部分放 ER 图和四张表的结构这是报告的浏览重点。这里说一个常见误用很多人的报告把 ER 图画成四个互不相连的方框。设计报告的 ER 图要把外键关系画出来room 到 reservation 是一对多customer 到 reservation 是一对多reservation 到 bill 是一对一。这张图画对了老师就知道你是真的理解了数据结构。数据流图则建议画两层第 0 层是“用户 → 系统 → 数据库”的顶层流第 1 层展开成“预订操作 → 房间状态检查 → 数据落库”的细化流不用画太复杂。另外设计报告中“测试”部分常被忽略其实这里能轻松拿分。提供一个测试用例表输入预订信息、点击保存、刷新房间列表、断言房间状态变为已预订。这样填三个用例报告的完整性就有保障。报告页数控制在 1215 页最合适太薄显得工作量大太厚老师反而怀疑你抄模板。4. 从数据库到界面的完整实现DAO、事务预订与Swing表格绑定4.1 DBUtil 工具类JDBC 连接与资源关闭的可靠写法数据库连接代码在每个 DAO 里重复写是教材刚上课时的做法期末大作业指望这种代码拿分不现实。连接统一收敛到 DBUtil这是设计报告里给“代码复用”举例的最好材料。工具类代码如下package com.hotel.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/hotel_db ?useUnicodetrue characterEncodingutf8 serverTimezoneAsia/Shanghai useSSLfalse allowPublicKeyRetrievaltrue; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(Connection conn, Statement stmt, ResultSet rs) { if (rs ! null) { try { rs.close(); } catch (SQLException ignored) {} } if (stmt ! null) { try { stmt.close(); } catch (SQLException ignored) {} } if (conn ! null) { try { conn.close(); } catch (SQLException ignored) {} } } }参数说明Class.forName在静态块里只执行一次作用是确保 MySQL 驱动被加载这里类的全限定名必须与驱动 jar 版本匹配。MySQL 8 对应com.mysql.cj.jdbc.Driver如果你用的是 MySQL 5.x 的驱动则要写成com.mysql.jdbc.Driver这一点错了就是经典的ClassNotFoundException。close方法里为什么每个 close 单独 try-catch 而不是一段 try-catch 包住因为第一个 close 抛异常时后面的资源也必须关闭。这个写法看着啰嗦但能在答辩时说出理由反而是亮点。4.2 RoomDAO发现列表、按条件查询与 PreparedStatement 防注入DAO 层是最容易让源代码和设计报告脱节的一层。报告里写了“查询、添加、修改、删除”代码里就要真的有一个方法对应一个动作。以 RoomDAO 为例至少要有四个方法findAll()查全部房间、findByKeyword(keyword)按房号或类型模糊查询、insert(room)新增、updateStatus(roomId, status)更新状态。下面给的是带模糊查询的实现public class RoomDAO { public ListRoom findByKeyword(String keyword) { ListRoom list new ArrayList(); String sql SELECT room_id, room_number, room_type, price, status FROM room WHERE room_number LIKE ? OR room_type LIKE ? ORDER BY room_id; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { String likePattern % keyword %; ps.setString(1, likePattern); ps.setString(2, likePattern); try (ResultSet rs ps.executeQuery()) { while (rs.next()) { list.add(new Room( rs.getInt(room_id), rs.getString(room_number), rs.getString(room_type), rs.getBigDecimal(price), rs.getInt(status) )); } } } catch (SQLException e) { e.printStackTrace(); } return list; } public boolean updateStatus(int roomId, int status) { String sql UPDATE room SET status ? WHERE room_id ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, status); ps.setInt(2, roomId); return ps.executeUpdate() 0; } catch (SQLException e) { e.printStackTrace(); return false; } } }这段代码有两个必须说明的点。第一个是PreparedStatement配合?占位符而不是字符串拼接 SQL。用拼接写法在期末作业里大概率被答辩老师点名在搜索框输入 OR 11 --就能把整个房间表拖出来你要现场解释这不是不知道解释完还要能当场改成 PreparedStatement。第二个是try-with-resources语法Connection、PreparedStatement、ResultSet 都实现了 AutoCloseable方法结束后自动关闭不需要手动调 close。如果你的 JDK 是 8 以下版本把这个语法换成手动 close否则编译不过。4.3 预订事务从房间检查到状态更新的原子操作预订是酒店管理系统里唯一必须用事务的地方。我把整个流程放在ReservationService里界面层调用一个方法就能完成全部业务这也对应设计报告里的“业务逻辑与界面分离”。public class ReservationService { public boolean createReservation(Reservation reservation) { Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 1. 锁定房间行检查状态这里 FOR UPDATE 是并发控制的关键 String checkSql SELECT status FROM room WHERE room_id ? FOR UPDATE; int status -1; try (PreparedStatement ps conn.prepareStatement(checkSql)) { ps.setInt(1, reservation.getRoomId()); try (ResultSet rs ps.executeQuery()) { if (rs.next()) { status rs.getInt(status); } } } if (status ! 0) { conn.rollback(); return false; // 房间不是空闲状态 } // 2. 计算总价天数 * 房间单价 BigDecimal roomPrice BigDecimal.ZERO; String priceSql SELECT price FROM room WHERE room_id ?; try (PreparedStatement ps conn.prepareStatement(priceSql)) { ps.setInt(1, reservation.getRoomId()); try (ResultSet rs ps.executeQuery()) { if (rs.next()) { roomPrice rs.getBigDecimal(price); } } } long days ChronoUnit.DAYS.between( reservation.getCheckInDate(), reservation.getCheckOutDate()); reservation.setTotalPrice(roomPrice.multiply(BigDecimal.valueOf(days))); // 3. 写入预订记录 String insertSql INSERT INTO reservation (room_id, customer_id, check_in_date, check_out_date, total_price, status) VALUES (?, ?, ?, ?, ?, BOOKED); try (PreparedStatement ps conn.prepareStatement(insertSql)) { ps.setInt(1, reservation.getRoomId()); ps.setInt(2, reservation.getCustomerId()); ps.setDate(3, Date.valueOf(reservation.getCheckInDate())); ps.setDate(4, Date.valueOf(reservation.getCheckOutDate())); ps.setBigDecimal(5, reservation.getTotalPrice()); ps.executeUpdate(); } // 4. 更新房间状态为“已预订” String updateSql UPDATE room SET status 1 WHERE room_id ?; try (PreparedStatement ps conn.prepareStatement(updateSql)) { ps.setInt(1, reservation.getRoomId()); ps.executeUpdate(); } conn.commit(); return true; } catch (Exception e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } e.printStackTrace(); return false; } finally { if (conn ! null) { try { conn.setAutoCommit(true); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }逻辑说明按顺序走关闭自动提交后第一步SELECT ... FOR UPDATE是事务中的行级排他锁这个操作确保即使两个窗口同时点预订第二个事务只能等第一个提交或回滚后才能读到房间状态。第 2 步计算总价这里必须用 BigDecimal 而不是 double价格精度在账单模块会被严格检查。第 3 步插入预订记录第 4 步把房间置为已预订这两步要么都成功、要么都回滚绝对不能出现“预订记录存在但房间状态没变”的中间状态。注意ChronoUnit.DAYS.between需要java.time.LocalDate而 JDBC 的setDate接受java.sql.Date所以代码里用Date.valueOf()做转换。如果是 JDK 8 之前的版本这里授你使用 java.util.Date 和 SimpleDateFormat 计算天数差但既然你是期末大作业JDK 8 是底线直接用 LocalDate 是正解。4.4 RoomPanel 界面JTable 模型刷新与按钮事件绑定界面层用 Swing 的时候最容易写成“界面里的 SQL 满天飞”。其实界面层只需要三样东西一个表格的 TableModel、一组按钮、一个调用 DAO 的方法。以房间管理面板为例关注点是表格数据刷新。public class RoomPanel extends JPanel { private final JTable table; private final DefaultTableModel model; private final RoomDAO roomDAO new RoomDAO(); public RoomPanel() { setLayout(new BorderLayout()); model new DefaultTableModel( new String[]{房间号, 类型, 价格, 状态}, 0) { Override public boolean isCellEditable(int row, int column) { return false; // 表格不可直接编辑所有修改走按钮 } }; table new JTable(model); add(new JScrollPane(table), BorderLayout.CENTER); JPanel btnPanel new JPanel(); JButton btnRefresh new JButton(刷新); JButton btnModifyStatus new JButton(设为维修/空闲); btnPanel.add(btnRefresh); btnPanel.add(btnModifyStatus); add(btnPanel, BorderLayout.SOUTH); btnRefresh.addActionListener(e - reloadData()); btnModifyStatus.addActionListener(e - changeStatus()); reloadData(); } private void reloadData() { model.setRowCount(0); for (Room r : roomDAO.findAll()) { model.addRow(new Object[]{ r.getRoomNumber(), r.getRoomType(), r.getPrice(), statusText(r.getStatus()) }); } } private void changeStatus() { int row table.getSelectedRow(); if (row 0) return; int roomId roomDAO.findAll().get(row).getRoomId(); int newStatus JOptionPane.showConfirmDialog(this, 确定切换该房间状态, 提示, JOptionPane.YES_NO_OPTION) 0 ? 3 : 0; roomDAO.updateStatus(roomId, newStatus); reloadData(); } private String statusText(int status) { switch (status) { case 0: return 空闲; case 1: return 已预订; case 2: return 已入住; case 3: return 维修中; default: return 未知; } } }这个类的设计意图isCellEditable强制返回 false防止用户直接在表格单元格里改数据。切记默认的 DefaultTableModel 允许双击编辑单元格你直接把表格内容改了之后并没有对应的 SQL 更新会出现“界面上改了、数据库没改”的假数据问题而这个假数据刷新后又变回原样这是一类很典型的界面一致性翻车。所有修改都走按钮 DAO reloadData 这个闭环才是管理系统的正确姿势。状态切换的示例逻辑简化了一些但在你的作业里它起到的作用是打通“表格选择、按钮事件、DAO 调用、模型刷新”这条链路设计报告里的“界面层与数据层交互流程”就照这个写。5. 期末大作业避坑指南驱动、乱码、并发与报告代码不一致5.1 现象ClassNotFoundException: com.mysql.cj.jdbc.Driver 或连接超时你按下“连接数据库”按钮控制台直接抛java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver或者是Communications link failure连接超时。前者原因是驱动 jar 没有放进项目的 classpathEclipse 里要右键项目 → Build Path → Add External JARsIDEA 里要 File → Project Structure → Libraries 添加很多人在这一步只下载了 jar 忘了加进构建路径。后者原因是驱动类名与 MySQL 版本不匹配——MySQL 5.x 驱动写com.mysql.jdbc.Driver才对8.x 写com.mysql.cj.jdbc.Driver。如果你两个 jar 都加了服务器又换过端口同样报这个错用下面命令先确认 MySQL 服务在运行netstat -ano | findstr 3306Windows 上没看到 3306 监听就去服务管理器里启动 MySQL 服务。解决路径一句话先确认 jar 进 classpath再核对驱动类名最后确认 3306 端口被 MySQL 监听。5.2 现象存进去是英文查询出来是中文乱码控制台输出中文乱码乱码是期末演示现场最容易出现的社死瞬间。现象分两种数据库中中文显示正常但 Swing 表格显示乱码或者数据库里直接就是乱码。前者通常是 MySQL 连接 URL 少了characterEncodingutf8或者你把 URL 里的参数顺序写错了。后者是建库时没指定 UTF-8导致表以默认编码创建。解决路径要按三层排查第一层检查建库语句是否带DEFAULT CHARACTER SET utf8mb4第二层检查连接 URL三个参数useUnicodetrue、characterEncodingutf8、serverTimezoneAsia/Shanghai缺一不可第三层是控制台乱码那是 IDEA 或 Eclipse 的控制台编码问题属于 IDE 环境而非代码问题把 IDE 的文件编码和运行编码都切到 UTF-8。这条踩坑记录写进设计报告的“测试与问题解决”一节比任何参考说法都可信。5.3 现象快速双击“预订”按钮出现两条重复订单这个坑在第 4 章事务部分已经铺垫过。现象是连点两次预订按钮数据库中出现了两条同房间同时间段的预订记录。原因是界面上没有做按钮防重复提交更重要的是业务层没有事务和行锁两次请求各自独立完成了“查状态 → 插记录”的流程。解决分两层第一层在界面上预订成功后按钮置灰提示“正在处理中”第二层一定要有第 4.3 节的SELECT ... FOR UPDATE事务保护。课程演示时你可以故意打开两个窗体同时对一个房间做预订给老师展示只有一次成功这是答辩现场最稳妥的加分操作。期末系统的量级还到不了高并发老师看看的是你意识或不意识得到并发问题这个观念在报告“系统不足与改进”里写一句效果很好。5.4 现象直接在表格里改房间状态点“刷新”后数据变回原样这个坑是 Swing 初学者的示范错误。现象是你双击表格单元格改状态为“已预订”但点击刷新按钮后数据恢复成数据库里的原始值。原因是 DefaultTableModel 的单元格编辑只修改了表格前端展示的内容没有任何代码把修改写回数据库。解决方法是第 4.4 节的写法重写isCellEditable返回 false禁止前端直接编辑。所有修改操作必须通过显式按钮触发 DAO 方法。这个坑如果答辩前没有自查到现场演示时非常容易暴露因为你的手会不自觉地想去双击单元格改个值看看。把表格做成“只读展示”的角色所有编辑走弹窗或按钮这是 Swing 管理类项目的通行规则。5.5 现象设计报告和源代码对不上答辩被追问细节设计报告是提前写好的代码是不断改出来的到了答辩那天往往发现报告里写了“支持客户积分管理”代码里根本没这个模块报告里的 ER 图有三个外键数据库里只建了两个外键。这些不一致会在答辩提问环节成为致命伤。有一个做法可以避免报告定稿前逐模块核对打开源码文件看对应功能是否真实存在。与其在报告里多写一堆“功能亮点”不如只写代码里有的功能并把每个功能的调用链描述清楚。如果你确实想赶时间还有个可操作的办法报告里描述功能的部分全部按你 README 或目录结构来倒推而不是按想象来写。源代码里有什么报告就写什么源代码里没有的报告里留一个“不足与改进方向”。期末大作业的验收重点是“代码能跑、逻辑完整、报告与代码一致”这三点做到分数已经超过一半人。6. 把作业做成A级的三个技巧演示脚本、运行数据准备与自检问答期末大作业的现场验收通常只有几分钟怎么在几分钟内让老师确信你完成了整个系统我给每个学生的建议是准备一份“演示剧本”。第一步数据库初始化脚本要带上演示数据不要给老师看一张空表。初始化脚本里插入大约 10 个房间、5 个客户、3 个已完成的历史预订这样一启动程序界面上就有数据老师立刻知道你做了种子数据整个演示节奏会顺很多。初始化 SQL 插到建表语句后面并把这份脚本连同一份说明写好放在项目根目录下。第二步演示顺序要固定先进房间管理搜索“单人间”展示模糊查询然后新建一个客户开一笔新预订展示事务流程再去账单模块结算展示金额计算与状态翻转。演示路径不要跳来跳去老师看起来像真实业务流程提问时也会顺着流程自然走。第三步准备一个自检问答清单。把第 5 章的五个坑整理成问题连接失败怎么排查、乱码怎么排查、并发重复预订怎么防御、表格编辑为什么禁用、报告里的 ER 图与表结构是否一致。每个问题准备一段两句话的回答演示结束后自己把这些问题主动讲一遍体现出你对系统的完整理解。最后我已经养成一个习惯答辩前一周把数据库删掉重新执行一遍初始化脚本把项目从 Git 里克隆到新目录从零开始跑一遍全流程。这个动作能暴露掉所有“本地能跑、换机器不能跑”的隐藏问题——比如依赖 jar 没随项目走、连接用户名密码写死了、初始化脚本里数据缺失。期末大作业的价值不在代码行数而在你对自己的作品能不能每一步都给出合理解释这一点想通了你以后写任何 Java 应用都会记得“可复现”三个字。希望帮到你。本文还有配套的精品资源点击获取
返回列表