基于Java SpringBoot与Hadoop的酒店预订管理系统设计与实现

发布时间:2026/10/12 6:50:32
基于Java SpringBoot与Hadoop的酒店预订管理系统设计与实现 做酒店预订管理系统这个方向说实在的每年都有一大批人在做。但“基于 Java SpringBoot Hadoop 技术的酒店服务一体化系统研发”这个题目已经不是在写普通增删改查了而是把酒店预订管理系统、智能酒店推荐与管理平台两件事合并成一套完整方案。我最近刚好完整跑通了一条链路HTML5 前端做展示与预订SpringBoot 提供接口和事务处理Hadoop 负责从用户行为日志里离线计算酒店热度与个性化推荐结果最后把推荐结果回填到业务库前端直接展示。整个系统做下来既有主流程闭环又有大数据分析亮点用来当毕设或者求职项目展示都压得住场。下面我把这套系统的设计思路、核心实现、常见坑一次性写清楚。这套方案适合什么人群看一是准备做酒店类管理系统毕设的学生二是在校招项目里想体现“技术栈有深度”的开发者三是对 SpringBoot 和 Hadoop 整合关系不太清楚的初学者。我会把为什么选这套技术栈、每个模块怎么拆、数据库怎么设计、推荐算法怎么落地说清楚过程中还会带上可以照着抄的代码和操作步骤。1. 项目整体设计与技术选型思路1.1 这个题到底要解决什么问题很多人在拿到“酒店预订管理系统”这个题目时第一反应就是做四个页面酒店列表、酒店详情、下单、订单管理。这确实能跑但答辩时老师问一句“这个项目里有什么值得讲的技术点”往往就答不上来。我把这个题目重新定义了一下系统要覆盖用户从“浏览酒店”到“完成入住”的全过程同时让酒店运营人员和平台管理员能够处理房态、订单、价格和数据统计。在这个基本盘之上再加入一个“智能推荐”模块根据用户浏览过哪些酒店、收藏过哪些酒店、下过哪些订单生成个性化的酒店推荐列表。这样设计的核心价值有几点。第一业务链路完整不是只做前端页面也不是只做后台 CRUD。第二推荐模块是可扩展亮点它天然和数据挖掘、大数据处理挂钩。第三使用 Hadoop 做离线分析让整个系统的技术形态从“纯 Web 应用”变成了“Web 应用 大数据分析链路”在毕设评分和简历描述上都有明显优势。整个系统分三条线来理解用户端注册登录、酒店搜索与筛选、酒店详情和房型查看、在线提交订单、在线支付模拟、订单查询、评论与收藏。管理端酒店信息维护、房型管理、房价和库存设置、订单审核与处理、用户评论管理。数据分析端采集用户行为日志通过 Hadoop 离线统计酒店热门程度、用户偏好生成推荐结果供用户端和运营看板调用。这种划分方式能让开发进度可控。先做用户端和管理端把业务闭环打通再在闭环基础上叠加数据分析和推荐避免一开始就陷入大数据细节最后连核心功能都没完成。1.2 技术选型背后的取舍先回答一个很多人纠结的问题既然是毕设为什么不选传统的 SSHSpring Struts Hibernate或者 SSMSpring SpringMVC MyBatis而用 SpringBoot这里有一个很现实的理由SpringBoot 简化掉了大量 XML 配置内置 Tomcat使用 Maven 或 Gradle 引入依赖后就能直接启动。对于毕业生来说省下来的时间可以投入到业务逻辑和数据分析上而不是被配置问题卡住。同时 SpringBoot 是当前企业级 Java 开发的主流框架掌握它本身就是一个求职加分点。再回答第二个问题前端为什么用 HTML5而不是用 JSP 或者纯分离的 Vue 项目标题里强调“基于 HTML5”我最终实现时用的是静态 HTML5 CSS3 JavaScript配合 Vue 的 CDN 模式完成数据绑定。这样做的原因是不需要单独维护前端工程和构建工具直接用浏览器打开 HTML 页面调用 SpringBoot 提供的 RESTful 接口即可。而且移动端适配做起来很容易加上响应式布局之后手机、平板、电脑都能正常使用。然后是 Hadoop 的定位。很多人一听 Hadoop 就害怕是不是得搭一个几十台机器的集群实际上毕设场景完全不需要。Hadoop 完全可以运行在本地伪分布式模式也就是在一台机器上使用多个进程分别模拟 NameNode、DataNode、ResourceManager、NodeManager。我的做法是业务数据存在 MySQL用户行为记录存在 MySQL 的 user_behavior 表中每隔一段时间导出数据到 HDFS再用 MapReduce 离线计算酒店热度评分和用户相似度最终把计算结果写回 MySQL 的 recommend_result 表。这样既体现了大数据处理思路又不需要引入复杂的实时计算框架。为什么不用 Spark 替代 Hadoop如果我重新做一遍可能也会考虑 Spark但题目明确写的是 Hadoop 技术我建议顺着题目要求来。Hadoop 的 MapReduce 模型简单直接和“酒店热度统计”这种场景非常匹配而且毕设答辩时讲 shuffer、combiner 这些机制比讲一个封装好的 Spark 算子更有说服力。1.3 模块划分与数据模型设计我在工程结构上采用了模块化拆分而不是把所有类都塞在一个 main 包下。整体工程分为接口层面向用户端和管理端提供 JSON 接口。业务层处理订单创建、支付回调、房态变更、推荐结果查询等核心逻辑。数据访问层基于 MyBatis 完成 MySQL 读写。大数据模块独立的一个子模块包含 Hadoop MapReduce 任务和数据导出工具。这样的好处是将来如果你想单独把大数据模块跑在另一台机器上或者把接口层拆出来做微服务都非常方便。演示时也可以直接跳过 Hadoop 部分只推荐结果表一直保留系统照样能运行做到“有大数据能讲没大数据能演示”。数据库设计上我最终保留了这么几张核心表user 用户表包括用户账号、密码、昵称、手机号、用户等级。hotel 酒店表酒店名称、城市、地址、星级、设施标签、描述图片。room_type 房型表所属酒店、房型名称、面积、床型、是否含早餐、门市价。room 房间实例表具体房号用于精确控房。orders 订单表订单号、用户 ID、酒店 ID、房型 ID、入住时间、离店时间、金额、状态。comment 评论表订单完成后用户提交的评分和内容。user_behavior 行为表记录浏览、收藏、下单等行为。recommend_result 推荐结果表保存离线计算后的推荐酒店列表。订单金额不建议直接存在订单表里当唯一价格来源而是下单时从房型表读取门市价再叠加会员折扣和平台优惠计算快照。这样后续修改房型价格也不会影响历史订单。2. 核心功能拆解与实现要点2.1 酒店浏览、搜索与预订主流程用户端最关键的一条链路是搜索酒店 - 查看详情 - 选择房型和日期 - 提交订单 - 模拟支付 - 订单生效。搜索功能一定要支持多条件组合城市、入住日期、离店日期、入住人数、价格区间、酒店星级。我的实现方式是动态拼接 MyBatis 查询条件返回符合条件的酒店列表并且附带该酒店在当前时间段内最低可订房型价格这样列表页可以直接展示价位。酒店详情页需要展示酒店基础信息、房型列表、评论列表和推荐酒店。房型是否可订取决于两个因素该房型在搜索区间内是否有空闲房间以及是否设置了停售状态。我在这里做了一个很实用的接口接收开始日期和结束日期返回每个房型每天的可售房间数。前端用日历表展示用户可以直观看到哪天满房、哪天有房。预订环节要处理两个关键逻辑一是库存校验二是订单状态。库存校验不能只在提交订单时做一次。因为用户从看房到提交中间有几秒甚至几分钟的间隔房态可能已经变化。我在创建订单时使用数据库行锁先锁定房型对应记录再检查剩余可用房间数如果足够则扣减可售库存并创建订单否则直接返回“该日期段已满房”。整个过程放在一个事务里防止脏数据。订单状态我设计了七种待支付、已支付、已确认、已入住、已离店、已取消、退款中。用户提交订单后状态是“待支付”模拟支付成功后变成“已支付”。管理端确认后变成“已确认”办理入住改为“已入住”退房后改为“已离店”。用户取消待支付订单、支付超时、或者管理端拒绝确认则进入“已取消”。这里有一个小技巧给订单表加一个 create_time 字段并在业务层定时扫描超过 30 分钟未支付的订单把状态由“待支付”改成“已取消”同时释放对应房型的库存。这个功能虽然简单但能体现你考虑到了“支付超时释放资源”这样的生产环境问题。2.2 推荐引擎从规则到离线计算推荐模块是我最想讲的部分。它看起来好像很高大上实际拆开后就两条路实时推荐和离线推荐。实时推荐适合做“猜你喜欢”。我用规则做兜底如果用户没有登录或者行为数据太少就推荐当前城市热门酒店。如果用户已经登录则优先展示该用户浏览或下单过的同类酒店。离线推荐则依赖 Hadoop 来完成。整体思路是三步第一步从 MySQL 的 user_behavior 表读取用户行为数据写入 HDFS。因为这张表可能很大使用 Sqoop 直接导入也可以但为了能把过程讲清楚我写了一个简单的导出程序把行为记录生成 TSV 文本文件上传到 HDFS 指定目录。第二步编写 MapReduce 任务做用户-酒店行为矩阵统计。Mapper 阶段输出键值对“用户ID 酒店ID - 行为类型权重值”Reducer 阶段按用户聚合得到每个用户对每个酒店的兴趣总分。第三步根据用户兴趣总分计算相似用户。简单做法是把每个用户喜欢的酒店集合拿出来利用“共同喜欢的酒店数量 / 偏好集合长度的几何平均值”计算相似度选择最相似的 N 个用户把他们喜欢的但当前用户没看过的酒店作为候选推荐结果。最终结果写入 recommend_result 表。整个计算过程不需要太花哨关键是形成一条完整链路原始数据 - HDFS - MapReduce - 分析结果 - MySQL - 前端展示。答辩时把这条链路画出来比空谈算法有效得多。代码层面MapReduce 的 Reducer 可以简化到这种程度public static class RecommendReducer extends ReducerText, IntWritable, Text, IntWritable { Override protected void reduce(Text key, IterableIntWritable values, Context context) throws IOException, InterruptedException { int sum 0; for (IntWritable value : values) { sum value.get(); } context.write(key, new IntWritable(sum)); } }这段代码的意义不在于算法复杂度而在于展示你掌握了“分而治之”的大数据思想相同 key 的数据被分到同一个 Reducer 处理聚合结果输出到结果集。2.3 管理端与订单状态机设计管理端做得是否完整直接影响系统最终得分。很多毕设只给用户端做得很丰富管理端却只有一个登录页和一个列表页这明显不够。我的管理端包含四个核心页面酒店与房态管理管理员可以维护酒店基本信息、增加房型、设置每日价格和可售数量。订单处理中心按状态分栏展示订单支持确认订单、办理入住、办理离店、取消订单。评论管理展示酒店评论处理违规内容。运营数据看板统计今日订单数、营业额、入住率、热门酒店 Top10。订单处理中心是整个管理端最核心的部分。我会把订单状态设计成一个状态机在代码里显式控制每个状态下允许发生哪些操作。比如“待支付”状态只允许“取消”或“支付”“已支付”状态只允许“确认”或“退款申请”“已确认”状态只允许“入住”“已入住”只允许“离店”“已离店”只允许“评论”。除了这些状态迁移其余操作全部拒绝。这样做可以避免出现类似“还没支付就直接入住”这样的逻辑漏洞。管理端的数据看板我建议从两个维度做一是实时从 MySQL 里 count 出今天的订单量和销售额二是展示 Hadoop 分析所得的热门酒店数据。前者属于业务统计后者属于数据挖掘结果两者并排展示刚好把两种技术路径都呈现给评委。3. 实操过程从环境搭建到系统部署3.1 开发环境与工程结构我使用的版本组合是经过多轮测试的尽量沿用这套配置能省去很多兼容性问题。JDK 1.8Maven 3.6.3SpringBoot 2.3.xMyBatis 2.1.xMySQL 5.7Hadoop 2.10.x 单机伪分布式IDEA 2024 或 Eclipse 均可工程结构建议这样组织hotel-system ├── hotel-common // 公共类、工具类、统一返回结果 ├── hotel-api // 用户端接口 ├── hotel-admin // 管理端接口 ├── hotel-service // 业务逻辑 ├── hotel-mapper // MyBatis Mapper ├── hotel-recommend // Hadoop MapReduce 任务 └── hotel-front // HTML5 静态页面如果你不想拆得这么细也可以只用一个 Maven 工程包名内部做区分。但我不建议为了省事把所有类放在一个包里因为答辩时老师会看工程结构一个层次清晰的工程结构本身就是项目质量的一部分。Hadoop 的部署我这里强调几个命令。伪分布式模式下先配置好core-site.xml、hdfs-site.xml、yarn-site.xml然后执行hdfs namenode -format start-dfs.sh start-yarn.sh启动后可以用jps检查进程确认 NameNode、DataNode、ResourceManager、NodeManager 都在。注意不要在 Windows 上直接硬跑建议使用 Linux 虚拟机或者云服务器Windows 环境下权限校验和本地库加载都会带来额外麻烦。3.2 核心表结构与关键代码直接用一份建表 SQL 来展示数据结构比文字描述更清晰。订单表的简化结构如下CREATE TABLE orders ( id bigint(20) NOT NULL AUTO_INCREMENT, order_no varchar(32) NOT NULL COMMENT 订单号, user_id bigint(20) NOT NULL COMMENT 用户ID, hotel_id bigint(20) NOT NULL COMMENT 酒店ID, room_type_id bigint(20) NOT NULL COMMENT 房型ID, check_in_date date NOT NULL COMMENT 入住日期, check_out_date date NOT NULL COMMENT 离店日期, night_count int(11) NOT NULL COMMENT 入住晚数, total_amount decimal(10,2) NOT NULL COMMENT 订单金额, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 订单状态, create_time datetime NOT NULL COMMENT 创建时间, pay_time datetime DEFAULT NULL COMMENT 支付时间, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_user_id (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;订单号我建议自己生成而不用数据库自增 ID。生成规则可以是“当前时间戳 用户ID后四位 随机数”保证全局唯一。这样做很容易扩展到多台服务器不会因为换库而出现 ID 冲突。创建订单的核心代码要把事务和库存更新放在一起。一个精简版实现思路如下Transactional(rollbackFor Exception.class) public OrderResult createOrder(OrderCreateDTO dto) { // 锁定房型记录 RoomType roomType roomTypeMapper.selectByIdForUpdate(dto.getRoomTypeId()); if (roomType null) { return OrderResult.fail(房型不存在); } // 判读房型是否停售以及区间内是否还有可售房间 int available roomMapper.countAvailable( dto.getCheckInDate(), dto.getCheckOutDate(), dto.getRoomTypeId()); if (available 0) { return OrderResult.fail(当前日期段已满房); } // 生成订单并保存 Order order buildOrder(dto, roomType); orderMapper.insert(order); return OrderResult.success(order.getOrderNo()); }这段代码有一个关键动作selectByIdForUpdate。它在数据库层面给房型记录加锁避免两个用户同时提交订单时都判断“还有房”结果最后超卖。对于毕设级别的高并发场景这种行锁方案已经足够。3.3 Hadoop 离线分析模块接入接入 Hadoop 模块时我踩过不少坑这里直接说最终做法。第一步是数据准备。从 MySQL 里导出行为数据我用一个简单的定时任务每天凌晨把昨天的 user_behavior 数据导出成文本文件上传到 HDFS 的/hotel/behavior目录。第二步是提交 MapReduce 任务。我写了一个 HotelAnalyzeDriver在 main 方法里配置 JobJob job Job.getInstance(conf, hotel analyze); job.setJarByClass(HotelAnalyzeDriver.class); job.setMapperClass(HotelAnalyzeMapper.class); job.setReducerClass(HotelAnalyzeReducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); FileInputFormat.addInputPath(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); System.exit(job.waitForCompletion(true) ? 0 : 1);第三步是把 HDFS 上的计算结果拉回 MySQL。我在 AnalysisResultLoader 里读取 MapReduce 输出目录的文件逐行解析后写入 recommend_result 表。这一步可以在 Hadoop job 跑完后自动触发也可以手动执行。这里需要强调不要把 Hadoop 集群的启动和 SpringBoot 应用启动绑死。SpringBoot 一启动就尝试连 HDFS 是非常不明智的因为集群可能还没就绪。正确做法是SpringBoot 提供 REST 接口点击“开始离线分析”按钮时才触发 Hadoop 任务或者由后台定时任务调用 Hadoop 命令。这样演示时能灵活控制就算 Hadoop 没启动系统其余的酒店预订功能也完全不受影响。3.4 前后端联调与部署演示前端页面我使用了 HTML5 语义化标签加 CSS3 响应式布局再配合 Vue 的 CDN 方式写交互逻辑。这里有一个经验尽量将接口地址统一放在一个api.js文件里管理一个 baseUrl 常量。调试的时候如果前端是直接打开本地 HTML而后端跑在 8080 端口需要解决跨域问题。SpringBoot 处理跨域有两种办法。一是写一个配置类实现 WebMvcConfigurer添加addCorsMappings允许所有来源访问二是在接口上用CrossOrigin注解。整体开发体验上我推荐用第一种省得每个接口都要加注解。后端打包命令mvn clean package -DskipTests打出来的 jar 包可以直接运行java -jar hotel-api-1.0.0.jar如果是本地演示建议提前准备一套看起来真实的数据10 个城市、每个城市 5 到 10 家酒店、每家酒店 3 到 5 个房型、50 个用户、200 条评论、1000 条行为记录。数据太少前端页面空空荡荡数据太多运行和演示会卡。这个规模是最合适的。4. 常见问题与排查技巧实录4.1 SpringBoot 和 Hadoop 的集成差异第一个坑是启动 Hadoop 之后8080 端口被占用。Hadoop 的 NameNode Web UI 默认使用 9870 端口ResourceManager 默认使用 8088 端口注意不要和 SpringBoot 的 8080 混在一起。如果相互冲突优先改 SpringBoot 的端口在application.yml里设置server.port8080是预设值被占用时改 8081 即可。第二个坑是 Windows 环境下 Hadoop 报权限异常。Hadoop 在解析文件路径和本地库时依赖用户身份Windows 下经常出现Permission denied。我的解决办法是在 Linux 虚拟机上运行 Hadoop实验室电脑访问虚拟机 IP 上的 Web UI 和 REST API。如果你强制在 Windows 上运行需要下载对应版本winutils.exe放到 Hadoop bin 目录并配置HADOOP_HOME麻烦且容易踩更多坑。第三个坑是日志隔离。将 Hadoop 日志和 SpringBoot 日志混在一个控制台里排错非常痛苦。我给 Hadoop 任务单独指定日志输出文件然后使用grep关键字过滤查看。在开发时可以写一个 shell 脚本运行 Hadoop job把输出重定向到analysis.loghadoop jar hotel-recommend-1.0.0.jar /hotel/behavior /hotel/output analysis.log 214.2 并发预订下的超卖与重复支付订单系统最怕两类问题一是超卖二是重复支付。超卖问题本质上是因为“查询可用房间”和“扣减库存”不是原子操作。两个用户同时查到还有 1 间房然后同时下单就会都成功。我在前面代码里使用了selectByIdForUpdate行锁能解决这个问题。注意这个方法必须在事务里使用而且锁定的对象要和后续扣减库存使用的是同一张表记录否则锁不住。如果不想对整行记录锁那么久还可以使用乐观锁版本号。在房型表加一个version字段更新时检查版本号int count roomTypeMapper.updateStockWithVersion( roomTypeId, date, version); if (count 0) { return OrderResult.fail(手慢了房间被订走了); }重复支付则是订单状态控制的问题。如果用户在“待支付”状态下多次点击支付按钮会生成多个支付请求。我的做法是在订单表创建时生成一个全局唯一的biz_id支付接口用这个 ID 做幂等判断。如果支付回调里发现订单状态已经变成“已支付”直接忽略不重复修改金额和状态。这部分逻辑虽然表面上看不到但能体现你对支付场景的理解。4.3 推荐冷启动和可视化展示的小技巧推荐系统最大的问题是冷启动。新用户没有行为数据协同过滤算不出结果。我的处理方式是多策略叠加有行为的登录用户优先使用离线推荐结果。无行为的新用户推荐当前城市评分最高的 6 家酒店。热门兜底推荐全局订单量最高的酒店。推荐结果表里增加一个recommend_type字段标明“协同过滤”“热门推荐”或“城市推荐”。前端页面根据类型展示不同标签比如“根据您的偏好推荐”“本城市热销”“精选推荐”。这样就算算法结果不多页面看起来也是有依据的。展示层面有一个小技巧不要把推荐结果做成一整排静态卡片而是加一个“换一批”按钮每次随机展示候选列表里的一部分酒店。实现只需要在后端接口里多加一个随机排序参数User-Agent 无法感知但演示时会显得系统很灵活。推荐候选池要保证至少 20 条数据不然“换一批”几次后就会看到重复项很尴尬。我还做了一个简单的效果对比把“使用推荐引擎后的订单转化率”和“纯热门推荐转化率”用表格展示原始数据从业务日志里统计。即使只是模拟数据也比干巴巴讲算法更有说服力。下面整理一份常见问题速查表方便你排错问题现象可能原因解决办法SpringBoot 启动后端口被占用Hadoop 的 Web UI 端口冲突修改 server.port检查端口占用订单创建报“当前日期段已满房”并发下单或库存未释放开启事务使用行锁定时释放未支付订单库存推荐结果为空用户行为数据过少或协同过滤无法计算增加热门数据兜底策略Hadoop 任务运行很慢本地虚拟机配置较低数据量过大抽样数据调整内存参数一次只跑一周数据前端页面跨域请求失败未配置 CORS添加 WebMvcConfigurer 配置全局跨域前端图片加载不出来使用本地上传图片路径丢失图片上传后返回可访问的绝对 URL 并存入数据库最后再分享一点我自己的体会。毕设项目最忌贪多不要一开始就想把实时推荐、分布式事务、微服务全套塞进来。我在做这套系统的过程中最耗时间的不是代码而是调整 Hadoop 与 SpringBoot 的协作方式让它们各自独立又能形成整体。建议你从“一个能完整运转的预订系统”出发再逐个加上分析功能保证每个阶段都能跑、能演示。数据量也不要追求“大数据”几千条到几万条就足够说明问题关键是链路要完整从用户行为到 HDFS从 MapReduce 到推荐结果再到前端展示每一步都能自圆其说。这一套做下来无论毕业答辩还是简历项目复盘都会非常有底气。