简介这是一份面向软件工程课程设计与系统分析学习者的航空机票预订系统结构化设计文档适合高校学生在课设答辩、系统建模或数据库设计时参考。内容以实体—关系图清晰梳理旅行者、机票信息、航空公司、旅行社、取票通知等核心实体及其属性联系用数据流图完整展现旅客提交预订、系统检索机票、信息传递至旅行社、最终生成取票通知的数据流动过程并通过状态转换图刻画系统从接收预订到通知送达各阶段的状态变迁配套的数据字典还逐项定义了旅客信息、机票信息、航空公司信息等数据项的字段与关系。文档逻辑严密、图示完整可直接作为课程设计报告中的逻辑模型章节或用于辅助完成数据库表设计、流程状态梳理等任务。资源包共含一个PDF文件大小仅57KB下载便捷。目前已有2971人学习下载适合正在完成软件工程课设、需要绘制系统分析图或理解机票预订业务逻辑的高校学生与开发者。1. 拿到航空机票预订系统四张图之后先分清实体、流动、状态、定义各自管什么带过几届软件工程课程设计见得最多的不是不会画图而是拿着一套现成的航空机票预订系统ER图、数据流图、状态转换图和数据字典不知道怎么改成自己的题目。这套PDF本质上是一份标准的结构化分析产物ER图回答“业务里有哪些对象、谁和谁发生关系”数据流图回答“数据从哪进来、经过什么加工、写到哪些存储”状态转换图盯着一笔订单从下单到取票的状态变化数据字典把每个数据项、每条数据流、每张表定义到字段级。这篇拆解不是复述PDF而是带你把四张图按“实体—流动—状态—字典”的顺序读透再把它改造成自己课程设计里能交差、能抗住追问的结构化分析文档。适合正在做课程设计或期末大作业、答辩前想补图的人。2. ER图怎么读透五个实体、四类联系以及怎么加出自己的订单2.1 五个实体是“谁和谁交易”的底牌ER图第一眼看的是实体。实体不是数据库表而是业务里真实存在的对象。这套图里一共出现五个核心实体旅客、机票信息、航空公司、旅行社和取票通知。它们的角色非常清晰旅客是需求方航空公司是资源提供方旅行社是代理中转方机票信息是买卖的标的取票通知是最终交付给旅客的凭证。把这五个角色先安到业务场景里再看属性和联系就不会乱。实体业务角色关键属性在系统里承担的事旅客需求方姓名、性别、身份证号、工作单位、旅行地点、旅行时间提交预订请求、接收取票通知机票信息交易标的价格、帐单、等级、可售机票时间、航班机票信息被查询、被预订、被出票航空公司供给方名称、合适航班提供航班和可售票资源旅行社代理方名称、合适航班代售机票、传递售出信息取票通知交付凭证旅客清单、售出机票信息告诉旅客去哪取票、取哪几张票这里有两个容易理解偏差的地方。一是“机票信息”不等于“航班”。航班是一架飞机从A城飞到B城的排班记录机票是某个航班上按日期、舱位拆出来的一批可售单元价格、等级、可售时间都挂在机票信息而不是航班上所以实体是“机票信息”而非“航班”。二是“取票通知”虽然名字里有“通知”但它带旅客清单和售出机票信息是业务里要被记录的交付结果所以作为实体存在而不是只当作一张纸。画ER图之前还要先把属性和实体分开。属性是描述实体的特征例如“工作单位”是旅客的特征不需要拆成单独实体。初学者经常把“旅行时间”单独拉一个实体觉得它重要就应该有身份这是把字段物化的典型错误。判断一个词到底是实体还是属性可以看它是否拥有自己的属性实体还能挂别的属性属性不能再挂属性。旅行时间没有下级特征留在旅客实体里当属性就够了。2.2 联系怎么定从“旅客订机票”推出基数关系实体之间要有联系画联系最核心的工作是定基数。基数只有三种一对一、一对多和多对多但课程设计里大多数业务联系都是1:N。先把这套图里的联系和理由看一遍关系基数判断依据旅客—机票信息1:N一位旅客可以一次订多张机票一张机票只属于一位乘机人航空公司—机票信息1:N一家公司拥有多个航班和对应的一批票一张票只归属一家公司旅行社—机票信息M:N一个旅行社代售多家公司的票同一张票也能同时挂在几个代售渠道上旅客—取票通知1:N一位旅客可收到多次取票通知一条通知对应一次取票结果旅客和票的1:N是最好理解的你不可能和另一个人共享同一张实体票但你可以替全家订五张票。航空公司与票的1:N同理。真正需要留意的是旅行社与机票的M:NM:N不能直接在关系数据库里落地后面建物理表时要拆成一张“代售关系”表这张表里存旅行社编号、票号、代售时间和分成比例。ER图阶段先画M:N没问题但自己心里要清楚它不是最终表结构。如果你打算照着这份PDF自己画一份可以直接用下面这段PlantUML脚本它和PDF里的ER图结构基本一致只是补齐了主键标识startuml left to right direction entity 旅客 as T { *旅客ID : char(12) -- 姓名 : string 性别 : char(2) 身份证号 : char(18) 工作单位 : string 旅行地点 : string 旅行时间 : datetime } entity 机票信息 as K { *票号 : char(14) -- 等级 : string 价格 : decimal(10,2) 帐单号 : char(12) 可售时间 : datetime 航班号 : char(8) } entity 航空公司 as A { *公司编号 : char(6) -- 名称 : string 合适航班 : string } entity 旅行社 as C { *旅行社编号 : char(6) -- 名称 : string 合适航班 : string } entity 取票通知 as N { *通知编号 : char(12) -- 旅客清单 : string 售出机票信息 : string } T ||--o{ K : 订购 A ||--o{ K : 提供 C }o--o{ K : 代售 T ||--o{ N : 接收 K }o--|| N : 对应 enduml这段脚本用的是PlantUML语法在支持PlantUML的编辑器或在线渲染器里可以直接转成实体关系图。符号说明*标注主键--把主键区和普通属性区分开||--o{表示一端一条、另一端多条也就是1:N}o--o{表示两端都是多条也就是M:N。如果手动画图用Visio或亿图也不难关键是基数符号和连线方向别画反。答辩时一定会问你“为什么旅客和票是1:N”按上面的理由答就行。2.3 照着PDF改图三步把你题目里的实体加进来拿到一份现成ER图正确用法不是照抄而是照着这个结构把你自己的课程设计题目重构一遍。我一般按三步走比直接画省力很多。第一步名词提取。把你题目描述里所有名词抄出来比如“订单”“支付”“退票”“航线”“会员积分”等等然后逐个问自己它有没有自己的属性它会不会和另一个实体发生联系如果两个答案都是“是”它就是候选实体如果只能回答一个“是”多半是属性或联系。以“订单”为例它有订单号、下单时间、总价也跟旅客、机票都有联系就是实体“支付方式”只有类型和账号密码一般不单独成实体。第二步做关系矩阵。把候选实体放进一个两两交叉的矩阵逐个判断基数。这一步能避免常见的“画着画着多了一条线”。例如实体A实体B基数理由旅客订单1:N一个旅客可下多笔订单一笔订单属于一个旅客订单机票信息1:N一笔订单可包含多张机票一张票一次只属于一笔订单旅客旅行社N:1旅客只在某一家旅行社柜台订票旅行社订单1:N一家旅行社经手多笔订单第三步决定要不要把“订单”实体加进去。PDF原图里旅客直接和机票信息相连这只适合“每次订一张票”的简化场景。真实航空预订系统里一次下单可能买两张票、选两个舱位还会把支付状态挂在订单上所以大多数课程设计应该增加“订单”实体把“旅客—机票”的连线改成“旅客—订单—机票”两段1:N。这样做的好处是后面画数据流图时“订单表”和“订单状态”都有地方放状态转换图也有明确的建模对象。改图时记住一条底线实体和属性但凡在需求描述里找不到就不要自己发明。指导老师追问“这个会员等级从哪来的”如果你答不出出处整张图的信任度都会下降。反过来需求里有但图里没有的字段例如“乘客联系电话”一定要补上这叫诚实画图。3. 数据流图从顶层拆到0层三个外部实体与四个加工的边界3.1 顶层图只画一个系统和三个外部参与者数据流图的价值在于把“系统边界”画出来。顶层图也叫上下文图全图只能有一个加工就是你要开发的“航空机票预订系统”剩下的方框只能是外部实体。外部实体的判定标准很严格它必须独立于系统之外能主动发出或接收数据且自身不受系统内部控制。按这个标准检查PDF里出现的参与者顶层图应该只保留三个外部实体旅客、旅行社、航空公司。旅客是预订行为的发起端也接收系统返回的取票通知和帐单。旅行社在本系统里是中间业务节点系统把售出机票信息给旅行社旅行社向系统提供可售机票信息和出票确认。航空公司是资源端向系统提供航班信息接收系统的订票清单。要特别注意“取票通知”不是外部实体它是系统内部加工产生的数据结果最终发给旅客不是第四个参与者。很多课程组在这里多画一个方框后面我们会在避坑部分展开说。顶层图的数据流要命名得清楚方向也不能含糊。我一般维护一张数据流清单防止画到最后连方向都记不住数据流起点终点内容预订请求旅客系统出发地、目的地、旅行时间、乘机人信息航班检索结果系统旅客可选航班、舱位价格、余票数售出机票信息系统旅行社已订机票的票号、乘客姓名、航班信息可售机票信息旅行社系统各渠道可售航班与舱位数据取票通知系统旅客取票地点、取票时间、机票清单订票清单系统航空公司待出票订单汇总这里有一个现实的建模选择PDF的文字描述里提到“系统将机票信息传递给旅行社旅行社将机票信息转换为取票通知”如果完全照这个描述旅行社会被画成系统内部的一个加工节点。我更建议把它作为外部实体处理理由很简单你的课程设计系统不可能实现旅行社的全套代售管理你要做的是“连接旅行社”而不是“变成旅行社”。把旅行社放外部系统边界清晰子图也容易拆如果你确实想做一个包含旅行社后台的系统那就把这些功能拆到0层图里同时说明系统范围变大数据存储也会多好几张表。3.2 0层图拆出四个加工受理、查询、出票、通知有了顶层图下一步把“系统”这个黑匣子打开画0层图。0层图里加工的数量没有固定标准但机票预订这类业务拆成四个加工最稳P1受理预订P2查询航班P3确认订单并出票P4发送取票通知。每个加工都要标注输入流、输出流和需要访问的数据存储。加工编号加工名输入数据流输出数据流访问的数据存储P1受理预订预订请求订单信息D1旅客表、D3订单表P2查询航班航班查询条件合适航班D2航班信息表P3确认订单并出票订单信息、可售机票信息售出机票信息D2航班信息表、D3订单表P4发送取票通知订单信息、旅客清单取票通知D4取票通知表这个拆分顺序对应真实订票流程旅客先发起预订系统校验乘机人信息然后按出发地、目的地和时间查航班查到可售票后提交订单系统向旅客确认价格与帐单最后生成取票通知发送出去。注意DFD中“查询航班”必须在“确认订单”之前两者之间有先后依赖但在DFD里不画箭头依赖而是通过数据流组合体现。如果你想表现时间顺序那是状态转换图或活动图的事不要混进数据流图。数据存储在0层图里用开口矩形表示上面表里的D1到D4就是最小集合。经常有人把“订票清单”和“取票通知”合并成一张存储我建议拆开订票清单是给航空公司结算用的取票通知是给旅客取票用的一个是结算数据一个是交付数据生命周期不一样。合并存储也许能少画一个矩形但后面写数据字典时字段会互相污染得不偿失。3.3 编号、命名与父子图平衡三条规整化规则DFD画到最后容易乱乱的原因通常是三条规则没守好。第一条是加工编号要自顶向下分层。顶层图不编号0层图用P1、P2、P3、P4如果再往下拆比如把P2“查询航班”继续拆成“按航线查询”“按日期查询”“按价格过滤”新加工编号就是P2.1、P2.2、P2.3。编号除了好看还有个实际作用指导老师问“P2.2是干什么的”你能立刻说出它的父加工是P2子加工数据流要和P2的输入输出对得上。第二条是数据流一定要用名词短语命名不能用动词短语。这是DFD新手最常见的命令错误。“查询航班”不是数据流“航班查询条件”才是“通知旅客”不是数据流“取票通知”才是。原因很简单数据流是数据在管道里流动时携带的内容内容永远是名词性的动词属于加工的职责放在加工框名称里。我给课程组检查图时会直接扫一遍所有数据流标签只要看到一个“XX并XX”的动词结构就说明他还没把DFD和程序流程图画分家。第三条是父子图平衡性检查。父图中进入某个加工的一条输入流在拆开子图后必须仍然存在并且最终要走到子图里的某个加工父图里加工产生的每条输出流在子图里要么作为某个子加工的输出要么作为子图与外部实体或数据存储之间的流。简单说父图的输入输出不能被丢掉也不能凭空多出来。这个检查我放在最后做因为往往要改两三轮才能平衡。你可以把父图和子图放在同一张纸的左右两侧用彩色笔把同名数据流连成线连不上就是不平衡。三条规则之外还有一个重要的边界数据流图绝不画控制流。你不需要在DFD里画“如果没票就提示失败”那是加工内部逻辑或状态转换图该表达的东西。DFD只表达数据从哪来到哪去画控制依赖会让图和程序流程框图趋同丢了结构化分析的意义。4. 状态转换图与数据字典动态行为与静态定义怎么互相补位4.1 订单状态机把“检索航班”踢出状态列表状态转换图在四张图里最容易被画错一个很重要的原因是很多人把它和“流程图”混在一起。状态转换图描述的是某个对象的一生在这个系统里这个对象就是一笔订单。它不是描述“系统先做什么、后做什么”而是描述“订单在某个时刻处于什么状态遇到什么事件会跳到下一个状态”。以航空机票预订系统的核心业务为例订单状态机至少包含五个状态待支付、已支付、已出票、已取票、已取消。把状态迁移画成一张表比直接画圈更利于检查当前状态触发事件下一状态备注待提交旅客提交预订待支付进入待支付前要校验乘机人信息待支付支付成功已支付库存占用生效待支付用户取消或超时已取消释放库存已支付出票成功已出票生成票号与帐单已出票旅客取票完成已取票终态已取消——终态这里要区分“状态”和“活动”两个概念。状态是业务对象在等待某个事件时停留的一种相对稳定的情形比如“待支付”表示订单挂在那里等支付结果。活动则是瞬间完成或持续进行的动作比如“系统检索机票信息”“发送取票通知”。如果你把“检索航班”写进状态框那张图就变成了一张披着状态图外衣的流程框图。判断某一项是不是状态可以问一个问题这个对象能不能在这个词上面停留五分钟能停留才有资格当状态。“正在检索”不可能停留五分钟因为检索要么开始要么结束所以它不是状态。状态转换图里每个状态间的连线还要标事件不能只画箭头不写字。事件名用动词短语没问题例如“支付通过”“退票申请”因为事件是动作触发的这和DFD里数据流必须用名词不冲突。画完整张状态图后最好把“订单状态”字段的所有取值和状态图里的圆框一一对照这已经算数据字典工作了正好引出下一节。4.2 数据字典分三层数据项、数据流、数据存储数据字典是四张图里最枯燥但也最堵漏洞的部分。很多人以为数据字典就是把图里的中文名字抄一遍结果指导老师一问“旅客编号几位数”就答不上来。严格的数据字典分三层数据项、数据流、数据存储外加每个加工的结构化说明。数据项是字段级定义用“”表示组成关系用“|”表示或关系。例如旅客编号 姓名 性别 身份证号 工作单位 旅行地点 旅行时间订单状态 待支付 | 已支付 | 已出票 | 已取票 | 已取消光写组成还不够重要字段要补类型、长度和取值范围。给大家一个可以抄作业的格式数据项类型/长度取值范围/备注旅客编号char(12)前4位日期后8位流水号身份证号char(18)按国标校验票号char(14)前8位航班号后6位座位序号价格decimal(10,2)单位元订单状态varchar(10)待支付、已支付、已出票、已取票、已取消数据流层是给DFD的每条数据流写定义。例如预订请求 旅客编号 出发地 目的地 旅行时间 舱位等级取票通知 通知编号 旅客清单 售出机票信息数据存储层则定义一张表的完整结构例如订单表 {订单号 旅客编号 航班号 订单状态 取票通知编号}按订单号组织索引加工说明用结构化自然语言描述一般不超过十行。例如P3“确认订单并出票”的加工说明可以写成IF 存在可售机票 THEN 生成订单记录置订单状态为“待支付”并返回价格帐单ELSE 返回“无票”信息。这样写的好处是后面编码阶段可以直接把这个结构化说明翻译成程序逻辑不用再回头猜图。4.3 四张图的字段一致性交叉检查数据字典不是画完就完了它最大的作用是当“校准尺”。因为ER图、DFD、状态转换图是三个不同视角画出来的如果没有统一的数据字典三张图很容易自相矛盾。我每次都会做一轮交叉检查照着下面五条逐一过ER图中每个实体挂的属性必须能在数据字典里找到对应的数据项或数据存储字段。找不到说明实体是空壳。DFD中每条数据流必须在数据字典的数据流层有定义且定义里的每个组成项都能在上游数据存储或外部实体数据中找到来源。状态转换图里出现的每一个状态值必须出现在“订单状态”数据项的取值列表中。有人状态图里写了“已支付”数据字典里却只有“已预订”这就是明显的断链。DFD里每个数据存储至少要对应ER图里的一个实体反过来ER图里的核心实体也至少要出现在一个数据存储里。每个状态迁移的触发事件在DFD的输入数据流中必须能找到对应的数据载体。例如“支付成功”事件数据字典里要有“支付结果通知”或“订单状态变更请求”这条数据流。这一轮检查做完四张图才真正成套。很多指导老师第一遍看课设不看实体也不看加工直接拿状态图里的状态值去数据字典里找找不到就直接扣分。所以请在交图前把上述五条当作验收清单逐项打勾。5. 避坑五连课程设计图件中最常见的五个翻车点这一章不说理论只说我在帮课程小组拆图、改图过程中反复踩过的坑。每一条都是“现象—原因—解决”的结构你在画图时照着比对就好。5.1 ER图联系线画成蜘蛛网现象旅客、旅行社、航空公司、机票信息、取票通知五个实体之间画了十几条连线连“航空公司—旅行社”都直接连上整张图密密麻麻根本没法读。原因画图时没有先判断两个实体之间是否存在直接业务关系只要业务上“沾边”就拉一条线。实际上很多联系是间接的通过中间实体就能表达。解决先列关系矩阵只保留有直接数据交换的实体对。航空公司和旅行社之间的代售关系通过“机票信息”这个中间实体就能表达不需要多画一条线如果题目明确要求记录“某个旅行社代售某航空公司机票”的代理关系那就新增“代售关系”实体而不是画一条无差别的线。判断标准一句话这条线不经过中间实体能不能解释出具体业务动作和数量基数解释不出来就不要画。5.2 顶层DFD里多画了“取票通知”这个盒子现象顶层图里出现四个外部实体旅客、旅行社、航空公司、取票通知。看起来好像没毛病毕竟系统确实产出了取票通知。原因把“系统画给别人的数据”误当成了“系统外部的人”。取票通知是系统内部加工后输出的一张凭证它不主动和系统交互也不能独立发起数据流。解决记住外部实体的三个条件独立于系统、能主动发起或接收数据、不受系统内部控制。取票通知三个条件一个都不满足。顶层图就三个外部实体旅客、旅行社、航空公司。如果取票通知也算外部实体那“帐单”“机票清单”是不是每个都要画一个盒子显然不成立。这层想通就能避免一系列重复盒子的错误。5.3 状态转换图画满了“正在检索”“正在出票”现象状态框里全是“正在查询航班”“正在生成通知”整张状态转换图看起来和流程图、DFD没什么区别。指导老师一眼就看出来你没理解状态建模。原因把加工动作直接搬进了状态框没有区分“对象的状态”和“系统的动作”。状态转换图的建模对象是订单不是系统CPU的忙碌情况。解决用“能不能停留五分钟”这个方法删掉假状态。订单可以“待支付”五分钟可以“已出票”好几天所以它们是状态订单不可能“正在检索”五分钟要么瞬间完成要么报错所以它不是状态。画完图后从头扫一遍看到“正在”“开始”“进行中”这类词直接改掉。如果你要表达系统内部处理顺序那是流程框图的事状态图管不了。5.4 数据字典没有类型、长度和取值范围现象数据字典里只有“订单订单号旅客信息航班信息”这样的中文组合表达式问“订单号几位数”“订单状态有哪几个值”回答不出来。原因把数据字典当成名词解释表没有认识到它本质上是给后续数据库设计提供依据的字段规范。解决给每一个关键数据项补上类型、长度、取值范围。订单号就写char(16)前8位日期、后8位流水号订单状态就写明只有“待支付、已支付、已出票、已取票、已取消”这几个合法值。你写不出来的字段数据库大概率也建不出来。指导老师问“旅客编号在哪定义”你直接把数据字典那一行指给他看比现编一个答案强得多。5.5 ER图、DFD、状态图字段各说各话现象ER图里旅客实体有“工作单位”但DFD里预订请求数据流没带这个字段状态图里也没有任何状态与它相关数据字典里更查不到。整份材料各图之间对不上。原因画图时没有一份统一的字段主表ER图归ER图画DFD归DFD画想到哪画到哪。解决建一张“字段主表”把系统所有字段的中文名、英文名、类型、长度、属于哪个实体、出现在哪条数据流全记在一张表里。之后画任何一张图字段都从主表里取不在主表里的字段不允许出现在图上。这比画完四张图再回头检查效率高很多。如果你已经画完了就用4.3节那五条交叉检查逆推把不一致的地方修掉。提示这五个坑有前后连带关系。我最常犯的是先画完ER图就急着画DFD结果字段不一致。建议按“ER—DFD—状态图—数据字典”的顺序画画完再做一轮反向检查。6. 答辩前的一页纸讲法用数据走查把四张图串成业务闭环图全画好之后最容易被忽略的一件事是“讲图”。答辩时你只有三五分钟把整套设计说明白如果按PDF顺序从ER图讲起大概率只讲到第二张图时间就到了。我习惯把四张图压成一条业务主线讲法如下先在黑板上从左到右写下三个外部实体——旅客、旅行社、航空公司中间写系统方框。开讲第一句话固定为“旅客提交预订请求系统查询航班确认订单后把售出机票信息同步给旅行社同时生成取票通知返回给旅客。”这句话把顶层DFD的主干数据流全带出来了。接下来按五个步骤展开每一步只讲一句话并指向对应图件步骤内容用哪张图一句话示例第一步定边界顶层DFD系统外部只有旅客、旅行社、航空公司第二步摆角色ER图旅客订票、公司供票、旅行社代售、取票通知作为交付凭证第三步看流转0层DFDP1到P4四个加工把预订请求变成取票通知第四步盯状态状态转换图一份订单按“待支付→已支付→已出票→已取票”走完生命周期第五步查定义数据字典所有数据流和订单状态取值在字典里都有定义这套讲法最实用的地方在于它不是背图而是顺着数据走。答辩前我还会做最后一轮“数据走查”——拿一笔具体的订单比如“某旅客本周五从A城订一张到B城的机票”从顶层图的预订请求进入沿着DFD走一遍。每经过一条数据流查一次数据字典有没有定义每到一个状态变化查一次状态转换图有没有这条迁移每碰到一个数据存储查一次ER图有没有对应实体。三分钟走完这笔订单整套图的断链就全部现形。有一次我帮某课程小组过图发现他ER图里有“支付记录”实体但DFD里没有对应的数据流状态图也没有“支付成功”这个触发事件。我让他拿一笔订单沿数据走查走一遍走到“待支付”那一站他自己就愣住了因为订单停在待支付后没有任何路径能往前走。后来他补了支付回调数据流状态图也加了“支付成功”迁移整套图才真正闭环。从那以后我每次交课设图之前都强制自己走一遍这条数据主线翻车率从肉眼可见降到基本为零。希望帮到你。本文还有配套的精品资源点击获取