news 2026/10/21 9:46:22

基于Spring Boot+Vue的酒店预订系统设计与实战全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Spring Boot+Vue的酒店预订系统设计与实战全解析

做酒店预订系统这个选题的,十有八九是拿来当毕设、课程设计或者练手项目。标题里写得很清楚:基于 Spring Boot + Vue 的酒店预订系统,附带源码、数据库脚本和文档。这个组合听起来很常规,但真的把它从零搭起来、跑通、再到能答辩或面试时讲清楚,其实有不少门道。我基于自己做过的一版相似系统,把核心设计、实现过程、踩坑记录完整拆一遍,你可以直接照着思路去复现。

1. 先聊清楚:这个系统到底该做成什么样

1.1 从一句话需求到一个可演示的系统

大家收到这类题目时,最常犯的错误就是上来就写代码。实际上,先把需求拆成一条一条可验证的功能点,后面才不会做着做着就乱了。

酒店预订系统,核心用户有两类:普通住客和管理员。住客能看到在售房间、下订单、查看自己的订单、取消未入住的订单,也有人希望加一个简单的评论功能。管理员则需要维护房间信息、处理订单状态、管理用户。这一套东西捋完,系统的边界就清楚了:前台展示 + 用户操作 + 后台管理,三个大模块。

我在动手前会把功能列表整理成一张表格,每做完一项就勾掉一项,这样能控制开发节奏,也方便最后写文档时对照着补内容。

模块功能点角色
用户端注册、登录、浏览房间、检索房间住客
用户端提交预订订单、订单支付模拟、取消订单住客
用户端查看订单历史、删除评论住客
管理端管理员登录、房间信息管理管理员
管理端房间类型管理、轮播图管理管理员
管理端订单状态管理、用户封禁管理员

1.2 为什么选 Spring Boot + Vue,能不能换别的

这个组合之所以在近几年的毕设项目里霸榜,不是因为跟风,而是因为它确实在"完成度"和"学习成本"之间拿捏得最好。

后端用 Spring Boot,免去了繁琐的 XML 配置,内置 Tomcat,打成 jar 包就能跑。对于学生或者刚开始做全栈的人来说,这比折腾 SSH(Spring + Struts + Hibernate)那套老古董要友好太多。配合 MyBatis-Plus,CRUD 操作基本不用手写 SQL,开发速度非常快。当然,如果你对 JPA 更熟也可以换,但 MyBatis-Plus 在中文社区资料多,遇到问题好搜,这是很实际的优势。

前端选 Vue,是因为它的响应式数据绑定和组件化开发,在实现"房间列表 - 详情 - 下单"这套流程时非常顺手。Vue 3 的组合式 API 比 Vue 2 的 Options API 更简洁,配合 Element Plus 组件库,后台管理界面半天就能搭出个像样的框架。

如果你已经熟练使用 React,那也可以换成 React,但如果你只是需要一个能快速出成果的方案,Vue 是更稳的选择。说句实在话,对于这种体量的系统,前端用什么框架不影响核心业务,重要的是你能解释清楚数据是怎么流转的。

1.3 整个系统的架构,一句话说明白

架构上不用搞得太复杂,前后端分离就够了。

前端 Vue 项目通过 Axios 调用后端提供的 RESTful 接口,后端 Spring Boot 接收请求后调用 Service 层处理业务逻辑,再通过 MyBatis-Plus 操作 MySQL 数据库。用户登录之后,后端签发一个 JWT Token,前端把它存在本地,每次请求时带上,后端通过拦截器校验 Token 并识别用户身份。

这套流程可以用这样一张数据流来描述:

Vue 页面 → Axios → Controller → Service → Mapper → MySQL ↑ ↑ JWT 拦截器 业务校验

理解了这条链路,后面写代码时心里就有数了。

2. 数据库设计:这个系统的心脏

2.1 到底需要几张表

数据库是很多新人最容易糊弄过去的地方,但订单系统最怕的就是表结构不合理。等写到订单状态流转时,你会为当初的草率付出代价。

