☰
JavaWeb航空订票系统:Servlet/JSP实战全链路解析
2026/10/9 11:19:27 网站建设 项目流程

简介:本资源是一套完整的JavaWeb航空系统课程设计实战项目,面向Java初学者与高校计算机专业学生,聚焦Web全栈开发能力训练,解决从需求分析、前后端协同到数据库集成的典型工程实践问题。压缩包共120个文件(2.46MB),含81个Java后端逻辑文件、14个HTML页面与14张JPG界面素材,辅以CSS、JavaScript实现响应式前端交互,SQL文件定义航班/订单/用户等核心数据表,Maven(pom.xml)、YAML与XML配置支撑环境部署,.gitignore保障团队协作规范。已有342人学习下载,可直接导入IDE运行,完整覆盖管理员航班发布、实时监控、电子票务管理,以及普通用户选座订票、增值服务选购等8大功能模块,代码结构清晰、注释充分,是理解JavaWeb分层架构与航空业务建模的优质教学范例。

1. 这不是Demo,是能跑通订票+航班管理+舱位定价的JavaWeb航空系统:119个文件里藏着81个Java类的真实业务闭环

你见过用admin_b_release_flight.html直接发布航班、用regular_b_fill_out_the_order.html完成实名制下单、再通过admin_e_ticketing_management.html核验电子客票的JavaWeb课程设计吗?这不是Spring Boot脚手架生成的空壳,也不是套着Bootstrap模板的静态页面堆砌——它是一套从用户注册、航班查询、值机选座、舱位产品配置到后台实时航班监控全链路打通的航空业务系统。81个Java源文件不是“Hello World”式练习,而是真实拆解了FlightService(航班调度)、TicketOrderManager(订单状态机)、CabinProductPricing(动态舱位定价)等核心模块;14个HTML页面不是孤立页面,而是按角色分层:regular_*对应旅客端三步下单流程,admin_*覆盖运控、票务、机务三大后台职能。它不依赖Tomcat Manager界面手动部署,mvnw.cmd开箱即用,.gitignore已预设target/和logs/排除规则——这意味着你拉下来就能在IDEA里右键Run,而不是先花两小时配JDK、Servlet版本、MySQL驱动。适合刚学完Servlet/JSP想验证“业务逻辑怎么落地”的人,也适合需要快速复现JavaWeb分层架构(DAO→Service→Servlet→JSP/HTML)的带教工程师。别被“课程设计”四个字骗了——它的SQL文件里有flight_schedule、passenger_info、ticket_order三张主表,字段命名直指民航业术语(如departure_gate、boarding_time、cabin_class_code),连regular_c_value-added_services.html都预留了行李额、选座、餐食的扩展钩子。


2. 从零启动:Maven构建、数据库初始化与前端资源加载路径解析

2.1 Maven构建链路:为什么必须用mvnw.cmd而非全局Maven

项目根目录下的mvnw.cmd(Windows)和mvnw(Linux/macOS)是Maven Wrapper,它强制使用项目绑定的Maven 3.8.6版本(由mvnw脚本内嵌的maven-wrapper.jar指定)。这解决了课程设计中最常见的环境冲突:你的系统装的是Maven 3.5,但pom.xml里声明的maven-compiler-plugin要求3.8+才能正确解析<source>11</source>。执行以下命令启动:

# Windows mvnw.cmd clean compile package -DskipTests # Linux/macOS ./mvnw clean compile package -DskipTests

提示:-DskipTests跳过单元测试是安全的——该项目未包含JUnit测试类(src/test/java为空),跳过可避免因H2内存数据库配置缺失导致的编译失败。

编译成功后,target/目录下会生成airline-system-1.0-SNAPSHOT.war。注意:不要直接双击运行WAR包。JavaWeb传统部署需容器,此处推荐两种方式:

  • 方式一(开发调试):在IDEA中右键pom.xml→Run Maven→ 执行tomcat7:run(pom.xml中已声明tomcat7-maven-plugin,端口默认8080)
  • 方式二(生产模拟):将WAR包丢进Tomcatwebapps/目录,启动bin/startup.bat(Windows)或bin/startup.sh(Linux)

pom.xml关键依赖解析:

  • javax.servlet-api:4.0.1:Servlet 4.0规范,支持异步处理(admin_c_real_time_flight_management.html的航班状态轮询依赖此)
  • mysql-connector-java:8.0.28:MySQL 8.0驱动,注意jdbc:mysql://localhost:3306/airline?serverTimezone=GMT%2B8&useSSL=false连接字符串中的时区参数,否则插入boarding_time会报错
  • jstl:1.2:JSP标准标签库,regular_a_flight_choosing.html中的航班列表循环用<c:forEach>实现,而非原生Java脚本片段

