1. 项目背景与需求分析
健身房行业近年来发展迅猛,但传统管理模式已经无法满足现代健身房的运营需求。作为一名长期从事健身行业信息化建设的开发者,我深刻理解这个行业的痛点所在。
传统健身房管理存在三大核心问题:
-
信息孤岛现象严重:会员档案、课程安排、教练排班等数据分散在各个Excel表格中,每次查询都需要打开多个文件,效率极低。我曾见过一个中型健身房的前台,每天要花费2小时整理各种表格。
-
预约流程混乱:课程预约主要依靠微信群接龙或前台登记,经常出现名额超限、时间冲突等问题。最夸张的一次,某热门课程因为微信群接龙混乱,导致同一时段预约人数是实际容量的3倍。
-
数据统计滞后:经营数据需要人工汇总,往往要等到月底才能看到报表,无法实时掌握运营状况。有位健身房老板告诉我,他曾经因为没能及时发现某个月会员流失率激增,导致当月亏损严重。
2. 系统架构设计
2.1 技术选型决策
在技术选型上,我们经过多次论证最终确定了以下技术栈:
后端技术栈:
- Spring Boot 2.7.5:提供快速开发能力,内置Tomcat服务器
- Spring Security:处理认证授权
- MyBatis-Plus 3.5.2:简化数据库操作
- Redis 6.2:缓存热点数据
- MinIO:文件存储服务
前端技术栈:
- Vue 3.2:构建响应式界面
- Element Plus:UI组件库
- Axios:处理HTTP请求
- ECharts:数据可视化
数据库:
- MySQL 8.0:主数据库
- Redis:缓存数据库
技术选型心得:Spring Boot的自动配置特性让我们可以快速搭建项目框架,而Vue3的组合式API则大大提高了前端开发效率。这两个框架的组合,让我们的开发周期缩短了40%。
2.2 系统架构图
系统采用经典的三层架构:
code复制┌───────────────────────────────────────┐
│ 表现层 │
│ ┌───────────┐ ┌───────────┐ │
│ │ Web端 │ │ 移动端 │ │
│ └───────────┘ └───────────┘ │
└───────────────────────────────────────┘
│
▼
┌───────────────────────────────────────┐
│ 业务逻辑层 │
│ ┌───────────┐ ┌───────────┐ │
│ │ 会员服务 │ │ 课程服务 │ │
│ └───────────┘ └───────────┘ │
│ ┌───────────┐ ┌───────────┐ │
│ │ 教练服务 │ │ 统计服务 │ │
│ └───────────┘ └───────────┘ │
└───────────────────────────────────────┘
│
▼
┌───────────────────────────────────────┐
│ 数据访问层 │
│ ┌───────────┐ ┌───────────┐ │
│ │ MySQL │ │ Redis │ │
│ └───────────┘ └───────────┘ │
│ ┌───────────────────────────────┐ │
│ │ MinIO │ │
│ └───────────────────────────────┘ │
└───────────────────────────────────────┘
3. 核心功能实现
3.1 会员管理模块
会员管理是系统的基础模块,我们设计了以下数据结构:
java复制// 会员实体类
public class Member {
private Long id;
private String name;
private String phone;
private String idCard; // 身份证号
private Integer gender;
private Date birthday;
private String avatar; // 头像URL
private Integer status; // 状态:0-正常 1-冻结 2-注销
@TableField(exist = false)
private List<MemberCard> cards; // 会员卡列表
}
// 会员卡实体类
public class MemberCard {
private Long id;
private Long memberId;
private Integer cardType; // 1-月卡 2-年卡 3-次卡
private Integer totalTimes; // 总次数(次卡专用)
private Integer remainingTimes;
private Date startDate;
private Date endDate;
private BigDecimal price;
private Integer status; // 0-未激活 1-已激活 2-已过期 3-已退卡
}
关键业务逻辑:
- 会员注册:采用手机号+验证码方式,确保真实性
- 会员卡管理:支持多卡并行,自动计算有效期
- 到期提醒:使用Spring Scheduler每天凌晨检查即将到期的会员卡
开发经验:会员卡状态管理是个难点,我们采用了状态模式(State Pattern)来封装不同状态下的行为,大大简化了业务逻辑代码。
3.2 课程预约模块
课程预约是系统的核心功能,我们实现了以下特性:
- 课程发布:
java复制public class Course {
private Long id;
private String name;
private Long coachId;
private Integer type; // 1-团课 2-私教
private Date startTime;
private Date endTime;
private Integer maxParticipants;
private Integer bookedCount;
private Integer status; // 0-未开始 1-进行中 2-已结束 3-已取消
private String location;
}
- 预约逻辑:
java复制@Transactional
public Result bookCourse(Long memberId, Long courseId) {
// 检查会员资格
Member member = memberService.getById(memberId);
if (member.getStatus() != 0) {
return Result.error("会员状态异常");
}
// 检查课程状态
Course course = courseService.getById(courseId);
if (course.getStatus() != 0) {
return Result.error("课程不可预约");
}
// 检查是否已预约
if (bookingMapper.existsByMemberAndCourse(memberId, courseId)) {
return Result.error("已预约该课程");
}
// 检查剩余名额
if (course.getBookedCount() >= course.getMaxParticipants()) {
return Result.error("课程已满");
}
// 创建预约记录
CourseBooking booking = new CourseBooking();
booking.setMemberId(memberId);
booking.setCourseId(courseId);
booking.setBookingTime(new Date());
booking.setStatus(0); // 0-已预约 1-已签到 2-已取消
// 更新课程预约数
course.setBookedCount(course.getBookedCount() + 1);
bookingMapper.insert(booking);
courseService.updateById(course);
// 发送通知
notificationService.sendBookingSuccess(member, course);
return Result.success();
}
预约流程优化点:
- 使用Redis分布式锁防止超卖
- 采用乐观锁更新预约数量
- 预约成功后异步发送通知
3.3 教练管理模块
教练管理模块实现了以下功能:
- 教练档案管理
- 排班系统
- 课程评价
排班算法核心逻辑:
java复制public List<Schedule> generateSchedule(Long coachId, Date startDate, Date endDate) {
// 获取教练不可用时间(个人设置)
List<UnavailableTime> unavailableTimes = unavailableTimeMapper
.selectByCoachAndDate(coachId, startDate, endDate);
// 获取已排课程
List<Course> existingCourses = courseMapper
.selectByCoachAndDate(coachId, startDate, endDate);
// 生成可排班时间段
List<TimeSlot> availableSlots = generateTimeSlots(startDate, endDate);
// 过滤不可用时间段
availableSlots = filterSlots(availableSlots, unavailableTimes, existingCourses);
return availableSlots.stream()
.map(slot -> new Schedule(coachId, slot.getStartTime(), slot.getEndTime()))
.collect(Collectors.toList());
}
4. 系统安全与性能优化
4.1 安全措施
- 认证授权:采用JWT+Spring Security实现
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/member/**").hasAnyRole("MEMBER", "ADMIN")
.antMatchers("/api/coach/**").hasAnyRole("COACH", "ADMIN")
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()))
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
- 数据加密:敏感字段如密码、身份证号使用AES加密存储
- 接口防刷:采用Redis实现接口限流
4.2 性能优化
- 缓存策略:
java复制@Cacheable(value = "courses", key = "#id")
public Course getCourseById(Long id) {
return courseMapper.selectById(id);
}
@CacheEvict(value = "courses", key = "#course.id")
public void updateCourse(Course course) {
courseMapper.updateById(course);
}
- 数据库优化:
- 为常用查询字段添加索引
- 采用读写分离架构
- 使用MyBatis二级缓存
- 前端优化:
- 组件懒加载
- 路由懒加载
- 图片压缩
5. 部署与运维
5.1 部署架构
我们采用Docker Compose进行容器化部署:
yaml复制version: '3.8'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
ports:
- "3306:3306"
redis:
image: redis:6.2
ports:
- "6379:6379"
minio:
image: minio/minio
ports:
- "9000:9000"
environment:
MINIO_ROOT_USER: ${MINIO_USER}
MINIO_ROOT_PASSWORD: ${MINIO_PASSWORD}
volumes:
- minio_data:/data
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
- minio
frontend:
build: ./frontend
ports:
- "80:80"
5.2 监控方案
- Spring Boot Actuator:暴露健康检查端点
- Prometheus + Grafana:监控系统指标
- ELK:日志收集与分析
6. 项目总结与反思
在开发这个健身房管理系统的过程中,我们积累了以下宝贵经验:
-
业务理解是关键:前期我们花了2周时间深入多家健身房实地调研,这比直接开始编码更有价值。只有真正理解业务痛点,才能设计出好用的系统。
-
并发控制很重要:在课程预约场景下,我们最初没有做好并发控制,导致测试时出现了超卖问题。后来通过Redis分布式锁+数据库乐观锁双重保障解决了这个问题。
-
用户体验细节:比如在课程预约成功后,系统会自动为用户保留15分钟的支付时间,这大大减少了用户因支付超时而需要重新预约的困扰。
-
技术债务管理:在项目初期,我们为了快速上线忽略了一些代码规范,导致后期维护困难。现在我们有严格的Code Review流程,确保代码质量。
这个系统目前已在3家健身房投入使用,平均为每家健身房节省了30%的人力成本,会员满意度提升了25%。未来我们计划增加智能硬件对接功能,让系统可以自动采集会员的运动数据,提供更个性化的健身建议。