我最终设计的是一套 8 张表的方案,逻辑比较顺,分享给你参考:

  • 用户表(t_user):id、用户名、密码(加密存储)、姓名、手机号、角色(1 表示管理员,0 表示普通用户)、创建时间。
  • 房间类型表(t_room_type):id、类型名(如大床房、双床房)、单价、面积、床型、可住人数、图片地址。
  • 房间信息表(t_room):id、所属类型 ID、房号、房间状态(0 表示空闲,1 表示已入住,2 表示打扫中)。
  • 订单表(t_order):id、订单编号、用户 ID、房间 ID、入住日期、退房日期、订单金额、下单时间、订单状态(0 待支付,1 已支付,2 已入住,3 已完成,4 已取消)。
  • 评论表(t_comment):id、用户 ID、房间 ID、评论内容、评分、评论时间。
  • 轮播图表(t_banner):id、图片地址、跳转链接、排序。
  • 收藏表(t_favorite):id、用户 ID、房间 ID。功能是让用户可以收藏心仪的房间。

这张表结构设计好之后,要记得在建表脚本里加上外键逻辑和索引。订单表中对用户 ID、房间 ID 建索引,因为查询订单时基本都是按用户维度高频访问,不加索引的数据量一上来就会卡。

2.2 房间库存与价格的建模

这里有一个比表结构更重要的问题:库存到底该怎么算。

很多人的直觉是给房间表加一个"剩余数量"字段,下单时减一。但酒店的真实情况是,库存不是简单的总数,而是"某一天是否有空房"。一个房间连续预订 5 晚,不代表它 5 天的库存都能卖出去,要看你按什么维度去卖。对于练手项目,为了控制复杂度和演示效果,我建议按"房间实体"来管理库存:每个房间号就是一个独立的可售卖单元,下单时根据所选日期区间判断该房间在区间内是否有重叠的订单。

这样做的好处是逻辑直观:一个房间在某个时间段被订单占用后,再有人想订同一时间段就会提示无房。虽然粒度比较粗,但完全满足毕设演示和业务讲解的需求。如果你有时间,后续可以升级为"按天生成库存表"的方案,但那套会多出很多逻辑,建议先不加。

2.3 订单状态机:从 A 状态到 B 状态

订单状态是整个系统里最容易出 bug 的地方,我见过很多人的代码里状态写成随意的字符串,然后在 if 判断里手滑拼错,排查了很久。

我建议把所有状态定义成常量类或枚举,项目中所有代码统一引用。订单状态我拆成了 5 个:

  • 0:待支付。下单后默认状态。
  • 1:已支付。模拟支付完成后进入。
  • 2:已入住。用户办理入住后由管理员标记。
  • 3:已完成。退房后由管理员标记。
  • 4:已取消。用户主动取消,或者订单超时未支付自动取消。

状态的流转方向是单向的:待支付 → 已支付 → 已入住 → 已完成。已取消是终态,不能再变更。后端在更新状态时,必须校验当前状态是否允许迁移到目标状态。比如待支付订单不能直接变已完成。这个校验逻辑虽然简单,但在答辩时讲出来会显得你的设计很专业。

3. 后端核心逻辑:从注册到下单的全链路实现

3.1 注册、登录与权限控制你不能绕过的那道坎

用户注册登录看着简单,但要用规范的方式做,而不是把密码明文存进数据库。我实际项目里用的方案是:密码通过 BCrypt 加密后再入库,这是 Spring Security 框架自带的能力,调用起来非常方便。

登录成功后,后端生成一个 JWT Token 返回给前端。前端把 Token 存在浏览器的 localStorage,之后每次发请求,在拦截器里自动把 Token 放到请求头的 Authorization 字段里。后端通过自定义拦截器对需要登录的接口做统一校验。

需要注意一个细节:JWT 生成时可以携带用户 ID 和角色信息,但不要携带密码等敏感数据。解析 Token 时如果过期或签名不一致,直接返回 401 状态码,前端收到后自动跳转到登录页。用户角色建议默认给普通用户,管理员账号可以在数据库初始化脚本里直接写死一个,密码也走 BCrypt 加密后的值。

3.2 房间查询接口的两种搜索方式

房间列表和查询是用户端的核心。真正的细节在于怎么处理"根据条件筛选房间"。

我做了两个查询接口:

  • 查询所有房间类型列表,用于首页展示。
  • 根据条件搜索房间,支持按房间类型、入住日期、退房日期筛选。

第二个接口的核心难度在于日期筛选。用户的逻辑是:我想入住日期是 A,退房日期是 B,那么系统要找出所有在 A 到 B 区间内没有冲突订单的房间。