2.2 数据库初始化:SQL文件结构与字段业务含义映射

项目中的airline_db.sql不是简单建表语句,而是按民航业数据模型分层设计:

  • 基础主数据表:airline_company(航司代码、名称)、airport(三字码、城市、跑道数)
  • 运行核心表:flight_schedule(航班号、机型、起飞/到达机场、计划时刻)、flight_instance(当日执飞实例,含实际起飞/到达时间、延误分钟数)
  • 销售与服务表:cabin_product(舱位等级、基准票价、行李额)、ticket_order(订单号、乘客ID、航班实例ID、支付状态)、passenger_info(证件类型、号码、姓名拼音——注意passport_no字段为VARCHAR(20),支持中国护照及外国护照混存)

执行SQL前必须创建数据库并设置字符集:

CREATE DATABASE airline CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE airline; -- 然后 source airline_db.sql

注意:utf8mb4是硬性要求。regular_b_fill_out_the_order.html中乘客姓名输入框若含中文emoji(如✈️),utf8会截断导致乱码,而utf8mb4支持4字节Unicode。

2.3 前端资源加载路径:HTML/CSS/JS如何与Java Servlet协同工作

前端文件并非静态托管,而是通过Servlet路由注入动态数据。以regular_a_flight_choosing.html为例:

  • 它本身是纯HTML,无JSP标签,但通过<script src="js/flight-search.js"></script>加载JS
  • flight-search.js中发起AJAX请求:fetch('/FlightSearchServlet?from=PEK&to=SHA&date=2024-06-15')
  • FlightSearchServlet.java(位于src/main/java/com/airline/servlet/)接收参数,调用FlightService.searchFlights(),返回JSON格式航班列表
  • JS解析JSON后,用DOM操作填充<tbody id="flight-list">表格

CSS资源路径需特别注意:regularUserCommon.css放在src/main/webapp/css/目录下,HTML中引用为<link rel="stylesheet" href="css/regularUserCommon.css">。若误将CSS放src/main/resources/,浏览器会404——因为resources目录仅对Java类路径可见,不参与Web资源映射。

图片资源同理:14个JPG文件(如logo_airline.jpg)必须置于src/main/webapp/images/,HTML中写<img src="images/logo_airline.jpg" alt="航司Logo">。曾有学生把图片放src/main/java/下,结果页面显示破损图标——这是JavaWeb新手最常踩的路径陷阱。


3. 角色权限与业务流程:旅客端下单与管理员后台的完整链路拆解

3.1 旅客端三步下单:从航班查询到电子客票生成

旅客流程严格遵循民航业SOP(标准作业程序),体现在HTML文件命名与跳转逻辑上:

  • Step 1:航班查询(regular_a_flight_choosing.html)
    用户输入出发地/目的地/日期,提交后跳转至FlightSearchServlet。该Servlet调用FlightService.getAvailableFlights(),查询flight_instance表中status='scheduled'且departure_time大于当前时间的航班。返回JSON示例:
    { "flights": [ { "flightNo": "CA123", "departureAirport": "PEK", "arrivalAirport": "SHA", "departureTime": "2024-06-15T08:30:00", "arrivalTime": "2024-06-15T10:15:00", "cabinProducts": [ {"classCode": "Y", "price": 1280, "seatsLeft": 42}, {"classCode": "C", "price": 3280, "seatsLeft": 8} ] } ] }
  • Step 2:填写订单(regular_b_fill_out_the_order.html)
    用户选择航班与舱位后,页面通过<form action="/OrderCreateServlet" method="post">提交。关键字段包括:
    • passengerName(必填,长度限制20字符)
    • idType(下拉选项:ID_CARD/PASSPORT/OTHER)
    • idNumber(正则校验:身份证18位或护照字母数字组合)
    • contactPhone(手机号,^1[3-9]\d{9}$校验)
    • cabinClass(隐藏域,值来自上一页选择)
  • Step 3:值机与出票(regular_c_value-added_services.html)
    订单创建成功后,跳转至此页。用户可勾选增值服务(行李额、优选座位、机上餐食),最终点击“确认出票”触发TicketIssueServlet。该Servlet执行原子操作:
    1. 检查cabin_product表中对应舱位seatsLeft > 0
    2. 插入ticket_order记录(order_status='issued')
    3. 更新cabin_product.seatsLeft = seatsLeft - 1
    4. 生成12位电子客票号(ETKT + YYYYMMDD + 6位随机数)

