ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

机场航班起降协调管理系统:Java毕设全解析与避坑指南

机场航班起降协调管理系统:Java毕设全解析与避坑指南

简介:基于Java的机场航班起降与协调管理系统毕业设计资料包,面向高校计算机专业学生及Java Web开发者,可作为毕业设计选题参考、项目实训素材或答辩准备资料。压缩包总大小约84.93MB,内含项目报告、答辩PPT、源代码、数据库脚本、系统截图及部署演示视频,文件类型覆盖文档、代码、数据库表设计与影音资料;其中项目报告完整记录了需求分析、系统架构设计、模块划分与测试优化思路,答辩PPT提炼了项目核心亮点,部署视频则演示了服务器环境配置、数据库导入和Web应用发布流程。已有495人学习下载,是同类毕设资源中较受关注的一套。资源内容涉及Servlet/JSP、MVC设计模式、Spring框架、MyBatis持久层、MySQL数据库、前端页面、安全权限控制及部署运维等多个核心技术点,通过实际航班管理业务将Java Web企业级开发流程完整串联。配合源代码与文档,读者既可深入理解业务逻辑与数据交互,也能按视频快速复现系统,同时获得项目文档撰写和答辩表达方法,资料包的各模块组织清晰,整体实用性强。

1. 拿到“机场航班起降与协调管理系统”这个毕设包,先确认它值不值得花时间跑

“机场航班起降与协调管理系统”这份基于 java 的毕设包,把项目报告、答辩PPT、源代码、数据库、截图和部署视频一次配齐了,属于毕设资源里包装完整、可以直接动手的类型。它的业务是航班起降动态管理、跑道与停机位资源分配、异常协调登记,不复杂但足够撑起一篇毕业设计;技术栈走 Spring Boot + MyBatis + MySQL 路线,答辩老师熟悉、网上资料也好找。这份包能不能用、怎么部署、哪里容易翻车、答辩讲什么,下面按实际动手顺序拆开讲。目标很直接:让你一个晚上跑起来,一周内改造成自己的项目样子。

2. 技术栈与目录结构:从项目骨架判断这份源码的成色

2.1 Spring Boot + MyBatis + MySQL:毕业设计最稳妥的三角组合

机场航班起降与协调管理系统从本质上说是一个业务管理系统,对这类项目,选技术栈的第一原则不是新潮,而是“老师能看懂、问题能搜到、部署不依赖复杂环境”。Spring Boot + MyBatis + MySQL 正好满足这三点。

Spring Boot 把 Spring/Spring MVC 原本那些繁琐的 XML 配置收进了自动配置里,项目启动只需要一个带@SpringBootApplication的入口类和一个 application.yml,对经验不多的学生来说,出问题的概率比 SSM 时代低很多。MyBatis 则把 SQL 交回开发者手里,mapper XML 里写着明确的 INSERT/UPDATE/SELECT,答辩现场被问到“这条更新改的是哪张表”,直接打开 XML 就能讲清楚,比全自动的 JPA 映射更好解释。MySQL 更不用说,几乎每台开发机器都有,装起来快,Navicat 连上就能看数据。

相比之下,纯 JSP+Servlet 方案在课堂练习里常见,但有经验的答辩老师会追问“不用框架,你自己管理连接池和事务的意义在哪”。Spring Boot 全家桶则能明确回答“它帮我处理了配置、连接池和事务管理”。前端方面,这类项目常见做法是 JSP 或 Thymeleaf 配合 Bootstrap,偶尔加入门级的 Vue,方便做航班列表和状态标签的渲染,也便于和数据库交互演示。不管压包里具体用的是哪种前端,关键看后端分层是否规整,接下来看目录就能判断。

2.2 解压后先读哪几个文件:三分钟判断项目可跑性

拿到压缩包别急着双击启动,先按下面这份典型的 Maven 目录结构核对一遍。缺少关键文件的项目,跑起来的概率会低一半:

