ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于SpringBoot+Vue的健身房预约管理系统设计与实现

基于SpringBoot+Vue的健身房预约管理系统设计与实现

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片!

一、 项目背景与意义

随着全民健身意识的提升和健身行业的快速发展,传统健身房管理模式(如电话预约、纸质登记)已难以满足现代用户对便捷性、实时性和高效管理的需求。基于SpringBoot+Vue的健身房预约管理系统应运而生,旨在通过信息化手段解决以下痛点:

  • 提升用户体验:用户可随时随地通过Web端或移动端查看课程、预约时段、管理个人健身计划,摆脱时间和空间限制。
  • 优化运营效率:系统自动化处理预约、签到、课程安排和会员管理,减少人工操作错误和沟通成本,提升健身房资源利用率。
  • 数据驱动决策:通过收集和分析会员活跃度、课程热度、设备使用率等数据,为健身房运营者提供科学的决策支持。
  • 技术实践价值:项目采用前后端分离架构,是学习与掌握SpringBoot后端开发、Vue前端框架、RESTful API设计以及系统集成能力的典型实战案例。

二、 技术栈选型

2.1 后端技术栈 (SpringBoot)

  • 核心框架:Spring Boot 2.x, 提供快速启动和自动配置能力。
  • Web框架:Spring MVC, 处理HTTP请求和响应。
  • 数据持久层:
    • ORM框架:MyBatis-Plus, 简化CRUD操作。
    • 数据库:MySQL 8.0, 存储会员、课程、预约等核心数据。
    • 连接池:HikariCP, 高性能数据库连接池。
  • 安全与权限:Spring Security + JWT (JSON Web Token), 实现用户认证与接口鉴权。
  • 其他组件:
    • 参数校验:Hibernate Validator。
    • API文档:Swagger2 / Knife4j。
    • 缓存:Redis (可选), 用于存储会话、验证码或热点数据。
    • 消息队列:RabbitMQ (可选), 用于异步处理预约通知等任务。

2.2 前端技术栈 (Vue)

  • 核心框架:Vue 3 (Composition API) 或 Vue 2, 构建用户界面。
  • 构建工具:Vite (推荐) 或 Vue CLI, 提供快速的开发服务器和构建流程。
  • 状态管理:Pinia (Vue 3) 或 Vuex (Vue 2), 管理跨组件共享状态。
  • 路由:Vue Router, 实现单页面应用(SPA)的路由跳转。
  • UI组件库:Element Plus (Vue 3) 或 Element UI (Vue 2), 提供丰富的预制组件,加速开发。
  • HTTP客户端:Axios, 用于向后端发起RESTful API请求。
  • 工具库:Day.js (日期处理)、Lodash (实用函数)等。

2.3 开发与部署

  • 版本控制:Git。
  • 项目管理:Maven (后端) / npm 或 pnpm (前端)。
  • 容器化:Docker (可选), 实现环境标准化和快速部署。
  • 部署:后端可打包为JAR部署至Linux服务器;前端静态资源部署至Nginx。

三、 核心功能模块与代码示例

3.1 数据库表设计 (核心表)

