1. 项目概述:SpringBoot机票预订系统设计与实现
这个基于SpringBoot的机票预订系统是我去年指导的一个本科毕业设计项目,也是目前航空票务领域非常典型的Web应用开发案例。系统采用B/S架构,前端使用Thymeleaf模板引擎配合Bootstrap,后端基于SpringBoot 2.7整合MyBatis-Plus,实现了从航班查询、在线选座到订单支付的完整业务流程。
在实际开发中,我发现这类系统有几个关键特性必须把握:首先是高并发的票务库存管理,需要处理好超卖问题;其次是复杂的业务状态流转(比如15分钟未支付自动取消订单);最后是第三方接口集成(如支付网关、短信通知)。这些都会在后续章节详细展开。
提示:虽然这是毕业设计项目,但我建议按照生产级标准开发,比如加入Redis缓存、分布式锁等机制,这对面试和实际工作都很有帮助。
2. 核心模块设计
2.1 系统架构图解
整个系统采用经典的三层架构:
code复制表示层(Web)
↑↓
业务逻辑层(Service)
↑↓
数据访问层(DAO)
关键组件依赖关系:
- Spring MVC:处理HTTP请求和视图渲染
- Spring Security:负责认证授权
- MyBatis-Plus:简化数据库操作
- HikariCP:高性能连接池
- Lombok:减少样板代码
2.2 数据库设计要点
主要表结构及其关系:
flight_info(航班信息表)- 包含起降时间、机场、机型等字段
- 与
ticket_inventory(机票库存表)一对多关联
user_order(用户订单表)- 使用状态机设计(待支付/已支付/已取消)
- 与
payment_record(支付记录表)一对一关联
sql复制CREATE TABLE `ticket_inventory` (
`id` bigint NOT NULL AUTO_INCREMENT,
`flight_id` bigint NOT NULL COMMENT '航班ID',
`cabin_class` varchar(20) NOT NULL COMMENT '舱位等级',
`price` decimal(10,2) NOT NULL,
`total_seats` int DEFAULT 0 COMMENT '总座位数',
`available_seats` int DEFAULT 0 COMMENT '可用座位数',
`version` int DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_flight_cabin` (`flight_id`,`cabin_class`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
注意:库存表一定要加乐观锁版本字段,防止超卖。这是我踩过的坑——早期用简单UPDATE语句导致库存出现负数。
3. 关键技术实现
3.1 并发订票解决方案
机票预订最核心的并发控制,我对比了三种方案:
| 方案 | 实现复杂度 | 性能 | 适用场景 |
|---|---|---|---|
| 数据库悲观锁 | 低 | 差 | 低并发场景 |
| 乐观锁+重试机制 | 中 | 较好 | 中等并发 |
| Redis分布式锁 | 高 | 优秀 | 高并发生产环境 |
最终选择方案二实现,核心代码如下:
java复制@Transactional
public boolean bookTicket(Long ticketId, Integer quantity) {
TicketInventory inventory = inventoryMapper.selectById(ticketId);
if (inventory.getAvailableSeats() < quantity) {
throw new BusinessException("余票不足");
}
// 乐观锁更新
int updated = inventoryMapper.updateAvailableSeats(
ticketId,
quantity,
inventory.getVersion());
if (updated == 0) {
// 重试3次
return retryBookTicket(ticketId, quantity, 3);
}
return true;
}
3.2 订单状态机设计
订单状态流转是个典型的状态模式应用场景:
code复制[待支付] --支付成功--> [已支付]
|--超时未支付--> [已取消]
|--用户取消----> [已取消]
使用Spring StateMachine实现:
java复制@Configuration
@EnableStateMachine
public class OrderStateMachineConfig
extends EnumStateMachineConfigurerAdapter<OrderState, OrderEvent> {
@Override
public void configure(StateMachineStateConfigurer<OrderState, OrderEvent> states)
throws Exception {
states
.withStates()
.initial(OrderState.PENDING)
.states(EnumSet.allOf(OrderState.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderState, OrderEvent> transitions)
throws Exception {
transitions
.withExternal()
.source(OrderState.PENDING)
.target(OrderState.PAID)
.event(OrderEvent.PAY_SUCCESS)
.and()
.withExternal()
.source(OrderState.PENDING)
.target(OrderState.CANCELLED)
.event(OrderEvent.TIMEOUT);
}
}
4. 开发环境搭建
4.1 基础环境配置
- JDK 1.8+(推荐Amazon Corretto 11)
- Maven 3.6+(配置阿里云镜像)
- MySQL 5.7+(建议8.0版本)
- Redis 6.x(用于缓存和分布式锁)
4.2 SpringBoot关键配置
application.yml部分配置示例:
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/airline?useSSL=false&serverTimezone=UTC
username: root
password: 123456
hikari:
maximum-pool-size: 20
connection-timeout: 30000
redis:
host: localhost
port: 6379
timeout: 5000
5. 典型问题解决方案
5.1 定时任务关闭超时订单
使用Spring Schedule实现:
java复制@Scheduled(cron = "0 */5 * * * ?")
public void cancelTimeoutOrders() {
List<Order> orders = orderMapper.selectTimeoutOrders(
LocalDateTime.now().minusMinutes(15));
orders.forEach(order -> {
stateMachine.sendEvent(OrderEvent.TIMEOUT);
// 释放库存
inventoryMapper.returnSeats(
order.getFlightId(),
order.getQuantity());
});
}
5.2 微信支付集成问题
常见坑点及解决方案:
- 签名验证失败
- 检查商户密钥配置
- 确认参数顺序和大小写
- 异步通知处理
- 必须返回success字符串
- 要做幂等处理
java复制@PostMapping("/wxpay/notify")
public String wxpayNotify(HttpServletRequest request) {
Map<String, String> params = parseRequest(request);
if (!wxpayService.verifySignature(params)) {
return "fail";
}
String orderNo = params.get("out_trade_no");
Order order = orderService.getByNo(orderNo);
if (order.getStatus() != OrderState.PAID) {
orderService.handlePaySuccess(orderNo);
}
return "success";
}
6. 项目扩展建议
如果想提升项目竞争力,可以考虑:
- 加入ELK实现日志分析
- 使用Spring Cloud Alibaba改造为微服务架构
- 增加OAuth2.0第三方登录
- 实现多级缓存(Caffeine+Redis)
我在实际开发中发现,机票价格浮动是个很好的扩展点。可以通过定时爬取竞争对手价格,实现动态调价策略:
java复制public void adjustPriceBasedOnCompetitor() {
List<FlightPrice> competitorPrices = crawlerService.getCompetitorPrices();
competitorPrices.forEach(cp -> {
BigDecimal ourPrice = priceService.calculateOptimalPrice(
cp.getPrice(),
getDemandLevel(cp.getFlightNo()));
priceService.updatePrice(cp.getFlightNo(), ourPrice);
});
}
7. 调试与部署要点
7.1 IDEA热部署配置
- 添加devtools依赖
- 开启Build->Compile自动编译
- 注册Ctrl+Shift+F9快捷键
7.2 生产环境部署
推荐使用Docker Compose编排:
dockerfile复制version: '3'
services:
app:
image: airline-system:1.0
ports:
- "8080:8080"
depends_on:
- redis
- mysql
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: 123456
redis:
image: redis:6-alpine
8. 毕业设计答辩技巧
根据多年指导经验,答辩时要注意:
- 演示前准备测试数据(至少5个完整业务流)
- 重点讲解技术选型对比过程
- 准备系统架构图的手绘版
- 对可能的问题提前准备:
- 为什么选SpringBoot而不是SSM?
- 如何保证订单支付的原子性?
- 如果出现重复支付怎么处理?
建议在代码中加入详细的注释,比如:
java复制/**
* 使用二段提交保证支付与订单状态的一致性
* 1. 创建支付记录(状态为处理中)
* 2. 更新订单状态
* 3. 支付记录状态改为成功
* 出现异常时启动补偿任务
*/
@Transactional
public void processPayment(Order order, PaymentRequest request) {
// 实现逻辑...
}
这个项目完整源码我已经整理好,包含数据库脚本、API文档和部署手册。开发过程中最大的收获是:业务系统光有CRUD不够,必须考虑分布式场景下的数据一致性。下次我会尝试加入Seata分布式事务,让系统更接近生产环境标准。
