电影在线购票系统是现代影院数字化转型的核心基础设施。作为一名长期从事Java企业级开发的工程师,我在实际项目中发现传统线下购票模式存在三大痛点:影院排片信息更新滞后、黄金座位难以公平分配、高峰时段排队购票体验差。基于Spring Boot 1.6.9框架实现的这套系统,正是为了解决这些行业痛点而生。
系统采用经典的三层架构设计:
特别说明选择Spring Boot 1.6.9版本的原因:这是最后一个同时支持JDK7和JDK8的稳定版本,对于需要兼容老旧服务器的企业环境尤为重要。虽然现在Spring Boot已迭代到3.x版本,但在银行、国企等保守行业,1.6.x系列仍是主流选择。
Spring Boot 1.6.9技术栈组合:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.6.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
注意:MyBatis版本必须与Spring Boot 1.6.9匹配,新版可能导致兼容性问题
前端技术组合:
影院核心表结构设计:
sql复制CREATE TABLE `t_movie` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '电影名称',
`duration` int(11) NOT NULL COMMENT '时长(分钟)',
`poster_url` varchar(255) DEFAULT NULL COMMENT '海报URL',
`score` decimal(3,1) DEFAULT '0.0' COMMENT '评分',
`show_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0未上映 1热映中 2已下映',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
关键设计考量:
座位锁定采用Redis分布式锁方案:
java复制public boolean lockSeats(List<Integer> seatIds, Integer scheduleId) {
String lockKey = "lock:schedule:" + scheduleId;
// 获取分布式锁
boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
if (!locked) {
throw new BusinessException("当前操作人数过多,请稍后再试");
}
try {
// 检查座位是否可用
List<Seat> seats = seatMapper.selectByIds(seatIds);
if (seats.stream().anyMatch(s -> s.getStatus() != 0)) {
return false;
}
// 更新座位状态为锁定
seatMapper.batchUpdateStatus(seatIds, 1);
return true;
} finally {
redisTemplate.delete(lockKey);
}
}
重要提示:必须设置合理的锁超时时间(建议15-30秒),避免死锁导致系统瘫痪
支付宝沙箱环境配置示例:
properties复制# application-pay.properties
alipay.app-id=2021000123456789
alipay.merchant-private-key=MIICdgIBADANBgkqh...
alipay.alipay-public-key=MIGfMA0GCSqGSIb3DQE...
alipay.notify-url=http://yourdomain.com/api/pay/notify
alipay.return-url=http://yourdomain.com/pay/success
支付结果异步通知处理流程:
三级缓存策略:
余票查询优化方案:
java复制@Cacheable(value = "schedule", key = "#scheduleId")
public ScheduleVO getScheduleWithSeats(Integer scheduleId) {
Schedule schedule = scheduleMapper.selectById(scheduleId);
List<Seat> seats = seatMapper.selectByScheduleId(scheduleId);
return new ScheduleVO(schedule, seats);
}
索引设计规范:
慢SQL排查方法:
sql复制-- 开启慢查询日志
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
XSS防护方案:
java复制@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.xssProtection()
.and()
.contentSecurityPolicy("script-src 'self'");
}
}
CSRF防护配置:
html复制<meta name="_csrf" th:content="${_csrf.token}"/>
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>
密码加密存储方案:
java复制public class PasswordUtil {
private static final int SALT_LENGTH = 16;
private static final int HASH_ITERATIONS = 1024;
public static String encrypt(String password) {
byte[] salt = SecureRandom.getSeed(SALT_LENGTH);
PBEParameterSpec spec = new PBEParameterSpec(salt, HASH_ITERATIONS);
// ...加密实现
}
}
Docker Compose部署文件:
yaml复制version: '3'
services:
app:
image: openjdk:8-jre
ports:
- "8080:8080"
volumes:
- ./app.jar:/app.jar
command: java -jar /app.jar
depends_on:
- redis
- mysql
redis:
image: redis:5
ports:
- "6379:6379"
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: 123456
ports:
- "3306:3306"
Spring Boot Actuator配置:
properties复制management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=always
Prometheus监控指标采集:
java复制@Bean
public MeterRegistryCustomizer<PrometheusMeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags("application", "movie-ticket");
}
日期处理坑:MySQL的datetime类型与Java8 LocalDateTime的时区转换问题
事务失效场景:
微信支付证书加载:
Vue响应式失效:
这套系统在多个中小型影院实际运行中,高峰期能稳定支撑500+并发购票请求。核心经验是:分布式锁粒度要细、缓存策略要分层、监控指标要全面。特别是在促销活动时,建议提前进行全链路压测,确保系统稳定性。