基于 Spring Boot + Vue3 的民宿预订管理系统设计与实现
发布时间:2026/10/29 1:52:52 锦皓数字建站

温馨提示本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系名片一、项目背景与意义随着短途旅行和个性化住宿需求的增长民宿已经成为旅游住宿市场的重要组成部分。与传统酒店相比民宿房源分散、房型差异大、房东多为个人经营者房源信息维护、房态管理、订单确认和结算等环节往往依赖人工沟通容易出现超卖、漏单、对账困难等问题。本文设计并实现一套基于 Spring Boot Vue3 的民宿预订管理系统面向房东、房客和平台管理员三类角色提供房源发布、房态日历、在线预订、订单流转和后台统计等能力帮助中小民宿经营者以较低成本完成数字化管理。二、系统需求分析2.1 角色与权限角色核心职责主要功能房客浏览与预订房源房源搜索、详情查看、日期选择、下单支付、订单查询、评价房东维护房源与订单房源发布与上下架、房态日历维护、订单确认与拒单、收入统计管理员平台运营管理用户管理、房源审核、订单监管、评价管理、数据看板2.2 核心业务流程flowchart TD A[房客搜索房源] -- B[选择入住日期与房型] B -- C{房态是否可用} C --|否| D[提示日期已被预订] C --|是| E[创建订单并锁定房态] E -- F[支付订单] F -- G{支付结果} G --|成功| H[通知房东确认] G --|失败| I[释放房态并关闭订单] H -- J[房东确认接单] J -- K[房客入住] K -- L[订单完成并生成评价入口]2.3 非功能性需求并发安全同一房源同一日期区间不允许重复预订需要通过数据库唯一约束或分布式锁保证一致性。响应性能房源列表与详情接口在常规数据量下响应时间控制在 300ms 以内热点数据使用 Redis 缓存。可维护性前后端分离接口遵循 RESTful 风格统一返回结构与异常处理。三、技术选型与整体架构3.1 技术栈层次技术选型说明前端Vue3 Vite TypeScript Element Plus Pinia组合式 API 开发Pinia 管理登录态与全局状态后端Spring Boot 3 Spring Security MyBatis-PlusJWT 无状态认证MyBatis-Plus 简化单表 CRUD数据库MySQL 8.0存储用户、房源、房态、订单、评价等业务数据缓存Redis缓存房源详情、房态日历实现下单防重与分布式锁文件存储MinIO / 阿里云 OSS存储房源图片与用户头像3.2 系统分层架构flowchart LR A[Vue3 前端应用] -- B[网关与鉴权层 JWT] B -- C[Controller 接口层] C -- D[Service 业务层] D -- E[Mapper 数据访问层] E -- F[(MySQL)] D -- G[(Redis)] D -- H[对象存储 OSS]四、数据库设计系统核心表包括用户表、房源表、房态表、订单表和评价表。房态表按「房源 日期」维度存储是防止超卖的关键。CREATE TABLE t_house ( id BIGINT PRIMARY KEY AUTO_INCREMENT, owner_id BIGINT NOT NULL COMMENT 房东ID, title VARCHAR(100) NOT NULL COMMENT 房源标题, city VARCHAR(50) NOT NULL COMMENT 所在城市, address VARCHAR(255) NOT NULL COMMENT 详细地址, price DECIMAL(10,2) NOT NULL COMMENT 每晚价格, cover_url VARCHAR(500) COMMENT 封面图, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待审核 1已上架 2已下架, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, KEY idx_city_status (city, status) ) COMMENT 房源表; CREATE TABLE t_room_calendar ( id BIGINT PRIMARY KEY AUTO_INCREMENT, house_id BIGINT NOT NULL COMMENT 房源ID, calendar_date DATE NOT NULL COMMENT 日期, status TINYINT NOT NULL DEFAULT 0 COMMENT 0可预订 1已锁定 2已预订, order_id BIGINT COMMENT 关联订单ID, UNIQUE KEY uk_house_date (house_id, calendar_date) ) COMMENT 房态日历表; CREATE TABLE t_order ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL COMMENT 订单号, house_id BIGINT NOT NULL, user_id BIGINT NOT NULL, check_in DATE NOT NULL, check_out DATE NOT NULL, total_amount DECIMAL(10,2) NOT NULL, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待支付 1待确认 2已确认 3已完成 4已取消, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_order_no (order_no), KEY idx_user_status (user_id, status) ) COMMENT 订单表;五、后端核心功能实现5.1 项目结构与统一返回RestControllerAdvice public class GlobalExceptionHandler { ExceptionHandler(BizException.class) public ResultVoid handleBiz(BizException e) { return Result.fail(e.getCode(), e.getMessage()); } ExceptionHandler(Exception.class) public ResultVoid handleOther(Exception e) { log.error(系统异常, e); return Result.fail(500, 系统繁忙请稍后重试); } }5.2 下单与房态锁定下单时先校验日期区间内房态是否全部可预订再通过 Redis 分布式锁按房源维度串行化处理最后批量更新房态并写入订单保证不超卖。Service RequiredArgsConstructor public class OrderService { private final RoomCalendarMapper calendarMapper; private final OrderMapper orderMapper; private final RedissonClient redissonClient; Transactional(rollbackFor Exception.class) public Long createOrder(OrderCreateDTO dto, Long userId) { RLock lock redissonClient.getLock(lock:house: dto.getHouseId()); lock.lock(10, TimeUnit.SECONDS); try { ListLocalDate dates dto.getCheckIn() .datesUntil(dto.getCheckOut()) .toList(); int available calendarMapper.countAvailable(dto.getHouseId(), dates); if (available ! dates.size()) { throw new BizException(所选日期已被预订请重新选择); } String orderNo OrderNoGenerator.next(); Order order Order.builder() .orderNo(orderNo) .houseId(dto.getHouseId()) .userId(userId) .checkIn(dto.getCheckIn()) .checkOut(dto.getCheckOut()) .totalAmount(dto.getTotalAmount()) .status(OrderStatus.WAIT_PAY) .build(); orderMapper.insert(order); calendarMapper.lockDates(dto.getHouseId(), dates, order.getId()); return order.getId(); } finally { lock.unlock(); } } }5.3 房源查询与缓存Service RequiredArgsConstructor public class HouseQueryService { private final HouseMapper houseMapper; private final RedisTemplateString, Object redisTemplate; public HouseDetailVO detail(Long id) { String key house:detail: id; HouseDetailVO cached (HouseDetailVO) redisTemplate.opsForValue().get(key); if (cached ! null) { return cached; } HouseDetailVO vo houseMapper.selectDetailById(id); if (vo null) { throw new BizException(房源不存在); } redisTemplate.opsForValue().set(key, vo, 30, TimeUnit.MINUTES); return vo; } }六、前端实现要点6.1 请求封装与登录态import axios from axios import { useUserStore } from /stores/user const request axios.create({ baseURL: import.meta.env.VITE_API_BASE, timeout: 10000 }) request.interceptors.request.use((config) { const userStore useUserStore() if (userStore.token) { config.headers.Authorization Bearer ${userStore.token} } return config }) request.interceptors.response.use( (res) { const { code, data, message } res.data if (code ! 0) { ElMessage.error(message) return Promise.reject(new Error(message)) } return data }, (error) { if (error.response?.status 401) { useUserStore().logout() router.push(/login) } return Promise.reject(error) } ) export default request6.2 房态日历组件房态日历使用日期网格渲染按接口返回的可预订日期集合标记状态用户选择入住与离店日期后实时计算总价。template div classcalendar div v-forday in days :keyday.date classday :class{ disabled: !day.available, selected: isSelected(day.date) } clickpick(day) {{ day.label }} /div /div /template script setup langts import { computed, ref } from vue const props defineProps{ days: CalendarDay[]; price: number }() const emit defineEmits[change]() const checkIn refstring() const checkOut refstring() const total computed(() { if (!checkIn.value || !checkOut.value) return 0 const nights (new Date(checkOut.value).getTime() - new Date(checkIn.value).getTime()) / 86400000 return nights * props.price }) function pick(day: CalendarDay) { if (!day.available) return if (!checkIn.value || checkOut.value) { checkIn.value day.date checkOut.value undefined } else { checkOut.value day.date emit(change, { checkIn: checkIn.value, checkOut: checkOut.value, total: total.value }) } } /script七、系统部署与运行准备 MySQL 8.0 与 Redis执行初始化 SQL 脚本创建库表。修改后端application.yml中的数据源、Redis 与对象存储配置。执行mvn clean package打包后端使用java -jar启动服务。前端执行npm install与npm run build将产物部署到 Nginx并配置接口反向代理。八、总结与展望本文完成了基于 Spring Boot Vue3 的民宿预订管理系统的需求分析、架构设计、数据库设计与核心功能实现重点解决了房态一致性与下单防超卖问题。后续可继续扩展在线支付对接、消息通知、房源地图检索和多房东分账结算等能力进一步提升系统的实用性与商业价值。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。