ARTICLE DETAIL

资讯详情

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

JSP+Servlet宾馆管理系统:JavaWeb期末作业实现与避坑指南

JSP+Servlet宾馆管理系统:JavaWeb期末作业实现与避坑指南 简介这是一款采用JavaWeb技术栈开发的宾馆管理系统源码运行环境包括MySQL数据库、IDEA开发工具、Tomcat服务器页面与逻辑分别基于JSP和Servlet技术实现。项目面向计算机相关专业学生的期末作业与课程设计适合需要快速搭建管理系统或完成实训任务的在校学生。压缩包大小22.34MB包含1370个文件其中主要文件类型有JSP视图页面、Java业务源码、Servlet控制类、编译后的class字节码、前端样式与交互脚本、数据库建表脚本以及XML配置文件完整覆盖了表示层、业务层与数据层目录结构清晰便于按模块研读与二次开发。系统已实现客房信息管理、预订订单处理、会员档案维护等核心功能界面简洁美观操作流程直观代码包含详细注释新手可以理解关键逻辑附带的文档说明也能帮助读者快速完成部署并运行到Tomcat上省去从零搭建的麻烦。资源已有375人学习下载可作为期末大作业、课程设计的高分参考实用性强也方便按照自身需求扩展改造。1. JSPServlet 宾馆管理系统JavaWeb 期末作业最快落地的那一套做 JavaWeb 期末作业最怕的不是不会写代码而是选错技术栈、装错环境、交上去一个跑不起来的半成品。这套基于 MySQL IDEA Tomcat JSP Servlet 的宾馆管理系统我拆完之后最大的感受是它把课程设计里最容易扣分的那几块——登录鉴权、房间状态流转、订单日期计算、后台管理——全部用最经典的原生 Servlet 实现了没有花哨框架每一行都能在答辩现场讲清楚。源码里带完整注释和文档说明新手不用猜每个类是干什么的打开就知道哪段对应哪个功能。适合拿去做期末大作业、课程设计或者只是想搞明白 JSP Servlet 到底怎么协作的人。2. 项目结构与技术选型五个核心类如何撑起前台到后台2.1 为什么这个项目适合课程设计很多同学一上来就想用 Spring Boot但期末作业的评分标准往往不是你用了多新的框架而是你能不能讲清楚请求怎么进来、数据怎么查、页面怎么渲染。Servlet JSP 这套组合虽然老却是 JavaWeb 的根基老师最熟悉也最容易在答辩时给出高分。这套宾馆管理系统的类文件集中在几个关键类上LoginServlet、TraverseDate、Query、ServiceManage、OrderView从名字就能看出它的职责划分——登录验证、日期遍历、数据查询、服务管理、订单视图每个类对应一个明确的功能模块代码量适中注释齐全新手照着读就能理清 MVC 的脉络。技术选型上MySQL 负责数据持久化Tomcat 负责运行环境IDEA 负责开发调试JSP 负责页面展示Servlet 负责请求处理。这套组合的好处是没有太多隐性的依赖配置只要版本匹配跑起来非常稳。我见过太多期末项目死在框架版本冲突上而这个项目用的全是 JavaWeb 最基础的组件任何一本教材里的环境配置步骤都能适用排查起来也容易。2.2 核心类文件与功能模块映射拿到资源后先别急着启动花十分钟把类文件对应到功能模块后面调试会省很多事。我拆解后的对应关系如下类文件对应的功能模块关键职责LoginServlet管理员登录接收账号密码、校验数据库、写入 SessionTraverseDate日期计算引擎遍历入住到退房日期、计算住宿天数与房费Query数据查询门户房间信息查询、订单状态查询、客户信息检索ServiceManage后台服务管理服务项目增删改、价格调整OrderView订单视图层订单展示、状态流转、明细查看这个结构的巧妙之处在于每一层都只做一件事。LoginServlet 只负责登录不掺业务逻辑TraverseDate 只算日期不碰数据库Query 只做查询不做修改。这样的拆分让答辩时可以非常清晰地回答老师的问题「你这个订单金额是怎么算出来的」——打开 TraverseDate逻辑一目了然。2.3 数据库设计的四张核心表项目对应的数据库设计也是课程设计标准答案级别的。表结构大致分为四张管理员表t_admin、房间表t_room、订单表t_order、服务表t_service。房间表和订单表通过房间号关联订单表记录了入住时间和退房时间服务表记录额外的消费项目。表结构的设计思路很实用管理员表只存账号密码房间表存房间号、类型、价格、状态订单表存客户姓名、房间号、入住日、退房日、总金额服务表存服务项目名称和价格。四张表没有任何冗余字段外键关系简单SQL 查询不会出现复杂的多表关联对刚接触数据库的初学者来说非常友好。-- 订单表核心字段示例 CREATE TABLE t_order ( order_id INT PRIMARY KEY AUTO_INCREMENT, customer_name VARCHAR(50) NOT NULL, room_id INT NOT NULL, checkin_date DATE NOT NULL, checkout_date DATE NOT NULL, total_amount DECIMAL(10,2) DEFAULT 0, order_status VARCHAR(20) DEFAULT 已入住, create_time DATETIME DEFAULT CURRENT_TIMESTAMP );这段建表 SQL 里有两个字段值得注意total_amount 默认值为 0原因是订单创建时可能还没退房金额需要根据实际住宿天数计算后更新order_status 用字符串而不是数字是为了让 JSP 页面直接展示「已入住」「已退房」这样的中文状态省去前端再做一次状态映射。这种设计很贴合课程设计场景——简单、直观、答辩时不用绕弯子解释状态码含义。3. 从零部署IDEA Tomcat MySQL 的三件套配置与运行验证3.1 MySQL 版本与编码设置的第一个坑部署的第一件事是准备数据库。项目是围绕 MySQL 设计的建议直接用 MySQL 5.7 或 8.0 版本。装好之后不要急着导入数据先把字符集设置好否则 JSP 页面显示中文会变成问号。我一般会在 MySQL 配置文件里加上默认字符集配置然后重启服务再创建数据库。# 创建数据库时强制指定字符集 CREATE DATABASE hotel_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;这里用 utf8mb4 而不是 utf8是因为在 MySQL 8.0 里 utf8 实际上是 utf8mb3遇到一些特殊符号存不进去。课程设计项目虽然大概率用不到 emoji但统一用 utf8mb4 可以避免一个隐藏的中文乱码问题——尤其是 JSP 页面提交表单后往数据库写入中文编码链路差了任何一环都会乱。字符集设置好后再导入项目附带的 SQL 文件顺序不能反。Tomcat 版本建议用 Tomcat 9对应 Servlet 4.0 规范和项目里的 Servlet 代码兼容性最好。我遇到过不少同学装 Tomcat 10 跑老项目结果所有 javax.servlet 包名全部报错因为 Tomcat 10 换成了 jakarta.servlet这是版本换代引起的包名迁移问题。项目源码里用的是 javax.servlet配 Tomcat 9 就能完美避开。3.2 IDEA 中配置 Tomcat 的运行三步走在 IDEA 里跑这个项目关键是把 Tomcat 和 Web 项目正确关联。很多同学在这里翻车是因为没有把项目打成 Artifact 部署到 Tomcat 的 webapps 目录导致启动 Tomcat 后访问 404。# 第一步确保项目结构里有 src/main/webapp 目录 # IDEA 中右键项目 - Add Framework Support - 勾选 Web Application # 第二步配置 Artifact # File - Project Structure - Artifacts - 点击 - Web Application: Exploded # 第三步配置 Tomcat # Run - Edit Configurations - 点击 - Tomcat Server - Local # 在 Deployment 标签页添加 ArtifactApplication context 填 /hotel这里我详细解释一下第二步和第三步背后的逻辑。IDEA 运行 Tomcat 时并不是直接把项目文件夹丢给 Tomcat而是先打包成一个 Artifact可以理解为编译后的 Web 项目快照再放到 Tomcat 的容器里执行。所以 Artifact 配置错了即使 Tomcat 正常启动页面依然访问不到。Application context 填 /hotel意味着访问路径是 http://localhost:8080/hotel/如果留空则是根路径。我习惯填上项目名因为答辩演示时 URL 更直观。3.3 JDBC 连接的敏感参数配置项目里的数据库连接方式是 JDBC通常在 db.properties 文件或工具类里配置连接参数。打开配置重点检查四个参数驱动类、连接地址、用户名、密码。// 数据库连接工具类核心代码 public class DBUtil { private static final String DRIVER com.mysql.cj.jdbc.Driver; private static final String URL jdbc:mysql://localhost:3306/hotel_db ?useSSLfalseserverTimezoneAsia/Shanghai; private static final String USER root; private static final String PASSWORD 123456; public static Connection getConnection() throws SQLException { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } return DriverManager.getConnection(URL, USER, PASSWORD); } }注意 URL 里的两个参数useSSLfalse 是必须加的因为 MySQL 8.0 默认开启 SSL 连接而 Tomcat 本地调试时的 SSL 握手经常出问题报错信息很迷惑实际原因就是证书校验失败serverTimezoneAsia/Shanghai 则是解决日期时间类的时区偏移问题不加这个参数从数据库取出 Date 类型时会出现 8 小时误差导致入住日期和退房日期的天数计算全部错位。密码部分如果你是本地 root 用户且没改过密码保持 123456 或电脑上实际的 root 密码即可。数据库连接的成功验证方式很简单——运行一个 main 方法调用 getConnection()不抛异常就说明通了。4. 核心代码逐段拆解登录、日期遍历与订单查询的实现细节4.1 LoginServlet 的登录校验与 Session 管理登录功能是每个期末作业的标配但细节差异很大。这个项目的 LoginServlet 写法非常规范接收前端 JSP 表单提交的 username 和 password调用 Query 类去数据库比对成功后把用户信息存入 Session再跳转到主页面失败则返回登录页并附带错误提示。WebServlet(/login) public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String username request.getParameter(username); String password request.getParameter(password); // 调用查询层验证账号密码 Query query new Query(); Admin admin query.findAdminByUsernameAndPassword(username, password); if (admin ! null) { HttpSession session request.getSession(); session.setAttribute(currentAdmin, admin); response.sendRedirect(request.getContextPath() /index.jsp); } else { request.setAttribute(errorMsg, 账号或密码错误); request.getRequestDispatcher(/login.jsp).forward(request, response); } } }两个关键细节doPost 里的 setCharacterEncoding(UTF-8) 必须放在读取参数之前否则表单提交的中文用户名会乱码登录成功用 sendRedirect 而不是 forward 跳转是为了避免用户按下 F5 刷新时重复提交登录请求。Session 中存的是 Admin 对象而不是用户名这样主页面可以直接从 session 里取出管理员详细信息进行展示不用再次查询数据库。实际测试中发现如果登录失败用 forward 返回 login.jsp页面上给出的错误提示能正常显示这个设计我很喜欢——错误提示通过 request 域传递跳转一次就能看到。// 查询层方法注意密码比对方式 public Admin findAdminByUsernameAndPassword(String username, String password) { Connection conn null; PreparedStatement ps null; ResultSet rs null; try { conn DBUtil.getConnection(); String sql SELECT * FROM t_admin WHERE username? AND password?; ps conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password); rs ps.executeQuery(); if (rs.next()) { Admin admin new Admin(); admin.setId(rs.getInt(id)); admin.setUsername(rs.getString(username)); return admin; } } catch (SQLException e) { e.printStackTrace(); } finally { closeResources(rs, ps, conn); } return null; }这里强烈建议使用 PreparedStatement 而不是拼接 SQL 字符串——传入的用户名如果包含单引号拼接 SQL 会导致语法错误甚至注入风险。PreparedStatement 的预编译机制自动处理了引号转义是课程设计答辩时老师一定会问的考点。finally 块里的资源关闭是另一道加分项很多没经验的代码会漏掉连接关闭长时间运行后连接池耗尽整个系统卡死。4.2 TraverseDate 的日期遍历与房费计算逻辑住宿天数的计算是宾馆管理系统的核心算法。这个项目的 TraverseDate 类把逻辑封装得非常干净输入入住日期和退房日期遍历每一天统计天数并计算总房费。// 日期计算核心逻辑简化版 public class TraverseDate { private static final long DAY_IN_MILLIS 24 * 60 * 60 * 1000; public int calculateDays(Date checkinDate, Date checkoutDate) { // 注意日期需要归一化到零点否则时间差可能丢失一天 Calendar checkin Calendar.getInstance(); checkin.setTime(checkinDate); checkin.set(Calendar.HOUR_OF_DAY, 0); checkin.set(Calendar.MINUTE, 0); checkin.set(Calendar.SECOND, 0); Calendar checkout Calendar.getInstance(); checkout.setTime(checkoutDate); checkout.set(Calendar.HOUR_OF_DAY, 0); checkout.set(Calendar.MINUTE, 0); checkout.set(Calendar.SECOND, 0); long diff checkout.getTimeInMillis() - checkin.getTimeInMillis(); return (int) (diff / DAY_IN_MILLIS); } public BigDecimal calculateAmount(Date checkin, Date checkout, BigDecimal pricePerDay) { int days calculateDays(checkin, checkout); return pricePerDay.multiply(BigDecimal.valueOf(days)); } }这个类实现里有三个细节值得关注。第一为什么用 Calendar 归一化时间因为从数据库读出的 Timestamp 可能带有时分秒如果入住是 2023-12-01 10:30退房是 2023-12-03 14:00直接算毫秒差是 48 小时加 3.5 小时除以 24 小时后得到 2 天还多强转 int 得到 2看起来没问题但如果退房是 2023-12-03 09:30毫秒差是 47 小时除以 24 得到 1.958转 int 变成 1 天——这就错了。归一化到零点后再算差逻辑就稳了。第二金额用 BigDecimal 而不是 double因为房费涉及小数计算double 的精度损失会在多天累加时放大。第三这个方法故意只算了房费不包含服务费服务费用由 ServiceManage 单独统计后与房费合并——这一设计让每个类的职责更聚焦排查问题时不会一头雾水。4.3 Query 与 OrderView 的订单状态流转Query 类承担了绝大部分数据库查询工作而 OrderView 负责把查询结果封装成视图对象供 JSP 渲染。两者的分工是Query 查原始数据OrderView 做数据组装。查询订单时需要关联房间表获取房间类型和价格。// 查询订单列表关联房间表 public ListOrderView findOrdersWithRoomInfo(String keyword) { ListOrderView orderViews new ArrayList(); Connection conn null; PreparedStatement ps null; ResultSet rs null; try { conn DBUtil.getConnection(); String sql SELECT o.order_id, o.customer_name, o.checkin_date, o.checkout_date, o.total_amount, o.order_status, r.room_type, r.price FROM t_order o LEFT JOIN t_room r ON o.room_id r.room_id ; if (keyword ! null !keyword.isEmpty()) { sql WHERE o.customer_name LIKE ? OR o.order_id ?; } ps conn.prepareStatement(sql); if (keyword ! null !keyword.isEmpty()) { ps.setString(1, % keyword %); ps.setString(2, keyword); } rs ps.executeQuery(); while (rs.next()) { OrderView view new OrderView(); view.setOrderId(rs.getInt(order_id)); view.setCustomerName(rs.getString(customer_name)); view.setRoomType(rs.getString(room_type)); view.setPrice(rs.getBigDecimal(price)); view.setTotalAmount(rs.getBigDecimal(total_amount)); view.setOrderStatus(rs.getString(order_status)); orderViews.add(view); } } catch (SQLException e) { e.printStackTrace(); } finally { closeResources(rs, ps, conn); } return orderViews; }这段查询的看点在于条件拼接方式先写基础 SQL再根据关键字是否为空决定是否拼接 WHERE 子句。注意 WHERE 后面的 AND 问题——如果在 WHERE 后面直接写 AND而当关键字为空时 SQL 变成纯粹的基础查询多出的 AND 就会语法报错。这里的处理是先拼 WHERE 再拼接条件用 LIKE 模糊查询客户名称订单号用精确匹配参数均为动态绑定。不要把用户输入直接拼进 SQL 字符串一是安全二是 LIKE 语句里的百分号和引号需要转义PreparedStatement 自动处理这些。订单状态流转的逻辑在 ServiceManage 里配合使用——退房操作会将 order_status 从「已入住」改为「已退房」同时把房间状态改为「空闲」。数据库里 status 字段的更新逻辑很简单就是一条 UPDATE 语句但要注意事务边界退房操作需要同时更新订单表和房间表两张表的更新必须在一个事务中完成否则会出现订单已退房但房间仍显示占用的情况。代码里通过 Connection 的 setAutoCommit(false) 配合 commit/rollback 实现事务控制这是一个高级加分点答辩时可以主动提。5. 部署避坑实录5 个让课程设计翻车的常见问题与排查5.1 页面 404Tomcat 找不到项目资源现象Tomcat 启动成功浏览器访问 http://localhost:8080/hotel/index.jsp 却显示 404。 原因最常见的是 Artifact 没有正确部署到 Tomcat或者 Application context 配置的和访问路径不一致。还有一种是 webapp 目录结构不对IDEA 新建项目时如果没有正确标记 webapp 目录JSP 文件根本不会被打进 Artifact。 解决打开 File - Project Structure - Artifacts检查 Output Layout 里是否包含了 webapp 目录下的全部文件再打开 Run/Debug Configurations确认 Deployment 里添加了 Artifact 且 Application context 是 /hotel。如果都没问题清掉 out 目录和 target 目录后重启 Tomcat。5.2 中文乱码从表单到数据库全链路编码不一致现象JSP 页面输入中文「张三」存入 MySQL 后变成「å¼ ä¸‰」。 原因三处编码不一致——JSP 页面编码、Servlet 请求编码、数据库表字符集。任何一个环节不是 UTF-8中文就保不住。 解决JSP 文件顶部设置 pageEncoding 为 UTF-8每个 Servlet 的 doPost 开头写 request.setCharacterEncoding(UTF-8)连接数据库 URL 加 useUnicodetruecharacterEncodingUTF-8。我遇到过一个奇怪场景数据库表已经建好了服了navicat 客户端显示正常但程序写入乱码——最后发现是 MySQL 连接配置没加 characterEncoding 参数。从那以后建任何项目我都会先验证中文写入再往下走。5.3 MySQL 驱动连接报错Communications link failure现象Tomcat 启动后访问查询功能报 Communications link failure 或者 SSL 异常。 原因MySQL 8.0 默认开启 SSL且驱动版本和数据库版本不匹配。很多人从网上下载的 mysql-connector-java 是旧版 5.x连 8.0 数据库时协议不兼容。 解决使用 mysql-connector-j 8.x 版本驱动连接 URL 加上 useSSLfalse 和 serverTimezoneAsia/Shanghai。检查驱动 JAR 是否放在 WEB-INF/lib 目录而不是仅加到 IDEA 的依赖列表——运行时 Tomcat 只认 WEB-INF/lib 里的 JARIDEA 编译通过不代表 Tomcat 运行时不报错。5.4 订单日期计算差一天时区导致的 Date 陷阱现象入住 2024-06-01退房 2024-06-03页面显示住宿 1 天而不是 2 天。 原因数据库取出的 Date 类型对象经过 JDBC 转换后带了当前虚拟机的时区信息如果 MySQL 连接 URL 没指定 serverTimezoneJDBC 用默认时区解析 DATETIME导致时分秒偏移归一化失败后日期差计算错误。 解决连接 URL 必须加 serverTimezoneAsia/Shanghai计算天数前用 Calendar 归一化到零点如果时间紧张最简单的验证方式是写一段测试代码故意设置为 00:00 和 23:59 的时间看计算结果是否符合预期。这个坑最容易在答辩前夜爆发因为演示时日期往往是当天的而计算逻辑对跨天场景敏感。5.5 SQL 语法异常漏掉空格或者字段名打错现象运行时日志打印 SQLException提示 Unknown column xx in field list 或 You have an error in your SQL syntax。 原因拼接 SQL 字符串时变量没有加空格比如 WHERE customer_name LIKE ? AND o.room_id 前后拼接处缺少空格SQL 变成了 WHERE customer_name LIKE ?AND o.room_id。还有一种情况是字段名写错尤其是有下划线的字段如 order_status 容易写成 orderstatus数据库根本不存在这个字段报错信息比较直观但容易被忽略。 解决用 IDEA 的 SQL 方言检查功能或者在本地用 Navicat 预执行一遍 SQL 确认语法拼接字符串时每行结尾保留空格字段名从建表语句里复制而不是手敲。如果你在 Query 类里用了 StringBuilder 拼 SQL养成习惯每行结尾加空格不要依赖下一行的开头空格。6. 答辩前必做的本地验收用一张检查清单验证系统完整性期末作业最惨的不是写完而是答辩现场演示时鼠标一点就崩。我在这类项目上交过太多次学费后来总结了一个强制验收流程每次演示前一天必须完整走一遍。先把 Tomcat 启动起来然后按以下顺序逐项验证不要跳步。序号验证项操作与预期结果相关类1数据库连接启动后首页打开无报错DBUtil2错误密码登录提示「账号或密码错误」并留在登录页LoginServlet3正确密码登录跳转 index.jsp页面右上角显示管理员名LoginServlet4日期计算开单选择 6 月 1 日入住、6 月 3 日退房金额为 2 晚费用TraverseDate5订单查询按客户名模糊搜索结果列表正确展示Query/OrderView6退房操作订单状态变为已退房房间状态变为空闲ServiceManage7数据持久化重启 Tomcat记录仍在MySQL这个清单的妙处在于每项都对应一个核心类答辩时如果老师问「这项目有哪些功能」你直接背这张表的第 2 到第 6 行每个功能都能说清对应代码在哪个类里、核心逻辑是什么。我一般会在验收时把 Tomcat 的控制台日志打开每一步操作看一眼有没有报异常很多隐藏的 SQLException 页面不显示日志里早就有记录了。关于文档说明资源里带的文档讲清楚了建表语句、默认账号密码和部署步骤。建议你拿到之后先按文档跑一遍成功后再自己改功能加功能——比如给订单表加一个备注字段练习从数据库到 Servlet 到 JSP 的完整链路改造。这套项目最好的一点是可扩展性极强房间表加一个床位字段订单表加一个押金字段都能顺着原有代码结构快速实现。从那以后我每次拿到类似项目都会强制走一遍「先跑基础流程 → 再改一项小功能 → 最后验证旧功能不被破坏」的三步流程。这套方法论救过我很多次希望帮到你。本文还有配套的精品资源点击获取
返回列表