1. 项目概述
航班订票管理系统是一个基于Java EE技术栈开发的B/S架构应用,专为航空公司或票务代理机构设计。系统采用经典的MVC分层架构,前端使用JSP+HTML5技术,后端基于Spring+SpringMVC+MyBatis框架组合,数据库选用MySQL 5.7版本。我在实际开发中发现,这种技术组合在中小型Web应用中具有极佳的开发效率和运行稳定性。
系统主要解决传统纸质票务管理中的几个痛点:信息更新不及时导致的超售问题、人工操作错误率高、数据统计困难等。通过数字化管理,可以实现实时座位库存更新、自动化票务处理和数据可视化分析。根据我的项目经验,这类系统上线后通常能将票务处理效率提升60%以上,错误率降低至0.5%以下。
2. 开发环境与技术选型
2.1 技术栈解析
2.1.1 后端技术组合
选择SSM框架而非Spring Boot主要基于以下考虑:
- 教学演示目的:SSM框架分层更明显,适合展示传统Java Web开发模式
- 可控性强:可以手动配置每个组件,方便讲解原理
- 企业现状:国内仍有大量传统企业使用SSM架构
数据库连接池使用Druid,相比HikariCP,它在监控方面更强大。我在配置时特别优化了以下参数:
xml复制<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="initialSize" value="5" />
<property name="minIdle" value="5" />
<property name="maxActive" value="20" />
<property name="validationQuery" value="SELECT 1" />
<property name="testWhileIdle" value="true" />
</bean>
2.1.2 前端技术方案
虽然现在Vue/React更流行,但本项目仍采用传统JSP方案,原因包括:
- 学习曲线平缓:适合Java初学者理解前后端交互
- 服务端渲染:对SEO更友好
- 开发效率:小型系统快速开发优势明显
2.2 开发环境搭建
2.2.1 基础环境配置
- JDK 1.8:选择LTS长期支持版本
- Tomcat 8.5:平衡新特性和稳定性
- Maven 3.6:依赖管理工具
- MySQL 5.7:企业级关系数据库
2.2.2 IDE选择与配置
推荐使用IntelliJ IDEA Ultimate版,关键配置包括:
- 编码统一为UTF-8
- 配置Maven镜像为阿里云
- 安装Lombok插件
- 设置JVM参数:-Xms512m -Xmx1024m
3. 系统架构设计
3.1 功能模块划分
系统采用经典的三层架构设计:
code复制表示层(JSP)
↓
业务逻辑层(Service)
↓
数据访问层(DAO)
↓
数据库(MySQL)
3.1.1 核心业务模块
- 用户管理模块
- 航班管理模块
- 订单管理模块
- 支付对接模块
- 数据统计模块
3.2 数据库设计
3.2.1 主要表结构设计
航班表(feiji)关键字段:
sql复制CREATE TABLE `feiji` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`feiji_name` varchar(200) DEFAULT NULL COMMENT '航班号',
`feiji_types` int(11) DEFAULT NULL COMMENT '飞机类型',
`feiji_start_time` datetime DEFAULT NULL COMMENT '起飞时间',
`feiji_start_address` varchar(200) DEFAULT NULL COMMENT '始发站',
`feiji_end_address` varchar(200) DEFAULT NULL COMMENT '目的地',
`feiji_new_money` decimal(10,2) DEFAULT NULL COMMENT '票价',
`seat_total` int(11) DEFAULT '200' COMMENT '总座位数',
`seat_remain` int(11) DEFAULT '200' COMMENT '剩余座位',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='航班信息表';
3.2.2 索引优化方案
- 航班查询字段建立复合索引:
sql复制ALTER TABLE feiji ADD INDEX idx_query (feiji_start_address, feiji_end_address, feiji_start_time); - 订单表建立用户ID索引:
sql复制ALTER TABLE feiji_order ADD INDEX idx_user (yonghu_id);
4. 核心功能实现
4.1 航班查询功能
4.1.1 查询接口设计
采用RESTful风格API设计:
java复制@RestController
@RequestMapping("/api/flight")
public class FlightController {
@Autowired
private FlightService flightService;
@GetMapping("/search")
public R search(
@RequestParam String from,
@RequestParam String to,
@RequestParam @DateTimeFormat(pattern="yyyy-MM-dd") Date date) {
List<Flight> flights = flightService.searchFlights(from, to, date);
return R.ok().put("data", flights);
}
}
4.1.2 缓存优化方案
使用Redis缓存热门航线数据:
java复制public List<Flight> searchFlightsWithCache(String from, String to, Date date) {
String cacheKey = "flight:" + from + ":" + to + ":" + new SimpleDateFormat("yyyyMMdd").format(date);
// 先查缓存
String cached = redisTemplate.opsForValue().get(cacheKey);
if(cached != null) {
return JSON.parseArray(cached, Flight.class);
}
// 查数据库
List<Flight> flights = flightMapper.search(from, to, date);
// 写入缓存,过期时间30分钟
redisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(flights), 30, TimeUnit.MINUTES);
return flights;
}
4.2 订单处理流程
4.2.1 下单业务逻辑
关键代码实现:
java复制@Transactional
public R createOrder(Long flightId, Long userId, Integer passengerCount) {
// 1. 检查航班余票
Flight flight = flightMapper.selectById(flightId);
if(flight.getSeatRemain() < passengerCount) {
return R.error("余票不足");
}
// 2. 扣减库存(使用乐观锁)
int updateCount = flightMapper.reduceSeat(flightId, passengerCount, flight.getVersion());
if(updateCount == 0) {
return R.error("座位已被其他用户预定");
}
// 3. 生成订单
Order order = new Order();
order.setFlightId(flightId);
order.setUserId(userId);
order.setPassengerCount(passengerCount);
order.setTotalAmount(flight.getPrice().multiply(new BigDecimal(passengerCount)));
order.setStatus(0); // 待支付
orderMapper.insert(order);
// 4. 发送订单创建通知
rabbitTemplate.convertAndSend("order.create", order.getId());
return R.ok().put("orderId", order.getId());
}
4.2.2 分布式事务处理
使用本地消息表+定时任务实现最终一致性:
- 创建订单时同时写入本地消息表
- 定时任务扫描未处理消息
- 调用支付系统接口
- 根据结果更新状态
5. 安全与性能优化
5.1 安全防护措施
5.1.1 常见攻击防护
- SQL注入:使用MyBatis预编译
- XSS攻击:添加过滤器转义特殊字符
- CSRF防护:Spring Security默认启用
- 暴力破解:登录失败次数限制
5.1.2 敏感数据保护
- 密码加密:BCrypt强哈希
- 身份证号脱敏存储
- 支付信息加密传输
5.2 性能调优实践
5.2.1 数据库优化
- 查询优化:避免SELECT *,只查询必要字段
- 批量操作:使用MyBatis批量插入
- 连接池配置:合理设置maxActive等参数
5.2.2 JVM调优
典型启动参数:
code复制-server -Xms512m -Xmx1024m -XX:MetaspaceSize=128m
-XX:MaxMetaspaceSize=256m -XX:+UseG1GC
-XX:+HeapDumpOnOutOfMemoryError
6. 部署与运维
6.1 生产环境部署
6.1.1 服务器配置建议
- CPU:4核以上
- 内存:8GB以上
- 磁盘:SSD,100GB以上
- 带宽:5Mbps以上
6.1.2 部署流程
- 打包:mvn clean package
- 上传war包到Tomcat webapps目录
- 配置server.xml连接池
- 启动Tomcat并验证
6.2 监控方案
6.2.1 基础监控
- JVM监控:VisualVM或Arthas
- 数据库监控:Druid内置监控
- 接口监控:Spring Boot Actuator
6.2.2 业务监控
- 订单成功率监控
- 支付超时监控
- 库存预警监控
7. 项目扩展方向
7.1 功能扩展建议
- 会员积分系统
- 航班延误预警
- 智能推荐座位
- 多平台接入(微信小程序等)
7.2 架构升级路径
- 服务拆分:按业务领域微服务化
- 引入Spring Cloud生态
- 容器化部署(Docker+K8s)
- 异地多活架构
在实际开发中,我特别建议重视日志系统的建设。完善的日志可以帮助快速定位问题,建议采用ELK栈(Elasticsearch+Logstash+Kibana)实现集中式日志管理。以下是一个典型的日志配置示例:
xml复制<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.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
对于高并发场景,我建议采用分布式锁解决超卖问题。以下是基于Redis的分布式锁实现:
java复制public boolean tryLock(String lockKey, long expireSeconds) {
String value = UUID.randomUUID().toString();
Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, value, expireSeconds, TimeUnit.SECONDS);
if(Boolean.TRUE.equals(result)) {
// 获取锁成功
lockValue.set(value);
return true;
}
return false;
}
public void unlock(String lockKey) {
String currentValue = redisTemplate.opsForValue().get(lockKey);
if(lockValue.get().equals(currentValue)) {
redisTemplate.delete(lockKey);
}
}