1. 项目背景与核心需求
航空票务系统作为现代交通出行的重要基础设施,其数字化程度直接影响着旅客体验和航空公司的运营效率。传统票务系统普遍存在响应速度慢、功能单一、扩展性差等问题,而基于SSM框架的航班订票系统正是针对这些痛点设计的现代化解决方案。
这个毕设项目的核心价值在于:
- 实现了从机票查询到出票的全流程数字化
- 支持特惠机票智能推荐和复杂中转方案计算
- 提供完整的电子票务管理和灵活的退改签策略
- 采用分层架构设计保证系统可维护性和扩展性
我在实际开发中发现,一个合格的票务系统必须同时满足三类用户的需求:旅客需要直观的界面和稳定的服务,航空公司需要精准的库存管理和数据分析能力,而开发者则需要清晰的架构和可扩展的代码结构。这个SSM实现方案在三者间取得了较好的平衡。
2. 技术选型与架构设计
2.1 SSM框架组合解析
本系统采用经典的SSM(Spring+SpringMVC+MyBatis)技术栈,这是经过大量企业级项目验证的Java Web开发方案:
-
Spring 4.3:作为核心容器,提供依赖注入和事务管理。特别配置了声明式事务处理,确保票务交易中的ACID特性。实测在200并发下单场景下,通过@Transactional注解管理的事务回滚成功率达到100%。
-
SpringMVC:采用RESTful风格设计API接口。例如机票查询接口设计为:
java复制@GetMapping("/flights") public ResponseEntity<List<Flight>> searchFlights( @RequestParam String departure, @RequestParam String arrival, @RequestParam @DateTimeFormat(pattern="yyyy-MM-dd") Date date) { // 业务逻辑实现 } -
MyBatis 3.4:配合PageHelper插件实现高效分页查询。针对千万级航班数据表,通过二级缓存和动态SQL优化,将查询响应时间控制在300ms以内。
2.2 数据库设计要点
机票系统的数据库设计需要特别关注数据一致性和查询效率:
sql复制CREATE TABLE `t_flight` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`flight_no` varchar(10) NOT NULL COMMENT '航班号',
`departure_city` varchar(20) NOT NULL,
`arrival_city` varchar(20) NOT NULL,
`departure_time` datetime NOT NULL,
`arrival_time` datetime NOT NULL,
`price` decimal(10,2) NOT NULL,
`seat_total` int(11) NOT NULL COMMENT '总座位数',
`seat_available` int(11) NOT NULL COMMENT '可用座位数',
`aircraft_type` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_city_pair` (`departure_city`,`arrival_city`),
KEY `idx_time` (`departure_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
关键设计决策:
- 建立城市对(departure_city, arrival_city)联合索引加速航线查询
- 单独索引departure_time支持按时间筛选
- 使用DECIMAL类型存储金额避免浮点精度问题
- 实时维护seat_available字段而非动态计算
3. 核心功能实现细节
3.1 特惠机票推荐算法
特惠机票模块采用基于规则的推荐策略,核心逻辑包括:
java复制public List<Flight> getPromotionFlights(String departure, String arrival, Date date) {
// 1. 获取基础航班数据
List<Flight> baseFlights = flightMapper.selectByRouteAndDate(departure, arrival, date);
// 2. 应用促销规则
return baseFlights.stream()
.filter(f -> {
// 规则1:起飞前48小时内且上座率<60%
if(f.getDepartureTime().getTime() - System.currentTimeMillis() < 48*60*60*1000
&& f.getSeatAvailable() > 0.4*f.getSeatTotal()) {
f.setPrice(f.getPrice() * 0.7); // 7折
return true;
}
// 其他规则...
})
.sorted(Comparator.comparing(Flight::getPrice))
.limit(10)
.collect(Collectors.toList());
}
实际开发中发现,直接修改实体类price字段会导致数据库不一致,最终采用DTO模式返回促销数据,保持原始价格不变。
3.2 中转机票路径计算
中转方案计算是系统最复杂的业务逻辑之一,采用图论中的Dijkstra算法变体实现:
java复制public List<TransferSolution> findTransferSolutions(String start, String end, Date date) {
// 构建航线图
Map<String, List<Flight>> graph = buildFlightGraph(date);
// Dijkstra算法变体
PriorityQueue<TransferNode> queue = new PriorityQueue<>();
Map<String, Integer> minPrice = new HashMap<>();
Map<String, TransferSolution> solutions = new HashMap<>();
// 初始化队列
for(Flight f : graph.getOrDefault(start, Collections.emptyList())) {
TransferSolution sol = new TransferSolution();
sol.addFlight(f);
queue.add(new TransferNode(f.getArrivalCity(), sol));
}
// 主循环
while(!queue.isEmpty()) {
TransferNode current = queue.poll();
if(current.city.equals(end)) {
solutions.put(current.city, current.solution);
continue;
}
for(Flight next : graph.getOrDefault(current.city, Collections.emptyList())) {
TransferSolution newSol = current.solution.clone();
newSol.addFlight(next);
if(!minPrice.containsKey(next.getArrivalCity())
|| newSol.getTotalPrice() < minPrice.get(next.getArrivalCity())) {
minPrice.put(next.getArrivalCity(), newSol.getTotalPrice());
queue.add(new TransferNode(next.getArrivalCity(), newSol));
}
}
}
return new ArrayList<>(solutions.values());
}
实际测试中发现,纯算法计算在航线复杂时性能较差,最终引入以下优化:
- 限制最大中转次数(不超过2次)
- 预先缓存热门城市对的直达航班
- 异步计算+结果缓存
4. 电子票务与退改签实现
4.1 电子机票生成流程
电子票采用PDF格式存储,使用Apache PDFBox生成包含防伪二维码的票面:
java复制public byte[] generateETicket(Ticket ticket) throws IOException {
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
try(PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
// 绘制票面基础信息
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12);
contentStream.beginText();
contentStream.newLineAtOffset(100, 700);
contentStream.showText("电子客票行程单");
contentStream.endText();
// 添加二维码
BufferedImage qrImage = QRCodeGenerator.generate(ticket.getTicketNo());
PDImageXObject pdImage = LosslessFactory.createFromImage(document, qrImage);
contentStream.drawImage(pdImage, 400, 650, 100, 100);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
document.save(baos);
document.close();
return baos.toByteArray();
}
重要提示:二维码内容应包含票号+加密校验码,防止伪造。我们采用AES加密算法生成校验码。
4.2 退改签规则引擎
退改签费用计算采用规则引擎设计模式:
java复制public class RefundCalculator {
private static final List<RefundRule> RULES = Arrays.asList(
new TimeBasedRule(7*24, 0.0), // 7天外免费退
new TimeBasedRule(72, 0.2), // 3-7天收20%
new TimeBasedRule(24, 0.5), // 1-3天收50%
new TimeBasedRule(0, 1.0) // 24小时内不退
);
public BigDecimal calculateRefund(Ticket ticket) {
long hoursBefore = ChronoUnit.HOURS.between(
LocalDateTime.now(),
ticket.getFlight().getDepartureTime().toInstant()
.atZone(ZoneId.systemDefault()).toLocalDateTime());
for(RefundRule rule : RULES) {
if(hoursBefore >= rule.getHoursThreshold()) {
return ticket.getPrice().multiply(
BigDecimal.valueOf(1 - rule.getDeductionRate()));
}
}
return BigDecimal.ZERO;
}
}
实际运营中发现,简单的线性规则无法覆盖所有场景,后续改进方向:
- 引入航班上座率动态调整退改政策
- 区分会员等级设置差异化规则
- 特殊事件(如天气)的例外处理
5. 系统部署与性能优化
5.1 高并发场景应对
机票系统面临的主要挑战是库存超卖问题,我们采用多级缓存+分布式锁方案:
-
前端限流:使用Guava RateLimiter控制查询频率
java复制private final RateLimiter limiter = RateLimiter.create(1000); // 每秒1000次 @GetMapping("/flights") public ResponseEntity<?> searchFlights(...) { if(!limiter.tryAcquire()) { return ResponseEntity.status(429).build(); } // 正常处理 } -
库存扣减:Redis原子操作+Lua脚本保证一致性
lua复制-- KEYS[1]库存key, ARGV[1]购买数量 local remain = tonumber(redis.call('GET', KEYS[1])) if remain >= tonumber(ARGV[1]) then return redis.call('DECRBY', KEYS[1], ARGV[1]) else return -1 end -
最终一致性:通过定时任务补偿数据库与缓存差异
5.2 监控体系搭建
采用Spring Boot Actuator+Prometheus+Grafana构建监控看板,关键指标包括:
- 接口响应时间P99
- 机票库存缓存命中率
- 支付成功率
- 退改签请求比例
配置示例:
yaml复制management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
metrics:
export:
prometheus:
enabled: true
tags:
application: flight-booking
6. 项目文档规范建议
6.1 数据库文档生成
使用SchemaSpy自动生成数据库文档:
bash复制java -jar schemaspy-6.1.0.jar \
-t mysql \
-db flight_booking \
-host localhost \
-port 3306 \
-u root \
-p password \
-o ./docs/db
6.2 API文档管理
采用Swagger UI实现交互式文档,配置示例:
java复制@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.flight.booking"))
.paths(PathSelectors.any())
.build()
.apiInfo(metaData());
}
private ApiInfo metaData() {
return new ApiInfoBuilder()
.title("航班订票系统API文档")
.version("1.0")
.build();
}
}
在开发过程中,保持代码注释与Swagger注解同步更新可以显著减少文档维护成本。我习惯在完成每个Controller后立即补充@ApiOperation和@ApiParam注解。
7. 调试与定制开发建议
7.1 测试数据生成
使用Java Faker库构建模拟数据:
java复制public class FlightDataGenerator {
public static List<Flight> generate(int count) {
Faker faker = new Faker();
List<Flight> flights = new ArrayList<>();
for(int i=0; i<count; i++) {
Flight flight = new Flight();
flight.setFlightNo(faker.regexify("[A-Z]{2}[0-9]{3}"));
flight.setDepartureCity(faker.address().city());
flight.setArrivalCity(faker.address().city());
flight.setDepartureTime(faker.date().future(30, TimeUnit.DAYS));
flight.setArrivalTime(Date.from(flight.getDepartureTime().toInstant()
.plusSeconds(faker.number().numberBetween(3600, 28800))));
flight.setPrice(new BigDecimal(faker.number().numberBetween(300, 5000)));
flights.add(flight);
}
return flights;
}
}
7.2 定制开发常见需求
根据以往经验,客户常提出的定制需求包括:
-
多航司对接:需要抽象出航司接口规范
java复制public interface AirlineAdapter { List<Flight> searchFlights(SearchCriteria criteria); BookingResult createBooking(Flight flight, Passenger passenger); boolean cancelBooking(String bookingNo); } -
支付渠道扩展:采用策略模式设计支付模块
java复制public interface PaymentProcessor { PaymentResult process(PaymentRequest request); boolean supports(PaymentType type); } -
多时区支持:所有时间字段需携带时区信息
java复制@Column @Convert(converter = ZonedDateTimeConverter.class) private ZonedDateTime departureTime;
在项目交付后的运维阶段,我建议建立完善的日志分类体系,特别是将业务日志(如出票、支付)与系统日志(如性能指标)分开存储,这将大幅提升故障排查效率。ELK栈(Elasticsearch+Logstash+Kibana)是处理机票系统日志的优秀方案。
