1. 项目概述:SpringBoot+Vue电影订票系统全栈实现
这套电影订票系统采用当前主流的前后端分离架构,后端基于SpringBoot 2.x构建RESTful API,前端使用Vue 2.x+ElementUI实现用户界面,数据存储选用MySQL 5.7+。系统完整实现了从影片管理、场次排期到在线选座、订单支付的完整业务流程,特别针对高并发选座场景做了乐观锁优化。
我在实际部署时发现,这套代码的亮点在于其"开箱即用"特性——项目自带Maven和npm的完整依赖配置,数据库提供了包含测试数据的SQL脚本,前后端分别只需一个命令即可启动。对于需要快速搭建电影票务系统的开发者而言,这比从零开始构建节省至少80%的开发时间。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构深度解析
2.1 后端SpringBoot核心设计
采用三层架构设计(Controller-Service-DAO),关键配置在application.yml中:
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/movie_booking?useSSL=false&serverTimezone=UTC
username: root
password: 123456
jpa:
show-sql: true
hibernate:
ddl-auto: update
特别值得关注的是座位锁定的实现逻辑。在SeatService中采用版本号乐观锁防止超卖:
java复制@Transactional
public boolean lockSeat(Integer seatId, Integer version) {
int count = seatMapper.updateSeatStatus(seatId, SeatStatus.LOCKED.getCode(), version);
return count > 0;
}
2.2 前端Vue工程结构
前端项目采用Vue CLI搭建,核心目录结构:
code复制src/
├── api/ # Axios请求封装
├── assets/ # 静态资源
├── components/ # 公共组件
│ ├── SeatMap.vue # 座位图组件
│ └── PayModal.vue # 支付弹窗
├── router/ # 路由配置
├── store/ # Vuex状态管理
└── views/ # 页面组件
座位选择模块使用Canvas绘制影院座位图,通过watch监听选中状态变化:
javascript复制watch: {
selectedSeats(newVal) {
this.$store.commit('updateSelected', newVal)
this.calculateTotal()
}
}
3. 数据库设计与优化
3.1 主要表结构设计
核心表包括:
sql复制CREATE TABLE `movie` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`title` VARCHAR(100) NOT NULL,
`cover_url` VARCHAR(255),
`duration` INT COMMENT '分钟',
`description` TEXT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
场次表与座位表的关联设计采用冗余存储提高查询性能:
sql复制CREATE TABLE `schedule` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`movie_id` INT NOT NULL,
`hall_id` INT NOT NULL,
`start_time` DATETIME NOT NULL,
`price` DECIMAL(10,2) NOT NULL,
`seat_info` JSON COMMENT '座位状态快照',
FOREIGN KEY (`movie_id`) REFERENCES `movie`(`id`)
);
3.2 性能优化实践
- 为高频查询字段添加索引:
sql复制ALTER TABLE `order` ADD INDEX idx_user_status (`user_id`, `status`);
- 使用Redis缓存热门影片数据:
java复制@Cacheable(value = "movies", key = "#id")
public Movie getMovieById(Integer id) {
return movieMapper.selectById(id);
}
4. 典型业务场景实现
4.1 选座购票流程
- 前端获取可选座位数据(带版本号)
- 用户选择座位后发起锁定请求
- 后端验证座位可用性并更新版本号
- 生成待支付订单
- 支付成功后更新订单状态
关键并发控制代码:
java复制public Result lockSeats(List<SeatDTO> seats) {
seats.forEach(seat -> {
while (!seatService.lockSeat(seat.getId(), seat.getVersion())) {
// 获取最新版本号重试
seat.setVersion(seatMapper.getVersion(seat.getId()));
}
});
return Result.success();
}
4.2 支付结果异步通知
采用支付宝沙箱环境模拟支付流程:
java复制@PostMapping("/pay/notify")
public String payNotify(HttpServletRequest request) {
Map<String, String> params = // 获取参数
boolean verifyResult = AlipaySignature.rsaCheckV1(...);
if (verifyResult) {
orderService.handlePaySuccess(params.get("out_trade_no"));
return "success";
}
return "fail";
}
5. 部署与运维实践
5.1 开发环境快速启动
后端启动:
bash复制mvn spring-boot:run -Dspring.profiles.active=dev
前端启动:
bash复制npm install
npm run serve
5.2 生产环境部署建议
- 使用Nginx配置前后端分离部署:
nginx复制location /api {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
}
location / {
root /path/to/dist;
try_files $uri $uri/ /index.html;
}
- 数据库连接池配置优化:
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 20
connection-timeout: 30000
6. 常见问题排查指南
6.1 跨域问题解决方案
开发环境配置CORS:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*");
}
}
6.2 日期时间序列化问题
统一配置Jackson日期格式:
java复制@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
return builder -> {
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
builder.serializers(new LocalDateTimeSerializer(
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
};
}
}
7. 扩展开发建议
- 增加分布式锁实现:
java复制public boolean lockWithRedis(String key, String value, long expire) {
return redisTemplate.opsForValue()
.setIfAbsent(key, value, expire, TimeUnit.SECONDS);
}
- 接入微信小程序端:
- 复用现有API接口
- 新增小程序授权登录模块
- 适配小程序支付流程
这套系统在实际影院项目实施时,建议根据业务量评估是否引入分库分表策略。对于日均订单量超过1万的场景,可考虑按影院ID进行水平分片。