玄学细节:regular_c_value-added_services.html中行李额选项的<input type="number" min="0" max="3" step="1">,其max="3"对应民航业标准——经济舱免费行李额20kg,超重按每公斤2%票价计费,此处简化为0/1/2/3件(每件23kg)。

3.2 管理员后台四维管控:航班发布、票务核验、舱位定价与实时监控

管理员功能按民航运控中心(AOC)职能划分,每个HTML文件对应一个核心岗位:

  • 航班发布(admin_b_release_flight.html)
    输入航班号、机型(B737-800/A320)、起降机场、计划时刻、执飞机组ID。提交后FlightReleaseServlet校验:
    • 航班号格式:CA\d{3}或MU\d{3}(国航/东航代码)
    • 时刻合法性:arrival_time > departure_time + 60分钟(最低航程时间)
    • 机组排班:crew_id必须存在于crew_schedule表中且当日无冲突
  • 票务管理(admin_e_ticketing_management.html)
    支持按订单号/乘客证件号/航班号搜索。关键操作是“异常订单处理”:当ticket_order.status='paid'但未出票时,管理员可手动触发TicketIssueServlet补发电子客票。
  • 舱位产品(admin_d_cabin_products.html)
    动态定价核心界面。可为同一航班不同舱位设置:
    • base_price(基准票价)
    • discount_rate(折扣率,0.0~1.0)
    • min_advance_days(提前预订天数,影响价格浮动)
    • max_seats(总座位数,用于计算seatsLeft)
  • 实时航班监控(admin_c_real_time_flight_management.html)
    使用setInterval(() => { fetch('/FlightStatusUpdateServlet') }, 30000)每30秒拉取flight_instance最新状态。表格列包括:
    • flightNo(航班号)
    • status(scheduled/boarding/departed/arrived/delayed)
    • actual_departure_time(实际起飞时间,为空则显示“未起飞”)
    • delay_minutes(延误分钟数,status='delayed'时高亮红色)

血泪经验:admin_c_real_time_flight_management.html的AJAX请求若返回500错误,大概率是FlightStatusUpdateServlet中SimpleDateFormat线程不安全导致的java.lang.NumberFormatException。解决方案:将new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")改为DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")(Java 8+)。


4. 避坑指南:81个Java类里最易翻车的5个边界问题与修复方案

4.1 现象:admin_b_release_flight.html提交后报404,控制台显示The requested resource [/FlightReleaseServlet] is not available

原因:web.xml中Servlet映射路径与HTML表单action不一致。检查src/main/webapp/WEB-INF/web.xml:

<servlet> <servlet-name>FlightReleaseServlet</servlet-name> <servlet-class>com.airline.servlet.FlightReleaseServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FlightReleaseServlet</servlet-name> <url-pattern>/flight-release</url-pattern> <!-- 注意这里是/flight-release --> </servlet-mapping>

而admin_b_release_flight.html中表单写的是<form action="/FlightReleaseServlet" ...>。
解决:将HTML中action改为/flight-release,或修改web.xml中<url-pattern>为/FlightReleaseServlet。

4.2 现象:regular_b_fill_out_the_order.html提交后,ticket_order表中passenger_name字段存为乱码(如李可)

原因:MySQL连接URL缺少characterEncoding=utf8mb4参数,且数据库表未设CHARSET=utf8mb4。
解决:

  1. 修改src/main/resources/db.properties:
    jdbc.url=jdbc:mysql://localhost:3306/airline?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf8mb4
  2. 执行SQL重建表:
    ALTER TABLE passenger_info CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

4.3 现象:admin_d_cabin_products.html中修改舱位价格后,regular_a_flight_choosing.html仍显示旧价格

原因:FlightService.searchFlights()方法中,航班查询结果缓存于HashMap<String, List<Flight>>静态变量,未失效。
解决:在CabinProductUpdateServlet更新价格后,添加缓存清理逻辑:

// CabinProductUpdateServlet.java FlightService.clearFlightCache(); // 新增方法,清空静态HashMap

4.4 现象:regular_c_value-added_services.html勾选“优选座位”后,ticket_order表seat_preference字段存为null

