
简介本资源是一套完整的Java Web课程设计项目——酒店客房管理系统源码与数据库面向计算机专业本科生及Java初学者解决课程设计、期末大作业与Web开发实践场景中的系统建模、前后端交互与数据库集成问题。压缩包共73个文件含31个Java业务逻辑与Servlet类、17个HTML页面模板、4个CSS样式文件、3个SQL脚本含建库建表与初始化数据、2个PNG/GIF图标资源以及Maven配置、Git管理文件和字体资源等整体仅467KB轻量易部署。已有538人学习下载项目结构清晰采用主流SSMSpringSpringMVCMyBatis技术栈覆盖用户权限管理、客房/房型全生命周期维护、实时空房查询、在线订退房及按日期/房型的营业额统计等核心功能模块配套hotel.sql可一键导入运行无需修改即能通过Tomcat启动验证是高分交付与快速上手Web开发的典型教学案例。1. 为什么一个“酒店客房管理系统”课程设计能帮你把 JavaWeb 从课本概念焊进肌肉记忆这不是又一个 CtrlC/V 的课设模板。当你在 IDEA 里双击index.jsp看到登录框弹出来、输入账号密码后跳转到房间列表页、点击“预订”按钮瞬间数据库里booking_status字段变成1——那一刻你才真正摸到了 JavaWeb 的脉搏HTTP 请求怎么被 Servlet 拦住、JSP 怎么把 Java 对象渲染成 HTML、MySQL 的事务怎么保证“房态更新”和“订单插入”不丢不乱。这个项目不是为交作业而生它是你第一次亲手把“请求-响应-数据库-页面”这条链路从黑匣子拧开、看清每个齿轮咬合点的实战沙盒。适合刚学完 Servlet/JSP/MySQL 基础、但一写综合项目就卡在“不知道该先建哪个类”的同学也适合想用真实业务逻辑入住、退房、房态联动、押金计算反向夯实 JDBC 连接池、MVC 分层、表单校验这些易错点的自学者。它不依赖 Spring Boot 的自动配置所有底层细节都摊开在你眼皮底下——这恰恰是课程设计最该给你的东西不是跑通而是看懂每一步为什么必须这么走。2. 从零搭起骨架用最简路径跑通登录与首页验证环境与分层结构2.1 创建标准 JavaWeb 工程结构拒绝“一个包打天下”很多同学直接在src下堆满.java文件结果后期改个 DAO 层要翻遍整个工程。本项目采用经典三层架构表现层 JSP/Servlet、业务层 Service、数据层 DAO目录结构必须严格对齐HotelSystem/ ├── src/ │ ├── cn/hotel/web/ // Servlet 和控制器 │ ├── cn/hotel/service/ // 业务逻辑含事务控制 │ ├── cn/hotel/dao/ // 数据访问JDBC 操作 │ ├── cn/hotel/entity/ // POJO 实体类Room, Guest, Booking │ └── cn/hotel/util/ // 工具类DBUtil, DateUtil ├── WebContent/ │ ├── WEB-INF/ │ │ ├── web.xml // 配置 Servlet 映射关键 │ │ └── lib/ // 放入 mysql-connector-java-8.0.33.jar │ ├── index.jsp // 首页未登录跳转至此 │ ├── login.jsp // 登录页面 │ └── admin/ // 后台管理页面需登录后访问 └── db/ // 数据库脚本建表初始化数据提示web.xml是 Servlet 3.0 以下版本的命脉。即使你用 Tomcat 9也建议手动配置而非全靠注解——因为课程设计要求你理解容器如何加载 Servlet。servlet标签里load-on-startup设为1确保服务器启动时就初始化连接池避免首次请求慢。2.2 写死登录逻辑用最笨的办法验证流程闭环别急着连数据库先写一个“假登录”来确认前端到后端的链路是否通畅。在cn/hotel/web/LoginServlet.java中// java WebServlet(/login) public class LoginServlet extends HttpServlet { Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username req.getParameter(username); String password req.getParameter(password); // 【临时硬编码】模拟管理员登录成功 if (admin.equals(username) 123456.equals(password)) { // 将用户信息存入 session供后续页面判断登录状态 req.getSession().setAttribute(user, admin); resp.sendRedirect(admin/index.jsp); // 重定向到后台首页 } else { req.setAttribute(error, 用户名或密码错误); req.getRequestDispatcher(login.jsp).forward(req, resp); // 转发回登录页并带错误信息 } } }关键参数说明req.getParameter()获取表单字段注意name属性必须与 HTML 表单中input nameusername一致req.getSession().setAttribute()是会话管理核心user是 session key后续所有受保护页面都通过session.getAttribute(user) null判断是否已登录sendRedirect()是客户端跳转URL 变forward()是服务端跳转URL 不变此处登录失败必须用forward才能保留req.setAttribute(error)传递错误提示。2.3 在login.jsp中展示动态错误信息JSP 不是静态 HTML它的价值在于嵌入 Java 逻辑。login.jsp关键片段!-- jsp -- form actionlogin methodpost input typetext nameusername placeholder用户名 required input typepassword namepassword placeholder密码 required button typesubmit登录/button /form !-- 【重点】动态显示错误信息 -- c:if test${not empty error} div stylecolor:red;${error}/div /c:if必须做的三件事在login.jsp顶部声明 JSTL 标签库% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %将jstl-1.2.jar和standard-1.1.2.jar复制到WEB-INF/lib/下否则c:if报错web.xml的web-app根标签必须声明version3.0或更高否则 JSTL 不生效。血泪经验90% 的新手卡在 JSTL 不显示错误信息本质是 jar 包没放对位置或 web.xml 版本声明缺失。不要跳过这一步——它教会你“容器如何识别并加载标签库”。3. 让数据活起来用 JDBC 连接 MySQL实现房间查询与状态联动3.1 设计符合业务的数据库表结构附建表 SQL酒店系统的核心是“房态实时性”。一张room表必须包含状态字段且不能只靠status VARCHAR(10)这种模糊定义。我们采用整型状态码便于程序判断-- mysql CREATE TABLE room ( id INT PRIMARY KEY AUTO_INCREMENT, room_number VARCHAR(10) NOT NULL UNIQUE, -- 房间号如 A101 room_type ENUM(单人间,双床房,豪华套房) NOT NULL, price DECIMAL(8,2) NOT NULL, status TINYINT NOT NULL DEFAULT 0, -- 0:空闲, 1:已预订, 2:已入住, 3:待打扫, 4:维修中 floor INT NOT NULL, created_time DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 初始化测试数据 INSERT INTO room (room_number, room_type, price, status, floor) VALUES (A101, 单人间, 280.00, 0, 1), (A102, 双床房, 350.00, 1, 1), (B201, 豪华套房, 680.00, 2, 2);为什么用TINYINT而不用ENUMENUM在 JDBC 中取值需额外处理返回字符串而非数字而TINYINT直接映射 Javabyteswitch(status)判断房态更直观。课程设计阶段可读性 理论完美性。3.2 封装 JDBC 工具类解决连接泄漏与性能瓶颈手写new Connection()是灾难源头。DBUtil.java必须实现连接复用// java public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/hotel?useSSLfalseserverTimezoneAsia/Shanghai; private static final String USER root; private static final String PASSWORD 123456; // 【关键】使用静态块初始化连接池简易版 private static DataSource dataSource; static { HikariConfig config new HikariConfig(); config.setJdbcUrl(URL); config.setUsername(USER); config.setPassword(PASSWORD); config.setMaximumPoolSize(20); config.setMinimumIdle(5); config.setConnectionTimeout(30000); config.setIdleTimeout(600000); config.setMaxLifetime(1800000); dataSource new HikariDataSource(config); } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); // 从此不再 new Connection() } public static void close(AutoCloseable... resources) { for (AutoCloseable r : resources) { if (r ! null) { try { r.close(); } catch (Exception e) { e.printStackTrace(); } } } } }必须引入的依赖mysql-connector-java-8.0.33.jar驱动HikariCP-5.0.1.jar高性能连接池比 C3P0 快 3 倍Tomcat 自带的 DBCP 已淘汰注意serverTimezoneAsia/Shanghai是 MySQL 8.0 必加参数否则DATETIME字段插入报错。这是课程设计中最常被忽略的“时区玄学”。3.3 编写 RoomDAO用 PreparedStatement 防止 SQL 注入DAO 层是安全边界。查询所有房间的代码必须用PreparedStatement而非字符串拼接// java public class RoomDAO { public ListRoom findAllRooms() throws SQLException { String sql SELECT id, room_number, room_type, price, status, floor FROM room ORDER BY floor, room_number; ListRoom rooms new ArrayList(); 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.setRoomNumber(rs.getString(room_number)); room.setRoomType(rs.getString(room_type)); room.setPrice(rs.getBigDecimal(price)); room.setStatus(rs.getByte(status)); // 直接映射 TINYINT room.setFloor(rs.getInt(floor)); rooms.add(room); } } return rooms; } }参数说明try-with-resources自动关闭Connection/Statement/ResultSet避免连接泄漏rs.getByte(status)比rs.getInt(status)更精准因数据库字段是TINYINTORDER BY floor, room_number保证前台展示按楼层升序排列符合酒店管理习惯。4. 避坑指南课程设计中 5 个高频翻车现场与自救方案4.1 现象登录后跳转到admin/index.jsp页面空白控制台无报错原因admin/index.jsp中未校验 session且该页面未设置pageEncodingUTF-8导致中文乱码触发 JSP 编译失败但错误被 Tomcat 吞掉。解决在admin/index.jsp顶部添加% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8%并在页面开头插入 session 校验逻辑% if (session.getAttribute(user) null) { response.sendRedirect(../login.jsp); return; } %4.2 现象点击“预订房间”按钮数据库room.status变成1但booking表没插入记录原因业务逻辑写在 Servlet 里未用 Service 层统一管理事务。RoomDAO.updateStatus()和BookingDAO.insert()分属两个独立数据库连接无法保证原子性。解决将操作封装到BookingService.bookRoom(int roomId, String guestName)方法中在 Service 层用Connection手动控制事务public void bookRoom(int roomId, String guestName) throws SQLException { Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 关闭自动提交 new RoomDAO().updateStatus(conn, roomId, (byte)1); new BookingDAO().insert(conn, roomId, guestName, new Date()); conn.commit(); // 全部成功才提交 } catch (Exception e) { if (conn ! null) conn.rollback(); // 任一失败则回滚 throw e; } finally { DBUtil.close(conn); } }4.3 现象room_number字段在数据库中是A101但 JSP 页面显示为A101?末尾多问号原因MySQL 表字符集为latin1而项目全程用 UTF-8。SHOW CREATE TABLE room查看建表语句发现DEFAULT CHARSETlatin1。解决执行ALTER TABLE room CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;并确保 JDBC URL 中有characterEncodingutf8参数。4.4 现象IDEA 中运行项目浏览器地址栏显示http://localhost:8080/HotelSystem/但页面 404原因web.xml中welcome-file-list未配置或index.jsp不在 WebContent 根目录。解决在web.xml的web-app内添加welcome-file-list welcome-fileindex.jsp/welcome-file /welcome-file-list并确认index.jsp位于WebContent/下而非WebContent/WEB-INF/内。4.5 现象修改RoomDAO.java后重新部署Tomcat 报ClassDefNotFound异常原因IDEA 的 Artifact 配置未勾选 “Include in project build”导致编译后的.class文件未打入 WAR 包。解决File → Project Structure → Artifacts → HotelSystem:war exploded → Output Layout检查Available Elements中是否有hotel-web.jar或compiled classes右键Put into Output Root。5. 让系统真正可用实现房态实时刷新与押金计算逻辑5.1 用 AJAX 局部刷新房态避免整页重载用户不想每次点“刷新”就让整个页面闪一下。在admin/room-list.jsp中为每个房间的“状态”单元格添加 ID并用 jQuery 实现局部更新!-- jsp -- c:forEach items${rooms} varroom tr td${room.roomNumber}/td td${room.roomType}/td td${room.price}/td td idstatus-${room.id}${room.statusDesc}/td !-- 状态描述由 Java 计算 -- td button onclickchangeStatus(${room.id}, 1)预订/button button onclickchangeStatus(${room.id}, 2)入住/button /td /tr /c:forEach script function changeStatus(roomId, newStatus) { $.post(room-status, {id: roomId, status: newStatus}, function(data) { if (data.success) { // 【关键】只更新状态单元格不刷新整页 $(#status- roomId).text(data.statusText); } else { alert(操作失败 data.msg); } }); } /script对应的RoomStatusServlet.java// java WebServlet(/room-status) public class RoomStatusServlet extends HttpServlet { Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int roomId Integer.parseInt(req.getParameter(id)); byte newStatus Byte.parseByte(req.getParameter(status)); try { new RoomService().updateRoomStatus(roomId, newStatus); // 返回 JSON 格式响应简化版不引入 Jackson String json String.format({\success\:true,\statusText\:\%s\,\msg\:\\}, Room.getStatusDesc(newStatus)); resp.setContentType(application/json;charsetUTF-8); resp.getWriter().write(json); } catch (Exception e) { String json String.format({\success\:false,\statusText\:\\,\msg\:\%s\}, e.getMessage()); resp.getWriter().write(json); } } }为什么不用ResponseBody课程设计要求你理解 HTTP 响应体构造。手动写 JSON 字符串比依赖 Spring MVC 注解更能暴露底层细节。5.2 押金计算用 Java 业务规则替代数据库硬编码酒店押金不是固定值而是房费的倍数如豪华套房收 2 倍。这个逻辑绝不能写死在 SQL 里必须放在 Service 层// java public class BookingService { public BigDecimal calculateDeposit(Room room) { BigDecimal basePrice room.getPrice(); switch (room.getRoomType()) { case 单人间: return basePrice.multiply(BigDecimal.valueOf(1.0)); case 双床房: return basePrice.multiply(BigDecimal.valueOf(1.5)); case 豪华套房: return basePrice.multiply(BigDecimal.valueOf(2.0)); default: return basePrice.multiply(BigDecimal.valueOf(1.0)); } } }在booking.jsp中调用% BookingService service new BookingService(); BigDecimal deposit service.calculateDeposit(room); % 押金金额% deposit % 元参数设计哲学BigDecimal而非double避免浮点数精度丢失如0.1 0.2 ! 0.3multiply(BigDecimal.valueOf(1.5))而非multiply(new BigDecimal(1.5))后者可能因字符串解析产生不可控精度。5.3 导出房间报表用 Apache POI 生成 Excel不依赖前端插件课程设计加分项导出功能。ExportRoomServlet.java生成 Excel 并下载// java WebServlet(/export-rooms) public class ExportRoomServlet extends HttpServlet { Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ListRoom rooms new RoomService().findAllRooms(); // 创建工作簿 XSSFWorkbook workbook new XSSFWorkbook(); XSSFSheet sheet workbook.createSheet(房间列表); // 表头 XSSFRow header sheet.createRow(0); String[] titles {房间号, 房型, 价格, 状态, 楼层}; for (int i 0; i titles.length; i) { header.createCell(i).setCellValue(titles[i]); } // 数据行 for (int i 0; i rooms.size(); i) { XSSFRow row sheet.createRow(i 1); Room r rooms.get(i); row.createCell(0).setCellValue(r.getRoomNumber()); row.createCell(1).setCellValue(r.getRoomType()); row.createCell(2).setCellValue(r.getPrice().doubleValue()); row.createCell(3).setCellValue(Room.getStatusDesc(r.getStatus())); row.createCell(4).setCellValue(r.getFloor()); } // 设置响应头触发下载 resp.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet); String fileName URLEncoder.encode(酒店房间报表.xlsx, UTF-8); resp.setHeader(Content-Disposition, attachment; filename fileName); workbook.write(resp.getOutputStream()); workbook.close(); } }必须引入的依赖poi-5.2.4.jar,poi-ooxml-5.2.4.jar,xmlbeans-5.1.0.jar。后悔药如果导出中文乱码检查URLEncoder.encode()的编码是否为UTF-8且 Tomcat 的server.xml中Connector标签添加URIEncodingUTF-8。6. 交付前的终极检查清单让老师一眼看出你不是复制粘贴6.1 代码层面3 个老师必查的“专业感”细节检查项正确做法错误示范为什么重要包名规范cn.hotel.web,cn.hotel.service全部小写地域项目名com.example.hotel,hotel.dao缺地域或大小写混乱包名是 Java 工程的身份证混乱意味着基础不牢SQL 字段命名room_number,created_time下划线分隔见名知义roomNumber,createtime驼峰或无分隔违反 MySQL 惯例数据库设计反映工程素养老师扫一眼就知道你是否真动手建过表异常处理catch(SQLException e) { logger.error(查询房间失败, e); throw new ServiceException(e); }e.printStackTrace();裸打印无日志无业务异常包装课程设计考察的是“生产级思维”不是“能跑就行”6.2 文档层面README.md 里必须写的 4 句话不要写“本系统基于 JavaWeb 开发”要说人话“数据库脚本在db/hotel.sql用mysql -u root -p db/hotel.sql一键导入”“登录账号admin/123456普通员工staff/123456权限不同后台菜单自动过滤”“房间状态说明0空闲1已预订2已入住3待打扫4维修中——所有状态变更均通过room-status接口完成”“导出 Excel 功能需点击‘房间管理’页的‘导出报表’按钮文件名含当前日期如酒店房间报表_20240520.xlsx”。我的习惯每次课程设计交付前我会用手机拍下自己在 Chrome 里操作系统的完整录屏从输入localhost:8080到完成一次预订导出剪成 60 秒视频和源码一起打包。老师看视频比读文档快十倍而你花 10 分钟做的事能让 TA 在 5 秒内确认“这学生确实做出来了”。希望帮到你。本文还有配套的精品资源点击获取