这里有一个很常见的误区:直接用 SQL 判断"订单的入住日期区间"是否与"用户选择区间"重叠。如果只判断"订单的开始日期不等于用户的开始日期"是不够的,因为重叠有多种情况:用户的区间完全包含在已有订单区间内、用户区间与已有订单区间部分重叠、已有订单区间完全包含在用户区间内。

正确的判断逻辑是:找出所有存在冲突的订单,条件是"订单的入住日期小于用户的退房日期,并且订单的退房日期大于用户的入住日期",然后把这两个条件之间冲突的订单对应的房间 ID 剔除,剩下的就是可订房间。

你可能会问我这样写 SQL 会不会很绕?确实有一点,但这是数据库日期区间重叠问题的标准做法,面试时也是高频考点。

3.3 下单与防超卖:事务和并发,必须一起处理

下单是整个系统最核心的业务逻辑,处理不好会出现一房多卖的情况。

我的具体实现流程是这样的:

  1. 前端把房间 ID、入住日期、退房日期提交到后端。
  2. 后端根据房间 ID 查询房间信息,计算出订单金额(单价 × 天数)。
  3. 校验所选日期范围内是否已有冲突订单。
  4. 如果没有冲突,则插入订单记录,初始状态为待支付。
  5. 模拟创建一个预支付单(实际系统中这一步会调用第三方支付接口)。

这里最容易踩的坑是并发问题。如果两个人同时点击预订同一个房间的同一个日期段,两个请求同时通过了冲突检查,然后都插入订单,房间就被重复预定了。

解决这个问题我用了两种手段叠加:

  • 在订单表中,对"房间 ID + 入住日期 + 退房日期"三个字段建立联合唯一索引。
  • 插入订单前先执行一条 SELECT ... FOR UPDATE,把对应房间的记录锁住,确保同一时间只有一个事务能通过校验。

对于毕设项目来说,联合唯一索引这一招就足够展示你懂并发问题了,双保险则更稳。在讲解时能主动提到"防超卖",这是一个实实在在的加分项。

3.4 模拟支付:精心设计的演示环节

这位系统的"支付"不需要真的接入微信或支付宝,那会涉及商户号、回调等很麻烦的资质问题。我采用的方案是模拟支付。

用户提交订单后,订单处于待支付状态,系统同时生成一个支付二维码的模拟图,前端展示一个"确认支付"按钮。用户点击后,调用后端支付接口,接口将订单状态从待支付修改为已支付。这个方案足以演示闭环流程。

如果你想做得更有真实感,可以加个 sleep 延迟制造一种"正在处理中"的等待效果,但要注意别做得太久,影响体验。核心目的是把状态流转演示出来,而不是真的去对接第三方支付。

4. 前端实现:Vue 3 工程化的实践细节

4.1 项目初始化和路由设计

前端我使用的是 Vue 3 + Vite。Vite 的启动速度和热更新体验比旧工具链好太多,对开发效率提升很大。项目创建后,第一件事是划分目录结构,我大致会分成这些部分:

  • views:页面组件,按用户端和管理端分目录。
  • components:公共组件(轮播图组件、房间卡片组件等)。
  • router:路由配置。
  • store:Pinia 状态管理。
  • api:接口请求封装。

路由设计上分为两个部分。用户端的路由有首页、房间列表、房间详情、登录注册、个人中心、我的订单。管理端路由有仪表盘、房间管理、订单管理、用户管理,统一挂载在一个管理后台布局组件下。管理端路由需要加一个前置守卫,判断当前登录用户的角色是否为管理员,不是就强制跳转首页。

4.2 接口封装与状态管理

Axios 封装是所有前端项目标配。我习惯创建一个 api/request.js,对所有请求进行统一配置:

  • baseURL 设置后端的地址前缀。
  • 请求拦截器里,从 localStorage 中取 Token 放到请求头。
  • 响应拦截器里,对返回的状态码做统一处理,比如 200 直接返回数据,401 则清除 Token 并跳转登录页。

这样为啥要封装?因为如果你在每一处发请求都手动拼 Token 和状态处理,代码会非常冗余,而且后面对接真实接口时,改动一处就行。这是前端工程化的基础操作,必须会。

