学生选课系统DFD绘制实战:从顶层图到数据字典
2026/9/18 20:50:20 网站建设 项目流程

简介:学生选课系统DFD图.doc提供了一套基于数据流图(DFD)的软件工程课程设计参考文档,面向需要完成系统分析、绘制逻辑模型的高校学生与开发人员。文档重点展示顶层DFD图和第一层DFD图,清晰界定管理员、教师、学生三类外部实体,并围绕用户登录、选课通知、教师开课、学生选课、成绩管理等环节,梳理出课程信息、选课信息、成绩信息、课程安排等关键数据流,便于理解系统边界、功能分解以及后续数据库与模块设计。资源是单个doc文件,大小仅23KB,无需解压多文件即可直接查阅和编辑;已有4139人学习/下载。内容覆盖登录异常处理、选课通知流程、开课申请、成绩录入与查询等细节,对撰写系统分析说明书或准备课程设计答辩有较强参考价值。

1. 为什么画学生选课系统的DFD图而不是先写代码

接手“学生选课系统”这类课程设计或毕业设计,最容易犯的错不是技术选型,而是拿到需求就开数据库表。等到功能写完才发现学生到底是跟“课程”交互还是跟“教师开课记录”交互,选课通知和数据流方向全乱。数据流图(Data Flow Diagram,简称DFD)的价值就在这里:它用外部实体、过程、数据流、数据存储四类元素把系统边界和职责先固定下来。顶层图回答“谁在用系统”,第一层图回答“系统里到底有几件事”。这份文档恰好给出了管理员、教师、学生三个外部实体,以及登录、选课管理、教师开课、学生选课四个一级过程,适合直接作为后续数据库设计和模块划分的依据。适合正在写课程设计文档、需要画 DFD 图但是对分解粒度拿不准的从业者参考。

2. 顶层DFD图:划定系统边界与识别三个外部实体

2.1 顶层图读图逻辑:方框、圆、箭头各代表什么

顶层DFD又被称为上下文图(Context Diagram),它的作用只有一个:定义系统的边界。在这张图里,整个系统被画成一个圆(Gane-Sarson符号)或一个矩形(Yourdon/DeMarco符号),外部实体放在圆或矩形外面,实体与系统之间的箭头表示数据流。箭头方向一旦画错,后面的数据字典和接口设计都会跟着错。

这份文档里的顶层图采用了经典的三外部实体结构:管理员、教师、学生。这个结构本身没有歧义,但要注意一个细节:外部实体是“人”还是“角色”?在这个项目里两者重合,因为管理员只做系统管理,不参与选课流程;教师是开课和成绩录入的主体;学生是选课行为的主体。如果某个系统里教师同时也要选课,那就必须把教师拆成两个角色实体,否则数据流图会混乱。课程设计中大部分情况不需要拆,但你要清楚这个判断逻辑。

2.1.1 外部实体的数据责任划分

把三个实体的输入输出数据流整理清楚,比直接动笔画图更重要。整理方式如下:

外部实体提供给系统的数据系统返回给实体的数据
管理员教师/学生账号信息、课程参数(人数、时间)、选课通知录入结果反馈、课程统计信息
教师登录凭证、开课申请、学生成绩评定选课通知、已开课程安排、选课学生名单
学生登录凭证、个人信息、选课操作、改选操作选课通知、全部选修课列表、个人课表、成绩信息

这张表直接对应顶层DFD中的每条箭头。画顶层图时,箭头只需要标到“系统”这个整体,标到具体过程是下一层图的事。

2.2 用 PlantUML 复现顶层 DFD 图

画正式文档里的 DFD 图,常见做法是用 Visio 或 draw.io 手绘,但需要反复改边界时,文本化的 PlantUML 更适合版本管理。下面的代码用 actor 表示外部实体,usecase 表示系统整体,箭头方向与文档中的顶层数据流方向保持一致。