原因:HTML中复选框<input type="checkbox" name="seatPreference" value="true">,但Servlet中request.getParameter("seatPreference")在未勾选时返回null,勾选时返回字符串"true",而ticket_order.seat_preference字段为TINYINT(1)(0/1)。
解决:在OrderCreateServlet中转换:

String seatPrefStr = request.getParameter("seatPreference"); boolean seatPreference = "true".equals(seatPrefStr); // 避免Boolean.parseBoolean(null)抛NPE order.setSeatPreference(seatPreference ? (byte)1 : (byte)0);

4.5 现象:admin_c_real_time_flight_management.html实时刷新时,部分航班状态显示为null

原因:FlightStatusUpdateServlet中ResultSet.getString("status")遇到NULL值,未做空值判断,导致JSON序列化失败。
解决:在构建JSON对象时增加判空:

String status = rs.getString("status"); jsonObj.put("status", status != null ? status : "scheduled"); // 默认为scheduled

5. 进阶技巧:用Chrome DevTools逆向分析前端交互,定位JavaWeb性能瓶颈

5.1 Network面板抓包:识别AJAX请求与响应延迟根源

打开regular_a_flight_choosing.html,在Chrome开发者工具(F12)中切换到Network标签页,勾选XHR过滤器。执行一次航班查询,观察FlightSearchServlet请求:

  • 看Headers:确认Request URL为http://localhost:8080/FlightSearchServlet?from=PEK&to=SHA&date=2024-06-15,Response Headers中Content-Type: application/json;charset=UTF-8正确。
  • 看Timing:重点关注Waiting (TTFB)时间。若超过500ms,说明后端处理慢。此时需检查FlightService.searchFlights()方法:
    • 是否在循环中多次查询数据库?应合并为单条SQL:SELECT * FROM flight_instance fi JOIN flight_schedule fs ON fi.flight_id = fs.id WHERE ...
    • 是否未加索引?在flight_instance表上为(departure_airport, arrival_airport, departure_time)创建联合索引。
  • 看Preview:查看返回JSON是否包含冗余字段(如flight_schedule全量字段)。优化方案:在FlightService中构造DTO对象,只返回前端所需字段(flightNo,departureTime,arrivalTime,cabinProducts)。

5.2 Performance面板录制:定位前端渲染卡顿点

在admin_c_real_time_flight_management.html页面,点击Performance面板的●录制按钮,等待30秒(覆盖一次AJAX刷新周期),停止录制。分析火焰图:

  • 高亮Layout事件:若Layout耗时>16ms(60fps阈值),说明DOM操作过多。flight-status.js中每次刷新都document.getElementById('flight-table').innerHTML = newHtml会触发全量重绘。
    优化:改用documentFragment批量更新:
    const fragment = document.createDocumentFragment(); data.flights.forEach(flight => { const row = document.createElement('tr'); row.innerHTML = `<td>${flight.flightNo}</td><td>${flight.status}</td>`; fragment.appendChild(row); }); document.getElementById('flight-table').appendChild(fragment);
  • 高亮Scripting事件:若JSON.parse()耗时长,说明返回数据量过大。检查FlightStatusUpdateServlet是否返回了所有航班(含历史数据)。应在SQL中加WHERE status IN ('scheduled','boarding','departed','arrived')过滤。

5.3 Console面板调试:捕获前端JavaScript异常与Java异常映射

在regular_b_fill_out_the_order.html中故意输入非法身份证号(如123),提交后观察Console:

  • 若出现Uncaught TypeError: Cannot read property 'length' of null,说明flight-search.js中未校验response.data是否存在。
  • 若出现Failed to load resource: the server responded with a status of 500 (),点击该请求,在Response中查看Java异常堆栈:
    java.lang.NumberFormatException: For input string: "123" at java.base/java.lang.Integer.parseInt(Integer.java:652) at com.airline.servlet.OrderCreateServlet.doPost(OrderCreateServlet.java:87)
    定位到OrderCreateServlet.java第87行——此处Integer.parseInt(request.getParameter("idNumber"))试图将身份证号转整型,显然错误。
    修复:身份证号必须用String接收,校验逻辑移至PassengerValidator.isValidIdCard(String id)工具类。

从那以后我每次接手JavaWeb项目,都会在Chrome里开三个标签页:Network看请求链路、Performance看渲染帧率、Console看异常源头。哪怕只是课程设计,这种习惯让我少踩80%的“前端说后端挂了,后端说前端传参错了”的互甩锅陷阱。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询