状态管理我用了 Pinia,主要是存储登录用户信息。用户登录成功后把用户对象存进去,用户端展示头像、用户名、退出登录按钮都从这里读取。订单、房间列表这些数据不必放全局状态里,因为在组件内部用 reactive 就够了,没必要把所有数据都塞进全局 store 增加复杂度。

4.3 几个关键页面的实现思路

首页的布局一般包含轮播图、房间类型快捷入口、特价推荐房间。轮播图数据从系统调用接口获取,接口返回图片路径列表,前端用 Element Plus 的 Carousel 组件循环渲染。

房间列表页要注意分页和筛选。筛选条件区放"房间类型"下拉框、"入住日期"和"退房日期"日期选择器,用户选择后点击搜索,触发列表接口重新请求。分页我用的是 El-Pagination 组件,后端接口接收 pageNum 和 pageSize 参数,返回总记录数和当前页数据。

房间详情页展示了房间图片、价格、床型、面积和入住人数,下面是一个预订表单,用户选择入住和退房日期,系统自动计算金额。顶部的日期选择器要禁用掉过去的日期,避免用户选错。

后台管理界面相对简单。房间管理表格展示房间号、类型、价格、状态,支持新增、编辑、删除操作。新增和编辑共用同一个表单弹窗,提交时根据是否传入 ID 来决定是新增还是更新。

5. 从本地联调到实际部署:把这套系统跑起来

5.1 本地环境的准备

本地开发时,我使用的工具版本供参考:JDK 1.8 或 17 都可以,但建议保持统一;MySQL 5.7 或 8.0;Node.js 14 以上;IDEA 或 VS Code 都行。

第一步是导入后端项目,用 IDEA 打开后等待 Maven 下载依赖。数据库方面需要先新建一个库,然后执行项目提供的 SQL 脚本,把表结构和初始数据导入。推荐用可视化工具执行,方便检查每条语句是否正确执行。

在 application.yml 里需要改两个地方:数据库用户名和密码。这个改了之后,启动 Spring Boot 项目,如果控制台出现"Started Application in x seconds",说明后端已经跑起来了。

前端项目用 npm install 安装依赖。如果慢就用国内镜像源。装完依赖后,npm run dev 启动开发服务器,默认地址是 5173 端口。这时候打开浏览器访问前端页面,如果页面能正常显示,就说明前后端环境都准备好了。

5.2 前后端联调的关键配置

前后端联调最容易出现的问题是跨域。前端地址是 5173 端口,后端是 8080 端口,端口不同便会触发跨域。解决方式我推荐在后端配置一个 Cors 过滤器,允许来自前端地址的请求,这个配置在后端代码里加上即可。

另一个需要注意的问题是后端接口访问地址。我用的是相对路径,比如 /api/room/list,这个路径需要保证前后端配置一致。建议在后端所有接口加一个统一的 api 前缀,后续调整路由或部署时不至于乱了套。

联调时优先试一遍登录功能。能登录成功,说明数据库配置、密码加密、Token 签发这一条完整链路都是通的。然后再测房间列表、下单、支付这三个核心链路,依次排除问题。

5.3 打包部署的两种常见方案

到了验收阶段,你需要把系统部署起来给别人演示。有三种常见的方案可以选。

第一种是前后端分别打包部署。后端打包成 jar 包,用 java -jar 命令运行;前端执行 npm run build,生成静态文件后扔到 Nginx 里托管。这种方式最接近真实项目环境,适合在演示服务器上使用。

第二种是对学生最推荐的方式:直接用 IDEA 运行后端 + npm run dev 运行前端,用开发模式演示。虽然只适合本地环境,但胜在简单稳定,不会因为环境问题影响演示效果。我当年验收时就用的这种方式。

第三种是把前端打包后的 dist 目录放到后端的 static 目录下,后端一个 jar 包同时提供接口和页面服务。这样做的好处是只需要启动一个服务,但容错性差一些,不太建议作为首选。

6. 联调与部署时的常见坑

6.1 印象最深的 5 个问题及排查思路