airport-management/ ├── pom.xml # Maven依赖清单,看Spring Boot版本和MySQL驱动 ├── src/main/java/com/airport/ │ ├── AirportApplication.java # Spring Boot启动入口 │ ├── controller/ # 控制层,接收页面请求 │ ├── service/ # 业务层,状态流转与协调逻辑 │ ├── mapper/ # MyBatis的Mapper接口 │ └── entity/ # 与数据库表对应的实体类 ├── src/main/resources/ │ ├── mapper/ # MyBatis XML文件 │ ├── static/ # 前端资源,含jsp页面或js/css │ └── application.yml # 端口、数据库连接、日志配置 ├── sql/ │ └── airport.sql # 建库建表与初始化数据脚本 └── 文档/ # 项目报告、答辩PPT与部署视频

判断项目能不能跑,我一般按三个顺序来。先看 application.yml 里的端口和数据库连接,端口默认 8080,数据库名、用户名、密码要和你本地对得上;再看 pom.xml 里 Spring Boot 的父版本,这直接决定你本机需要 JDK 8 还是 JDK 17;最后打开 sql 目录下的脚本,数一数建了几张表,是否覆盖航班、跑道、停机位、协调日志这些核心对象。这三样都齐全,项目大概率完整;如果缺数据库脚本,再怎么调代码都跑不通,因为没有表结构,MyBatis 一执行 SQL 就报 “Table doesn't exist”。

另外要顺手看一眼静态资源目录里有没有截图里出现的 css 和图片。有些包会把前端资源精简过头,页面能打开但样式全丢,答辩现场观感很差。如果发现 static 目录几乎是空的,优先补一套 Bootstrap 本地文件,别依赖公共 CDN,因为答辩现场不一定有外网。

2.3 四类角色与业务边界:先画清用例图再动手改代码

毕业设计答辩时最容易被问住的一句话是“你这个系统的核心业务逻辑是什么”。机场航班起降与协调管理系统的核心业务,不是普通管理系统里的单表增删改查,而是“多个航班在有限的跑道、停机位资源上如何被安排和调整”。围绕这一点,常见的用例设计是四类角色:

  • 系统管理员:维护用户账号、角色权限、机场基础数据(航空公司、机场三字码)。
  • 航务调度员:录入航班计划,执行到达/起飞动态更新,分配跑道、停机位,处理协调请求。
  • 值班经理:查看协调记录,对异常航班(延误、取消、备降)做最终确认。
  • 查询用户:按航班号、日期、航空公司查询各班次的计划与实时状态。

把这四类角色画成用例图放进项目报告,答辩老师会认为你做过需求分析,而不是凭空写了几个页面。后续所有代码和表结构都围绕这个边界检查:有没有用户表、有没有区分角色、航班动态有没有记录操作人。只要这三点在,项目报告的“业务分析”和“系统设计”两章就都能填满,也方便你后期把这个骨架改造成其他领域的资源调度系统,比如物流中转站或医院手术室排程,换一下业务名词即可。

3. 数据库设计:航班起降系统的表结构与建表SQL脚本

3.1 六张核心表的关系:基础档案与实时动态为什么要分开

这套系统的数据库设计,最见功底的一点是“把航班的固定信息和实时信息分开存放”。固定信息比如航班号、所属航空公司、计划起降时间、起降机场,录入航班计划后基本不变;实时信息比如实际起飞时间、实际到达时间、当前占用的跑道和停机位、当前状态,运行过程中会被频繁更新。如果混在一张表里,每改一次状态就要更新整行,既容易产生锁竞争,也没法保留历史轨迹。

常见做法是把核心表拆成六张:用户表负责账号与权限;航班信息表 flight_info 保存计划数据;航班动态表 flight_dynamic 保存每一次状态变更与资源占用;跑道表 runway_info 和停机位/登机口表 gate_info 是两种独立资源;协调记录表 coordination_log 登记人为调整的资源分配。拆分的好处,答辩时这样讲:航班动态表记录了“什么时候、由谁、把什么资源从哪边变到哪边”,这本身就是机场协调管理要求的审计需求,也是这套系统区别于普通 CRUD 的重点。

3.2 建表SQL与关键字段说明:直接可以执行的初始化脚本

