1. 项目概述
这个基于SSM框架和Android平台的电影院在线订票系统,是我去年为一个本地连锁影院开发的实际项目。当时影院老板找到我,说他们还在用纸质票和人工售票窗口,经常出现排长队、座位冲突等问题。经过三个月的开发迭代,我们成功上线了这个系统,现在影院90%的票务都通过这个APP完成了。
系统最大的特点就是"前后分离":后端用SSM框架搭建RESTful API服务,前端用Android开发移动应用。这种架构既保证了后台管理的高效稳定,又给用户提供了便捷的移动端体验。上线半年后,影院的上座率提升了35%,人力成本降低了40%,效果非常明显。
2. 系统架构设计
2.1 后端服务架构
后端采用经典的SSM框架组合,这是我经过多次项目验证后选择的方案。相比传统的SSH,SSM更加轻量灵活,特别适合这种中小型的业务系统。
Spring框架主要负责依赖注入和事务管理。我特别喜欢它的声明式事务,用@Transactional注解就能搞定复杂的订单业务。比如用户下单时,需要同时更新座位状态、生成订单记录、扣除用户余额,这些操作必须在一个事务里完成,否则就会出现数据不一致。
Spring MVC处理HTTP请求,我们完全采用RESTful风格设计API。比如获取影片列表的接口是GET /api/movies,下单接口是POST /api/orders。这种设计让前后端分离得很彻底,Android端只需要关心JSON数据的交互。
MyBatis作为ORM框架,我特别喜欢它的动态SQL功能。比如查询影片时,用户可能按类型筛选、按评分排序,或者搜索关键词,用MyBatis的
2.2 数据库设计
数据库用了MySQL 8.0,主要设计了以下几张核心表:
-
影片表(movie):存储影片基本信息,包括片名、导演、主演、时长、类型、简介等。这里有个细节是海报存储,我们没直接存图片,而是存URL地址,图片文件实际放在阿里云OSS上。
-
影院表(cinema):记录影院名称、地址、联系方式、营业时间等。地址字段特意拆分了省市区,方便后续按区域筛选。
-
影厅表(hall):每个影厅的座位数、排布方式(比如8排10列)。这里用JSON格式存储座位模板,方便不同影厅有不同的座位排布。
-
场次表(schedule):关联影片和影厅,记录放映时间、票价。票价设计成基础价+服务费的模式,方便后续做促销活动。
-
订单表(order):最复杂的表,关联用户、场次、座位,记录订单状态、支付金额、支付时间等。状态机设计很关键,从"待支付"到"已完成"再到"已退款",每个状态转换都要严格校验。
2.3 Android端架构
Android端采用MVVM模式,配合Jetpack组件,这是目前最主流的架构方案。
数据层用Retrofit处理网络请求,配合Gson解析JSON。这里有个优化点:我们对API响应做了统一封装,包含code、message、data三个字段,客户端可以根据code统一处理错误情况。
ViewModel负责业务逻辑,比如下单流程:先检查座位是否可用,然后生成订单,最后调起支付。这些操作都放在ViewModel里,Activity只负责UI更新。
UI层用Kotlin+Jetpack Compose开发,比传统XML布局效率高很多。特别是座位选择界面,用Compose的Canvas自定义绘制,可以很灵活地实现各种影厅的座位图。
3. 核心功能实现
3.1 在线选座功能
选座是系统最核心也最复杂的功能,涉及到高并发下的座位锁定问题。我们是这样实现的:
-
座位状态存储:用Redis的Hash结构存储每个场次的座位状态,key是schedule_id,field是seat_id,value是状态(0可用,1已售,2锁定中)。Redis的高性能保证了即使热门场次也能快速响应。
-
座位锁定机制:用户选座后,客户端调用/lock接口,后端用Redis的SETNX命令实现分布式锁,防止多个用户同时锁定同一个座位。锁定有效期5分钟,超时自动释放。
-
支付完成处理:用户支付成功后,系统将座位状态改为"已售",并持久化到MySQL。如果支付超时,系统会扫描所有超时未支付的订单,自动释放锁定座位。
踩坑提醒:初期我们没做分布式锁,结果测试时发现两个用户同时选同一个座位,都提示成功。后来加了Redis锁才解决这个问题。
3.2 支付集成
支付对接了微信支付和支付宝,这是国内最主流的两种方式。技术实现上:
-
后端生成支付参数:根据订单金额、描述等信息,调用支付平台API获取支付参数(如微信的prepay_id)。
-
Android端调起支付:用官方的SDK发起支付请求,处理支付结果回调。这里要注意签名验证,确保回调是真的来自支付平台。
-
支付结果异步通知:支付平台会主动通知我们的服务器,我们需要处理这种异步通知,更新订单状态。为了防止重复处理,要对通知做幂等性校验。
支付流程中最容易出问题的是网络中断。我们做了本地订单状态缓存,即使支付过程中APP崩溃,重新打开后也能继续处理未完成的订单。
3.3 影院管理后台
影院管理员用的后台是Vue.js开发的Web应用,主要功能:
-
影片管理:可以上传新影片,设置上下映时间。上传海报时我们做了自动压缩,原图和大中小三种缩略图,适配不同场景展示。
-
排片管理:可视化排片界面,可以拖拽调整场次时间。排片时会自动检查影厅冲突,避免同一个影厅同一时间排两部电影。
-
数据统计:用ECharts展示票房趋势、上座率等数据。支持按日、周、月查看,帮助影院优化排片策略。
4. 性能优化实践
4.1 缓存策略
系统采用了多级缓存来提升性能:
-
Redis缓存:热门影片信息、近期场次数据都缓存在Redis,设置合理的过期时间(影片信息1天,场次信息1小时)。
-
本地缓存:Android端用Room数据库缓存用户历史订单、收藏影片等数据,减少网络请求。
-
CDN加速:静态资源如图片、JS/CSS文件放在CDN上,提升用户下载速度。
4.2 数据库优化
-
索引优化:给所有查询条件字段加索引,比如影片表的type字段、场次表的movie_id和cinema_id字段。
-
读写分离:查询走从库,写入走主库。用Sharding-JDBC中间件实现透明的读写分离。
-
分表策略:订单表按月分表,避免单表数据量过大影响查询性能。
4.3 Android端优化
-
图片加载:用Glide库实现图片懒加载和缓存,列表页先用缩略图,详情页再加载高清图。
-
网络请求:合并多个接口请求,比如进入首页时一次性获取影片列表、推荐影片、优惠活动等数据。
-
内存管理:用LeakCanary检测内存泄漏,特别是Activity和Fragment的泄漏问题。
5. 安全防护措施
5.1 接口安全
-
HTTPS加密:所有API接口强制HTTPS,防止中间人攻击。
-
签名验证:每个请求都要带签名参数,防止参数被篡改。签名算法用HMAC-SHA256,密钥定期更换。
-
频率限制:对登录、下单等敏感接口做限流,防止暴力破解和刷单。
5.2 数据安全
-
敏感数据加密:用户密码用BCrypt加密存储,支付密码用AES加密。
-
日志脱敏:日志中的手机号、身份证号等敏感信息自动打码。
-
SQL防注入:MyBatis全部用#{}参数绑定,禁止拼接SQL字符串。
5.3 业务安全
-
防重复下单:用户5分钟内不能重复购买同一场次的相同座位。
-
防黄牛机制:热门场次限制每个账号的购买数量,需要手机号验证。
-
退票审核:退票需要人工审核,防止恶意退票占用座位。
6. 项目部署方案
6.1 后端部署
后端服务用Docker容器化部署,配合Kubernetes实现自动扩缩容。日常流量跑2个Pod,周末或热门影片上映时自动扩展到5个Pod。
数据库用阿里云RDS,配置了主从复制和定时备份。每天凌晨自动备份,保留最近7天的备份文件。
6.2 Android发布
Android端采用多渠道打包,不同影院可以定制自己的APP图标和启动页。版本更新用腾讯Bugly实现热更新,小版本更新用户无感知。
6.3 监控系统
-
业务监控:用Prometheus监控接口成功率、响应时间等指标,异常情况触发告警。
-
日志分析:ELK收集和分析日志,方便排查问题。
-
APM监控:用SkyWalking追踪分布式调用链,定位性能瓶颈。
7. 遇到的问题及解决方案
7.1 座位超卖问题
初期版本在高并发下会出现座位超卖,原因是MySQL的读已提交隔离级别不能完全防止幻读。最终解决方案:
- 用SELECT FOR UPDATE加行锁
- Redis分布式锁双重校验
- 乐观锁版本号控制
7.2 支付掉单问题
有时用户支付成功了,但系统没收到回调通知。我们做了以下改进:
- 增加主动查询机制:对状态为"支付中"的订单,定时向支付平台查询最新状态
- 补偿对账任务:每天凌晨跑对账任务,修复状态不一致的订单
- 增加人工处理后台:运营人员可以手动核对和修复异常订单
7.3 Android兼容性问题
不同厂商的Android手机有很多兼容性问题,特别是支付和通知相关。我们:
- 建立了真机测试实验室,覆盖主流品牌和系统版本
- 针对每个问题写适配代码,比如华为的后台限制、小米的通知权限等
- 收集用户反馈,快速响应和修复问题
8. 项目成果与展望
系统上线后取得了很好的效果:
- 用户方面:购票平均时间从原来的15分钟缩短到2分钟,用户满意度提升40%
- 影院方面:人力成本降低40%,上座率提升35%,广告收入增加20%
- 技术方面:系统稳定运行半年,最高承载过每秒500订单的峰值流量
未来我们计划:
- 增加小程序版本,覆盖更多用户场景
- 引入推荐算法,根据用户历史行为推荐影片
- 拓展卖品电商功能,支持爆米花饮料在线购买
- 开发会员积分体系,提升用户粘性
这个项目让我深刻体会到,一个好的技术方案必须紧密结合业务需求。比如座位锁定时间设为5分钟,就是经过多次测试后找到的平衡点:太短用户来不及支付,太长影响其他用户购票。每个技术决策背后都要考虑实际的用户体验和业务场景。