1. 项目背景与核心需求
校园电影院售票系统是一个典型的B/S架构应用,旨在为高校师生提供便捷的电影票务服务。这个系统需要解决几个核心问题:
- 票务管理:包括场次安排、座位管理、票价设置等基础功能
- 用户管理:区分学生、教职工等不同身份的用户权限
- 支付对接:集成校园一卡通或第三方支付接口
- 数据统计:为影院运营提供数据支持
选择SpringBoot+Vue的技术栈主要基于以下考虑:
- SpringBoot简化了Java后端开发,内置Tomcat服务器,约定优于配置
- Vue.js轻量高效,适合构建交互复杂的前端界面
- 前后端分离架构有利于团队协作和后期维护
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 后端技术选型
后端采用SpringBoot 2.7.x版本,主要依赖包括:
xml复制<dependencies>
<!-- Web支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 数据库访问 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 安全认证 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Redis缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
2.2 前端技术选型
前端使用Vue 3组合式API,主要技术栈:
- Vue 3 + Vite构建工具
- Element Plus组件库
- Axios HTTP客户端
- Vue Router路由管理
- Pinia状态管理
2.3 数据库设计
核心表结构设计:
-
用户表(user)
- id, username, password, role(角色), student_id(学号)等
-
电影表(movie)
- id, title, director, actors, duration, description等
-
放映厅表(hall)
- id, name, seat_count, seat_layout(座位布局JSON)
-
场次表(schedule)
- id, movie_id, hall_id, start_time, end_time, price
-
订单表(order)
- id, user_id, schedule_id, seats(座位号), status, create_time
3. 核心功能实现
3.1 座位选择与锁定
这是售票系统的核心难点,需要考虑并发场景下的座位锁定问题。我们采用Redis实现分布式锁:
java复制public boolean lockSeats(Long scheduleId, List<String> seatNumbers) {
String lockKey = "schedule:" + scheduleId + ":lock";
String requestId = UUID.randomUUID().toString();
try {
// 尝试获取锁
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, requestId, 30, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(locked)) {
// 检查座位是否可用
List<Seat> seats = seatRepository.findByScheduleAndNumberIn(scheduleId, seatNumbers);
if (seats.stream().anyMatch(s -> !s.isAvailable())) {
return false;
}
// 锁定座位
seatRepository.lockSeats(scheduleId, seatNumbers);
return true;
}
} finally {
// 释放锁
if (requestId.equals(redisTemplate.opsForValue().get(lockKey))) {
redisTemplate.delete(lockKey);
}
}
return false;
}
3.2 支付流程设计
校园场景下通常需要对接校园卡支付系统,基本流程:
- 前端提交订单后生成待支付订单
- 调用支付接口发起支付请求
- 支付系统回调通知支付结果
- 更新订单状态并释放或确认座位
java复制@PostMapping("/pay")
public ResponseEntity<?> payOrder(@RequestBody PaymentRequest request) {
// 1. 验证订单
Order order = orderService.getOrder(request.getOrderId());
if (order == null || order.getStatus() != OrderStatus.CREATED) {
return ResponseEntity.badRequest().body("无效订单");
}
// 2. 调用支付接口
PaymentResult result = paymentService.pay(
order.getId(),
order.getTotalAmount(),
request.getPaymentMethod()
);
// 3. 处理支付结果
if (result.isSuccess()) {
orderService.completeOrder(order.getId());
return ResponseEntity.ok("支付成功");
} else {
orderService.cancelOrder(order.getId());
return ResponseEntity.badRequest().body("支付失败");
}
}
3.3 场次管理功能
后台管理系统需要提供灵活的场次编排功能:
vue复制<template>
<el-form :model="form" label-width="120px">
<el-form-item label="选择电影">
<el-select v-model="form.movieId" filterable>
<el-option
v-for="movie in movies"
:key="movie.id"
:label="movie.title"
:value="movie.id"
/>
</el-select>
</el-form-item>
<el-form-item label="选择影厅">
<el-select v-model="form.hallId">
<el-option
v-for="hall in halls"
:key="hall.id"
:label="hall.name"
:value="hall.id"
/>
</el-select>
</el-form-item>
<el-form-item label="放映时间">
<el-date-picker
v-model="form.startTime"
type="datetime"
placeholder="选择日期时间"
/>
</el-form-item>
<el-form-item label="票价">
<el-input-number v-model="form.price" :min="0" :step="5" />
</el-form-item>
</el-form>
</template>
4. 系统安全与性能优化
4.1 安全防护措施
- 认证授权:使用Spring Security实现基于角色的访问控制
- 数据校验:前后端双重校验,防止非法输入
- 防刷机制:接口限流,防止恶意刷票
- 敏感数据保护:密码加密存储,日志脱敏
安全配置示例:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public JwtAuthenticationFilter jwtFilter() {
return new JwtAuthenticationFilter();
}
}
4.2 性能优化方案
-
缓存策略:
- 热门电影信息缓存
- 场次座位状态缓存
- 使用Redis集群提高缓存可用性
-
数据库优化:
- 合理设计索引
- 读写分离
- 分表策略(按时间分表)
-
前端优化:
- 组件懒加载
- 图片懒加载
- API请求合并
5. 部署与运维
5.1 本地开发环境
推荐使用Docker Compose搭建开发环境:
yaml复制version: '3'
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: cinema
ports:
- "3306:3306"
volumes:
- ./data/mysql:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
volumes:
- ./data/redis:/data
5.2 生产环境部署
推荐部署方案:
-
后端:
- 打包为JAR文件
- 使用Docker容器化部署
- 配置Nginx反向代理
- 使用Jenkins实现CI/CD
-
前端:
- 使用Vite打包
- 部署到Nginx或CDN
- 启用Gzip压缩
-
数据库:
- MySQL主从复制
- 定期备份策略
6. 常见问题与解决方案
6.1 跨域问题
前后端分离开发时常见的跨域问题解决方案:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.maxAge(3600);
}
}
6.2 性能监控
使用Spring Boot Actuator监控系统健康状态:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
配置application.properties:
properties复制management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=always
6.3 日志管理
推荐使用Logback+ELK栈实现集中式日志管理:
xml复制<!-- logback-spring.xml -->
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
7. 项目扩展方向
- 移动端适配:开发微信小程序或APP版本
- 推荐系统:基于用户历史行为实现个性化推荐
- 社交功能:添加影评、评分等互动功能
- 数据分析:使用ELK或Flink实现实时数据分析
- 微服务改造:将系统拆分为多个微服务
实际开发中,我发现在座位锁定环节最容易出现问题。特别是在高并发场景下,单纯依赖数据库乐观锁可能导致超卖。我们的解决方案是采用Redis分布式锁+数据库事务的组合方案,先通过Redis快速锁定资源,再通过数据库事务保证最终一致性。这种方案在实际运行中表现稳定,能够承受校园场景下的购票高峰。