下面是一份按 MySQL 8.0 编写的建库建表脚本,取核心表为例。完整脚本一般按这个结构放在 sql 目录下,字段注释都在 SQL 中写明了:

CREATE DATABASE IF NOT EXISTS airport_ms DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE airport_ms; -- 用户表:登录账号与角色,区分管理员/调度员/经理/查询用户 CREATE TABLE sys_user ( id BIGINT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE COMMENT '登录名', password VARCHAR(100) NOT NULL COMMENT 'MD5后的密码', real_name VARCHAR(50) COMMENT '姓名', role_code VARCHAR(20) NOT NULL DEFAULT 'QUERY' COMMENT '角色: ADMIN/DISPATCH/MANAGER/QUERY', create_time DATETIME DEFAULT CURRENT_TIMESTAMP, status TINYINT DEFAULT 1 COMMENT '1正常 0停用' ) ENGINE=InnoDB COMMENT='系统用户表'; -- 航班基础信息:计划数据,随运行不频繁变化 CREATE TABLE flight_info ( id BIGINT AUTO_INCREMENT PRIMARY KEY, flight_no CHAR(8) NOT NULL COMMENT '航班号,如CA1234', airline VARCHAR(50) COMMENT '航空公司', depart_airport VARCHAR(10) COMMENT '起飞机场三字码,如PEK', arrive_airport VARCHAR(10) COMMENT '到达机场三字码,如PVG', plan_depart_time DATETIME COMMENT '计划起飞时间', plan_arrive_time DATETIME COMMENT '计划到达时间', aircraft_type VARCHAR(20) COMMENT '机型,如B737', status TINYINT NOT NULL DEFAULT 0 COMMENT '0计划 1延误 2到达 3起飞 4取消', UNIQUE KEY uk_flight_no_depart (flight_no, plan_depart_time), KEY idx_depart_time (plan_depart_time) ) ENGINE=InnoDB COMMENT='航班基础信息表'; -- 航班动态:状态变更与资源占用的流水记录 CREATE TABLE flight_dynamic ( id BIGINT AUTO_INCREMENT PRIMARY KEY, flight_id BIGINT NOT NULL COMMENT '关联flight_info.id', old_status TINYINT COMMENT '变更前状态', new_status TINYINT COMMENT '变更后状态', runway_id BIGINT COMMENT '占用的跑道id', gate_id BIGINT COMMENT '占用的停机位/登机口id', operate_user_id BIGINT COMMENT '操作人,对应sys_user.id', operate_time DATETIME DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(200) COMMENT '变更原因,如天气、流量控制', KEY idx_flight_id (flight_id), KEY idx_operate_time (operate_time), CONSTRAINT fk_dynamic_flight FOREIGN KEY (flight_id) REFERENCES flight_info (id) ) ENGINE=InnoDB COMMENT='航班动态与资源占用流水表';

资源表的结构更简单,跑道和停机位只差一个名称字段,以跑道表为例:

