1. 项目概述:SSM框架下的影院票务系统实战
这个基于SSM框架的电影票务管理系统,是我去年为本地连锁影院开发的线上选座解决方案。系统上线后影院周末上座率提升了40%,最让我自豪的是经受住了春节档单日8000+订单的并发考验。现在把核心设计和实现细节分享出来,特别适合需要实战项目的Java学习者,或是准备做影院管理系统毕业设计的同学。
系统采用经典的MVC分层架构:Spring MVC处理前端请求,Spring管理业务组件,MyBatis操作MySQL数据库。前端用jQuery+Bootstrap实现响应式布局,后台管理端则采用EasyUI快速搭建。亮点在于选座算法的设计和并发锁票机制,这也是影院系统最核心的技术难点。
提示:项目完整源码已托管在Gitee,包含数据库脚本和详细配置文档。建议配合源码阅读本文,遇到问题可以直接在仓库提issue。
2. 技术栈选型与项目搭建
2.1 为什么选择SSM框架组合
SSM(Spring+Spring MVC+MyBatis)作为JavaEE开发的"三件套",在中小型项目中依然有不可替代的优势。相比Spring Boot的自动化配置,SSM需要更多手动整合,但这正是学习框架原理的好机会:
- Spring 5.2.8:控制反转和AOP的实现,管理Service层事务
- Spring MVC 5.2.8:DispatcherServlet配置、拦截器处理权限验证
- MyBatis 3.5.6:XML映射文件与注解混合开发模式
- MySQL 8.0:采用InnoDB引擎支持事务,使用utf8mb4字符集存储emoji影评
<!-- 典型POM依赖示例 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.6</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency>2.2 IntelliJ IDEA项目配置要点
使用IDEA 2022.3开发时,这几个配置直接影响开发效率:
- Lombok插件必装:减少Getter/Setter模板代码
- Database工具连接MySQL:可视化执行SQL脚本
- 配置Tomcat 9.0:设置热部署(Update classes and resources)
- 推荐安装MyBatisX插件:XML与接口方法智能跳转
避坑提示:遇到"Java: 警告: 源发行版17需要目标发行版17"错误时,需同步检查三处设置:Project Structure中的Project/Modules的Language Level、pom.xml的maven-compiler-plugin版本、Settings中Java Compiler的Target bytecode version。
3. 核心功能模块设计
3.1 数据库ER图与表结构
系统包含12张核心表,以下是关键表设计:
| 表名 | 字段示例 | 说明 |
|---|---|---|
| t_movie | id, name, duration, type, score | 影片基础信息 |
| t_cinema | id, name, address, hall_count | 影院信息 |
| t_schedule | id, movie_id, hall_id, start_time, price | 排片表 |
| t_hall | id, name, seats_layout, cinema_id | 影厅及座位模板 |
| t_order | id, schedule_id, seats, status, pay_time | 订单表 |
-- 座位模板存储设计 CREATE TABLE t_hall ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, seats_layout JSON NOT NULL, -- 存储座位矩阵 cinema_id INT NOT NULL );3.2 选座算法实现
选座功能是系统的技术难点,主要解决两个问题:
- 座位状态实时同步:采用WebSocket+Redis方案
- 前端建立WS连接接收座位状态变化
- Redis缓存影厅座位图,key格式:schedule:{id}:seats
- 使用SETNX实现分布式锁,防止超卖
// 选座核心逻辑代码片段 public Result selectSeats(OrderDTO dto) { String lockKey = "lock:schedule:" + dto.getScheduleId(); try { // 获取分布式锁(3秒超时) boolean locked = redisTemplate.opsForValue() .setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS); if (!locked) return Result.error("当前选座人数过多"); // 验证座位是否可用 String seatKey = "schedule:" + dto.getScheduleId() + ":seats"; String seatsStatus = redisTemplate.opsForValue().get(seatKey); if (seatsStatus.contains(dto.getSeats())) { return Result.error("座位已被选择"); } // 更新座位状态(实际开发需用Lua脚本保证原子性) redisTemplate.opsForValue().set(seatKey, seatsStatus + "," + dto.getSeats()); } finally { redisTemplate.delete(lockKey); } // 后续订单处理... }- 座位推荐算法:基于观影体验的智能推荐
- 黄金区域优先:影厅中间偏后区域
- 情侣座特殊处理:自动保留相邻座位
- 散客隔离策略:新订单尽量远离已有座位
4. 高并发场景下的优化实践
4.1 缓存策略设计
电影票务系统必须应对瞬时高并发,我们的缓存方案:
多级缓存架构:
- 前端:localStorage缓存影院列表(1小时过期)
- 服务端:Redis缓存热门影片数据(设置不同TTL)
- 数据库:MySQL查询缓存
缓存更新策略:
- 排片信息:定时任务提前预热
- 座位状态:变更时立即失效缓存
- 使用@Cacheable注解简化开发:
@Cacheable(value = "movies", key = "#id") public Movie getMovieById(Integer id) { return movieMapper.selectById(id); }4.2 订单超时处理方案
针对用户选座后未支付的情况,采用状态机+延迟队列:
订单状态流转:
graph LR A[待支付] -->|15分钟超时| B[已取消] A -->|支付成功| C[已完成] C -->|退款申请| D[退款中]技术实现:
- 创建订单时发送延迟消息到RabbitMQ
- 使用死信队列处理超时订单
- 补偿机制:定期扫描异常订单
// RabbitMQ配置示例 @Bean public Queue orderDelayQueue() { return QueueBuilder.durable("order.delay.queue") .withArgument("x-dead-letter-exchange", "order.event.exchange") .withArgument("x-dead-letter-routing-key", "order.release") .withArgument("x-message-ttl", 900000) // 15分钟 .build(); }5. 典型问题排查实录
5.1 座位状态不同步问题
现象:用户A看到座位空置,点击选择时提示已被占用
排查过程:
- 检查WebSocket连接状态(Network → WS)
- 验证Redis订阅/发布通道是否正常
- 发现Nginx配置缺少WebSocket支持
解决方案:
location /ticket-websocket { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }5.2 超卖问题分析
场景:热门场次出现同一座位被售出多次
根本原因:缓存与数据库不一致
终极方案:
- 引入Redisson分布式锁
- 采用CAS(Compare And Set)更新库存
- 数据库添加唯一索引防止重复
ALTER TABLE t_order_seat ADD UNIQUE INDEX idx_schedule_seat (schedule_id, seat_number);6. 项目扩展方向
这个基础系统还可以进一步优化:
数据分析模块:
- 使用ECharts展示票房趋势
- 基于用户购票记录实现协同过滤推荐
移动端适配:
- 开发微信小程序版本
- 集成Apple Pay/支付宝快捷支付
运维监控:
- Prometheus+Grafana监控系统健康状态
- ELK日志分析平台
经验之谈:在开发类似系统时,一定要提前与影院经理沟通业务流程。比如我们最初不知道影院会有"锁座"需求(为团体客户预留座位),导致第一版上线后紧急加了此功能。