@startuml left to right direction skinparam rectangle { BackgroundColor #FEFEFE } actor "管理员" as admin actor "教师" as teacher actor "学生" as student rectangle "学生选修课管理系统" as system admin --> system : 录入教师/学生信息\n分配账号密码\n设定课程人数与时间 teacher --> system : 用户名密码\n开课申请\n成绩评定 student --> system : 用户名密码\n个人信息\n选课与改选 system --> admin : 录入结果\n课程统计信息 system --> teacher : 选课通知\n课程安排\n学生选课名单 system --> student : 选课通知\n选修课列表\n个人课表\n成绩信息 @enduml

这段代码里的left to right direction决定布局方向为从左到右,适合外部实体较多的情况。\n用来在多行数据流标签上做换行。有一点要留意:PlantUML 默认把 actor 画成小人,课程设计文档如果要求严格规范,建议导出图后在 Visio 里把 actor 改成矩形框再提交。顶层图的核心是数据流方向,不是图形样式。

3. 第一层DFD图:按角色拆解成四个过程的数据流建模

3.1 第一层分解的依据与过程划分

第一层DFD的任务是把顶层图里那个“系统”圆拆成若干个子过程。拆分的依据不是代码模块,而是业务功能域。这份文档给出的分解结果是四个过程:用户登录、选课系统管理(管理员侧)、教师开课、学生选课。每个过程都要遵守一条规则:至少有一条输入数据流和一条输出数据流,否则它是一个不完整的过程。

四个过程的划分逻辑很清晰。用户登录是独立过程,因为它承担身份验证和密码修改功能,被另外三个过程共用;选课系统管理是管理员侧操作,负责发布选课通知、创建课程、指定任课教师、设定人数和开课时间、分配账号密码;教师开课过程处理申请开课、浏览课程安排、查询选课学生名单、录入和统计成绩;学生选课过程处理个人信息维护、浏览选修课、选课、查看课表、改选、查看成绩。四者之间还有联动:选课通知驱动教师开课,教师开课完成后驱动学生选课。

3.2 用户登录过程的建模细节

用户登录过程虽然简单,但最容易在DFD上画漏错误分支。文档里明确提到“用户名、密码错误或不匹配时反馈错误提示”,这在DFD里是一条独立的数据流,从过程流向外部实体,方向是从系统到用户。很多初画DFD的人只画“用户名密码”这一条输入流,把错误反馈漏掉,后面做界面原型时才补,结果数据字典和测试用例全部要返工。

登录过程的数据流至少包括四条:用户输入的用户名密码(输入)、账号密码校验结果(输出)、错误提示(输出)、密码修改请求与结果(输入输出)。这四条流在图上的起点和终点都要明确。密码正确与错误的处理分支是否要在第一层就画出来?不建议,那是第二层或第三层细化时的事,第一层保持“登录过程接收凭证、返回结果”即可,过度细化会让DFD变成流程图。

3.3 选课系统管理员侧的过程建模

这个过程的输入输出相对复杂,需要特别关注数据流与数据存储的关系。管理员执行录入操作后,数据要保存到存储中,而不是直接流给教师或学生。常见的错误是把“课程信息”画成从管理员直接指向学生,正确的画法应该是:管理员发送录入课程信息,过程把数据写入课程信息存储,学生浏览时从课程信息存储读取数据。

第一层图里这个过程建议包含以下数据流:

数据流名称起点终点数据内容
录入信息管理员选课系统管理教师/学生个人信息
账号分配信息选课系统管理用户登录/系统存储账号与初始密码
课程创建信息选课系统管理课程信息存储课程名称、任课教师、人数、时间
选课通知选课系统管理教师/学生通知文本

账号分配这个数据流的终点要特别注意。分配账号密码本身是管理员发起的,但生成后的账号信息应该进入系统存储,而不是重新流给学生。DFD里如果出现“管理员 → 选课系统管理 → 学生”的账号流程,等于默认管理员需要主动告知每个学生账号,实际系统里通常是学生自己初始化密码,所以正确的流是写入存储,登录时再读取。

3.4 教师开课与学生选课过程的对照关系

这两个过程可以放在一起检查,因为它们之间的数据流是典型的“生产者-消费者”关系。教师开课过程产出“课程安排”和“学生选课情况”,学生选课过程消费“课程安排”并产出“所选课程信息”。两张图放在一起时,必须保证一方输出的数据流名称与另一方输入的数据流名称一致,这个过程在DFD术语里叫数据流一致性检查。

@startuml left to right direction actor "管理员" as admin actor "教师" as teacher actor "学生" as student rectangle "系统" { usecase "1.0 用户登录" as login usecase "2.0 选课系统管理" as sysmgr usecase "3.0 教师开课" as teach usecase "4.0 学生选课" as stuchoose } teacher --> login : 用户名密码 student --> login : 用户名密码 teacher --> teach : 开课申请\n成绩评定 teach --> teacher : 课程安排\n学生选课名单 student --> stuchoose : 选课操作\n个人信息\n改选申请 stuchoose --> student : 选修课列表\n个人课表\n成绩信息 admin --> sysmgr : 录入教师/学生信息\n课程参数 @enduml
3.4.1 教师开课的边界条件

教师开课过程有前置条件:必须收到选课系统发布的通知后才允许申请。这个约束在DFD里无法表达,它是数据字典里的业务规则。画图时,可以通过课程信息存储的写入顺序来暗示:选课系统管理先写入课程信息,教师开课过程后续读取。如果文档需要更严谨的表达,在数据字典中为“选课通知”数据流附加说明“教师仅在收到通知后才可发起开课申请”。

成绩处理也归到教师开课过程里,此时学生选课情况数据流作为输入进入过程,成绩信息作为输出流向存储。这类“输入旧数据、输出新数据”的过程在DFD里属于更新型过程,它的数据流数量一定大于等于二,不会出现只有输出没有输入的情况。第一层图做到这个粒度已经足够支撑数据库设计了。

4. 从DFD图到可落地的实现:数据字典与表结构映射

4.1 数据字典里必须出现的元素

DFD图本身不能直接指导编码,真正连接画图和建表的是数据字典。数据字典为图中的每一条数据流和数据存储定义结构。以学生选课系统为例,至少需要定义以下几类条目:数据流(用户名密码、开课申请、选课操作)、数据存储(学生信息、教师信息、课程信息、选课记录、成绩信息)、数据项(学号、课程编号、开课时间、容量、成绩)。

条目定义的粒度参考:数据项定义说明类型和长度,数据流定义说明来源和去向,数据存储定义说明包含的数据项。做过一次完整的数据字典后,再往MySQL或PostgreSQL里建表会省很多改表时间。文档没有提供存储命名,我沿用常见规范给出一份可直接使用的数据字典版本。

4.2 数据存储与数据库表的映射关系

DFD里的数据存储不等于数据库物理表,但可以一对一映射。

DFD数据存储数据库表名关键字段来源过程
学生信息存储studentsno, sname, password管理员录入
教师信息存储teachertno, tname, password管理员录入
课程信息存储coursecno, cname, tno, capacity, schedule, semester管理员创建 + 教师申请
选课记录存储scsno, cno, selected_time学生选课
成绩信息存储scoresno, cno, score, submit_time教师评定

注意课程信息存储和教师开课申请之间的关系:课程创建由管理员发起,任课教师由管理员指定,教师申请开课只是补充申请,这两条业务规则决定了course表的tno由管理员写入而不是教师写入。如果把教师申请建模为teacher表向course表写数据,就需要单独的course_apply表,第一层DFD的粒度不支持这个细节,留到第二层处理即可。

4.3 用SQL验证数据流方向

画完图、定完字典后,建议立刻建表验证一遍数据流是否闭环。下面这份SQL只取核心字段,重点在验证关系,不追求完整约束。

CREATE TABLE student ( sno CHAR(10) PRIMARY KEY, sname VARCHAR(50) NOT NULL, password VARCHAR(64) NOT NULL DEFAULT '123456' ); CREATE TABLE teacher ( tno CHAR(6) PRIMARY KEY, tname VARCHAR(50) NOT NULL, password VARCHAR(64) NOT NULL DEFAULT '123456' ); CREATE TABLE course ( cno CHAR(6) PRIMARY KEY, cname VARCHAR(100) NOT NULL, tno CHAR(6) NOT NULL, capacity INT CHECK (capacity > 0), schedule VARCHAR(100), semester VARCHAR(20), FOREIGN KEY (tno) REFERENCES teacher(tno) ); CREATE TABLE sc ( sno CHAR(10), cno CHAR(6), selected_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (sno, cno), FOREIGN KEY (sno) REFERENCES student(sno), FOREIGN KEY (cno) REFERENCES course(cno) ); CREATE TABLE score ( sno CHAR(10), cno CHAR(6), score DECIMAL(5,2) CHECK (score >= 0 AND score <= 100), submit_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (sno, cno), FOREIGN KEY (sno) REFERENCES student(sno), FOREIGN KEY (cno) REFERENCES course(cno) );

这段SQL的snocno分别是学生账号和课程编号,主键设计决定了选课记录表的粒度是“一个学生只能选同一门课一次”。如果业务要求允许同一学生重复选同一门课,主键就要增加选课批次字段,这时DFD的数据流“选课信息”需要扩展为“选课信息+批次号”,不修改DFD直接改表,会留下文档与实现不一致的隐患。CHECK约束这里用了两处,分别限制课程容量大于0和成绩在0到100之间,数据流图里无法表达这些规则,必须落到数据字典和建表语句中。

5. 画完DFD图的三个自检技巧:平衡、命名与一致性

5.1 检查父子图是否平衡

顶层图里的系统圆被分解成第一层的四个过程后,必须满足一个条件:父图的全部输入输出数据流,必须完整出现在子图中。所谓“完整”是名称和方向都要对应。选课系统文档中,顶层图里“课程安排”这条系统到教师的数据流,在第一层图里要能从教师开课过程向外找到;“登录成功”这类隐含信息也不能凭空出现在子图里,它的父亲在顶层图里不存在。

检查建议:不要在图上肉眼对箭头,把顶层图每个数据流抄成一行,然后把第一层图所有数据流抄成第二列,逐条比对。补漏方法是给每个过程的输入和输出编号,过程1.0的所有输出编号以F1开头,这样父图子图的数据流序号天然可追溯,写数据字典时也更顺手。

5.2 检查数据流命名是否用了动词

DFD最容易被扣分的地方是数据流名字起得像文件名。正确命名是“用户名密码”而不是“用户数据”,是“选课申请”而不是“选课信息表”。判断标准很简单:看这条流能不能变成一条动作,帮助系统完成一件有明确结果的事。下面的Python脚本可以辅助一致性检查,适合图最终定稿前跑一遍。

# 数据流检查脚本,手动维护流清单后运行 flows = [ ("admin", "2.0 选课系统管理", "录入信息"), ("2.0 选课系统管理", "course_store", "课程创建信息"), ("teacher", "3.0 教师开课", "开课申请"), ("3.0 教师开课", "teacher", "课程安排"), ("student", "4.0 学生选课", "选课操作"), ("4.0 学生选课", "student", "个人课表"), ] def process_edges(flows, process): in_edges = [(src, flow) for src, dst, flow in flows if dst == process] out_edges = [(dst, flow) for src, dst, flow in flows if src == process] return in_edges, out_edges for p in ["2.0 选课系统管理", "3.0 教师开课", "4.0 学生选课"]: in_e, out_e = process_edges(flows, p) print(f"{p}: 入 {len(in_e)} 条, 出 {len(out_e)} 条") for e in in_e: print(f" 进入 <- {e[0]}: {e[1]}") for e in out_e: print(f" 流出 -> {e[0]}: {e[1]}")

这段脚本可以快速发现没有入边或没有出边的孤立过程,也能在增删数据流后校验影响范围。脚本以(源, 目标, 名称)三元组维护图结构,process_edges函数按过程名筛选出入边和出边。实际使用时把flows列表替换成你的最终数据流清单即可。

5.3 一致性自查表

最后一个技巧是维护一张“数字一致性”表格,放在文档附录中,答辩和评审时可以直接说明绘图依据。表里记录三组数字:外部实体数量、第一层过程数量、关键存储数量。学生选课系统的数字是3个外部实体、4个过程、5个存储。哪个数字变了,说明文档哪一层的功能描述需要更新。这类细节往往比图本身更能体现建模功底。把这份清单放进提交前的checklist里,通常能比反复看图更快发现边界漏画或数据流名称不一致的问题。

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

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

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

立即咨询