CREATE TABLE runway_info ( id BIGINT AUTO_INCREMENT PRIMARY KEY, runway_code VARCHAR(20) NOT NULL COMMENT '跑道编号,如36R/18L', length_meter INT COMMENT '跑道长度,单位米', occupied_flag TINYINT DEFAULT 0 COMMENT '1占用 0空闲', update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB COMMENT='跑道资源表';

几个关键字段说明一下。航班号用 CHAR(8) 而不是 VARCHAR,因为国际航班号通常是 2 位字母加 4 位数字的固定长度,定长字符类型在等值查询上表现更好,也避免 VARCHAR 尾部空格带来的匹配问题。计划时间全部用 DATETIME,因为航班调度会跨天,需要完整的日期时间而不是单纯的时分。状态用 TINYINT 数字枚举,比字符串存储小、判断快,Java 代码里对应定义一套常量。外键只建了必须的 flight_id,资源表不强加外键,因为协调操作会频繁更改资源占用,强外键在批量更新时容易误伤,业务层来做一致性控制更灵活。

初始化数据建议至少插入三条:一个 admin 账号(密码用 MD5 或 BCrypt 加密后的字符串),两条跑道记录(比如 36R 和 18L),以及 3 到 5 条不同状态的航班计划。有了这些数据,导入后登录才能直接看到界面效果,否则一进去全是空表,会以为系统没跑起来。

3.3 时间类型、状态枚举与索引:三个容易在答辩时被追问的细节

时间字段是这套系统里最容易被追问的设计点。MySQL 的 DATETIME 和 TIMESTAMP 都能存时间,但 TIMESTAMP 的范围只到 2038 年而且会受时区转换影响,部署时只要 MySQL 服务器和 Java 虚拟机时区不一致,显示出来就会差 8 小时,这就是很多项目在视频里看起来正常、到自己电脑跑就不对劲的根源之一。统一用 DATETIME 后,后端按本地时区把 java.util.Date 存进去,取值时按数据库字符串原样读出,少一类玄学问题。

状态枚举用数字做主键值。定义 0 计划、1 延误、2 到达、3 起飞、4 取消,状态流转的判断逻辑收敛在 Service 层,数据库里不散落字符串魔法值。索引方面,航班信息的实时查询通常按“航班号 + 计划时间”或“起飞时间范围”来做,所以建了联合唯一键 uk_flight_no_depart 和单列索引 idx_depart_time;动态表随时间追加,查某航班历史轨迹走 idx_flight_id,查当天协调记录走 idx_operate_time。这两个查询就是项目报告“系统性能分析”那一节的两个典型用例,讲清楚为什么建索引,答辩基本能过关。

4. 核心功能实现:航班状态流转与资源协调的Java代码

4.1 航班状态流转:为什么单独建一张动态流水表

航班从录入计划到实际起飞、到达、取消,状态不是简单一个 UPDATE 就能了事。机场协调管理系统要交代“这个航班为什么会从计划变成延误”“是谁改的、什么时候改的”,所以核心实现一定是一张动态流水表加一段状态机。常见做法是在 FlightServiceImpl 里写一个类似这样的方法,项目包的源代码里可以对照找到:

@Transactional public boolean updateFlightStatus(Long flightId, Integer targetStatus, Long operatorId, String remark) { FlightInfo info = flightInfoMapper.selectById(flightId); if (info == null) { throw new BusinessException("航班不存在"); } Integer current = info.getStatus(); // 状态机校验:只有可流转的状态才放行 if (current == 4) { throw new BusinessException("已取消航班不能再次变更状态"); } if (current != 0 && targetStatus == 0) { throw new BusinessException("状态不能回退到计划"); } // 先写动态流水,再更新主表,两个操作在同一事务里 FlightDynamic dynamic = new FlightDynamic(); dynamic.setFlightId(flightId); dynamic.setOldStatus(current); dynamic.setNewStatus(targetStatus); dynamic.setOperateUserId(operatorId); dynamic.setRemark(remark); dynamic.setOperateTime(new Date()); int i = flightDynamicMapper.insert(dynamic); int j = flightInfoMapper.updateStatus(flightId, targetStatus); return i > 0 && j > 0; }

这段代码的逻辑分三层看。第一层是事务边界,方法加@Transactional,确保“写流水 + 改主表”要么都成功要么都回滚,否则会出现动态表记录已经变了、航班主表状态还是旧值的不一致。第二层是状态机校验,两个 if 拦截了最典型的非法流转:取消的航班不许再改、已进入执行的航班不许退回计划。第三层是审计字段,remark 记录变更原因,答辩时可以说这是对接机场运行手册里“异常情况必登记”的规则。targetStatus 为 2 表示到达、3 表示起飞、1 表示延误,Controller 层可以只开放按钮对应的目标状态,保证非法值进不到 Service。

4.2 跑道冲突检测:一段可以直接抄的区间重叠判断

这套系统最重要的业务价值,是防止两架飞机在同一时间段被分到同一条跑道或同一个停机位。这个功能的代码层面就是一个时间区间重叠判断:两个时间段出现重叠的充要条件是,一个区间的开始时间早于另一个的结束时间,同时一个区间的结束时间晚于另一个的开始时间。很多同学会写出一堆 if-else 分支,其实核心就是下面这个方法:

public boolean checkRunwayConflict(Long runwayId, Date startTime, Date endTime, Long excludeFlightId) { // 查出该跑道当前处于占用状态的动态记录 List<FlightDynamic> activeList = flightDynamicMapper.selectActiveListByRunway(runwayId); for (FlightDynamic dynamic : activeList) { if (dynamic.getFlightId().equals(excludeFlightId)) { continue; // 排除自己,处理改跑道但时间不变的场景 } Date occupiedStart = dynamic.getPlanStartTime(); Date occupiedEnd = dynamic.getPlanEndTime(); // 区间重叠判断的核心条件 if (startTime.before(occupiedEnd) && endTime.after(occupiedStart)) { return true; // 存在冲突 } } return false; }

这段代码有两个要点。第一,selectActiveListByRunway 并不是查全表再遍历,而是在 Mapper XML 里通过 SQL 条件只查出“当前占用中”的记录,比如 WHERE runway_id = #{runwayId} AND occupied_flag = 1,把过滤下推到数据库,减少 Java 内存里的无效遍历。第二,excludeFlightId 参数用来排除当前这趟航班自己,因为在“给已经占用的航班调整跑道”场景中,如果不排除自己,系统永远会提示冲突,这是个很容易复现的逻辑坑。页面层分配跑道时先调用此方法做预校验,冲突就弹提示并拒绝提交,不冲突才进入后面的协调事务。

配套地,在协调操作完成后,要给冲突检测方法准备一个“释放时间”的更新入口。也就是跑道占用记录结束时,把 occupied_flag 置回 0,否则第一次分配后跑道永久显示占用,后面所有航班都分不进去。毕业设计的演示环节里这一步最容易被评委点出来,务必要在 Service 里闭环。

4.3 协调操作的事务控制:改资源、写日志必须是一个完整动作

“协调”在业务上就是一次资源再分配。一次典型的协调操作:把 CA1234 从跑道 36R 调整到 18L,原跑道释放,停机位从 3 号改到 5 号,同时登记“流量控制”备注。这涉及对 flight_dynamic 插入新记录、对 runway_info 更新占用标记、对 gate_info 更新占用标记,以及向 coordination_log 插入一条协调记录,四步必须全部成功,否则会出现“飞机已经换了跑道但数据库里还写着老跑道”的尴尬局面:

@Transactional(rollbackFor = Exception.class) public void assignRunway(Long flightId, Long runwayId, Long gateId, Long operatorId, String reason) { // 1. 业务校验:目标资源是否存在且当前空闲 RunwayInfo runway = runwayInfoMapper.selectById(runwayId); GateInfo gate = gateInfoMapper.selectById(gateId); if (runway == null || gate == null || runway.getOccupiedFlag() == 1 || gate.getOccupiedFlag() == 1) { throw new BusinessException("目标跑道或停机位不可用"); } // 2. 释放旧资源 Long oldRunwayId = flightDynamicMapper.getCurrentRunwayId(flightId); if (oldRunwayId != null) { runwayInfoMapper.updateOccupied(oldRunwayId, 0); } // 3. 占用新资源 runwayInfoMapper.updateOccupied(runwayId, 1); gateInfoMapper.updateOccupied(gateId, 1); // 4. 更新航班动态并登记协调记录 flightDynamicMapper.updateCurrentResource(flightId, runwayId, gateId); coordinationLogMapper.insert(new CoordinationLog(flightId, operatorId, reason, new Date())); }

这里的rollbackFor = Exception.class是很关键的参数。Spring 默认只在 RuntimeException 时回滚,检查异常不会回滚。如果漏掉 rollbackFor,自定义的 BusinessException 如果不继承 RuntimeException,事务也会静默失效,从而出现“日志没写但资源已变更”的隐患。我一般会把 BusinessException 直接继承 RuntimeException,在全局异常处理器中转成 JSON 提示,这样 Controller 层不用到处 try-catch。

另外注意事务的调用边界:这个事务方法写在 Service 类里,外部 Controller 调用才生效。如果在同一个类里通过 this 调用另一个@Transactional方法,事务会失效,这是 Spring AOP 代理的经典坑。答辩老师问到“事务为什么没生效”时,你可以主动把这个机制讲出来,反而会给项目加分,因为这说明你踩过坑、知道底层原理。

5. 部署与运行避坑:从源代码到跑起来最常见的5个坎

5.1 启动报错 Communications link failure:MySQL版本与连接URL不匹配

第一次运行,最常见的失败是控制台刷出“Communications link failure”和“The last packet successfully received from the server was xxx milliseconds ago”。这行报错让不少同学误以为 MySQL 服务没启动,其实绝大多数情况下是数据库连接参数不对。原因有两个层面:项目里设置的是 MySQL 5.x 时代的连接方式,而本地装的是 MySQL 8.0,驱动类从 com.mysql.jdbc.Driver 变成了 com.mysql.cj.jdbc.Driver;同时 MySQL 8 默认要求显式指定时区和 SSL 行为,旧 URL 没带这些参数就会被拒绝。

解决方式是打开 application.yml,把连接字符串改成jdbc:mysql://localhost:3306/airport_ms?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8,并确认 pom.xml 里的 mysql-connector-java 版本是 8.0 以上。顺手核对用户名和密码是否与本地一致。这里最直观的验证方式:先用 Navicat 手工连一次同一个库,Navicat 能连上而 Java 连不上,重点排查 URL 参数;两边都连不上,那就是 MySQL 服务本身没起或密码错了。

5.2 Tomcat端口被占用:一个总能遇到的翻车现场

Spring Boot 内嵌 Tomcat 默认占用 8080 端口。如果本机已经开了别的服务,启动日志会明确报“Port 8080 was already in use”。排查路径比较固定:Windows 下执行netstat -ano | findstr 8080找到占用端口的 PID,再到任务管理器结束对应进程;Linux 或 macOS 习惯用lsof -i:8080。嫌麻烦就直接改端口,在 application.yml 里加一行 server.port: 8081,改完重新启动。

这里要顺带提醒一个部署视频里常见的认知混淆:Spring Boot 项目打包成 jar 后,用java -jar airport-management.jar直接启动即可,不需要再装独立的 Tomcat。如果项目打成 war 包再丢进外部 Tomcat,需要把 spring-boot-starter-tomcat 的 scope 设为 provided,否则里外两个容器会起冲突。看到包里有部署视频,先确认它演示的是 jar 启动还是 war 部署,照对应方式操作,别混着来。

5.3 中文全部变成问号:编码问题的三处检查点

航班管理系统里的航空公司名称、机场名称全是中文,部署后最常见的翻车现场是:航班号里的英文和数字正常,中文列在页面上全是“???”。这属于老生常谈的编码问题,按三处位置依次检查。第一处是连接串上的 characterEncoding=utf8,缺这个参数时,Java 到 MySQL 的传输环节可能用了默认字符集;第二处是表和库本身的字符集,建库脚本要明确写 utf8mb4,如果建库时误选了 latin1,后面想转回来就是一场数据清洗;第三处是前端页面,JSP 需要 pageEncoding="UTF-8" 和 contentType 里的 charset=UTF-8,静态 HTML 看 meta 标签里的 charset。

判断到底是哪一处的技巧:先用 Navicat 往表里直接插入一条中文数据,再用 Java 代码查询,如果页面显示正常,说明前端没问题而是写入链路编码错了;如果 Navicat 手动插入也乱码,问题出在表字符集,需要执行ALTER TABLE xxx CONVERT TO CHARACTER SET utf8mb4。一次排查下来,基本能消除这个看不见的黑匣子。答辩现场若被问到乱码,能说出这三处检查点,印象分不会差。

5.4 SQL脚本导入一半失败:先看字符集再看外键顺序

把 sql 目录下的初始化脚本导入数据库时,经常看到错误在某个位置中断,前面的表建好、后面的表没建。最常见的两个原因:一个是脚本文件本身是 UTF-8 编码,而导入工具按 GBK 打开,导致注释里的中文变成非法字符在中途报错;另一个是脚本里有 DROP TABLE 和 CREATE TABLE 交织,如果表之间存在外键,后建的表引用了还没建成的表,就会报外键相关错误。解决方式比较简单:用 Navicat 导入时在高级选项里明确选择 UTF-8 编码;如果报外键错误,就手动调整执行顺序,先建不依赖别人的基础表 sys_user、runway_info、gate_info、flight_info,再建有外键的 flight_dynamic 和 coordination_log。

更稳妥的做法是用命令行导入,报错信息比图形化工具更直接,能看到具体停在哪一行。常用命令就一条:

mysql -uroot -p airport_ms < sql/airport.sql

导入成功后马上用SHOW TABLES;数一遍表数量,再执行SELECT COUNT(*) FROM sys_user;验证初始化数据是否写进去了。这一步能避免启动项目后因为某张表缺失而报 “Table 'airport_ms.flight_dynamic' doesn't exist”,那种错误排查起来比建表麻烦得多。

5.5 本地JDK版本与项目不对应:改配置三分钟,排查两小时

源代码导入开发工具后,大量“程序包 org.springframework.boot 不存在”“Cannot resolve symbol Java”的红色报错,十有八九不是代码问题,而是 JDK 和项目要求不匹配。Spring Boot 2.7 系列的父依赖要求 JDK 8 或 11,Spring Boot 3.x 必须 JDK 17 以上。如果你本地装 JDK 17,却导入一个 Spring Boot 2.7 的项目,Maven 编译会因为字节码版本问题报错,但显示出来的现象却像依赖没下载完。这类问题的排查路径:先看 pom.xml 里 parent 的版本号,再打开 IDE 的 Project Structure 确认 Project SDK 和模块的 Java 版本,最后在 Maven 面板点 Reimport,让项目按正确的 JDK 重新解析依赖。

这里还要提醒一个细节:JAVA_HOME 环境变量和 IDE 内部 SDK 经常不一致。命令行执行 java -version 是 17,IDE 里配置的却是 8,两边各管各的,所以不能只看一个地方。我一般把 IDEA 的 Maven Runner 的 JRE 设置也改成与 Project SDK 一致,三处统一,这类由 java 环境配置引起的编译问题一次清干净。

6. 答辩演示技巧:把“管理系统”讲成“资源协调系统”

答辩演示不是把每个页面点一遍,而是按一条“发现问题 → 解决问题”的故事线走。我建议演示顺序固定为:管理员登录后新增一条航班计划,说明数据从哪来;列表查询航班,展示搜索条件与分页;给该航班分配跑道和停机位,演示成功占用;再造一条时间段重叠的航班,再次提交分配,系统弹出冲突提示并拒绝;进入协调日志页面,展示刚才两次操作的完整记录与操作人。这条线在 5 分钟内讲完,全程突出“冲突检测”和“审计日志”,这是普通管理系统没有、而机场协调系统必须有的两个差异化点。演示前用一张对照表准备,现场照着走不容易乱:

演示操作预期界面反馈对应答辩提问点
新增航班 CA1234列表出现新纪录计划与实时数据为什么分两张表
分配跑道 36R跑道状态变为占用资源表与动态表如何联动
再分配同段跑道给 CA5678系统提示冲突并拒绝区间重叠判断算法怎么写的
查看协调日志可见操作人、时间、原因事务如何保证数据一致性

准备时记住一个习惯:提前在数据库里预置几组“计划、延误、到达、取消”状态的航班,演示时用真实数据切换状态,而不是现场录入,现场录数据一旦日期选错就会卡壳。我自己第一次答辩就吃过顺序颠倒的亏,后来把演示写成半页纸脚本、对着预置数据跑三遍才踏实。这套系统能跑起来、能把冲突检测讲清楚,已经超过大多数只做普通增删改查的同期同学了。希望这份拆解能帮到你,动手前多看一遍部署视频,数据库脚本先导成功,大概率就能顺利落地。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进