1. 项目概述
"基于微信小程序实现电影订票系统"是一个典型的O2O(Online to Offline)应用场景开发案例。这个项目完整实现了从用户选座购票到影院核销的全流程闭环,包含了前端小程序界面、后端业务逻辑和数据库设计三大核心模块。作为一名经历过多个小程序项目开发的老手,我认为这个案例特别适合想要学习全栈开发的中级开发者,因为它既包含了基础的CRUD操作,又涉及支付对接、座位锁定等典型业务场景。
在实际开发中,我们选择了Java+MySQL的技术栈作为后端支撑,主要考虑到Java生态的成熟稳定和MySQL在事务处理方面的可靠性。前端小程序部分则充分利用了微信提供的原生组件和API,特别是需要特别注意的顶部导航栏适配问题——不同机型的状态栏高度差异会导致布局错位,这个坑我当年也踩过。
提示:微信小程序顶部导航栏高度需要动态获取,使用wx.getSystemInfoSync()获取statusBarHeight和titleBarHeight进行适配
2. 系统架构设计
2.1 技术选型分析
前端采用微信小程序原生开发而非uniapp等跨平台方案,主要基于两点考虑:一是原生开发能100%兼容微信API,二是项目不需要多端发布。后端选择Spring Boot框架搭建RESTful API,数据库使用MySQL 5.7版本(考虑到8.0版本在某些云服务上的兼容性问题)。
数据库设计中特别注意了以下几个关键点:
- 影院影厅表采用JSON格式存储座位模板
- 订单表设计了乐观锁版本号字段防止超卖
- 电影排期表建立了复合索引(影院ID+影厅ID+放映时间)
2.2 核心业务流程
选座购票流程:
- 前端获取座位状态 → 用户选择座位 → 后端临时锁定座位(15分钟有效期)
- 调用微信支付接口 → 支付成功后生成正式订单 → 更新座位状态
- 超时未支付自动释放座位
退票流程:
- 开场前2小时可退票 → 原路返回支付金额的80%
- 生成退票记录 → 更新座位状态为可用
核销流程:
- 影院管理员扫码 → 验证订单有效性 → 标记已使用状态
- 同步更新销售统计数据
3. 关键实现细节
3.1 微信小程序前端实现
首页采用swiper组件轮播热映电影,实测中发现iOS设备会出现视频加载失败的问题(对应热词中的media_err_network错误)。解决方案是:
- 检查视频域名是否加入小程序业务域名
- 添加referer白名单
- 使用https协议且证书有效
// 获取视频地址示例 function getVideoUrl() { wx.request({ url: 'https://api.example.com/movie/preview', success(res) { this.setData({ videoSrc: res.data.url + '?t=' + Date.now() // 加时间戳避免缓存 }) } }) }3.2 后端Java核心代码
订单服务采用Spring事务管理,特别注意处理并发场景:
@Transactional public OrderResult createOrder(OrderRequest request) { // 1. 检查座位状态 List<Seat> seats = seatMapper.selectByIds(request.getSeatIds()); if (seats.stream().anyMatch(s -> s.getStatus() != SeatStatus.AVAILABLE)) { throw new BusinessException("座位已被预定"); } // 2. 临时锁定座位(乐观锁) int affected = seatMapper.lockSeats( request.getSeatIds(), SeatStatus.LOCKED, LocalDateTime.now().plusMinutes(15) ); if (affected != request.getSeatIds().size()) { throw new ConcurrentOrderException("座位状态变更,请重新选择"); } // 3. 创建订单记录 Order order = new Order(); // ...订单属性设置 orderMapper.insert(order); // 4. 调用支付服务 PaymentResponse payment = paymentService.create(order); return new OrderResult(order, payment); }3.3 MySQL优化实践
针对高频查询的排期表,我们设计了如下索引:
CREATE TABLE `schedule` ( `id` bigint NOT NULL AUTO_INCREMENT, `cinema_id` bigint NOT NULL, `hall_id` int NOT NULL, `movie_id` bigint NOT NULL, `show_time` datetime NOT NULL, `price` decimal(10,2) NOT NULL, `created_at` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_cinema_hall_time` (`cinema_id`,`hall_id`,`show_time`), KEY `idx_movie_time` (`movie_id`,`show_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;注意:MySQL安装时如果遇到服务启动失败(对应热词中的安装报错),通常是my.ini配置问题或端口冲突导致
4. 典型问题解决方案
4.1 微信授权问题处理
用户授权流程中常见两个坑:
- 背景定位权限拒绝:需要在app.json中声明requiredPrivateInfos字段
- 用户拒绝授权后的引导:使用
<button open-type="openSetting">引导用户重新授权
4.2 Java内存溢出处理
订单导出功能容易引发OOM(对应热词中的OutOfMemoryError),解决方案:
- 使用分页查询+流式处理
- 增加JVM参数:-XX:+UseG1GC -Xmx1024m
- 对大对象及时置null帮助GC回收
4.3 高并发场景应对
春节档期可能出现秒杀场景,我们采用三级防护:
- 前端按钮防重复点击(loading状态)
- 接口层Redis分布式锁
- 数据库最终一致性保证
// Redis分布式锁示例 public boolean tryLock(String key, long expireSeconds) { String value = UUID.randomUUID().toString(); Boolean result = redisTemplate.opsForValue() .setIfAbsent(key, value, expireSeconds, TimeUnit.SECONDS); if (Boolean.TRUE.equals(result)) { // 成功获取锁 return true; } return false; }5. 部署与运维实践
5.1 小程序发布要点
- 服务器域名配置:需在微信公众平台配置request合法域名
- 业务域名配置:用于web-view加载的页面
- 上传代码时注意:基础库版本不能设置过高
5.2 后端服务部署
推荐使用Docker容器化部署,docker-compose.yml示例:
version: '3' services: mysql: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} volumes: - ./mysql/data:/var/lib/mysql - ./mysql/conf:/etc/mysql/conf.d ports: - "3306:3306" app: build: . depends_on: - mysql ports: - "8080:8080" environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/movie?useSSL=false5.3 监控与日志
- 使用Spring Boot Actuator暴露健康检查端点
- 配置Logback日志分级存储
- 关键业务操作记录审计日志
6. 项目扩展方向
现有系统可以进一步优化:
- 增加推荐算法模块(基于用户历史行为)
- 实现影院选座可视化(使用Canvas绘制影厅平面图)
- 接入第三方票务平台同步排期
- 开发管理端Vue.js应用
我在实际部署时发现,小程序包体积优化很关键。建议:
- 使用分包加载技术
- 图片资源走CDN加速
- 非必要组件按需引入
对于Java面试常见问题(对应热词中的java八股文),这个项目涉及的技术点包括:
- Spring事务传播机制
- MySQL索引优化
- 分布式锁实现
- 接口幂等设计
- 缓存一致性方案