航班进出港管理系统是现代机场运营的核心支撑平台,我去年参与某区域枢纽机场的数字化升级项目时,深刻体会到这类系统的复杂性。传统Excel+纸质工单的管理方式在面对日均300架次航班时,经常出现机位分配冲突、行李转运延误、旅客登机信息不同步等问题。
这个SpringBoot+Vue实现的系统主要解决三个核心痛点:
我们放弃了传统的三层架构,采用六边形架构设计:
code复制 +---------------+
| REST API |
+-------^-------+
|
+----------------------------------+
| Domain Layer | Adapter Layer|
| - 航班状态机 | - JDBC |
| - 机位分配算法 | - Redis |
| - 业务规则引擎 | - RabbitMQ |
+----------------------------------+
选择SpringBoot 2.7.x而非3.0的原因很实际:当时关键依赖库(如spring-data-redis)对Jakarta EE 9的支持尚不完善。配置了多数据源:
yaml复制datasource:
primary:
url: jdbc:mysql://.../flight_ops?useSSL=false
hikari:
maximum-pool-size: 20
secondary:
url: jdbc:sqlserver://.../legacy_system
hikari:
maximum-pool-size: 5
采用Vue3+TypeScript+Pinia的方案,放弃Element UI选择了Naive UI,因为其动态主题切换能更好适应塔台暗光环境。关键优化点包括:
用枚举+策略模式实现状态流转:
java复制public enum FlightStatus {
SCHEDULED {
void transit(FlightContext ctx) {
if (ctx.getWeatherAlert())
ctx.changeStatus(DELAYED);
}
},
DELAYED {
void transit(FlightContext ctx) {
if (ctx.getNewETD().isBefore(now.plusHours(2)))
ctx.changeStatus(BOARDING);
}
};
abstract void transit(FlightContext ctx);
}
状态变更通过Spring事件机制广播:
java复制@EventListener
public void handleFlightStatusChange(FlightStatusChangeEvent event) {
redisTemplate.convertAndSend("flight.update", event.getFlightId());
legacySystemAdapter.notifyStatusChange(event);
}
核心冲突检测逻辑:
python复制def check_stand_conflict(flight1, flight2):
# 翼展安全间距:机型翼展*1.5
min_clearance = max(flight1.wingspan, flight2.wingspan) * 1.5
# 时间重叠检测
time_overlap = (flight1.eta < flight2.etd) and (flight1.etd > flight2.eta)
# 物理距离检测
distance = calculate_distance(flight1.stand, flight2.stand)
return time_overlap and (distance < min_clearance)
实际项目中还加入了机型-机位兼容性检查(如A380只能停靠特定机位)
采用虚拟滚动技术,只渲染可视区域内航班:
vue复制<template>
<div class="viewport" @scroll="handleScroll">
<div class="flight-list" :style="{ height: totalHeight }">
<div v-for="flight in visibleFlights"
:key="flight.id"
:style="{ transform: `translateY(${flight.offset}px)` }">
<!-- 航班卡片内容 -->
</div>
</div>
</div>
</template>
<script>
// 计算可见航班
const visibleFlights = computed(() => {
const startIdx = findNearestItem(scrollY.value);
return flights.value.slice(startIdx, startIdx + 30);
});
</script>
使用Spring Batch处理夜间航班计划导入:
java复制@Bean
public Step importFlightsStep() {
return stepBuilderFactory.get("importFlights")
.<RawFlightData, Flight>chunk(200)
.reader(xmlItemReader())
.processor(flightDataProcessor())
.writer(jpaItemWriter())
.faultTolerant()
.skipPolicy(new FlightDataSkipPolicy())
.build();
}
某次航班显示时间突然偏移8小时,发现是:
最终解决方案:
javascript复制// 前端统一处理
moment.utc(flight.etd).local().format('YYYY-MM-DD HH:mm')
地勤同时修改航班保障状态导致数据覆盖,通过乐观锁解决:
java复制@Entity
public class Flight {
@Version
private Integer version;
//...
}
@Transactional
public void updateServices(Long flightId, List<Service> services) {
Flight flight = flightRepo.findById(flightId)
.orElseThrow(...);
// 自动触发版本检查
flight.setServices(services);
}
采用Docker Swarm而非Kubernetes,考虑因素:
典型服务配置:
dockerfile复制# 前端构建
FROM node:16 as build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 生产镜像
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
这个项目让我深刻体会到航空领域软件的特殊性:每个异常分支都可能影响数千旅客的行程。比如我们为除冰车调度单独开发了优先级算法,因为冬季早高峰时段的除冰延误会产生连锁反应。现在回看,采用领域驱动设计(DDD)是项目成功的关键,它帮助不同背景的团队成员(航空专家与软件开发人员)建立了统一的业务语言。