现象原因解决办法
前端请求接口,控制台报 404后端接口路径与前端请求路径不一致打开后端控制台,看启动日志中接口映射的完整路径,用 Postman 直接测试接口,确认路径后再修改前端
登录接口报 500,密码错误一直登不上数据库密码字段长度不足,BCrypt 加密后字符串超长被截断把密码字段长度改为 60 以上,重新执行 SQL 脚本,重新注册再测试
前端页面加载出来但没有数据数据库连接失败或 SQL 脚本没执行成功检查后端日志中的数据库连接报错信息,确认账号密码正确、库已创建
提交订单时提示房间已被占用,但明明没有该订单事务未提交时自己也查到了冲突订单检查是否有事务注解,确认在冲突校验时使用的是当前事务级别查询
前端登录成功后刷新页面,用户信息丢失用户状态只存在内存中,没有持久化将用户信息存到 localStorage,刷新时从本地读取并恢复登录状态

6.2 几个容易被忽视但很影响体验的细节

第一,房间日期选择器的禁用逻辑要处理到位。入住日期不能选今天之前,退房日期不能早于入住日期。少数前端组件库对日期禁用提供了现成的属性,但你还是要在提交时做一次后端校验,防止有人绕过前端直接调接口。

第二,订单编号的生成要保持唯一。直接使用主键自增再做展示会暴露数据量,可能显得项目很业余。我建议用"时间戳 + 用户 ID 后四位 + 随机数"的组合来生成订单号,格式类似 20250515xxxx,演示的时候也更好讲解。

第三,管理员账号的初始密码最好用一次性密码,首次登录后提示修改,不过如果在演示场景下,保持简单密码会更方便现场操作。这个可以根据你的处境自己权衡。

我个人在实际做这种项目的过程中,体会最深的是千万不要小看数据库设计和订单状态管理这两块。它们在你最开始觉得"无非就是写几个接口"的时候,会精准地把你打回原形。无论是毕设答辩时要解释的"并发防超卖",还是面试官可能会深挖的"日期区间重叠查询",本质上都是这两个核心点的延伸。把这套内容彻底吃透,比你多写两个页面有用得多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 11:20:33

继续教育课堂汇报AI工具指南:10款写作降重润色工具实操

1. 继续教育课堂汇报的痛点与工具选型逻辑1.1 为什么继续教育场景对汇报工具的需求如此特殊继续教育这个场景,跟全日制本科或研究生课堂有本质区别。学员往往是在职人士,白天上班晚上上课,时间碎片化严重;课程周期短,通…

作者头像 李华
网站建设 2026/10/21 3:17:28

电网101/104规约测试:报文解析与模拟主站实战指南

简介:一套面向电力系统自动化领域的规约测试工具组合,专用于IEC 60870-5-101/104通信规约的调试与验证,适合电网设备厂商、调试工程师及变电站运维人员使用。压缩包共169个文件、约21.62MB,其中dat/cfg配置样本用于组织测试场景&a…

作者头像 李华
网站建设 2026/10/21 1:25:08

Claude Code Prompt Cache 工程实践:上下文熵值调控与 token 节省

1. 这不是“缓存”,是 Claude Code 的推理成本控制中枢最近在几个技术社区里,频繁看到开发者讨论Claude Code 的 Prompt Cache——这个词听起来像传统 Web 开发里的 Redis 缓存,但实际完全不是一回事。我带团队落地过 3 个基于 Claude Code 的…

作者头像 李华
网站建设 2026/10/21 10:27:17

AI辅助论文写作的学术自主性实践指南

1. 这不是“AI代写”,而是把论文写作变成一场可控的协同实验“如何借助 AI 撰写一篇优秀的论文|Part Ⅴ”——看到这个标题,我第一反应不是点开,而是暂停三秒。因为过去两年里,我带过十几位不同学科背景的研究生和青年…

作者头像 李华
网站建设 2026/10/17 13:59:54

二叉树递归实战:从左叶子之和到路径总和的解题框架

二叉树这块,很多朋友学到“二叉树的进阶操作”就开始犯懵,尤其是遇到“左叶子之和”和“路径总和”这种一听名字就带着“递归味儿”的题目,往往看答案能看懂,自己一上手就不知道从哪开始写。这背后其实不是智商问题,而…

作者头像 李华
网站建设 2026/10/20 21:16:57

EmbeddingGemma 2 + Gemma 4:端侧RAG轻量级落地实践

1. 项目概述:为什么端侧 RAG 正在从“概念验证”走向“真实可用”最近在几个技术社区和开发者群聊里,反复看到一个组合词被高频提及:“EmbeddingGemma 2 Gemma 4”。它不像过去那些堆参数、拼算力的模型方案,而是带着一种明确的落…

作者头像 李华