1. 项目背景与核心价值
去年帮本地一家影院做系统升级时,发现他们还在用纸质票+Excel登记的原始方式。高峰期排队购票的顾客经常抱怨,而影院经理也为排片统计和财务对账头疼不已。这个基于SpringBoot+Vue的电影票务系统就是为解决这类痛点而设计的现代化解决方案。
这套系统实现了从影片上架、场次排期到在线选座、电子票务的全流程数字化管理。特别值得一提的是移动端适配的选座界面,采用了与淘票票相似的影院座位图可视化交互,让用户能像在购票APP上一样直观地完成选座操作。
2. 技术架构解析
2.1 后端技术栈设计
采用SpringBoot 2.7作为核心框架,主要基于以下考量:
- 自动配置特性快速集成MyBatis-Plus(3.5.3)
- 内置Tomcat简化部署(对比传统SSM需要单独配Tomcat)
- Actuator端点方便监控系统运行状态
数据库选用MySQL 8.0,关键表设计包括:
CREATE TABLE `schedule` ( `id` bigint NOT NULL AUTO_INCREMENT, `movie_id` bigint NOT NULL COMMENT '影片ID', `hall_id` int NOT NULL COMMENT '影厅ID', `show_time` datetime NOT NULL COMMENT '放映时间', `price` decimal(10,2) NOT NULL DEFAULT '0.00', `seat_status` varchar(500) COMMENT '座位状态JSON', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;2.2 前端技术选型
Vue 3组合式API带来以下优势:
- 响应式座位图:使用Canvas动态渲染影厅座位布局
- 状态管理:Pinia管理用户选座状态
- UI组件:Element Plus的表格组件用于后台管理
典型座位状态数据结构:
{ "A1": { "status": 0, "type": "normal" }, // 0-可选 1-已售 2-锁定 "A2": { "status": 1, "type": "vip" }, ... }3. 核心功能实现
3.1 高并发座位锁定机制
当多个用户同时选择相同座位时,采用Redis分布式锁保证数据一致性:
public boolean lockSeats(Long scheduleId, List<String> seatNos) { String lockKey = "lock:" + scheduleId; try { // 获取分布式锁(设置3秒过期防止死锁) Boolean locked = redisTemplate.opsForValue() .setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS); if(Boolean.TRUE.equals(locked)) { // 检查座位状态并更新 int affected = scheduleMapper.updateSeatStatus( scheduleId, seatNos, 2); // 2表示锁定状态 return affected == seatNos.size(); } return false; } finally { redisTemplate.delete(lockKey); } }3.2 支付超时自动释放
使用Spring的@Scheduled实现定时任务:
@Scheduled(fixedRate = 60000) // 每分钟检查一次 public void releaseTimeoutSeats() { // 查询超过15分钟未支付的锁定座位 List<Order> timeoutOrders = orderMapper.selectTimeoutOrders(15); timeoutOrders.forEach(order -> { scheduleMapper.releaseSeats( order.getScheduleId(), order.getSeatNumbers().split(",") ); orderMapper.updateStatus(order.getId(), 3); // 3-已取消 }); }4. 关键问题解决方案
4.1 座位状态同步难题
初期采用WebSocket全量推送方案导致带宽占用过高,优化为差异推送:
- 前端首次加载获取全量座位数据
- 服务端通过Redis Pub/Sub广播座位变更事件
- 前端仅更新发生变化的座位DOM节点
4.2 退票手续费计算
实现灵活的策略模式:
public interface RefundStrategy { BigDecimal calculate(BigDecimal originalPrice, LocalDateTime showTime); } @Component @Qualifier("normalStrategy") public class NormalRefundStrategy implements RefundStrategy { // 距离放映24小时前可全额退款 public BigDecimal calculate(BigDecimal price, LocalDateTime showTime) { if(LocalDateTime.now().isBefore(showTime.minusHours(24))) { return price; } return price.multiply(new BigDecimal("0.8")); } }5. 性能优化实践
5.1 影厅座位缓存策略
使用二级缓存架构:
- 第一层:Caffeine本地缓存(有效期5分钟)
- 第二层:Redis集群缓存(有效期30分钟)
- 缓存击穿防护:采用BloomFilter过滤非法scheduleId
配置示例:
caffeine: spec: maximumSize=1000,expireAfterWrite=5m redis: timeout: 3000 lettuce: pool: max-active: 85.2 订单分库分表方案
按影院ID进行水平分片:
- 订单表order_${cinemaId % 4}
- 每个分片配置单独的读写数据源
- 使用ShardingSphere实现路由
6. 安全防护措施
6.1 防刷票机制
基于Guava RateLimiter实现:
// 每个IP每分钟限购5张票 private static final RateLimiter limiter = RateLimiter.create(5.0 / 60); public boolean tryAcquireTicket(HttpServletRequest request) { String ip = request.getRemoteAddr(); if(!limiter.tryAcquire()) { log.warn("IP {} 触发热门场次限流", ip); throw new BusinessException("操作过于频繁"); } return true; }6.2 电子票防伪验证
采用SM4国密算法生成验票码:
public String generateTicketCode(Long orderId) { String rawText = orderId + "|" + System.currentTimeMillis(); return SM4Util.encryptECB(rawText, SECRET_KEY); }7. 监控与运维
7.1 Prometheus监控指标
关键监控项包括:
- 购票接口QPS
- 座位锁定成功率
- 平均响应时间
- MySQL连接池使用率
配置示例:
@Bean MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() { return registry -> registry.config() .commonTags("application", "cinema-ticket"); }7.2 ELK日志收集
Logstash过滤规则示例:
filter { grok { match => { "message" => "\[%{TIMESTAMP_ISO8601:timestamp}\] %{LOGLEVEL:level} %{DATA:traceId} \[%{DATA:thread}\] %{DATA:class} : %{GREEDYDATA:msg}" } } date { match => ["timestamp", "ISO8601"] } }8. 项目部署方案
8.1 Docker Compose编排
典型部署文件:
version: '3' services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} volumes: - ./mysql-data:/var/lib/mysql redis: image: redis:6-alpine ports: - "6379:6379" backend: build: ./backend ports: - "8080:8080" depends_on: - mysql - redis8.2 CI/CD流程
GitLab Runner配置要点:
- 单元测试覆盖率要求≥80%
- 使用SonarQube进行代码质量检测
- 生产环境采用蓝绿部署策略
9. 实际运营数据
在某中型影院(6个影厅)上线后:
- 购票线上化率从12%提升至89%
- 平均购票时间从7分钟缩短至1.5分钟
- 错票率从3.2%降至0.15%
- 高峰期系统吞吐量达到1200 TPS
10. 扩展优化方向
近期正在开发的功能:
- 会员积分抵现系统
- 动态票价算法(根据上座率自动调整)
- 小程序端快速购票通道
- 基于用户画像的智能推荐
这个项目让我深刻体会到,即使是传统的影院行业,通过合适的技术改造也能显著提升运营效率。特别是在处理高并发座位竞争时,分布式锁与缓存策略的组合使用非常关键。建议在开发类似系统时,尽早进行压力测试,我们就是在模拟500人同时抢票时才发现最初的锁机制存在严重性能瓶颈。