资讯动态

机票预订系统课程设计:瀑布式六文档与 C# WinForms 数据库实现

发布时间:2026/9/17 17:49:20 来源:尧图企业网站定制
简介这是一份软件工程课程设计报告模板主题为飞机售票机票预定系统面向高校软件工程、计算机相关专业的学生与课程指导教师。报告按瀑布模型完整覆盖软件生存周期各环节项目开发计划书、需求规格说明书、设计规格说明书、源程序清单、测试报告与用户手册六大部分包含术语定义、相关文档、任务与工作产品划分、工作量与规模估算、资源需求计划及进度计划表等规范内容需求部分给出查询、预定、取消预定等场景描述与用例分析还整理了性能测试、虚拟用户、响应时间、吞吐量、并发用户数等术语并列出 Word2007、Visual Studio 2008、Rational Rose、SQL Server 2005 等开发与测试环境配置便于读者对照撰写与答辩准备。资源包内共1个doc文档约432KB共52页章节结构清晰、格式规范可直接作为课程设计报告的参考范文或改写底稿。目前已有1841人学习下载适合需要快速搭建报告框架、补充需求分析与测试环节内容的学习者参考借鉴。1. 机票预订系统课程设计报告六份文档串起一条瀑布式开发链路课程设计截止前一周多数人手里只有几段能跑的界面代码缺的是把需求、设计、编码、测试串成一条线的那份文档。这份52页的机票预订系统课程设计报告把项目开发计划书、需求规格说明书、设计规格说明书、源程序清单、测试报告、用户手册六份材料装进同一份 Word 文档对应瀑布模型从需求分析到运行维护的完整链路。系统本身不复杂旅客查航班、旅行社订票并打印取票通知和账单、起飞前24小时取票、退票按规则扣手续费但每个环节都要落到用例、类、表和代码上。技术栈是当年课程设计的主流组合——Visual Studio 2008 写 C# WinForms 客户端SQL Server 2005 存航班与订单Rational Rose 画用例图和类图。它的价值不在代码量而在文档之间的对应关系需求里的一个用例能在设计里找到对应的类和表在源程序里找到对应的事件处理函数在测试报告里找到对应的用例编号。建议按文档编号通读一遍重点盯住需求用例表、模块类清单和数据字典三处。2. 需求规格说明书的拆解从场景描述到功能需求点列表2.1 场景描述为什么要写成对话剧本报告里最不像文档的部分就是场景描述售票员A和旅客B一问一答从我想订一张成人的票一直写到用我的 VISA 卡卡号是1111-2222-3333-4444。这种写法在评审时容易被批太啰嗦但它解决的是需求分析里最难的一环——把业务人员脑子里的隐性流程变成可编号的动作序列。预定场景里能数出九步点击查询、输入航班信息、系统列出符合条件航班、点击新建订单、录入旅客证件信息、填写联系方式、确认付款、系统返回银行验证结果、打印账单和取票通知单。每一步往前推是一个界面状态往后退是一条异常分支。写这类场景有三条经验。第一一次只写一个参与者的视角别在旅客的动作里混进数据库写入动作第二每个动作后面必须跟一句系统响应否则后面对应画序列图时找不到返回消息第三把没有找到符合条件的航班账单号错误这类可选事件流单独拎出来写不要塞在主流程中间。软件工程课程设计里最常被扣分的地方就是主流程和异常流程糊成一段后面测试用例根本没法从需求里长出来。2.2 用例表的要素与事件流边界五个核心用例的写法定下来之后评审时最容易被追问的是触发条件写了没有后置条件写的是业务还是数据。用一张对照表把边界钉住用例主要参与者触发条件主事件流关键节点可选事件流查询航班旅客无主界面已打开输入目的地/时间/航班号→系统查询→列表显示无符合条件航班机票预定旅行社、机场售票员旅客来电或到柜台查询→新建订单→填写旅客信息→确认付款→打印账单无符合航班询问是否改签取消预定机场售票员旅客来电要求取消输入订单号→显示账单→确认取消→退还订金→删除账单未找到订单返回待输入状态退票机场售票员旅客持票到柜台输入票号→核对身份→计算手续费→退款→机票状态改待售查不到票号提示核对真伪取票机场售票员旅客到场取票输入账单号→核对24小时限制→打印机票→状态改已售出账单错误返回待输入前置条件写系统状态比如机票预定系统主界面已经打开后置条件写数据状态变化比如可订机票减少、定金总量增加、数据库更新。主事件流编号要和2.1里的场景步骤对得上否则两处描述会互相打架。表里核对24小时限制这一条就是后面取票校验代码的落点需求阶段埋下的每一个判断后面都得在代码里还债。2.3 功能需求点列表与性能需求点列表怎么填功能需求点列表一般六列编号、功能名称、使用人、功能描述、输入内容、输出内容。填一条示例编号2功能名称预定机票使用人旅行社输入预定的机票号、用户信息输出预定完成通知。这张表最大的用处不是给人看而是给后面的模块清单和测试用例提供锚点——功能点编号和测试用例编号最好成对出现答辩时一眼就能看出哪个功能压根没测。性能需求点列表要落到可量化的数字上。报告里的时间要求是查询最长等待0.5分钟、记账处理最长1分钟、远程数据传输1分钟空间要求是支持终端数1、不支持并行操作、处理的文件和记录数4、处理任务数15、输入输出精度为双精度、中间过程小数点后保留4位。这些数字看着随意但它们是测试报告里系统满足性能需求这句话唯一的依据。改需求文档时顺手把数字也改了测试报告就对不上了。2.4 把用例表落成可校验的结构化数据Word 表格改起来费劲字段还容易漏。我一般先把用例写成结构化文本再用脚本生成文档表格改一处就能全量重排。{ use_case_id: UC-02, name: 机票预定, primary_actor: 旅行社, secondary_actor: [旅客, 机场售票员], precondition: 系统处于主界面售票人员等待旅客, trigger: 旅客提出订票需求, main_flow: [ 售票员进入查询界面并输入航班信息, 系统返回符合条件的航班列表, 售票员点击新建订单, 录入旅客姓名、证件类型、证件号、证件地址, 录入联系人手机、固定电话、Email, 选择支付方式并提交支付, 系统等待银行返回验证结果, 打印账单与取票通知单 ], alt_flow: [ {step: 2, condition: 无符合条件航班, action: 提示无航班并询问是否改签} ], postcondition: 订单写入数据库可订座位数减少定金金额增加, related_module: M-01 旅行社系统, test_case_id: TC-02 }字段说明use_case_id与test_case_id成对出现是需求到测试的追溯线related_module指向设计规格说明书里的模块编号main_flow的数组下标要和 Word 版用例表里的步骤编号一致改编号时两边同步。用 python-docx 读这个文件批量生成表格比手工敲六张用例表省事得多字段也不会今天漏一个明天补一个。3. 设计规格说明书的落地类图、模块清单与四张核心数据表3.1 从用例到类边界类、控制类、实体类的划分用例表里的名词就是候选类。参与者一侧有旅客、旅行社、机场售票人员、机场管理人员实体一侧有航班、机票、客户订单、账单、取票通知单。WinForms 客户端里每个窗体天然是一个边界类主界面 Form1 承担控制类入口的角色把用户动作分派到旅行社系统、售票员系统、旅客查询系统三个模块。划分时最容易犯的错是把打印账单当成一个类。打印是动作不是名词它要么是账单类上的方法要么是一个独立的打印服务类。判断标准很直接能存进数据库的当实体出现在界面上的当边界协调多个实体完成一次用例的当控制。按这条线切下来类图上的关系基本就是一对多和聚合不会出现一团乱麻的双向关联。3.2 模块类清单与命名规则模块清单四列编号、模块英文名、功能简述、接口简述。编号模块类英文名功能简述接口简述M-01AgencyModule预定、收费、打印通知单与账单BookTicket(orderId)、PrintBill(billId)M-02CounterModule打印机票、退订金、退票Refund(ticketNo)、IssueTicket(billNo)M-03QueryModule航班查询、交费查询SearchFlight(toCity, date, flightNo)命名规则在报告1.2节里只写了申明全局变量、局部变量对象的命名规则实际要写死才管用。常见做法是全局变量加g_前缀窗体控件沿用 WinForms 默认名btnQuery、dgvFlight数据库表名用T_前缀加下划线字段名小驼峰视图加V_。规则一旦写进文档后面接手改代码的人就不会各写一套源程序清单里的函数名也能和模块清单对得上号。3.3 四张核心表与字段类型设计报告里用框图列了账单、取票通知单、机票、客户订单四组数据落到 SQL Server 2005 大致是这个样子。-- 航班表查询与余座的基础 CREATE TABLE T_Flight ( FlightNo VARCHAR(10) NOT NULL PRIMARY KEY, FromCity NVARCHAR(20) NOT NULL, ToCity NVARCHAR(20) NOT NULL, DepartTime DATETIME NOT NULL, ArriveTime DATETIME NOT NULL, SeatTotal INT NOT NULL DEFAULT 0, SeatLeft INT NOT NULL DEFAULT 0, Price DECIMAL(18,4) NOT NULL ); -- 机票表取票后状态改已售出退票后改待售 CREATE TABLE T_Ticket ( TicketNo VARCHAR(20) NOT NULL PRIMARY KEY, FlightNo VARCHAR(10) NOT NULL, SeatNo VARCHAR(5) NULL, TicketDate DATETIME NOT NULL, Status TINYINT NOT NULL DEFAULT 0 -- 0待售 1已预定 2已售出 3已退 ); -- 订单与账单票价、订金、手续费分开存退票时才算差额 CREATE TABLE T_Order ( OrderId VARCHAR(20) NOT NULL PRIMARY KEY, CustomerName NVARCHAR(30) NOT NULL, IdCard VARCHAR(20) NOT NULL, CardNo VARCHAR(24) NULL, TicketNo VARCHAR(20) NULL, CreateTime DATETIME NOT NULL DEFAULT GETDATE() ); CREATE TABLE T_Bill ( BillNo VARCHAR(20) NOT NULL PRIMARY KEY, OrderId VARCHAR(20) NOT NULL, Amount DECIMAL(18,4) NOT NULL, -- 票价 Deposit DECIMAL(18,4) NOT NULL, -- 订金 Fee DECIMAL(18,4) NOT NULL DEFAULT 0, -- 手续费 PrintTime DATETIME NULL, ExpireTime DATETIME NULL -- 取票截止时间 );字段说明SeatLeft必须在订票成功和退票成功时同步加减它是查询界面显示余座的唯一来源Status用 tinyint 枚举而不是中文串否则打印和统计时到处做转换金额统一 DECIMAL(18,4)对应性能需求里小数点后4位别用 float手续费累加会出现分位误差ExpireTime存取票截止时间取票界面拿它和当前时间比较判断是否还在起飞前24小时之外。数据库课程设计里这四张表就是数据字典的主体字段注释一行都别省。3.4 接口设计打印接口与银行结算接口接口表要写清七个字段接口名称、接口内容、接口设施、接口数据结构、传输速率、带宽、协议。接口名称接口内容设施数据结构协议打印接口输出机票、账单、取票通知单本地打印机文本流 版式模板本地调用无网络协议银行结算接口扣款、退款、验证结果返回银行中间件请求卡号、金额、订单号响应返回码、流水号按银行提供的规范打印接口在 WinForms 里通常封装成 PrintService入参是账单号内部按模板填充字段银行结算接口在课程设计阶段一般用模拟函数代替但要保留返回码字段测试报告里才有支付失败这条异常分支可写。接口签名一旦确定源程序清单里的函数名和参数顺序就不能再随便动否则设计文档和代码两张皮。4. WinForms 源程序实现Form1 主控界面、ADO.NET 参数化查询与退票事务4.1 Form1 主控界面与窗体间数据传递源程序清单里给出的是 WinForms 设计器自动生成的部分类包含 components 字段、Dispose 重写和 InitializeComponent 框架。这段代码本身没什么可改的重点在主界面按钮与子窗体的对应关系。控件功能对应模块涉及表btnQuery查询航班M-03T_FlightbtnBook新建订单并付款M-01T_Order、T_Bill、T_TicketbtnCancel取消预定M-01T_Order、T_BillbtnRefund退票M-02T_Ticket、T_BillbtnIssue取票并打印机票M-02T_Bill、T_Ticket窗体之间传订单号或票号有两条路构造函数注入比如new FormRefund(ticketNo)或者做一个静态会话类 CurrentSession保存当前售票员工号、当前订单号、当前账单号。课程设计里窗体数量不多构造函数注入更直观也方便以后单测。主界面在子窗体关闭后要刷新余座列表否则退完票回来看到的还是旧数据答辩时很容易被当场点破。4.2 ADO.NET 参数化查询封装查询用例有三个可选条件目的地、起飞时间、航班号。WHERE 子句动态拼接最容易写出注入漏洞正确做法是先把条件拼成参数占位符再统一绑定参数值。public DataTable SearchFlight(string toCity, DateTime? departDate, string flightNo) { var sql new StringBuilder( SELECT FlightNo, FromCity, ToCity, DepartTime, SeatLeft, Price FROM T_Flight WHERE 11 ); var cmd new SqlCommand(); if (!string.IsNullOrEmpty(toCity)) { sql.Append( AND ToCity ToCity ); cmd.Parameters.Add(ToCity, SqlDbType.NVarChar, 20).Value toCity; } if (departDate.HasValue) { // 只比较日期部分避免时分秒把当天航班过滤掉 sql.Append( AND CONVERT(date, DepartTime) DepartDate ); cmd.Parameters.Add(DepartDate, SqlDbType.Date).Value departDate.Value.Date; } if (!string.IsNullOrEmpty(flightNo)) { sql.Append( AND FlightNo FlightNo ); cmd.Parameters.Add(FlightNo, SqlDbType.VarChar, 10).Value flightNo; } cmd.CommandText sql.ToString(); using (var conn new SqlConnection( ConfigurationManager.ConnectionStrings[TicketDb].ConnectionString)) using (var da new SqlDataAdapter(cmd)) { cmd.Connection conn; var dt new DataTable(); da.Fill(dt); // DataAdapter 自动 Open/Close 连接 return dt; } }代码逻辑先拼一个恒真条件11再按用户实际填了哪些字段追加 AND 子句每个子句对应一个 SqlParameter值永远不拼进 SQL 文本。参数说明ToCity用 NVarChar因为目的地是中文城市名DepartDate用 date 类型并取.Date绕开 datetime 的时分秒精度问题连接字符串放在 App.config 的 connectionStrings 节点换库时不用重新编译。返回 DataTable 直接绑到 DataGridView比逐行读 DataReader 少写一层循环。注意SqlDataAdapter.Fill 会自动开关连接但 SqlCommand 必须挂到同一个 SqlConnection 上漏掉cmd.Connection conn会报未将对象引用设置到对象的实例。4.3 退票手续费计算与退款事务退票用例里有三个动作必须一起成功机票状态改为待售、写入退款流水、账单标记已退。任何一步失败都会留下钱退了票还在的脏数据所以用事务包起来。手续费阶梯常见做法是按离起飞时间分档离起飞时间手续费比例说明起飞前24小时内票价的20%与取票时间同一临界点24至72小时票价的10%中间档72小时以上票价的5%最低档建议设最低收费金额public decimal Refund(string ticketNo) { using (var conn new SqlConnection(connStr)) { conn.Open(); using (var tran conn.BeginTransaction()) { try { // 1. 取票面信息加更新锁避免同一张票被两个窗口同时退 var cmd new SqlCommand( SELECT t.Status, f.Price, f.DepartTime FROM T_Ticket t WITH (UPDLOCK) JOIN T_Flight f ON t.FlightNo f.FlightNo WHERE t.TicketNo TicketNo, conn, tran); cmd.Parameters.AddWithValue(TicketNo, ticketNo); // ... 读取 Status / Price / DepartTime if (status ! 2) throw new InvalidOperationException(该票未售出不能退票); decimal fee CalcFee(price, departTime, DateTime.Now); // 按阶梯表计算 decimal refund price - fee; // 2. 机票状态回到待售座位还回去 new SqlCommand(UPDATE T_Ticket SET Status 0 WHERE TicketNo TicketNo, conn, tran).ExecuteNonQuery(); // 3. 手续费与退款金额写回账单4. 写退款流水 // ... tran.Commit(); return refund; } catch { tran.Rollback(); // 任一步失败状态与金额一起回滚 throw; } } } }参数说明UPDLOCK提示在同一事务里对机票行加更新锁退票按钮被重复点击时第二次会阻塞或报错而不是把同一张票退两次CalcFee接收票价、起飞时间、当前时间三个入参阶梯规则改了只动这一个函数Rollback()放在 catch 里并把异常抛给界面层弹提示。起飞前24小时这个临界点被取票和退票共用建议抽成一个 TimeSpan 常量别在两处各写一遍。4.4 打印机票与取票通知单的技术要点打印走 System.Drawing.Printing 里的 PrintDocument在 PrintPage 事件里用 Graphics.DrawString 按坐标画字段再挂到 PrintPreviewDialog 上预览。课程设计里字段固定直接算坐标比上模板引擎省事账单和取票通知单共用一份打印代码用一个版式参数区分标题和字段清单即可。取票前的校验顺序别写反先用账单号查到记录再判断当前时间是否早于 ExpireTime超过就提示账单已过期最后才改机票状态为已售出并调打印。顺序反了会出现票打了但状态没改或者状态改了但没打出来两种情况退票时对不上账。5. 测试报告与验收响应时间口径、边界用例和自查清单5.1 响应时间与并发指标怎么测才有说服力需求里写的是查询最长等待0.5分钟、记账1分钟测试报告就得给实测数字。做法是在按钮事件外面套一个 Stopwatch连续跑20次取平均值和最大值并记录数据量否则耗时35毫秒这种结论别人无法复现。var sw Stopwatch.StartNew(); var dt svc.SearchFlight(北京, DateTime.Today, null); sw.Stop(); Console.WriteLine($返回 {dt.Rows.Count} 行耗时 {sw.ElapsedMilliseconds} ms);并发方面需求写明不支持并行操作、支持终端数1所以不必做压测但要验证同一订单被两个窗口同时打开时的冲突开两个退票窗口输入同一个票号第二个应该被行锁挡住或提示已处理。这类记录写进测试报告比一句系统运行稳定有分量得多也正好复用4.3节里 UPDLOCK 的设计意图。5.2 边界用例清单与答辩自查用例编号场景预期结果TC-05-01查询条件全为空返回全部航班或提示补充条件不报错TC-05-02起飞时间刚好在24小时后允许取票手续费按24小时档计TC-05-03账单号不存在提示账单错误返回待输入状态TC-05-04同一票号重复退票第二次提示该票未售出TC-05-05证件号超长输入框截断或提示格式错误TC-05-06手续费高于订金退款金额为0不允许负数入账答辩前对着这张表和需求里的功能需求点列表逐个打勾凡是功能点列表里有编号、测试表里没有对应行的就是缺口。填预期结果时写成可观察的现象——提示什么文字、状态变成哪个值、哪张表多了一行——评委照着点一遍就能复现这份测试报告才算立住。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价