1. 项目概述
这个电影售票系统是我去年指导的一个计算机专业本科毕业设计项目,采用Java语言开发,实现了从影片管理、场次排期到在线选座购票的完整业务流程。系统后台使用Spring Boot框架,前端采用Vue.js,数据库选用MySQL,是一个典型的全栈式Web应用开发案例。
对于计算机专业的学生来说,这类系统既不会过于简单导致工作量不足,又不会太过复杂难以完成。它涵盖了用户认证、数据持久化、事务处理、前后端交互等常见业务场景,能很好地检验学生对Java Web开发技术的掌握程度。
2. 系统架构设计
2.1 技术选型考量
选择Spring Boot作为后端框架主要基于以下几点考虑:
- 内嵌Tomcat服务器,简化部署流程
- 自动配置特性大幅减少XML配置
- 丰富的Starter依赖可以快速集成常用组件
- 完善的文档和社区支持
前端选用Vue.js而非传统JSP的原因:
- 前后端分离架构更符合现代Web开发趋势
- 组件化开发便于功能模块复用
- 响应式数据绑定简化了座位选择等交互逻辑
2.2 系统模块划分
系统主要分为以下核心模块:
- 用户管理模块:处理注册、登录、权限控制
- 影片管理模块:CRUD操作、分类管理
- 放映厅管理模块:厅室信息、座位布局
- 场次排期模块:设置放映时间、票价策略
- 订单管理模块:购票流程、支付对接
- 统计报表模块:销售数据分析
3. 数据库设计
3.1 核心表结构
sql复制CREATE TABLE `film` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`director` varchar(50) DEFAULT NULL,
`actors` varchar(200) DEFAULT NULL,
`duration` int DEFAULT NULL COMMENT '分钟',
`poster_url` varchar(255) DEFAULT NULL,
`description` text,
`status` tinyint DEFAULT '0' COMMENT '0-待上映 1-热映中 2-已下架',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `schedule` (
`id` int NOT NULL AUTO_INCREMENT,
`film_id` int NOT NULL,
`hall_id` int NOT NULL,
`show_time` datetime NOT NULL,
`price` decimal(10,2) NOT NULL,
`remaining_seats` int NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_film` (`film_id`),
KEY `idx_time` (`show_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 关键设计要点
- 座位设计采用行列坐标法,便于可视化选座
- 场次表设置剩余座位数字段,避免频繁联表查询
- 使用乐观锁处理并发购票场景
- 建立适当的索引提升查询性能
4. 核心功能实现
4.1 选座购票流程
java复制@Transactional
public Order createOrder(Integer scheduleId, Integer userId, List<Seat> seats) {
// 1. 检查场次有效性
Schedule schedule = scheduleMapper.selectById(scheduleId);
if(schedule == null || schedule.getRemainingSeats() < seats.size()){
throw new BusinessException("场次已满或不存在");
}
// 2. 锁定座位(分布式环境下建议使用Redis)
if(!seatService.lockSeats(scheduleId, seats)){
throw new BusinessException("座位已被占用");
}
// 3. 创建订单
Order order = new Order();
order.setUserId(userId);
order.setScheduleId(scheduleId);
order.setTotalPrice(calculateTotalPrice(seats, schedule.getPrice()));
orderMapper.insert(order);
// 4. 生成票务记录
List<Ticket> tickets = seats.stream()
.map(seat -> new Ticket(order.getId(), seat.getRowNum(), seat.getColNum()))
.collect(Collectors.toList());
ticketMapper.batchInsert(tickets);
// 5. 更新场次余票
scheduleMapper.updateRemainingSeats(scheduleId, -seats.size());
return order;
}
4.2 支付超时处理
使用Spring的@Scheduled注解实现定时任务,自动取消未支付订单:
java复制@Scheduled(cron = "0 */5 * * * ?")
public void cancelUnpaidOrders() {
LocalDateTime deadline = LocalDateTime.now().minusMinutes(15);
List<Order> unpaidOrders = orderMapper.selectUnpaidBefore(deadline);
unpaidOrders.forEach(order -> {
// 释放锁定座位
seatService.unlockSeats(order.getScheduleId(),
ticketMapper.selectByOrderId(order.getId()));
// 更新订单状态
order.setStatus(OrderStatus.CANCELLED);
orderMapper.updateById(order);
});
}
5. 系统安全设计
5.1 关键安全措施
- 接口防刷:使用Guava RateLimiter限制高频请求
- XSS防护:前端使用vue-sanitize过滤输入,后端对输出编码
- CSRF防护:Spring Security默认启用CSRF保护
- SQL注入:全部使用MyBatis参数化查询
- 密码存储:BCryptPasswordEncoder加密
5.2 权限控制示例
java复制@PreAuthorize("hasRole('ADMIN')")
@PostMapping("/films")
public Result addFilm(@RequestBody Film film) {
filmService.addFilm(film);
return Result.success();
}
@PreAuthorize("#userId == authentication.principal.id")
@GetMapping("/users/{userId}/orders")
public Result getUserOrders(@PathVariable Integer userId) {
return Result.success(orderService.getByUser(userId));
}
6. 部署与性能优化
6.1 生产环境部署方案
- 使用Docker容器化部署
- Nginx作为反向代理和静态资源服务器
- 配置Redis缓存热门影片数据和座位锁定状态
- 使用Prometheus + Grafana监控系统性能
6.2 性能优化要点
- 影片列表接口添加二级缓存(Redis + 本地缓存)
- 场次查询使用覆盖索引避免回表
- 购票接口添加分布式锁防止超卖
- 静态资源启用CDN加速
- 启用Gzip压缩减少传输体积
7. 毕设开发建议
7.1 功能扩展方向
- 会员积分系统
- 影片推荐算法
- 退票改签功能
- 第三方支付对接
- 微信小程序端开发
7.2 论文撰写要点
- 重点描述并发控制方案
- 详细说明数据库设计思路
- 分析系统性能优化措施
- 对比传统和现代架构差异
- 总结开发过程中的收获
8. 常见问题解决
8.1 开发环境问题
-
MySQL连接失败:
- 检查application.yml中的数据库配置
- 确认MySQL服务已启动
- 验证用户名密码是否正确
-
前端跨域问题:
java复制@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowCredentials(true) .maxAge(3600); } }
8.2 业务逻辑问题
-
座位重复售卖:
- 确保使用事务管理
- 实现乐观锁或分布式锁
- 添加唯一索引防止数据不一致
-
支付状态同步:
- 实现支付回调接口
- 添加定时任务补偿检查
- 记录完整的支付流水日志
9. 源码使用说明
项目采用标准的Maven多模块结构:
code复制movie-ticket-system/
├── movie-common // 公共模块
├── movie-dao // 数据访问层
├── movie-service // 业务逻辑层
├── movie-web // Web接口层
└── movie-admin // 管理后台前端
启动步骤:
- 创建MySQL数据库并执行init.sql
- 修改application.yml中的数据库配置
- 启动后端服务:mvn spring-boot:run
- 进入movie-admin目录执行npm install && npm run serve
10. 开发心得分享
在实际开发过程中,有几个特别值得注意的技术点:
-
座位选择算法:将影厅座位布局存储在二维数组中,前端根据数据结构动态渲染选座界面,比硬编码方式更灵活。
-
购票并发控制:最初使用数据库悲观锁导致性能瓶颈,改为Redis分布式锁+乐观锁方案后,TPS提升了5倍。
-
定时任务补偿:支付超时检查不能仅依赖前端通知,必须有多重保障机制。
-
缓存策略:影片详情这类读多写少的数据适合用缓存,但要注意缓存击穿问题,我们的解决方案是使用互斥锁重建缓存。