-- 会员表 CREATE TABLE `member` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', `username` varchar(50) NOT NULL COMMENT '用户名', `password` varchar(255) NOT NULL COMMENT '密码(加密)', `phone` varchar(20) DEFAULT NULL COMMENT '手机号', `email` varchar(100) DEFAULT NULL COMMENT '邮箱', `avatar` varchar(500) DEFAULT NULL COMMENT '头像', `status` tinyint DEFAULT '1' COMMENT '状态(1正常 0禁用)', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员表'; -- 课程表 CREATE TABLE course ( id bigint NOT NULL AUTO_INCREMENT COMMENT '主键', name varchar(100) NOT NULL COMMENT '课程名称', coach_id bigint NOT NULL COMMENT '教练ID', description text COMMENT '课程描述', capacity int NOT NULL COMMENT '可预约人数', start_time datetime NOT NULL COMMENT '开始时间', end_time datetime NOT NULL COMMENT '结束时间', status tinyint DEFAULT '1' COMMENT '状态(1可预约 0已取消)', PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课程表'; -- 预约记录表 CREATE TABLE reservation ( id bigint NOT NULL AUTO_INCREMENT COMMENT '主键', member_id bigint NOT NULL COMMENT '会员ID', course_id bigint NOT NULL COMMENT '课程ID', status tinyint NOT NULL COMMENT '状态(1已预约 2已签到 3已取消)', create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (id), KEY idx_member_id (member_id), KEY idx_course_id (course_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='预约记录表';

3.2 后端核心代码示例

3.2.1 实体类 (Member.java)
import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.time.LocalDateTime; @Data @TableName("member") public class Member { @TableId(type = IdType.AUTO) private Long id; private String username; private String password; private String phone; private String email; private String avatar; private Integer status; @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; }
3.2.2 服务层接口与实现 (ReservationService.java)
public interface ReservationService { /** * 预约课程 * @param memberId 会员ID * @param courseId 课程ID * @return 预约结果 */ boolean reserveCourse(Long memberId, Long courseId); /** * 取消预约 * @param reservationId 预约记录ID * @param memberId 会员ID (用于鉴权) * @return 取消结果 */ boolean cancelReservation(Long reservationId, Long memberId); } @Service public class ReservationServiceImpl implements ReservationService { @Autowired private ReservationMapper reservationMapper; @Autowired private CourseMapper courseMapper; @Override @Transactional(rollbackFor = Exception.class) public boolean reserveCourse(Long memberId, Long courseId) { // 1. 检查课程是否存在且可预约 Course course = courseMapper.selectById(courseId); if (course == null || course.getStatus() != 1) { throw new BusinessException("课程不存在或不可预约"); } // 2. 检查是否已满员 (简化逻辑,实际需考虑并发) Integer currentCount = reservationMapper.countByCourseIdAndStatus(courseId, 1); if (currentCount >= course.getCapacity()) { throw new BusinessException("课程预约已满"); } // 3. 检查用户是否已预约该课程 Reservation existing = reservationMapper.selectOne( new LambdaQueryWrapper<Reservation>() .eq(Reservation::getMemberId, memberId) .eq(Reservation::getCourseId, courseId) .eq(Reservation::getStatus, 1) ); if (existing != null) { throw new BusinessException("您已预约该课程"); } // 4. 创建预约记录 Reservation reservation = new Reservation(); reservation.setMemberId(memberId); reservation.setCourseId(courseId); reservation.setStatus(1); // 已预约 return reservationMapper.insert(reservation) > 0; } // cancelReservation 方法实现略... }
3.2.3 控制器层 (ReservationController.java)
@RestController @RequestMapping("/api/reservation") public class ReservationController { @Autowired private ReservationService reservationService; @PostMapping("/reserve") public Result<Void> reserve(@RequestBody ReservationRequest request, @RequestHeader("Authorization") String token) { // 从JWT token中解析出当前用户ID (简化) Long currentMemberId = JwtUtil.getMemberIdFromToken(token); boolean success = reservationService.reserveCourse(currentMemberId, request.getCourseId()); return success ? Result.success("预约成功") : Result.error("预约失败"); } @PostMapping("/cancel/{id}") public Result<Void> cancel(@PathVariable Long id, @RequestHeader("Authorization") String token) { Long currentMemberId = JwtUtil.getMemberIdFromToken(token); boolean success = reservationService.cancelReservation(id, currentMemberId); return success ? Result.success("取消成功") : Result.error("取消失败"); } }

3.3 前端核心代码示例 (Vue 3 + Element Plus)

3.3.1 课程列表与预约组件 (CourseList.vue)
<template> <div class="course-list"> <el-table :data="courseList" style="width: 100%"> <el-table-column prop="name" label="课程名称" width="180" /> <el-table-column prop="coachName" label="教练" width="120" /> <el-table-column prop="startTime" label="开始时间" width="180"> <template #default="scope"> {{ formatDate(scope.row.startTime) }} </template> </el-table-column> <el-table-column prop="capacity" label="容量" width="80" /> <el-table-column prop="bookedCount" label="已预约" width="80" /> <el-table-column label="操作" width="120"> <template #default="scope"> <el-button v-if="scope.row.status === 1 && scope.row.bookedCount < scope.row.capacity" type="primary" size="small" @click="handleReserve(scope.row)" > 预约 </el-button> <el-tag v-else type="info">已满</el-tag> </template> </el-table-column> </el-table> </div> </template> <script setup> import { ref, onMounted } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' import { getCourseList, reserveCourse } from '@/api/course' import { formatDate } from '@/utils/date' const courseList = ref([]) const loadCourseList = async () => { try { const res = await getCourseList() courseList.value = res.data } catch (error) { ElMessage.error('加载课程列表失败') } } const handleReserve = async (course) => { try { await ElMessageBox.confirm(确定要预约【${course.name}】吗?, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }) await reserveCourse({ courseId: course.id }) ElMessage.success('预约成功') loadCourseList() // 刷新列表 } catch (error) { if (error !== 'cancel') { ElMessage.error(error.message || '预约失败') } } } onMounted(() => { loadCourseList() }) </script>
3.3.2 API请求封装 (course.js)
import request from '@/utils/request' export function getCourseList(params) { return request({ url: '/api/course/list', method: 'get', params }) } export function reserveCourse(data) { return request({ url: '/api/reservation/reserve', method: 'post', data }) }

四、 总结

本文介绍了基于SpringBoot+Vue的健身房预约管理系统的技术栈选型、项目背景意义,并提供了数据库设计、后端核心业务逻辑(课程预约)以及前端组件交互的核心代码示例。该系统采用前后端分离架构,后端SpringBoot提供稳健的RESTful API,前端Vue构建交互友好的管理界面,是一个典型的企业级全栈应用实践。开发者可在此基础上扩展更多功能,如微信小程序端、智能排课、数据报表等,以满足更复杂的业务需求。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进