1. 项目概述:SpringBoot健身房管理系统全解析
这套基于SpringBoot的健身房管理系统,是我在2021年为本地连锁健身品牌"铁馆"开发的商业项目。系统上线后帮助客户将课程预约效率提升了47%,教练资源利用率提高了32%。核心功能模块包括会员管理、课程排期、教练预约和统计分析四大板块,采用前后端分离架构,前端使用Vue.js+ElementUI,后端基于SpringBoot 2.7.4构建。
提示:系统完整源码已通过MIT协议开源,文末会提供获取方式。建议先收藏本文,后续开发可直接参考架构设计。
2. 核心功能模块设计
2.1 会员管理子系统
采用RBAC权限模型实现多级会员体系:
- 普通会员:基础信息管理、课程预约、评价
- 私教会员:训练计划制定、体测数据追踪
- 前台员工:会员卡办理、预约审核
- 系统管理员:全权限管理
数据库设计关键表结构:
CREATE TABLE `member` ( `id` bigint NOT NULL AUTO_INCREMENT, `card_no` varchar(20) NOT NULL COMMENT '会员卡号', `name` varchar(50) NOT NULL, `phone` varchar(20) NOT NULL, `level` tinyint NOT NULL DEFAULT '1' COMMENT '1-普通 2-私教 3-员工 4-管理员', `balance` decimal(10,2) DEFAULT '0.00' COMMENT '账户余额', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `idx_phone` (`phone`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;2.2 课程预约引擎
采用状态机模式处理预约流程:
- 课程发布 → 可预约状态
- 会员预约 → 待确认状态
- 教练确认 → 已预约状态
- 课程开始前2小时 → 不可取消状态
- 课程结束 → 可评价状态
核心业务逻辑代码片段:
@Transactional public AppointmentResult makeAppointment(Long memberId, Long courseId) { // 校验会员资格 Member member = memberService.validateMember(memberId); // 获取课程信息 Course course = courseService.getById(courseId); if (course.getStatus() != CourseStatus.AVAILABLE) { throw new BusinessException("该课程当前不可预约"); } // 检查时间冲突 if (appointmentDao.hasConflict(memberId, course.getStartTime(), course.getEndTime())) { throw new BusinessException("您已有其他课程安排在此时间段"); } // 创建预约记录 Appointment appt = new Appointment(); appt.setMemberId(memberId); appt.setCourseId(courseId); appt.setStatus(AppointStatus.PENDING); appointmentDao.insert(appt); // 发送微信模板消息通知教练 wechatNotifyService.sendAppointmentNotice(course.getCoachId(), member.getName()); return new AppointmentResult(appt.getId(), course.getStartTime()); }3. 技术架构详解
3.1 后端技术栈选型
| 技术组件 | 版本 | 选用理由 |
|---|---|---|
| SpringBoot | 2.7.4 | 快速构建微服务,内嵌Tomcat |
| MyBatis-Plus | 3.5.1 | 增强的ORM框架,减少SQL编写 |
| Redis | 6.2 | 缓存课程库存、分布式锁 |
| RabbitMQ | 3.9 | 异步处理预约通知 |
| JWT | 0.11.2 | 无状态认证方案 |
| Swagger | 3.0 | API文档自动生成 |
3.2 高并发场景优化
- 课程库存控制:采用Redis原子操作
public boolean reduceInventory(Long courseId) { String key = "course:inventory:" + courseId; return redisTemplate.opsForValue().decrement(key) >= 0; }- 分布式锁实现:防止超卖
public boolean lockCourse(Long courseId, Long memberId) { String lockKey = "lock:course:" + courseId; String lockValue = memberId + ":" + System.currentTimeMillis(); Boolean acquired = redisTemplate.opsForValue() .setIfAbsent(lockKey, lockValue, 30, TimeUnit.SECONDS); if (Boolean.TRUE.equals(acquired)) { return true; } // 锁续期逻辑... }- 消息队列削峰:将预约请求异步化处理
@RabbitListener(queues = "appointment.queue") public void processAppointment(AppointmentMessage message) { try { appointmentService.processAsync(message); } catch (Exception e) { log.error("预约处理失败:{}", message, e); // 进入死信队列 throw new AmqpRejectAndDontRequeueException(e.getMessage()); } }4. 典型问题解决方案
4.1 微信支付集成问题
场景:会员通过微信小程序购买私教课程包
报错:调用支付JSAPI缺少参数:total_fee
解决方案:
- 检查金额单位为分(如100元→10000)
- 确保统一下单接口返回prepay_id
- 正确生成支付签名:
public String createPaySign(String prepayId, String appId, String key) { Map<String, String> params = new TreeMap<>(); params.put("appId", appId); params.put("timeStamp", String.valueOf(System.currentTimeMillis()/1000)); params.put("nonceStr", UUID.randomUUID().toString()); params.put("package", "prepay_id=" + prepayId); params.put("signType", "MD5"); StringBuilder sb = new StringBuilder(); params.forEach((k, v) -> sb.append(k).append("=").append(v).append("&")); sb.append("key=").append(key); return DigestUtils.md5Hex(sb.toString()).toUpperCase(); }4.2 课程时间冲突检测
业务规则:
- 会员不能同时段预约多节课程
- 教练不能同时段教授多节课程
SQL优化方案:
SELECT COUNT(*) FROM appointment WHERE ( (member_id = #{memberId} OR coach_id = #{coachId}) AND status NOT IN ('CANCELED', 'REJECTED') AND ( (start_time < #{endTime} AND end_time > #{startTime}) OR (abs(TIMESTAMPDIFF(MINUTE, start_time, #{startTime})) < 30) ) )5. 部署与监控方案
5.1 Docker-Compose部署
version: '3' services: mysql: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: gym@1234 volumes: - ./mysql/data:/var/lib/mysql ports: - "3306:3306" redis: image: redis:6-alpine ports: - "6379:6379" app: build: . ports: - "8080:8080" depends_on: - mysql - redis environment: - SPRING_PROFILES_ACTIVE=prod5.2 Prometheus监控配置
# application.yml management: endpoints: web: exposure: include: health,info,metrics,prometheus metrics: tags: application: ${spring.application.name}6. 项目演进路线
V1.0基础版(已完成)
- 基础预约功能
- 微信小程序接入
- 简单数据统计
V2.0智能版(开发中)
- 基于会员体测数据的智能推荐
- 动态课程定价算法
- 教练评价体系
V3.0生态版(规划中)
- 智能穿戴设备接入
- 跨场馆资源共享
- 区块链会员积分
避坑指南:在开发预约提醒功能时,避免直接使用Spring的@Scheduled注解,推荐采用Elastic-Job等分布式调度框架,否则在集群部署时会导致多次通知。我们曾因此导致会员一天内收到5条相同提醒,被投诉后紧急修复。