1. 项目概述:基于S2SH框架的航空订票系统设计与实现
这个毕业设计项目采用经典的S2SH(Struts2 + Spring + Hibernate)框架组合开发航空订票管理系统。作为Java EE领域的传统技术栈,S2SH虽然在新技术浪潮中略显"复古",但仍然是理解企业级应用开发的绝佳教学案例。系统核心功能包括航班查询、在线订票、订单管理、用户管理等模块,完整覆盖了航空票务业务的基础流程。
我在实际开发中发现,这类系统最考验的不是技术新颖性,而是对业务规则的精确实现。比如机票的退改签规则、座位锁定机制、航班状态同步等业务逻辑,都需要在代码层面严谨处理。采用S2SH框架的优势在于其分层结构清晰,Struts2负责前端交互,Spring管理业务组件,Hibernate处理数据持久化,这种分工明确的架构特别适合教学场景下的理解与实践。
2. 技术架构解析
2.1 S2SH框架整合原理
S2SH的整合关键在于Spring的IoC容器如何串联各层:
- Struts2:通过
struts.xml配置Action,但Action实例由Spring创建管理 - Spring:配置
applicationContext.xml定义Service层Bean和数据源 - Hibernate:通过
hibernate.cfg.xml配置ORM映射,SessionFactory交由Spring管理
典型配置示例:
xml复制<!-- Spring整合Struts2 -->
<bean id="userAction" class="com.air.action.UserAction" scope="prototype">
<property name="userService" ref="userService"/>
</bean>
<!-- Spring整合Hibernate -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>com/air/entity/User.hbm.xml</value>
</list>
</property>
</bean>
2.2 数据库设计要点
航空订票系统的ER图核心实体包括:
- 用户表(users):存储会员信息
- 航班表(flights):航班基础信息
- 机票表(tickets):可售机票库存
- 订单表(orders):交易记录
特别注意字段设计:
sql复制CREATE TABLE flights (
flight_no VARCHAR(20) PRIMARY KEY,
departure_city VARCHAR(50) NOT NULL,
arrival_city VARCHAR(50) NOT NULL,
departure_time DATETIME NOT NULL,
arrival_time DATETIME NOT NULL,
price DECIMAL(10,2) NOT NULL,
seats INT NOT NULL,
status ENUM('scheduled','delayed','canceled') DEFAULT 'scheduled'
);
关键提示:航班状态字段建议使用枚举类型,避免业务逻辑中出现无效状态。座位数量更新需要处理并发问题,后面会详细说明。
3. 核心功能实现细节
3.1 航班查询模块
前端通过Struts2的Action接收查询参数:
java复制public class FlightAction extends ActionSupport {
private String departureCity;
private String arrivalCity;
private Date flightDate;
// getters & setters
public String execute() {
List<Flight> flights = flightService.searchFlights(departureCity, arrivalCity, flightDate);
ServletActionContext.getRequest().setAttribute("flights", flights);
return SUCCESS;
}
}
Service层实现查询逻辑时应考虑:
- 日期范围查询(起飞时间在当天00:00-23:59之间)
- 城市名称模糊匹配(使用HQL的like查询)
- 只显示有余票的航班(seats > 0)
3.2 订票事务处理
订票是系统最复杂的业务场景,必须处理:
- 座位库存的并发控制
- 订单创建的原子性
- 支付超时后的自动解锁
推荐采用悲观锁实现:
java复制@Transactional
public boolean bookTicket(Long flightId, Long userId) {
Session session = sessionFactory.getCurrentSession();
// 悲观锁锁定航班记录
Flight flight = (Flight)session.get(Flight.class, flightId, LockMode.PESSIMISTIC_WRITE);
if(flight.getSeats() <= 0) {
return false;
}
// 扣减库存
flight.setSeats(flight.getSeats() - 1);
session.update(flight);
// 创建订单
Order order = new Order();
order.setUser(userDao.get(userId));
order.setFlight(flight);
order.setStatus("unpaid");
order.setCreateTime(new Date());
session.save(order);
return true;
}
踩坑记录:早期版本使用乐观锁(@Version)处理并发,但在高并发测试时出现大量失败订单。后来改用悲观锁虽然性能略有下降,但保证了业务可靠性。
4. 典型问题解决方案
4.1 性能优化实践
问题现象:航班列表页在数据量超过1万条时加载缓慢
解决方案:
- 添加数据库索引:
sql复制CREATE INDEX idx_flight_cities ON flights(departure_city, arrival_city);
CREATE INDEX idx_flight_time ON flights(departure_time);
- 启用Hibernate二级缓存(Ehcache配置):
xml复制<!-- hibernate.cfg.xml -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<!-- 实体类注解 -->
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Flight { ... }
4.2 支付超时处理
业务规则:订单创建后30分钟内未支付自动取消
实现方案:
- Spring定时任务扫描超时订单:
java复制@Component
public class OrderTimeoutTask {
@Autowired
private OrderService orderService;
@Scheduled(fixedRate = 60000) // 每分钟执行
public void checkTimeoutOrders() {
List<Order> orders = orderService.findUnpaidOrdersBefore(
new Date(System.currentTimeMillis() - 30 * 60 * 1000));
for(Order order : orders) {
orderService.cancelOrder(order.getId(), "timeout");
}
}
}
- 订单取消时需要:
- 恢复航班座位
- 更新订单状态
- 记录操作日志
5. 毕业设计进阶建议
5.1 功能扩展方向
- 机票改签功能:
- 实现同航班不同舱位的升舱/降级
- 处理不同航班间的改签规则
- 计算差价补退逻辑
- 会员积分系统:
- 根据票价累计积分
- 积分兑换机票
- 会员等级特权
- 航班动态推送:
- 对接第三方航班状态API
- WebSocket实时推送延误/取消通知
- 自动触发改签建议
5.2 技术升级路径
如果想提升项目技术含量,可以考虑:
- 前端改用Vue+ElementUI
- 后端迁移到Spring Boot
- 引入Redis缓存热点数据
- 使用Quartz替代Spring Task
- 增加Docker部署方案
我在重构自己的毕业设计时发现,保持业务逻辑不变的情况下,仅技术栈升级就能让项目焕然一新。比如用Spring Boot简化配置后,原本复杂的XML配置全部转为注解,代码量减少了40%。
6. 开发心得与避坑指南
-
版本控制:尽早使用Git管理代码,每天提交小的功能点而非累积大改动。我曾因未及时提交导致一周代码丢失,教训深刻。
-
测试策略:
- 单元测试:对Service层重点测试
- 集成测试:验证Struts Action到DAO的全流程
- 使用DBUnit准备测试数据
- 文档规范:
- JavaDoc注释必须规范
- 数据库字段要有注释
- 复杂业务逻辑添加流程图
- 性能陷阱:
- 避免N+1查询(启用Hibernate的@BatchSize)
- 分页查询必须使用数据库分页(setFirstResult/setMaxResults)
- 谨慎使用OpenSessionInView模式
这个项目让我深刻体会到,好的系统不在于用了多少炫技的技术,而在于对业务细节的把握。比如退票时的手续费计算规则,就需要仔细研读航空公司的实际政策。建议开发前先整理完整的业务规则文档,这比直接写代码更重要。
