
简介面向Java课程设计与毕业设计的酒店宾馆管理系统完整项目包基于Java Swing搭建GUI界面覆盖登录注册、客房管理、入住退房、预订登记、用户信息维护等核心业务模块。源码与数据库脚本整合在一个ZIP内解压导入即可运行适合需要快速交付高分课设或练习Swing桌面应用开发的学生。压缩包共370个文件主要包括64个Java源文件、131个class编译文件、130个png界面图片另有SQL数据库脚本、工程配置文件和依赖JAR包整体约43.65MB。目前已有432人学习下载。除可直接复用的完整代码外包内还提供数据库建表初始化语句与项目目录结构便于对照学习Java Swing的事件处理、界面布局及数据访问层实现细节也有助于在此基础上二次扩展。1. 别急着解压先搞清楚这个课设到底给了你什么拿到一个《基于Java swing带GUI界面的酒店宾馆管理系统源码数据库95分以上课设.zip》很多人第一反应是解压、点开、看能不能跑。说实话这类包在课设交易里非常常见但它的价值不在于“能跑”而在于你怎么把它变成自己能讲清楚、能答上问、能拿高分的东西。这类项目的本质是用Java Swing搭建桌面端界面配合MySQL或SQL Server这类关系型数据库完成酒店日常业务包括房间管理、客人入住、退房结账、预订登记等。它既能覆盖Java基础语法、面向对象、事件监听这些教学重点又能体现JDBC数据库操作和界面布局能力所以是课设的常青树选题。适合正在做Java课程设计、需要快速落地一个完整Demo的在校生也适合想复习Java桌面开发的初级开发者。但我要先泼一盆冷水如果你只管把它跑起来答辩时老师一问“登录逻辑在哪”“数据表为什么这么设计”就答不上来那这个包就真成了黑匣子再高的分也救不了你。接下来我从项目结构、环境搭建、数据库连接、常见坑到答辩验证一步一步拆给你看。2. 把酒店管理系统拆开看三层结构为什么是课设最优解拿到项目第一件事不是急着运行而是先搞清楚这套系统是怎么组织的。一个能拿高分的Swing课设代码结构通常不是你想象的那样——“把所有SQL写进按钮事件里拉倒”而是按三层结构组织界面层、业务逻辑层、数据访问层。这种分层不是一个装饰它直接决定老师愿不愿意给你高分。2.1 界面层、业务层、数据层各干什么一个典型的Swing酒店管理系统源码包打开后你能看到类似的包结构com.hotel.ui 存放所有窗体类比如 LoginFrame、MainFrame com.hotel.service 存放业务逻辑类比如 RoomService、OrderService com.hotel.dao 存放数据库操作类比如 RoomDao、UserDao com.hotel.entity 存放实体类比如 Room、Guest、Order com.hotel.util 存放工具类比如 DBUtil、StringUtil这套结构对应到实际功能就是用户在前台窗口点一个“入住登记”按钮界面层把文本框里的数据收集起来传给业务层业务层做合法性校验比如身份证号是否为空、房间是否已被占用然后调用数据访问层的insert方法把数据写进数据库。好处很明显如果入住和退房要改业务规则只改service层不用动界面如果MySQL要换SQL Server只改dao层和DBUtil界面完全不动。我见过不少课设把SQL散落在十几个按钮事件里那种项目一旦老师让你加一个“按房型筛选房间”的功能你就得翻遍所有窗口类找代码分分钟翻车。2.2 数据表设计先看这几张核心表数据库脚本是整个项目的灵魂课设评分时老师一定会看你的表结构。一个酒店管理系统无论功能多少这几张表是标配CREATE TABLE room_type ( id INT PRIMARY KEY AUTO_INCREMENT, type_name VARCHAR(20) NOT NULL COMMENT 房型如单人间/标准间, price DECIMAL(10,2) NOT NULL COMMENT 门市价, remark VARCHAR(255) ); CREATE TABLE room ( id INT PRIMARY KEY AUTO_INCREMENT, room_no VARCHAR(10) NOT NULL COMMENT 房号, type_id INT NOT NULL COMMENT 外键关联房型表, status INT DEFAULT 0 COMMENT 0空闲 1已入住 2已预订 3维修, FOREIGN KEY (type_id) REFERENCES room_type(id) ); CREATE TABLE guest ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20) NOT NULL, id_card VARCHAR(18) NOT NULL COMMENT 身份证号, phone VARCHAR(11), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE orders ( id INT PRIMARY KEY AUTO_INCREMENT, room_id INT NOT NULL COMMENT 外键关联房间, guest_id INT NOT NULL COMMENT 外键关联客人, checkin_time DATETIME NOT NULL COMMENT 入住时间, checkout_time DATETIME COMMENT 退房时间, deposit DECIMAL(10,2) COMMENT 押金, total_amount DECIMAL(10,2) COMMENT 最终结算金额, status INT DEFAULT 0 COMMENT 0进行中 1已退房, FOREIGN KEY (room_id) REFERENCES room(id), FOREIGN KEY (guest_id) REFERENCES guest(id) );注意看这里的三处细节这也是答辩时老师最爱问的点。第一room表里没有直接存房间价格而是通过type_id外键关联room_type表这叫避免数据冗余。第二guest和orders分开而不是把客人信息直接写进订单表这样同一个客人第二次入住不用重复录入。第三状态字段用int而不是varchar比如房间状态0、1、2、3对应文档里说明的文字程序里维护一个状态映射即可查询和统计都更高效。2.3 登录和权限最容易被忽视的加分项很多课设的登录就是一张user表一个用户名一个密码一个角色字段。请不要止步于此——酒店管理系统有一个天然的权限诉求前台只能做入住、退房、预订而管理员能看统计报表、修改房价、管理员工。哪怕你只做“管理员和前台两种角色”也要在登录后的主界面里根据角色决定菜单是否可见。用户表的最小设计长这样CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(20) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, real_name VARCHAR(20), role VARCHAR(10) DEFAULT 前台 COMMENT 管理员/前台 );密码字段不建议明文存储课设范围内用MD5或SHA-256加密一下即可项目里如果已有加密工具类直接复用。登录窗口拿到账号密码后先做一次空值校验再查库比对密码摘要匹配通过后把当前用户对象挂到全局会话里后面所有窗口都能读取当前操作人。这么做在答辩时是有说服力的——“如何证明某个操作是谁做的”你就说订单表里加了operator字段登录后写入当前用户名这就是一个完整的责任溯源链条。3. 本地跑通整套源码环境搭建与项目导入全过程现在进入最实操的部分怎么让这个zip在你的电脑上跑起来。这一步卡住的人最多但翻来覆去就是几个原因JDK版本不匹配、数据库连不上、缺少依赖包、字符集乱掉。下面按我平时带人的顺序一步步来。3.1 JDK、数据库版本先对齐不然后面全是泪Swing项目有一个特点它依赖的JDK内库非常传统从JDK 8到JDK 17都能编译但问题往往出在数据库驱动和JDBC连接的兼容性上。我一般建议的统一基线是JDK 8如jdk1.8.0_211、MySQL 5.7或8.0、Navicat或SQLyog做可视化操作。如果项目里用的是mysql-connector-java 5.1.x驱动而你的MySQL装的是8.0连接时大概率会报“Communications link failure”或者时区错误。解决办法要么把驱动升级到8.0系列版本要么在连接URL里加上时区参数这个下面单独讲。检查你电脑上的JDK版本打开命令行输入java -version javac -version如果javac提示“不是内部或外部命令”说明JAVA_HOME和PATH没配好。这一步不用慌重新设置环境变量JAVA_HOME指向JDK安装目录然后在PATH里追加%JAVA_HOME%\bin重开命令行验证即可。记住一个判断标准能同时看到java和javac的版本号才算配置成功。3.2 用IDEA导入项目而不是直接双击Java文件拿到源码不要用记事本一个个打开直接导入到IDE里。IntelliJ IDEA导入这类老项目的常见做法有两种如果zip里解压出来就是完整工程目录且能看到.idea目录或.project、.classpath文件那就选择“Open”直接打开如果里面只有src文件夹和一堆Java文件那就选择“New Project from Existing Sources”导入。导入后第一件事是配置Project Structure快捷键CtrlAltShiftS里的Project SDK确认选择的是你的JDK 8。然后看Modules这一页如果项目里lib下放着mysql驱动jar包需要在这里把jar添加为依赖如果没有lib目录那就在“Libraries”里新建一个把驱动jar指过去。这一步不做后面运行会报ClassNotFoundException: com.mysql.cj.jdbc.Driver这是新手第一道坎所有数据库操作全部瘫痪。3.3 初始化数据库脚本导入的两种路径数据库脚本通常在zip里的db或sql文件夹文件名一般是hotel.sql、hotel_db.sql之类。拿到脚本后打开Navicat新建一个数据库名字建议和脚本里的CREATE DATABASE语句保持同名然后右键选择“运行SQL文件”把脚本导进去。如果你没有可视化工具命令行操作也可以打开MySQL的bin目录执行mysql -u root -p hotel.sql执行完毕后用show tables;验证一下表是否都建好了。注意脚本里如果有USE xxx;语句它会自动切换到对应数据库不用手动指定。导入时报错多半是两种一是脚本里带了DROP DATABASE IF EXISTS而当前连接用户没权限二是字符集声明和MySQL实际配置不一致导致中文乱码。导入成功后手工往room_type、room表里插几条数据是值得的因为空数据状态下登录进去什么都看不到不仅测试不方便答辩演示时也撑不起场面。演示数据的SQL我放到第6章专门讲。3.4 修改连接参数让程序找到你的数据库这步是Java课设里最经典的拦路虎十个人里得有五个人在这卡住。找到工具类DBUtil或者DBConnection里面有一段类似这样的代码Class.forName(com.mysql.jdbc.Driver); String url jdbc:mysql://localhost:3306/hotel_db?useUnicodetruecharacterEncodingutf8; String user root; String password root;Class.forName这行负责加载驱动类。注意5.1版本的驱动类名是com.mysql.jdbc.Driver而8.0版本的驱动类名变成了com.mysql.cj.jdbc.Driver如果你手里的jar是版本8.0而代码里还写的旧类名直接报ClassNotFoundException。url里的localhost:3306/hotel_db分别指数据库地址、端口、数据库名改Database Name就够了。user和password按你的MySQL实际登录凭据填。很多源码包喜欢把密码写死成root但你自己电脑上可能设了别的密码不改就是连不上。改完这四样就可以尝试运行了。如果主类找不到就看类里的main方法在哪个类——Swing项目通常入口是一个LoginFrame带一个main方法。右键运行看到登录窗口弹出来的那一刻说明第一关已经过了。4. 数据库连接与增删改查不把SQL写死在界面里的工程习惯跑起来只是开始能讲清楚增删改查才是拿高分的关键。我见过太多课设窗口做得花里胡哨但老师一打开代码发现SQL全写在按钮监听器里印象分直接腰斩。这一章教你写出一套让老师愿意多看两眼的DAO层。4.1 DAO类里的增删改查长什么样以房间管理为例一个正常的RoomDao包含以下标准方法queryAll、queryById、add、update、delete、可按条件查询。下面是典型的查询所有空闲房间的方法用JDBC预编译去写public ListRoom queryAvailableRooms() { ListRoom list new ArrayList(); String sql SELECT r.id, r.room_no, r.type_id, rt.type_name, rt.price FROM room r INNER JOIN room_type rt ON r.type_id rt.id WHERE r.status 0; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { while (rs.next()) { Room room new Room(); room.setId(rs.getInt(id)); room.setRoomNo(rs.getString(room_no)); room.setTypeId(rs.getInt(type_id)); room.setTypeName(rs.getString(type_name)); room.setPrice(rs.getBigDecimal(price)); list.add(room); } } catch (SQLException e) { e.printStackTrace(); } return list; }这里有两个关键点你需要仔细看。第一是采用PreparedStatement而不是写死SQL拼接避免SQL注入的同时还利用了预编译机制这条在答辩时主动说出来非常加分。第二是查询联表把type_name和price直接带出来了这样界面层拿到Room对象直接显示不必再回表查房型价格。4.2 写操作要手动控制事务多表关联的写操作——比如办理入住时要往guest表插入客人信息、往orders表插入订单、还要把room表的status改成1——这三步必须放在同一个事务里不能只成功一半。如果客人信息插入成功但房间状态没改成已入住那这套系统就会出现一间房被重复入住的严重Bug。事务控制在JDBC里是这么做的public boolean checkIn(Order order, Guest guest) { Connection conn DBUtil.getConnection(); try { conn.setAutoCommit(false); // 关闭自动提交 // 第一步插入客人信息 String sqlGuest INSERT INTO guest(name, id_card, phone) VALUES(?,?,?); PreparedStatement ps1 conn.prepareStatement(sqlGuest, Statement.RETURN_GENERATED_KEYS); ps1.setString(1, guest.getName()); ps1.setString(2, guest.getIdCard()); ps1.setString(3, guest.getPhone()); ps1.executeUpdate(); ResultSet keys ps1.getGeneratedKeys(); int guestId 0; if (keys.next()) guestId keys.getInt(1); // 第二步插入订单 String sqlOrder INSERT INTO orders(room_id, guest_id, checkin_time, deposit, status) VALUES(?,?,NOW(),?,0); PreparedStatement ps2 conn.prepareStatement(sqlOrder); ps2.setInt(1, order.getRoomId()); ps2.setInt(2, guestId); ps2.setBigDecimal(3, order.getDeposit()); ps2.executeUpdate(); // 第三步修改房间状态为已入住 String sqlRoom UPDATE room SET status1 WHERE id?; PreparedStatement ps3 conn.prepareStatement(sqlRoom); ps3.setInt(1, order.getRoomId()); ps3.executeUpdate(); conn.commit(); return true; } catch (SQLException e) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } e.printStackTrace(); return false; } finally { try { conn.setAutoCommit(true); } catch (SQLException e) { e.printStackTrace(); } DBUtil.close(conn); } }setAutoCommit(false)开启手工事务commit()提交rollback()回滚finally里恢复自动提交并关闭连接。这套代码建议你背到条件反射——面试也好课设答辩也好事务是必问题目。重点跟老师讲解三步操作中任何一步抛异常前面已经执行成功的SQL也不会生效数据库不会出现脏数据。4.3 连接参数设置四个必调参数一次说清JDBC连接URL里的参数不是摆设每个参数背后都有具体坑。参数建议值作用与坑点useUnicodetrue配合characterEncoding使用缺失时中文可能变问号characterEncodingutf8和数据库端字符集保持一致不一致则乱码useSSLfalse本地开发设为false否则MySQL 8.0会警告SSL连接serverTimezoneAsia/ShanghaiMySQL 8.0必须设置缺失时DateTime字段解析报错把这些参数拼成完整URL就是String url jdbc:mysql://localhost:3306/hotel_db ?useUnicodetruecharacterEncodingutf8 useSSLfalseserverTimezoneAsia/Shanghai;注意连接信息不要散落在各个DAO类里统一写在DBUtil的静态常量中改一处全局生效。这是我强调了很多次的做法——一个项目里如果出现了三份不同的数据库密码那一定是架构腐烂的开始。5. 课设最常翻车的5个细节现象、原因与后悔药这一章全是血泪经验。以下问题我在不同人的课设里反复见过每个都足以让你的程序当场崩溃或让老师对你的印象打折。5.1 窗口弹出来但点登录没反应这是一个非常典型的现象界面正常显示输入用户名密码后点登录程序像死了一样控制台也没有任何输出。原因通常是数据库连接超时——MySQL没启动、连接地址不对、或者密码错误而代码里把异常吞掉了。我见过有源码在登录按钮的监听器里只写了e.printStackTrace()这段错误信息打印在控制台你如果不切到控制台窗口根本看不见。解决方法是点击登录后立刻看IDE下方控制台有没有红色异常堆栈。如果是Access denied for user rootlocalhost那就是密码不对如果是Unknown database hotel_db那就是数据库名没创建好。先看异常再动手比瞎猜效率高得多。5.2 中文字符全部变成问号数据库里存进去的中文是问号界面显示的也是乱码这是课设里第二高频问题。原因涉及三层字符集数据库表字段的字符集、JDBC连接URL里的characterEncoding、以及Java源文件的编码。解决方法从源头一层层查。先确认数据库表和字段用了utf8或utf8mb4然后把JDBC URL里加上characterEncodingutf8最后检查IDEA右下角当前文件编码是否为UTF-8老项目里如果是GBK源码在UTF-8环境下打开中文字符串常量会显示乱码这时选择File Encoding里的“Reload in GBK”能把源码恢复正常。三个地方都对了中文乱码不可能出现。5.3 日期控件怎么都取不到值Swing的日期输入经常用第三方组件JCalendar里的JDateChooser常见的翻车方式是点击日期选择器选了日期但提交时getDate()返回null。原因是这个组件需要正确的初始化流程某些环境下如果不先调用setDateFormatString(yyyy-MM-dd)组件内部格式化器没有被正确赋值。常见的可靠写法是JDateChooser chooser new JDateChooser(); chooser.setDateFormatString(yyyy-MM-dd); chooser.setPreferredSize(new Dimension(150, 28));取日期时用SimpleDateFormat配套转换Date date chooser.getDate(); SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd HH:mm:ss); String checkinTime sdf.format(date);另外老版本的JCalendar和JDK 8以上高版本配合时可能出现日期面板不弹出的边界问题如果遇到优先换用高版本的JCalendar jar包。5.4 房间状态改了但列表不刷新办理入住后回到房间列表一看那个房间还是显示“空闲”。这不是数据写错了而是界面的JTable没有刷新数据模型。Swing的JTable显示的是TableModel里的快照不是实时读数据库的数据库变了它不会自己知道。解决办法是在窗口重新显示或每次操作完成后重新调用查询方法用新的List构建TableModel再调table.setModel(newModel)。如果用的是DefaultTableModel也可以先setRowCount(0)清空所有行再逐行addRow。你的代码里每个“增删改”操作成功后都应该主动触发一次列表刷新而不是指望组件自己感知。5.5 打包成jar后运行提示找不到主类这属于交作业前最后一哆嗦。在IDEA里能正常运行但导出jar后双击没反应或提示NoClassPathEntry。原因有两个一是Swing项目的资源文件存在src外jar包没把resources目录打进去二是mysql驱动和JCalendar的jar没有作为依赖打包进最终产物。要稳妥地解决最简单的方式是Artifacts配置里选择“extract directory”方式把所有依赖jar解包合进一个fat jar这样单文件双击就能跑。然后进入jar的同级目录打开命令行执行java -jar xxx.jar如果双击不能启动多半是jar里MANIFEST.MF的Main-Class路径写错用压缩工具打开jar检查META-INF目录即可发现。能在你电脑上单文件启动换台电脑才能保证评委也能跑起来。6. 给课设答辩加分的验证技巧让老师看一次就信服你费这么多力气跑通的项目最终是在答辩现场被打分的所以最后教你三个我实践过有效的验证技巧让你的系统不只是“能点”而是“看得懂”。第一准备一段有故事性的演示数据。不要登录进去只有空荡荡的界面。我先造好五六个房型把楼层、朝向、价格都设计得真实一点再预置两位常客的档案姓名电话身份证齐全。演示时从“客人来电订房”开场现场走一遍登记、排房、入住、换房、退房结算的完整链路。每一步都对应到订单表状态和房间状态的可见变化。第二把关键SQL的执行结果痕迹留在桌面上。答辩时老师问到“这个系统怎么保证不超售”你现场打开数据库执行这条查询SELECT room_no, CASE status WHEN 0 THEN 空闲 WHEN 1 THEN 已入住 WHEN 2 THEN 已预订 ELSE 维修 END AS 状态 FROM room ORDER BY room_no;表格一输出房间状态一目了然。再把orders表按入住时间排个序展示一下历史订单这就让老师看到你的数据不是摆样子的而是真实在流转。第三做一个异常路径演示。我每次答辩都会刻意演示一遍“错误密码登录被拒绝”和“办理入住时身份证号空着点提交被拦截”这不是自曝其短而是在展示系统的健壮性。空值校验、格式校验、重复数据拦截这些代码里做的防守在演示时是实实在在的加分项比嘴上说“我做了校验”有力得多。最后说一个个人习惯项目在交之前我会把整个数据库导出一次SQL备份存到zip里再把一份说明文档写在readme里里面写清楚JDK版本、数据库端口、初始账号密码、导入步骤。这样做的直接好处是即使换台电脑十分钟内也能从零恢复整个环境。答辩现场最怕的就是设备不配合提前把后悔药备好永远比临场发挥靠谱。希望这些经验对你有用少踩一个坑就多一分拿到高分的把握。本文还有配套的精品资源点击获取