简介:这是一套基于 IDEA 开发、采用 Maven 拆分聚合的酒店管理系统完整工程,面向毕业设计、课程设计、期末大作业、工程实训与初期项目立项等场景。后端由 JSP、Spring、Spring MVC、MyBatis Plus、Shiro 构成,并接入第三方短信验证接口;前端使用 layUI 与 EasyUI,数据库为 MySQL。资源包共 2000 个文件,约 111.36MB,其中 718 个 CSS、613 个 HTML、439 个 JS、96 个 JSP,以及若干 JSON、XML、JAVA 文件,涵盖页面样式、前端交互、后端接口与配置信息,目录结构清晰,便于对照学习和二次开发。已有 37 人学习下载。项目经过严格测试,功能完整,可用于复现复刻,也可作为设计报告的参考蓝本;资源内包含源码、工程文件及说明(如有),适合需要完整可运行项目来支撑答辩或扩展功能的开发者。下载后如遇环境配置或运行问题,可与作者交流获取帮助。 做酒店管理系统这个项目的人真的非常多,可以说是我见过最经典的 Java Web 练手题目之一。我在 IDEA 里从零到一完整实现过一版,从表结构设计到房间状态流转都踩过不少坑,这篇博文就把整套思路、技术选型和实操步骤完整梳理一遍,包括那些网上教程不会告诉你的细节。无论你是准备课程设计、毕业设计,还是想通过一个完整项目巩固 Spring Boot 和 MyBatis 的用法,这篇内容都适合你。
1. 这项目到底做了什么,值不值得做
酒店管理系统本质上是典型的 CRUD 加业务流程管理项目,核心就三件事:管房间、管客户、管订单。听起来简单,但它完整覆盖了一个真实业务系统的所有关键环节:登录认证、数据建模、状态流转、金额计算、统计查询,每一块都是找工作面试时会被反复问到的内容。
我选择基于 IDEA 来开发,原因很简单——IDEA 是当前 Java 开发事实上的标准 IDE,它的代码提示、调试器、Git 集成、数据库工具都做得非常成熟。用 IDEA 做这种项目,你可以把精力放在业务逻辑本身,而不是跟编辑器较劲。搭好环境之后,从创建 Spring Boot 项目到跑通第一个接口,全程鼠标点点点就能完成。
这类项目真正有价值的地方在于业务闭环。酒店的房间不是静态数据,它有空闲、已预订、已入住几个状态;客户下单要考虑日期冲突;退房时要按天数算钱。这些逻辑串起来就是一个完整的小型业务系统,远比单纯写几个增删改查接口有含金量。做完这个项目,你对 Spring Boot + MyBatis 的整体协作方式、前后端数据交互、数据库表之间的关系都会有非常直观的理解。
2. 环境准备与IDEA配置:别在这一步劝退
2.1 工具版本怎么选
很多初学者一开始就在环境上卡住。我的建议是:不用追新,用稳定版本。JDK 用 8 或者 11 都可以,Spring Boot 用 2.7.x 系列,Maven 用 3.8.x,MySQL 用 5.7 或 8.0。这套组合在网上能找到海量资料,遇到问题也好搜。
IDEA 方面,我推荐直接用 IntelliJ IDEA,旗舰版或者社区版都行。社区版免费,日常 Java 开发完全够用,不需要花时间折腾其他东西。如果你主要做后端开发,不涉及前端专业框架,社区版是你最省心的选择。
2.2 IDEA最关键的几处配置
IDEA 装完之后不要急着写代码,先做三件事。第一是配置 Maven。打开 Settings → Build Tools → Maven,把 Maven home path 指向你本地解压的 Maven 目录,User settings file 指向你的 settings.xml。然后在 settings.xml 里配置阿里云镜像,不然下载依赖会慢到你怀疑人生。
<mirror> <id>aliyunmaven</id> <mirrorOf>central</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/public</url> </mirror>第二是配置 JDK。在 Project Structure → Project 里把 SDK 选成你安装的 JDK 版本,Language level 选择对应的版本。这里最容易踩的坑是:JDK 装好了,但 IDEA 里的 Project SDK 还是空的,导致代码标红。第三是建议在 IDEA 自带的 Database 面板里连接一次你的 MySQL 数据库,好处是后面写 SQL、看表结构都不用再切到 Navicat,直接在 IDEA 里操作。
注意:settings.xml 里不要只配置 mirror,最好把本地仓库位置也设一下。默认本地仓库在用户目录下的 .m2 文件夹,我习惯改成 D 盘或其他非系统盘,避免重装系统时环境全丢。
3. 技术选型与表结构设计:先把地基打牢
3.1 技术栈:老牌组合最稳
技术选型我没有做任何花哨的东西,就是 Spring Boot + MyBatis + MySQL,前端用简单的 Thymeleaf 模板引擎加上 Bootstrap。这套组合的好处是学习曲线平缓,每一层的作用都非常清晰。Spring Boot 负责装好整个应用的骨架,MyBatis 负责数据库操作,Thymeleaf 直接在 HTML 里写数据渲染逻辑,配合 Bootstrap 能快速出一个看着不丑的管理界面。
很多人会纠结要不要用 MyBatis-Plus,我建议学习阶段先用原生 MyBatis,把 SQL 自己写一遍。等你理解了 Mapper 接口和 XML 的映射关系,再切换 MyBatis-Plus 只是加一个依赖的事。直接用 Plus 会让你跳过很多基础概念,后面排查问题会吃力。
3.2 数据库设计:五张表搞定核心业务
我设计的数据库一共六张表,覆盖了用户、房间、客户、预订、入住这几个核心概念。下面是表结构和关键字段说明。
| 表名 | 作用 | 关键字段 |
|---|---|---|
| sys_user | 系统登录用户 | id, username, password |
| t_room | 房间信息 | id, room_no, room_type, price, status |
| t_customer | 客户信息 | id, name, phone, id_card |
| t_reservation | 预订记录 | id, room_id, customer_id, check_in_date, check_out_date, status |
| t_checkin | 入住记录 | id, reservation_id, room_id, customer_id, deposit, create_time |
| t_order | 退房结算订单 | id, checkin_id, total_amount, settle_time |
核心表就是上面这些,关键的 DDL 也比较简洁,比如房间表我这样建:
CREATE TABLE `t_room` ( `id` int NOT NULL AUTO_INCREMENT, `room_no` varchar(10) NOT NULL COMMENT '房间号', `room_type` varchar(20) DEFAULT NULL COMMENT '房型:单人间/双人间/套房', `price` decimal(10,2) DEFAULT NULL COMMENT '门市价', `status` tinyint DEFAULT '0' COMMENT '0-空闲 1-已预订 2-已入住', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;状态字段用数字而不是字符串,国内大多数业务系统都这么设计。好处是存储空间小、查询效率高,但需要在代码里定义常量或枚举来对应。
设计表的时候最大的教训是:预订表和入住表一定要分开。最开始我想省事,一张订单表搞定所有,结果退房结算时逻辑混乱得不行。拆开之后思路清晰很多——预订是客户还没来,入住的客户已经到了,这两种数据的状态完全不同。
4. 核心功能实现:把房间状态流转玩明白
4.1 登录认证:学习项目别上框架
登录认证这块,我没有引入 Spring Security,原因是这个项目体量用不上那么重的框架,学习阶段自己写个拦截器更能理解原理。用户登录成功后把用户信息放 Session,同时写一个拦截器统一校验。
public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); Object user = session.getAttribute("loginUser"); if (user == null) { response.sendRedirect("/login"); return false; } return true; } }密码存储绝对不要用明文,我用的 BCrypt 加密,Spring Security 里的 crypto 模块可以直接引用,不需要引入整个 Security 框架。
注意:拦截器一定要把你放行的路径配置对了,比如 /login、/css/、/js/这些。我一开始忘了放行静态资源,导致登录页 CSS 全部加载失败,页面丑成一坨,排查了半天才发现是拦截器把所有静态请求也拦了。
4.2 房间管理与状态机
房间状态是整个系统的核心,我的设计是 0-空闲、1-已预订、2-已入住。三种状态之间的流转关系:
- 空闲 → 已预订:客户下预订单
- 已预订 → 已入住:客户到店办理入住
- 已入住 → 空闲:客户退房结账
- 已预订 → 空闲:客户取消预订或超时未到
这个流转关系我用一个单独的 RoomStatus 常量类来管理,避免魔法数字散落在代码各处。改房间状态时,前端下拉列表要根据当前状态动态生成选项,不能让人把一个已入住的房间改成空闲,否则账目就乱了。
4.3 预订、入住、退房的完整闭环
预订的核心逻辑是日期冲突校验。客户要订某个房间之前,必须检查这个房间在目标时间段内是不是已经被占了。SQL 这样写:
select count(*) from t_reservation where room_id = #{roomId} and status in (0, 1) and ((check_in_date < #{checkOutDate} and check_out_date > #{checkInDate}))这个时间段重叠的判断条件,凡是做过排课、订房、会议室预约的人应该都不陌生——新订单的开始时间要小于已有订单的结束时间,新订单的结束时间要大于已有订单的开始时间,条件成立就说明有重叠。
入住办理比较简单,先把预订状态改成已使用,然后往入住表插一条记录,同时把房间状态改成已入住。退房结账是另一个容易出问题的地方:房价 × 天数,但延迟退房怎么收费、押金怎么抵扣,这些业务规则都要提前想好。我当时的规则是下午两点前退房不加钱,两点后按半天收,超过六点按全天收。
用 Java 写天数计算时有个坑,直接拿毫秒数除以 86400000 会有问题,最好用 LocalDate 的 ChronoUnit.DAYS.between 方法,能避免夏令时和毫秒舍入带来的误差。
5. 从零创建工程:一套能直接跑通的步骤
5.1 新建Spring Boot项目
打开 IDEA,选择 New Project → Spring Initializr。如果你访问 start.spring.io 很慢,可以把 Server URL 改成阿里云的https://start.aliyun.com,速度会快很多。GAV 坐标自己定好,Java 版本选 8,依赖那里勾选 Spring Web、Thymeleaf、MyBatis Framework、MySQL Driver 这四个就够了。
项目创建完后,IDEA 会自动下载依赖,第一次会比较慢,等右下角进度条跑完就好。如果下载失败,检查一下上一章说的 Maven 镜像配置。
5.2 配置文件与代码分层
application.yml 里的配置是重头戏,数据库连接一定要把时区参数带上:
server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/hotel_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.hotel.entity configuration: map-underscore-to-camel-case: true最后那个map-underscore-to-camel-case: true非常关键,它能让数据库的下划线字段名自动映射成 Java 的驼峰属性名,比如room_no可以自动映射到roomNo字段,不用在 XML 里写一堆 resultMap。
代码分层我严格按照 Controller → Service → Mapper 三层来走,实体类放 entity 包,统一放在 com.example.hotel 包下面。
5.3 跑通一次全流程
基础代码写完之后,我最先跑通的是房间列表查询。先在 t_room 表里插几条测试数据,然后写 RoomMapper 接口:
public interface RoomMapper { List<Room> findAll(); Room findById(Integer id); int updateStatus(@Param("id") Integer id, @Param("status") Integer status); }再写对应的 RoomMapper.xml,注意 namespace 一定要和接口全限定名一致。接着写 RoomService 和 RoomController,最后在 Thymeleaf 模板里用th:each循环渲染列表。这一套流程跑通之后,剩下的预订、入住功能就是在它的基础上加业务判断而已。
重点:每次改完 Mapper XML 里的 SQL,建议按 Ctrl+Shift+F9 重新编译一下对应模块,否则可能加载到旧的 SQL。IDEA 有时候不会自动热更新 XML 文件,我因为这个"改 SQL 不生效"的问题浪费过不少时间。
6. 实操中遇到的坑与排查技巧
整个项目做下来,遇到的问题大大小小有十几个,下面这几个最有代表性,分享出来帮大家少走弯路。
Maven 依赖下载慢或失败。除了配阿里云镜像,还要注意 IDEA 里 Maven 的 "Always update snapshots" 选项,很多时候 IDEA 缓存了旧的失败记录,导致后续即使镜像通了也不重新下载。遇到这种情况,执行mvn clean package -U强制刷新一次。
启动报数据库连接失败。先确认 MySQL 服务有没有启动,再用命令行工具试一下能不能连上。很多时候是密码写错或者时区参数没加,报错信息里带The server time zone value基本就是时区问题。
MyBatis 报 "Invalid bound statement (not found)"。这基本是 XML 文件没有正确扫描到。检查三点:pom 里有没有把 mapper 目录打进类路径(resource 文件夹下的 XML 一般没问题)、application.yml 的 mapper-locations 路径对不对、XML 的 namespace 和接口是不是一致。
IDEA 修改代码后不生效。Spring Boot 默认没开热部署,我每次改完代码都手动重启,后来干脆加了一个依赖 spring-boot-devtools,改完代码自动重启,效率提升很明显。不过要注意 devtools 和远程调试有冲突,本地开发用就好。
Git 提交代码时报错。IDEA 里 Git 提交如果提示Please tell me who you are,说明没有设置用户名和邮箱,在终端里执行:
git config --global user.name "你的名字" git config --global user.email "你的邮箱"端口被占用。IDEA 启动时提示Port 8080 was already in use,先查一下是什么进程占用的端口。Windows 上是netstat -ano | findstr 8080,然后去任务管理器结束对应 PID 的进程,或者直接改 application.yml 里的 server.port。
7. 写在最后:几点真实体会
项目全部跑通之后,我的感受是:酒店管理系统这种老牌项目能够长盛不衰,是因为它麻雀虽小、五脏俱全。开发过程中最值钱的部分不是代码量,而是业务流程设计的思维——房间状态怎么流转、订单怎么关联、日期冲突怎么判断,这些问题面试官随便挑一个都能聊很久。
我个人有个建议:第一版不要追求功能大而全,先把预订、入住、退房这个闭环做到毫无 bug,然后把代码重构得干净一点,把异常处理做好,这比堆十个华而不实的功能都有用。等这个闭环完全跑通,你自然会知道哪些地方可以扩展,比如接入支付、做会员等级、上线小程序端,整个系统的扩展路径会非常清晰。
做完这个项目之后,我对 IDEA 的熟练度也上了一个台阶,快捷键、断点调试、数据库面板、Git 操作这些都已经变成了肌肉记忆。工具这个东西就是这样,在真实项目中反复用,才能真正内化成自己的技能。
本文还有配套的精品资源,点击获取