1. 项目概述:前后端分离影院购票系统的技术架构
影院购票系统作为典型的在线交易场景,需要处理高并发选座、实时支付和票务核销等核心业务。采用SpringBoot+Vue的分离架构,既能保证后端服务的稳定性,又能提供流畅的前端用户体验。我在实际开发中发现,这种架构特别适合需要快速迭代的电商类项目。
系统采用经典的三层架构设计:
- 表现层:Vue 3.x + Element Plus构建响应式管理后台和用户端
- 业务层:SpringBoot 2.7.x提供RESTful API
- 数据层:MyBatis-Plus + MySQL 8.0实现数据持久化
提示:选择SpringBoot 2.7而非3.0版本,主要考虑国内企业环境对JDK17的适配尚不普及
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心模块设计与实现
2.1 影院场次管理模块
场次管理是系统的核心业务,涉及复杂的座位状态同步问题。我们采用乐观锁解决并发冲突:
java复制// 座位锁定逻辑示例
@Transactional
public boolean lockSeats(SeatLockDTO dto) {
// 检查座位状态
List<Seat> seats = seatMapper.selectBatchIds(dto.getSeatIds());
if(seats.stream().anyMatch(s -> s.getStatus() != 0)){
throw new BusinessException("座位已被预定");
}
// 更新状态
int rows = seatMapper.updateStatusBatch(dto.getSeatIds(), 1);
if(rows != dto.getSeatIds().size()){
throw new OptimisticLockingFailureException("座位状态变更冲突");
}
return true;
}
2.2 支付系统集成
支付模块需要特别注意事务一致性问题。我们采用本地消息表+定时任务补偿的方案:
- 创建订单时,同步插入支付任务记录
- 调用第三方支付接口
- 支付成功后更新订单和任务状态
- 定时任务每小时扫描超时未支付订单
注意:支付超时时间建议设置为15分钟,过长影响座位释放效率
3. 关键技术实现细节
3.1 Vue前端性能优化
针对影院选座场景的特殊性,我们做了这些优化:
- 使用WebSocket实现座位状态实时同步
- 采用虚拟滚动技术处理大型影厅的座位渲染
- 对Element Plus表格进行二次封装,支持万级数据渲染
javascript复制// 虚拟滚动配置示例
<el-table
:data="tableData"
height="500"
row-key="id"
:row-height="50"
:virtual-scroll="true"
:buffer-size="20"
>
<!-- 列定义 -->
</el-table>
3.2 MyBatis动态SQL实践
影片筛选功能需要灵活的条件组合查询:
xml复制<select id="selectMovies" resultType="Movie">
SELECT * FROM movie
<where>
<if test="name != null">
AND name LIKE CONCAT('%',#{name},'%')
</if>
<if test="minDuration != null">
AND duration >= #{minDuration}
</if>
<choose>
<when test="orderBy == 'heat'">
ORDER BY sales DESC
</when>
<otherwise>
ORDER BY release_date DESC
</otherwise>
</choose>
</where>
</select>
4. 系统部署方案
4.1 生产环境部署架构
推荐使用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql-data:/var/lib/mysql
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
frontend:
build: ./frontend
ports:
- "80:80"
4.2 性能调优参数
MySQL关键配置(my.cnf):
code复制[mysqld]
innodb_buffer_pool_size = 2G # 建议为物理内存的50-70%
innodb_log_file_size = 256M
max_connections = 500
thread_cache_size = 50
SpringBoot应用参数(application-prod.yml):
yaml复制server:
tomcat:
max-threads: 200
min-spare-threads: 20
spring:
datasource:
hikari:
maximum-pool-size: 50
connection-timeout: 30000
5. 开发中的典型问题与解决方案
5.1 选座并发冲突处理
初期直接使用数据库行锁导致性能瓶颈,最终方案:
- 使用Redis缓存热门场次座位状态
- 前端限制连续点击频率
- 后端采用乐观锁+重试机制
5.2 票务二维码生成优化
原始方案使用UUID存在安全问题,改进为:
java复制public String generateTicketCode(Long userId, Long scheduleId) {
String raw = userId + "|" + scheduleId + "|" + System.currentTimeMillis();
return DigestUtils.md5DigestAsHex(raw.getBytes());
}
6. 安全防护措施
6.1 XSS防护配置
SpringSecurity配置增加内容安全策略:
java复制@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.contentSecurityPolicy("script-src 'self'")
.and()
.xssProtection()
.block(true);
}
6.2 SQL注入防护
除了使用MyBatis预编译语句外,额外添加:
- 定期执行SQL注入漏洞扫描
- 关键表操作增加审计日志
- 使用Druid的WallFilter
7. 项目扩展方向
基于现有系统可以进一步扩展:
- 会员积分系统
- 影片推荐算法
- 影院自助取票机对接
- 微信小程序端开发
实际开发中,我发现影院系统的场次状态机设计尤为关键。建议使用状态模式实现:
java复制public interface ScheduleState {
void confirm(ScheduleContext context);
void cancel(ScheduleContext context);
}
// 具体状态实现
public class PublishedState implements ScheduleState {
@Override
public void confirm(ScheduleContext context) {
context.setState(new ConfirmedState());
}
}
