1. 项目概述:基于SpringBoot+Vue的电影票销售管理系统
这个电影票销售管理系统是我去年为一个本地影院连锁品牌开发的核心业务平台。当时客户面临的主要痛点是:原有系统基于传统PHP架构,高峰期经常崩溃,移动端体验差,且无法实时同步各影院的座位库存。我们采用SpringBoot+Vue的前后端分离架构,在3个月内完成了系统重构,上线后成功支撑了春节档单日超2万张票的销售峰值。
系统最核心的价值在于实现了:
- 多影院实时座位库存同步(误差<100ms)
- 动态票价策略(根据时段、上座率自动调整)
- 全渠道统一管理(网站/小程序/柜台终端)
- 秒级出票与二维码核销
提示:选择SpringBoot+Vue组合时,要特别注意两者版本兼容性。我们最初用SpringBoot 2.7配Vue 2就遇到了axios拦截器冲突,后来降级到SpringBoot 2.6才解决。
2. 技术架构设计解析
2.1 后端SpringBoot技术栈选型
后端采用三层架构设计:
- 表现层:SpringMVC + 自定义API响应包装器
- 业务层:Spring Transaction管理 + 策略模式实现动态定价
- 持久层:MyBatis-Plus + 多数据源路由(主从分离)
关键配置示例(application.yml):
yaml复制spring:
datasource:
master:
url: jdbc:mysql://master:3306/ticket?useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
slave:
url: jdbc:mysql://slave:3306/ticket?useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
redis:
cluster:
nodes: 192.168.1.101:6379,192.168.1.102:6379
2.2 前端Vue技术栈实现
前端采用Vue CLI搭建的模块化工程:
- 核心库:Vue 2.x + Vuex + Vue Router
- UI组件:Element-UI + 自定义主题
- 特色功能:
- WebSocket实时座位状态推送
- 基于Canvas的影院座位图渲染
- 微信支付SDK集成
典型组件代码(SeatMap.vue):
javascript复制export default {
methods: {
drawSeats() {
const canvas = this.$refs.canvas;
const ctx = canvas.getContext('2d');
// 绘制座位矩阵逻辑
this.seats.forEach(seat => {
ctx.fillStyle = seat.status === 'available' ? '#67C23A' : '#F56C6C';
ctx.fillRect(seat.x, seat.y, 30, 30);
});
}
}
}
3. 核心业务模块实现
3.1 实时座位库存管理
采用Redis集群+分布式锁保证库存一致性:
- 使用Hash结构存储每个场次的座位状态
- 选座时获取Redisson分布式锁
- 采用Lua脚本保证检查-占用的原子性
库存同步关键代码:
java复制public boolean lockSeats(Long scheduleId, List<Integer> seatNos) {
String lockKey = "lock:schedule:" + scheduleId;
RLock lock = redissonClient.getLock(lockKey);
try {
if (lock.tryLock(3, 10, TimeUnit.SECONDS)) {
String hashKey = "schedule:seats:" + scheduleId;
// 检查座位是否可用
List<Object> availability = redisTemplate.opsForHash()
.multiGet(hashKey, seatNos.stream().map(String::valueOf).collect(Collectors.toList()));
if (availability.contains("0")) {
return false;
}
// 标记座位为锁定
Map<String, String> updates = seatNos.stream()
.collect(Collectors.toMap(String::valueOf, v -> "0"));
redisTemplate.opsForHash().putAll(hashKey, updates);
return true;
}
} finally {
lock.unlock();
}
return false;
}
3.2 动态票价策略引擎
实现策略模式+规则引擎的混合方案:
- 基础策略:时段定价(早场/午间/黄金档)
- 高级策略:基于上座率的动态浮动(开场前2小时触发)
- 特殊策略:节假日溢价(通过配置中心管理)
策略配置表示例:
sql复制CREATE TABLE pricing_strategy (
id BIGINT PRIMARY KEY,
strategy_type ENUM('TIME_BASED','OCCUPANCY','SPECIAL_EVENT'),
schedule_id BIGINT,
trigger_condition JSON, -- 如 {"beforeShowTime": 120}
adjustment_rule JSON, -- 如 {"base": 0.2, "per10Percent": 0.05}
active BOOLEAN DEFAULT true
);
4. 系统部署与性能优化
4.1 生产环境部署方案
我们采用Docker Swarm集群部署(当时K8s资源不足):
- 后端服务:3节点Swarm集群(2C4G配置)
- 前端Nginx:单独容器+CDN静态资源缓存
- 数据库:MySQL Group Replication(1主2从)
- 缓存:Redis Cluster(6节点)
部署目录结构:
code复制/deploy
├── docker-compose.yml
├── nginx
│ ├── conf.d
│ │ └── ticket.conf
│ └── nginx.conf
├── backend
│ └── Dockerfile
└── frontend
└── Dockerfile
4.2 高并发场景优化
针对春节档压力测试发现的问题及解决方案:
- 座位查询接口超时
- 添加Redis二级缓存
- 改用Pipeline批量查询
- 支付回调堆积
- 引入RabbitMQ削峰
- 增加消费者线程池
- 二维码生成瓶颈
- 预生成基础二维码模板
- 使用本地缓存替代实时生成
优化前后性能对比:
| 场景 | 优化前QPS | 优化后QPS | 错误率下降 |
|---|---|---|---|
| 座位查询 | 215 | 1,200 | 98% |
| 创建订单 | 180 | 850 | 95% |
| 支付回调处理 | 150 | 不限流 | 99.9% |
5. 典型问题排查实录
5.1 分布式事务问题
场景:用户支付成功后,订单状态更新但座位未释放
排查过程:
- 检查日志发现支付服务与订单服务通信超时
- 确认是Seata分布式事务未正确回滚
- 根本原因:Nacos配置中心未同步Seata配置
解决方案:
java复制// 添加Seata全局事务注解
@GlobalTransactional
public void completePayment(Long orderId) {
paymentService.confirm(orderId);
orderService.updateStatus(orderId, PAID);
seatService.releaseLock(orderId); // 原缺失的关键步骤
}
5.2 Vue内存泄漏问题
现象:长时间使用后浏览器标签页卡顿
排查工具:Chrome Memory面板+快照对比
发现原因:
- 未销毁的WebSocket连接
- 影院筛选组件未正确解绑事件
修复方案:
javascript复制beforeDestroy() {
// 销毁WebSocket
this.socket.close();
// 移除事件监听
this.$bus.$off('cinema-filter', this.handleFilter);
}
6. 项目演进建议
这套系统目前已在5家影院稳定运行1年多,根据实际运营反馈,后续可重点优化:
-
引入电影推荐算法
- 基于用户历史购票记录
- 结合协同过滤+内容相似度
-
增强BI分析模块
- 上座率热力图
- 票价敏感度分析
-
升级到Vue3+SpringBoot3
- 体验Composition API优势
- 利用Java17新特性
实际开发中我们发现,电影票务系统最关键的不仅是技术实现,更要理解影院运营的线下场景。比如我们最初设计的15分钟自动释放座位,在实际运营中就被要求调整为8分钟——这直接影响了整个锁座逻辑的设计。
