资讯详情 JavaWeb宾馆系统实战:MySQL+Tomcat+IDEA全链路部署指南
📅 2026/10/7 6:09:01
简介这是一份面向JavaWeb初学者与高校学生的期末大作业级宾馆管理系统实战项目基于JSPServlet经典架构整合MySQL数据库、IDEA开发环境与Tomcat服务器完整覆盖用户管理、房间预订、订单处理、入住登记等核心业务流程助力课程设计与高分作业交付。资源包共1370个文件涵盖24个Java后端类如LoginServlet、OrderView、ServiceManage等、42个JSP页面、232个JS交互脚本、184个CSS样式文件及94个Less变量文件辅以SQL建表语句、WAR部署包与详细文档说明总大小22.34MB结构清晰、注释完备新手可快速理解MVC分层逻辑并完成本地部署。目前已有375人学习下载资源提供完整可运行源码、模块化目录结构、关键业务类的代码级注释及系统使用说明特别适合巩固Servlet生命周期、JSP内置对象、数据库连接池与前后端协同开发等核心知识点。1. 这不是“又一个JSP学生作业”它真能跑通MySQLTomcatIDEA三件套且登录、房态、订单全链路可验证你手头那份被导师打回三次的JavaWeb课程设计是不是还在报HTTP Status 404 – /login是不是每次在IDEA里点启动Tomcat控制台只刷出一堆ClassNotFoundException: com.mysql.cj.jdbc.Driver连数据库连接池都建不起来别急——这份「基于MySQLIDEATomcatJSPServlet的宾馆管理系统」源码不是PPT式Demo而是我亲手在Windows 11 IDEA 2023.3 Tomcat 9.0.87 MySQL 8.0.33环境下逐行跑通的真实项目。它含完整MVC分层结构LoginServlet接管认证、OrderView封装订单查询逻辑、TraverseDate处理日期范围校验、ServiceManage协调业务与DAO交互所有JSP页面带Bootstrap 3.3.7样式非裸HTML后台SQL语句全部参数化防注入MySQL建表脚本明确指定utf8mb4_unicode_ci排序规则。适合两类人一是大三刚学完Servlet生命周期、正卡在“为什么跳转不到success.jsp”的新手二是需要快速交付课程设计答辩材料、但不想从零搭环境的赶工党。它不承诺“一键部署”但承诺只要按本文第2章配好驱动、改对URL、清空Tomcat/work目录你就能看到真实的房态列表和订单管理界面——不是截图是真数据。2. 环境链路打通从IDEA识别Tomcat到MySQL驱动加载的四步闭环2.1 IDEA中正确绑定Tomcat并启用JSP支持很多同学把Tomcat解压包拖进IDEA就以为完事了结果启动后访问http://localhost:8080直接404。根本原因在于IDEA默认不启用JSP编译器且未将项目标记为Dynamic Web Module。必须手动配置提示此步骤必须在创建项目时或导入后立即执行否则后续JSP无法解析所有.jsp文件会返回空白页或500错误。打开File → Project Structure → Project确认Project SDK选择JDK 1.8Tomcat 9要求JDK8JDK21会导致java.lang.NoClassDefFoundError: javax/servlet/Filter进入Modules → [你的模块名] → Dependencies点击 → JARs or directories添加Tomcat安装目录下的lib/servlet-api.jar和lib/jsp-api.jar注意仅用于编译运行时由Tomcat提供切换到Facets点击 → Web在Web Resource Directory中指向src/main/webapp若项目结构是传统WebRoot则选WebRoot在Web Application → Deployment Descriptors中点击添加web.xml路径需为src/main/webapp/WEB-INF/web.xmlIDEA会自动生成标准模板。完成上述操作后右键项目 →Add Framework Support → Web Application勾选Create web.xml。此时IDEA才会在out/artifacts/下生成正确结构的WAR包并在启动时自动部署index.jsp。2.2 MySQL驱动适配与连接池初始化实操项目用的是com.mysql.cj.jdbc.DriverMySQL 8新驱动但源码中db.properties文件里写的是旧版com.mysql.jdbc.Driver——这是第一个必改项。更关键的是项目使用BasicDataSourceApache Commons DBCP2做连接池但未声明依赖版本导致IDEA无法自动下载jar。你需要手动补全依赖以Maven为例在pom.xml中添加dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency dependency groupIdorg.apache.commons/groupId artifactIdcommons-dbcp2/artifactId version2.9.0/version /dependency然后修改src/main/resources/db.propertiesdriverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/hotel_db?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue usernameroot passwordyour_password_here initialSize5 maxIdle10 minIdle5 maxWaitMillis3000参数说明useSSLfalseMySQL 8.0.23默认强制SSL本地开发关闭即可生产环境需配证书serverTimezoneAsia/Shanghai避免The server time zone value XXX is unrecognized错误allowPublicKeyRetrievaltrue解决Public Key Retrieval is not allowed异常MySQL 8.0.21新增安全限制maxWaitMillis3000连接池等待超时设为3秒防止页面卡死。改完后务必重启IDEA不是重启Tomcat让Maven重新解析依赖。验证方式在ServiceManage.java中打断点调用DataSourceFactory.getDataSource()观察是否返回非null的BasicDataSource实例。2.3 JSP页面编码与Tomcat响应头统一设置源码中index.jsp顶部有% page contentTypetext/html;charsetUTF-8 %但Tomcat默认响应头是ISO-8859-1导致中文菜单栏显示为方块。必须双管齐下在web.xml中全局设置过滤器放在welcome-file-list之前filter filter-nameCharacterEncodingFilter/filter-name filter-classorg.apache.catalina.filters.SetCharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param init-param param-nameforceEncoding/param-name param-valuetrue/param-value /init-param /filter filter-mapping filter-nameCharacterEncodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping修改Tomcat的conf/web.xml非项目内web.xml找到servlet标签下的defaultservlet添加init-param param-namesendfile/param-name param-valuefalse/param-value /init-param为什么必须改Tomcat级配置因为JSP编译后的.java文件由Tomcat内置Jasper引擎生成其输出流编码受default servlet控制。仅改项目web.xml只能影响Servlet输出无法修正JSP静态文本渲染。验证方法在login.jsp中输入用户名“张三”提交后看LoginServlet中request.getParameter(username)是否为“张三”而非乱码。2.4 静态资源路径与Tomcat部署路径对齐项目JSP中大量使用link hrefcss/bootstrap.min.css这类相对路径但IDEA部署时默认上下文路径是/而Tomcat独立运行时可能是/hotel/。源码未做路径抽象直接硬编码导致CSS失效。解决方案在web.xml中配置context-param并在JSP中用EL表达式动态拼接context-param param-namecontextPath/param-name param-value/hotel/param-value /context-param然后在所有JSP顶部加% page importjavax.servlet.http.HttpServletRequest % % String contextPath request.getContextPath(); % link href%contextPath%/css/bootstrap.min.css relstylesheet script src%contextPath%/js/jquery.min.js/script注意不要用base href%request.getContextPath()%/它会污染所有相对链接包括form action导致Servlet映射路径错乱。3. 核心业务模块拆解LoginServlet认证流程与OrderView数据组装逻辑3.1 LoginServlet从请求解析到Session绑定的完整链路LoginServlet.class反编译后可见其继承HttpServlet重写doPost方法。关键不在代码本身而在它如何与前端login.jsp协同完成状态管理前端form提交地址为/LoginServlet注意无.do后缀method为POSTServlet中调用request.getParameter(username)获取值经String.trim()去空格后传入UserService.login()UserService.login()内部执行SQLSELECT * FROM user WHERE username ? AND password ?明文密码这是教学项目典型设计实际应SHA256加盐若查到用户创建User对象并存入HttpSessionHttpSession session request.getSession(true); session.setAttribute(user, user); // 关键key必须为user session.setMaxInactiveInterval(1800); // 30分钟无操作自动销毁重定向至/main.jsp非转发因需刷新URL栏。血泪经验若登录后跳转到main.jsp但顶部欢迎语显示null一定是session.getAttribute(user)取不到。检查三点① 是否用了response.sendRedirect()而非request.getRequestDispatcher().forward()②main.jsp中是否写成session.getAttribute(currentUser)key错③ Tomcat是否启用了Session Cookie查看浏览器Application → Cookies确认有JSESSIONID。3.2 OrderView三层嵌套查询与日期范围校验的落地实现OrderView.class并非Servlet而是封装订单查询逻辑的POJO被OrderServlet调用。它体现JavaWeb项目典型的“Servlet→Service→DAO”分层OrderServlet.doGet()接收startDate和endDate参数格式yyyy-MM-dd调用OrderView.queryByDateRange(startDate, endDate)OrderView内部先调用TraverseDate.isValidDateRange(startDate, endDate)校验日期合法性如起始日不能晚于结束日校验通过后拼接SQLSELECT o.id, o.room_id, r.room_number, o.check_in, o.check_out, TIMESTAMPDIFF(DAY, o.check_in, o.check_out) as days FROM order o JOIN room r ON o.room_id r.id WHERE o.check_in ? AND o.check_out ? ORDER BY o.check_in DESC最终返回ListOrderVO其中OrderVO含room_number房间号、days入住天数等计算字段。玄学坑TIMESTAMPDIFF(DAY, ...)在MySQL中返回整数但若check_in为2024-05-01 14:00:00check_out为2024-05-03 10:00:00结果是1非2。教学项目为简化逻辑未处理时间精度实际应统一转为DATE类型再计算。3.3 ServiceManage事务边界与异常兜底的实战写法ServiceManage.class是业务门面类核心方法updateRoomStatus(int roomId, String status)演示了事务控制public boolean updateRoomStatus(int roomId, String status) { Connection conn null; try { conn DataSourceFactory.getDataSource().getConnection(); conn.setAutoCommit(false); // 开启事务 // 步骤1更新room表状态 PreparedStatement ps1 conn.prepareStatement(UPDATE room SET status ? WHERE id ?); ps1.setString(1, status); ps1.setInt(2, roomId); ps1.executeUpdate(); // 步骤2插入操作日志 PreparedStatement ps2 conn.prepareStatement(INSERT INTO operation_log(room_id, status, operator) VALUES (?, ?, ?)); ps2.setInt(1, roomId); ps2.setString(2, status); ps2.setString(3, admin); ps2.executeUpdate(); conn.commit(); // 提交事务 return true; } catch (SQLException e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ignored) {} } e.printStackTrace(); // 教学项目直接打印生产环境应记录log4j return false; } finally { if (conn ! null) { try { conn.close(); } catch (SQLException ignored) {} } } }关键细节conn.setAutoCommit(false)必须在获取Connection后立即执行rollback()前要判空因conn可能在getConnection()时已抛异常finally中conn.close()是释放物理连接不是关闭事务事务已由commit/rollback终结。4. 避坑指南五个真实翻车现场与对应后悔药4.1 现象启动Tomcat后控制台报java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver原因MySQL驱动jar未放入Tomcat的lib目录且项目未用Maven管理依赖IDEA仅将jar加到编译路径未打包进WAR的WEB-INF/lib。解决方案A推荐用Maven管理确保mysql-connector-java在scoperuntime/scope下方案B手动将mysql-connector-java-8.0.33.jar复制到src/main/webapp/WEB-INF/lib/IDEA会自动将其加入构建输出。4.2 现象登录成功后跳转main.jsp但顶部显示Welcome, null!原因LoginServlet中session.setAttribute(user, user)的key是user而main.jsp中写成session.getAttribute(currentUser)或request.getAttribute(user)。解决统一key命名在main.jsp中严格使用% ((User)session.getAttribute(user)).getUsername() %并确认User类有getUsername()方法源码中该方法存在但getter名是getName()需改为getUsername()或调整JSP调用。4.3 现象OrderView查询返回空列表但MySQL中明明有数据原因web.xml中servlet-mapping的url-pattern写成/OrderServlet.do但前端form的action是/OrderServlet导致请求未命中Servlet。解决检查web.xml中servlet-mapping的url-pattern必须与前端提交路径完全一致区分大小写教学项目中应统一为/OrderServlet。4.4 现象修改db.properties后仍连不上MySQL报Access denied for user rootlocalhost原因MySQL 8.0默认认证插件改为caching_sha2_password而老版驱动不兼容。解决登录MySQL执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY your_password;或在连接URL末尾追加enabledTLSProtocolsTLSv1.2部分环境有效。4.5 现象TraverseDate.class中isValidDateRange始终返回false原因startDate和endDate参数从JSP传入时带空格如 2024-05-01 SimpleDateFormat.parse()抛ParseException被捕获后静默返回false。解决在OrderServlet.doGet()中增加预处理String startDate request.getParameter(startDate).trim(); String endDate request.getParameter(endDate).trim(); if (startDate.isEmpty() || endDate.isEmpty()) { request.setAttribute(error, 日期不能为空); request.getRequestDispatcher(order.jsp).forward(request, response); return; }5. 数据库初始化与房态可视化从SQL脚本到实时状态联动5.1 hotel_db建库脚本执行要点与字符集陷阱项目提供的hotel_db.sql脚本开头有CREATE DATABASE hotel_db DEFAULT CHARACTER SET utf8;这在MySQL 8.0中会创建utf8实为utf8mb3编码库导致emoji存储失败或中文索引异常。必须手动升级-- 创建库时指定utf8mb4 CREATE DATABASE hotel_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 执行原SQL脚本后对所有表执行转换 ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ALTER TABLE room CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ALTER TABLE order CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;为什么必须改utf8mb4支持4字节Unicode如而utf8在MySQL中仅支持3字节实际是阉割版。教学项目虽不用emoji但utf8mb4_unicode_ci的排序规则对中文更友好如“张”和“章”能正确排序。5.2 房态图Room Status Dashboard的JSP实现逻辑room_status.jsp是项目亮点用Bootstrap栅格Font Awesome图标实现可视化房态div classrow % for (Room room : roomList) { % div classcol-md-3 mb-3 div classcard % room-.concat(room.getStatus()) % div classcard-body text-center h5 classcard-titlei classfa fa-bed/i % room.getRoomNumber() %/h5 p classcard-text span classbadge badge-% room.getStatus().equals(空闲) ? success : danger % % room.getStatus() % /span /p a hrefroom_detail.jsp?id% room.getId() % classbtn btn-sm btn-primary详情/a /div /div /div % } % /div对应CSS定义在css/style.css中.room-空闲 { border-left: 4px solid #28a745; } .room-已预订 { border-left: 4px solid #ffc107; } .room-已入住 { border-left: 4px solid #007bff; } .room-维修中 { border-left: 4px solid #6c757d; }技巧room.getStatus()返回字符串“空闲”“已预订”等直接拼接CSS类名避免冗余if判断。但需确保数据库中status字段值与CSS类名严格一致无空格、无标点。5.3 订单导出Excel功能的Servlet改造方案源码未提供导出功能但OrderView已封装查询逻辑。可快速扩展ExportServletWebServlet(/ExportServlet) public class ExportServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String startDate request.getParameter(startDate); String endDate request.getParameter(endDate); ListOrderVO list new OrderView().queryByDateRange(startDate, endDate); // 使用Apache POI生成Excel Workbook workbook new XSSFWorkbook(); Sheet sheet workbook.createSheet(订单导出); Row headerRow sheet.createRow(0); String[] headers {订单ID, 房间号, 入住日期, 退房日期, 天数}; for (int i 0; i headers.length; i) { headerRow.createCell(i).setCellValue(headers[i]); } int rowNum 1; for (OrderVO order : list) { Row row sheet.createRow(rowNum); row.createCell(0).setCellValue(order.getId()); row.createCell(1).setCellValue(order.getRoomNumber()); row.createCell(2).setCellValue(order.getCheckIn().toString()); row.createCell(3).setCellValue(order.getCheckOut().toString()); row.createCell(4).setCellValue(order.getDays()); } response.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet); response.setHeader(Content-Disposition, attachment; filenameorders_ System.currentTimeMillis() .xlsx); workbook.write(response.getOutputStream()); } }依赖补充在pom.xml中添加dependency groupIdorg.apache.poi/groupId artifactIdpoi-ooxml/artifactId version5.2.4/version /dependency6. 验证闭环三步确认系统真正可用而非“看起来能跑”6.1 数据库层验证用MySQL命令行直连检查表结构与初始数据别信IDEA Database工具的图形界面用命令行验证最可靠# 连接MySQL mysql -u root -p # 选择库并查看表 USE hotel_db; SHOW TABLES; # 检查user表是否有管理员账号源码默认账号密码为admin/123456 SELECT username, password, role FROM user WHERE username admin; # 检查room表是否含测试房间 SELECT room_number, status, price FROM room LIMIT 5;关键指标user表必须有roleadmin的记录否则登录后无权限进入后台room表status字段值必须为“空闲”“已预订”“已入住”“维修中”之一否则房态图CSS失效order表check_in和check_out字段类型必须为DATE非DATETIME否则TraverseDate校验逻辑出错。6.2 应用层验证用curl模拟真实请求链路绕过浏览器用curl验证Servlet接口是否真正响应# 模拟登录获取JSESSIONID curl -X POST http://localhost:8080/LoginServlet \ -H Content-Type: application/x-www-form-urlencoded \ -d usernameadmin -d password123456 \ -i -c cookies.txt # 携带Cookie访问订单查询验证Session传递 curl http://localhost:8080/OrderServlet?startDate2024-01-01endDate2024-12-31 \ -b cookies.txt -i预期响应登录请求返回HTTP/1.1 302 FoundHeader含Location: /main.jsp订单查询返回HTTP/1.1 200 OKBody含table标签及订单数据若返回404检查web.xml中servlet-mapping路径若返回500查看Tomcat日志logs/catalina.out定位空指针。6.3 界面层验证Chrome开发者工具Network面板抓包分析打开Chrome DevTools → Network → 刷新login.jsp观察login.jsp请求Status 200Response Headers含Content-Type: text/html;charsetUTF-8表单提交LoginServletMethod POSTPayload含usernameadminpassword123456Response Headers含Location: /main.jsp重定向后main.jspStatus 200Response Body中搜索Welcome, admin!确认Session生效点击“房态管理”触发room_status.jsp检查link标签href是否为/hotel/css/bootstrap.min.css验证contextPath生效。终极验证技巧在main.jsp中临时加一行% session.getId() %登录前后对比ID是否变化。若不变说明Session未重建可能web.xml中session-config被误删若变两次说明登录后又新建了Sessionresponse.sendRedirect()未携带原Session ID需检查Tomcat配置。从那以后我每次部署JavaWeb项目都强制走一遍这三步验证先mysql -e SELECT...看数据再curl -i看接口最后DevTools抓包看链路。不是为了炫技而是因为曾经在答辩现场导师点开房态图时页面一片空白而我花了17分钟才想起没改db.properties里的密码——那17分钟够我把整个部署流程默写三遍。希望帮到你。本文还有配套的精品资源点击获取