1. 项目概述:在线健身课程预约平台的设计初衷
去年帮朋友改造健身房管理系统时,我深刻感受到传统线下预约的痛点:会员排队等前台登记、教练手工记录课程安排、老板无法实时掌握经营数据。这正是我们选择开发这套多端在线预约系统的原因——用Uniapp实现跨端用户触达,SpringBoot构建稳定后端服务,Vue打造管理后台可视化界面。
这套系统最核心的价值在于实现了三类角色的闭环协同:
- 用户端:随时查看课程表、预约私教课、查看历史记录
- 教练端:管理个人课表、查看学员档案、接收预约通知
- 管理端:课程排期审核、营收数据统计、系统权限管理
技术选型心得:Uniapp的跨端能力让我们用一套代码同时覆盖微信小程序和APP,相比原生开发节省了40%人力成本。实测在Redmi Note 11上,课程列表页渲染速度仅187ms。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计与核心模块
2.1 前端技术栈实现方案
采用Uniapp+Vue3组合开发用户端小程序,关键配置在manifest.json中需要特别注意:
json复制{
"networkTimeout": {
"request": 10000,
"uploadFile": 30000
},
"app-plus": {
"nvueCompiler": "uni-app",
"compilerVersion": 3
}
}
跨端适配的三大难点解决方案:
- 样式兼容:通过条件编译解决小程序和APP的样式差异
css复制/* #ifdef MP-WEIXIN */
.wx-specific {
padding: 10rpx;
}
/* #endif */
- 支付对接:封装统一支付接口,内部区分微信/支付宝SDK
javascript复制const payMap = {
'wechat': () => uni.requestPayment(...),
'alipay': () => my.tradePay(...)
}
- 性能优化:采用虚拟列表加载课程数据,避免长列表卡顿
vue复制<uv-list :data="courses" :height="800" :item-size="120">
<template v-slot="{ item }">
<course-card :data="item" />
</template>
</uv-list>
2.2 后端服务架构设计
SpringBoot后端采用经典三层架构,但针对健身行业特性做了特殊设计:
领域模型核心字段示例(课程模块):
java复制@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Enumerated(EnumType.STRING)
private CourseType type; // 团课/私教
@ManyToOne
@JoinColumn(name = "coach_id")
private Coach coach;
@Temporal(TemporalType.TIMESTAMP)
private Date startTime;
private Integer duration; // 分钟
private Integer maxUsers;
@OneToMany(mappedBy = "course")
private Set<Reservation> reservations;
}
高性能接口设计技巧:
- 课程查询接口采用Redis缓存热点数据
- 预约操作使用@Transactional保证数据一致性
- 分页查询统一使用PageHelper插件
2.3 管理后台技术实现
基于Vue3+Element Plus的管理后台有三个创新点:
- 可视化课程排期表:采用FullCalendar组件实现拖拽排课
- 实时数据看板:ECharts动态展示营收趋势
- 权限控制系统:RBAC模型结合动态路由
javascript复制// 动态路由处理示例
router.beforeEach(async (to) => {
const userStore = useUserStore()
if (!userStore.roles.length) {
await userStore.getInfo()
const accessRoutes = await generateRoutes(userStore.roles)
accessRoutes.forEach(route => router.addRoute(route))
return { ...to, replace: true }
}
})
3. 核心业务逻辑实现细节
3.1 预约业务流程完整实现
典型的课程预约涉及六个关键步骤:
- 课程状态检查(是否可约)
- 用户账户校验(余额/会员卡)
- 并发控制(避免超卖)
- 创建预约记录
- 通知相关方
- 更新缓存数据
关键代码片段(SpringBoot):
java复制@Transactional
public ReservationDTO createReservation(ReservationRequest request) {
// 1. 验证课程状态
Course course = courseRepository.findByIdForUpdate(request.getCourseId())
.orElseThrow(() -> new BusinessException("课程不存在"));
if (course.getStatus() != CourseStatus.AVAILABLE) {
throw new BusinessException("课程不可预约");
}
// 2. 校验用户资格
User user = userRepository.findById(request.getUserId())
.orElseThrow(() -> new BusinessException("用户不存在"));
if (user.getBalance().compareTo(course.getPrice()) < 0) {
throw new BusinessException("余额不足");
}
// 3. 并发控制
if (course.getReservations().size() >= course.getMaxUsers()) {
throw new BusinessException("课程已满");
}
// 4. 创建预约记录
Reservation reservation = new Reservation();
reservation.setUser(user);
reservation.setCourse(course);
reservation.setCreateTime(new Date());
reservationRepository.save(reservation);
// 5. 发送通知
notificationService.sendToCoach(course.getCoach().getId(),
"新预约提醒", user.getName() + "预约了您的课程");
// 6. 更新缓存
redisTemplate.opsForValue().decrement(
"course:available:" + course.getId(), 1);
return convertToDTO(reservation);
}
3.2 实时消息推送方案
采用WebSocket实现三类实时通知:
- 预约成功提醒(用户端)
- 新预约通知(教练端)
- 课程变更公告(全员)
Uniapp端事件监听实现:
javascript复制uni.connectSocket({
url: 'wss://yourdomain.com/ws'
});
uni.onSocketMessage((res) => {
const msg = JSON.parse(res.data);
switch (msg.type) {
case 'RESERVATION_CONFIRM':
showToast(`成功预约${msg.courseName}`);
break;
case 'COURSE_CANCEL':
showModal('课程取消通知', msg.reason);
break;
}
});
4. 典型问题排查与性能优化
4.1 微信小程序白屏问题解决方案
现象描述:
开发环境正常,但上传体验版后出现白屏,控制台报错"Failed to load font"
排查过程:
- 检查静态资源路径 - 确认无误
- 查看小程序包体积 - 发现字体文件过大
- 验证网络请求 - 发现跨域问题
最终解决方案:
- 将TTF字体转换为WOFF2格式,体积减少60%
- 配置nginx添加字体文件CORS头
nginx复制location ~* \.(woff2)$ {
add_header Access-Control-Allow-Origin *;
}
4.2 高并发场景下的优化实践
在促销活动期间,我们遭遇了以下性能问题:
- 课程详情接口响应时间从200ms飙升到2s
- MySQL CPU利用率持续超过90%
- 预约接口出现超卖现象
优化三部曲:
- 查询优化:
sql复制-- 原查询
SELECT * FROM course WHERE status = 'AVAILABLE';
-- 优化后
SELECT id,name,cover FROM course
WHERE status = 'AVAILABLE' AND start_time > NOW()
ORDER BY start_time LIMIT 20;
- 缓存策略:
java复制@Cacheable(value = "courses", key = "#type + ':' + #page")
public Page<Course> listAvailableCourses(CourseType type, int page) {
// ...
}
- 限流措施:
java复制@RateLimiter(value = 100, key = "'reservation:' + #courseId")
public Reservation createReservation(Long courseId) {
// ...
}
5. 安全防护体系建设
5.1 常见攻击防御方案
- XSS防护:
java复制@Bean
public FilterRegistrationBean<XssFilter> xssFilter() {
FilterRegistrationBean<XssFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new XssFilter());
registration.addUrlPatterns("/*");
return registration;
}
- CSRF防护(Vue端):
javascript复制// axios拦截器
instance.interceptors.request.use(config => {
config.headers['X-CSRF-TOKEN'] = getCookie('csrfToken')
return config
})
- 预约接口防刷:
java复制@PreAuthorize("@rateLimit.check('reservation', #userId, 10, 60)")
@PostMapping("/reserve")
public Result reserve(@RequestParam Long userId, ...) {
// ...
}
5.2 敏感数据处理规范
- 密码加密存储:
java复制public String encryptPassword(String raw) {
return new BCryptPasswordEncoder().encode(raw);
}
- 日志脱敏处理:
java复制@Bean
public PatternLayout patternLayout() {
PatternLayout layout = new PatternLayout();
layout.setReplacement("%msg{replace('身份证号':'\\\\d{4}(\\\\d{10})','$1****')}");
return layout;
}
6. 多端发布与运维实践
6.1 Uniapp跨端发布流程
小程序发布checklist:
- 配置合法域名(request、socket、uploadFile)
- 设置业务域名(防止webview白屏)
- 压缩图片资源(使用tinypng API)
- 开启v3编译(提升性能)
APP打包注意事项:
- 处理第三方库冲突(如微信支付SDK)
gradle复制configurations {
all*.exclude group: 'com.tencent.mm.opensdk', module: 'wechat-sdk'
}
- 适配启动图尺寸(安卓需5种分辨率)
- 配置应用权限(相机、定位等)
6.2 生产环境部署方案
采用Docker Compose编排服务:
yaml复制version: '3'
services:
app:
image: openjdk:11-jre
ports:
- "8080:8080"
volumes:
- ./logs:/app/logs
environment:
- SPRING_PROFILES_ACTIVE=prod
redis:
image: redis:6-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
监控体系搭建:
- SpringBoot Actuator暴露健康指标
- Prometheus收集性能数据
- Grafana展示关键metrics
7. 项目演进方向与扩展思考
在实际运营过程中,我们发现了三个有价值的扩展点:
- 智能推荐系统:基于用户训练记录和身体数据,使用协同过滤算法推荐适合课程
python复制# 简易推荐算法示例
def recommend_courses(user_id):
user_vector = get_user_preferences(user_id)
all_courses = Course.objects.all()
return sorted(all_courses,
key=lambda c: cosine_similarity(user_vector, c.feature_vector),
reverse=True)[:5]
- 直播课集成:通过腾讯云直播服务接入实时互动功能
javascript复制// Uniapp端集成直播组件
<live-player
src="https://live.url"
mode="live"
@statechange="onStateChange"
/>
- 可穿戴设备对接:通过蓝牙API连接运动手环获取实时心率数据
javascript复制uni.startBluetoothDevicesDiscovery({
success: (res) => {
uni.onBluetoothDeviceFound((devices) => {
if(devices[0].name.includes('Mi Band')){
this.connectDevice(devices[0]);
}
});
}
});
这个项目给我的最大启示是:技术方案必须紧扣业务场景。比如在预约冲突处理上,我们最初采用数据库乐观锁,后来发现健身课程更适合用预占机制——教练可提前锁定某些时段专门用于私教课。这种业务认知的深化,往往比单纯的技术优化更有价值。
