简介:《图书管理系统 软件工程》面向软件工程课程设计、毕业设计及信息系统开发初学者,提供一套贯穿需求分析、系统设计、数据库设计、编码实现与测试的文档范例,可用于梳理图书管理业务、规划系统模块和撰写项目报告。压缩包内为1个doc文档,约535KB,篇幅集中、便于检索,适合作为课程作业或小型管理系统的参考底稿。目前已有442人学习。文档目录覆盖绪论、系统目标与性能要求、读者借还书和系统管理员维护等用例图、时序图、类关系,以及数据库E-R图、数据表创建与连接、Visual Basic 6.0和Rational Rose实现思路、登录窗体详细设计等内容,可帮助读者快速搭建报告框架、对照关键建模产物,并补齐需求到实现的文档链条。目录按软件工程阶段组织,也适合准备课程答辩、检查文档完整性和复盘小型系统开发流程的读者参考。
1. 从「三类角色、八张表」倒推:这套图书管理系统软件工程文档解决什么问题
「图书管理系统」这个题目每年都有人做,难点在于需求分析里画的用例,系统设计里有没有对应的类;类图的属性,数据库里有没有对应的字段。这份图书管理系统软件工程文档把 VB6.0、SQL Server 2000、Rational ROSE 这条技术栈走完整,从读者、图书管理员、系统管理员三类角色出发,落到八张数据表和一套 ADO 连接层,中间用用例图、时序图、类图、E-R 图把需求到实现串起来。适合要交软件工程课程设计或毕设的人照着搭结构,也适合代码已经写完、正在补文档的人对照补漏。
2. 需求分析落地:三类参与者切成九个用例,再用时序图和类图接住
需求分析最怕写成功能清单。把「能借书、能还书、能查书」一条条列出来,读起来像产品说明,画用例图时又会发现每个功能都能再拆三层,最后图上一团线。我一般按参与者切,每个参与者只保留他真正发起或确认的动作,细粒度的检索方式、字段校验都塞进用例描述的业务规则里,图就干净了。
2.1 角色切分:读者、图书管理员、系统管理员各自的边界
原文把需求定义写得比较散,归拢之后三类角色的诉求是这样的:读者要能按书名、编号、作者查藏书,要能借、续借、还,要能看自己的资料和借阅记录;图书管理员是系统的高频使用者,核心只有两件事,处理借出、处理返还,顺带维护图书信息;系统管理员管的是「人和书」的基础数据,注册新读者、改读者信息、注销读者,增加书目、更新书目、下架过期图书,另外还要能发布超期名单和馆藏统计。
按这个边界切出来的用例清单如下,编号在后面的追溯矩阵里还会用到:
| 编号 | 用例 | 主要参与者 | 说明 |
|---|---|---|---|
| UC-01 | 系统登录 | 三类角色 | 共用一个入口,登录后按角色跳不同主界面 |
| UC-02 | 查询图书信息 | 读者 | 书名、图书编号、作者三种检索条件 |
| UC-03 | 查询个人借阅信息 | 读者 | 在借书目、应还日期、是否超期 |
| UC-04 | 借阅图书 | 读者、图书管理员 | 读者发起,管理员在借书窗口确认 |
| UC-05 | 续借图书 | 读者 | 未超期且未续借过的记录延一期 |
| UC-06 | 归还图书 | 读者、图书管理员 | 管理员确认,系统计算逾期天数 |
| UC-07 | 读者信息维护 | 系统管理员 | 注册、修改、注销 |
| UC-08 | 图书信息维护 | 系统管理员 | 新增书目、增加复本、下架 |
| UC-09 | 系统状态维护 | 系统管理员 | 超期名单、馆藏统计、罚款汇总 |
这里有取舍。原文对读者的检索写得很细,「按书名、编号、作者」三种方式,如果每种画一个用例,用例图会膨胀到十几个椭圆,但读者真正做的决策只有一个:我要不要借这本书。所以 UC-02 只保留一个,三种检索方式写进用例描述的前置规则。反过来,借阅和归还不能合并成「借还书」,因为前者要校验读者资格,后者要算逾期和罚款,异常流完全不同,合并了答辩时说不清。
2.2 从用例到时序图:以「管理员添加图书」为例拆交互
用例图说明谁做什么,时序图说明内部怎么响应。原文给了七个时序图,添加图书、添加读者、删除更新图书、删除更新读者、处理借书、处理还书、读者查询,全覆盖了,但真正需要画细的是带分支的那几个。
以系统管理员添加图书为例,消息序列是四步:维护窗口收到add item(),向书目数据发find(string)查重,返回 true 或 false,再决定是否调create(integer, title)。很多人画时序图习惯直接从界面画到数据库再画回来,三个箭头结束,看不出业务判断在哪。这四个消息的价值在于把「先查重、再入库」这个规则显式化了——find返回 true 说明同名书目已经存在,此时不该新建书目,只应该给这本书加一个复本;返回 false 才走create。
对应的实现骨架放在窗体的事件处理里,逻辑很短但顺序不能错:
' frmBook.frm —— 添加图书按钮的处理 Public Function AddItem(ByVal sTitle As String, ByVal sBookNo As String) As Boolean ' 第一步永远是查重,同名书目存在就只加复本,不新建书目记录 If TitleExists(sTitle) Then AddCopy sTitle, sBookNo ' 复本数 +1,写入新的条码号 AddItem = True Else CreateTitle sTitle, sBookNo ' 新建书目 + 第一条复本 AddItem = True End If End FunctionTitleExists参数是书名,走的是 title 表的唯一性检查;AddCopy的第二个参数是条码号,也就是每本实体书的唯一标识;CreateTitle一次写两张表,书目信息和第一条馆藏记录,这两步必须放在同一个事务里,否则会出现「有书目没复本」的空记录,读者永远借不到。
把添加图书的用例描述补全,文档里就有东西可查了:
| 项目 | 内容 |
|---|---|
| 用例编号 | UC-04 借阅图书 |
| 参与者 | 读者(发起)、图书管理员(确认) |
| 前置条件 | 读者已登录且状态正常;图书状态为在馆 |
| 主流程 | 1 读者提交借阅请求;2 系统校验读者状态与在借数量;3 系统校验图书状态;4 管理员确认;5 写借阅记录并把图书状态置为借出;6 返回应还日期 |
| 异常流 | 2a 读者有超期未还或欠费,拒绝并提示原因;3a 图书已借出,提示可预约;5a 写库失败,事务回滚 |
| 后置条件 | borrow 表新增一条记录,book.state 变为借出 |
时序图上的每个箭头,都应该能在主流程或异常流里找到出处,找不到就说明这个箭头是凑数的。
2.3 类图与多重性:为什么要把 title 和 item 拆成两个类
原文列了六个核心类:item(书目/馆藏)、title(书名)、loan(借出)、reader(读者)、librarian(图书管理员)、administrator(系统管理员)。这个拆分是整套设计里最值得讲的一点。同一本《数据结构》,馆里可能有五本,读者借走的是其中某一本实体书,不是「《数据结构》」这个概念。所以 title 表示书目信息(书名、作者、出版社、分类号),item 表示具体的那一本(条码号、入库日期、价格、状态),一个 title 对应一到多个 item,借阅记录 loan 关联的是 item 而不是 title。
读者类的定义可以直接落成 VB 的类模块,属性和行为一一对应:
' clsReader.cls —— 读者类,只放属性和与自身相关的行为 Private mCardNo As String ' 证件号码,和 user 表主键同名 Private mName As String Private mSex As String Private mStatus As String ' 正常 / 冻结 / 注销 Private mBorrowCount As Integer ' 当前在借数量 Public Property Get CardNo() As String CardNo = mCardNo End Property Public Property Let CardNo(ByVal v As String) mCardNo = v End Property ' 能否借阅:状态正常且在借数未达上限(默认 5 本) Public Function CanBorrow() As Boolean CanBorrow = (mStatus = "正常") And (mBorrowCount < 5) End FunctionmCardNo的命名特意和数据库字段user_cardnumber做了一层对应,后面对字段的时候不容易错位;CanBorrow里把上限 5 写成常量更规范,这里为了代码短直接硬编码,实际做的时候会放到配置表里,因为不同馆的借阅上限不一样。
类之间的关系,用文字描述清楚比画一堆箭头更有用:reader 与 loan 是一对多,一个读者可以有多条借阅记录;item 与 loan 也是一对多,一本书历史上会被借多次;librarian 与 loan 是「处理」关系,一条借还记录一定有一个经办人;administrator 与 title、item、reader 都是「维护」关系。写论文的时候把这几句话放在类图下面,比只丢一张图要稳得多。
3. 数据库设计:八张表、一张 E-R 图和一层 ADO 封装
数据库这一章是文档里最容易注水的地方,把建表语句贴一遍就交差。其实评委看的是三件事:字段口径统一没有,实体和联系拆对了没有,连接层有没有把访问逻辑收口。这三件事做不好,后面代码写得再漂亮也会在答辩时被追问。
3.1 表结构与字段字典:八张表各自管什么
正文里点明要建八张表,落到字段清单上是七张有明确字段定义,第八张是书籍类别表,功能说明里提到的类别编号、类别名称、关键词、备注恰好就是它的字段。八张表的职责划分如下:
| 表名 | 用途 | 主键 | 关键字段 |
|---|---|---|---|
| book | 馆藏图书 | bookname(建议改为 bannercode) | 书名、条码号、分类号、作者、出版社、出版日期、入库日期、价格、状态、简介 |
| bookkind | 书籍类别 | kindno | 类别编号、类别名称、关键词、备注 |
| borrow | 借阅记录 | 无(联合唯一) | 证件号码、图书编号、借书日期、还书日期、是否续借 |
| user | 读者信息 | user_cardnumber | 姓名、性别、身份、地址、注册日期、有效期、状态 |
| login | 登录账号 | user_name | 用户名、密码、角色 |
| punishment | 罚款记录 | user_cardnumber | 证件号码、罚款总额 |
| libraryer | 图书管理员 | libr_name | 姓名、性别、地址 |
| admin | 系统管理员 | Adminname | 姓名、性别、地址 |
book 表的字段最密,这里有几个设计点值得在文档里写一句。原文把bookname(书名)设成主键,bannercode(图书编号)设成唯一约束,实际做的时候我一般反过来:条码号做主键,书名只做普通索引。原因很实际,同一书名会有不同版本、不同出版社,书名做主键会导致重复入库失败,而且 varchar 类型的主键会被 borrow 表当外键带着走,长度一长索引就重。这个改动在文档里写清楚动机,反而是加分项。
borrow 表的字段少但每条都关键:
| 列名 | 类型 | 允许为空 | 说明 |
|---|---|---|---|
| user_cardno | varchar(20) | 否 | 证件号码,对应 user 表主键 |
| bannercode | varchar(30) | 否 | 图书编号,对应 book 表唯一约束 |
| borrowdate | date | 否 | 借书日期 |
| receivedate | date | 是 | 还书日期,未还时为空 |
| renew | varchar(2) | 是 | 是否续借,是/否 |
receivedate允许为空是这套设计的关键:一条记录只要还书日期为空,就代表这本书还在读者手上;还书日期一填,这条记录就归档成历史。判断「某本书是否可借」不用去翻 book.state,直接看 borrow 表里有没有未归还记录就够了,多一条校验路径能挡掉不少脏数据。
3.2 E-R 图到物理表:联系怎么落成外键和独立表
E-R 图上有四个实体:读者、图书、图书管理员、系统管理员。读者和图书之间是多对多,一个人借多本书,一本书被多人借过;图书管理员和借阅之间是一对多,一个人处理多笔借还;系统管理员和读者、图书之间都是维护关系,一对多。
多对多不能直接落表,必须拆成独立的联系表,这就是 borrow 表存在的原因,borrowdate、receivedate、renew是联系上的属性,不是任何一个实体的属性。这一步在文档里画成 E-R 图之后,一定要补一句话说明「读者与图书的多对多联系被拆解为 borrow 表」,否则评委无法从图上看出你是懂还是蒙的。
另一个需要交代的是冗余字段。原始需求里写着借书信息要包含读者姓名和书籍名称,也就是 borrow 表里除了两个外键还存了姓名和书名。这是典型的反范式设计,好处是借阅列表页不用 join 三张表,查询快;代价是读者改名、图书改名之后历史记录会对不上。我的处理是:姓名和书名作为展示冗余字段存下来,但所有业务校验一律走外键,姓名只用于显示,改读者信息时不做级联更新,因为借阅记录本来就是历史快照,当时叫什么名字就该记什么名字。这个理由在文档里写清楚,比删掉冗余字段更站得住。
3.3 ADO 连接层:连接串别写死,访问逻辑收口到一个模块
原文的连接类把连接串放在F://conn.txt里读,这个做法在开发机上没问题,换台机器或者刻成光盘交作业的时候就崩了,盘符根本不存在。我一般改成放在程序目录下的 ini 文件里,用App.Path取相对路径。
' modDB.bas —— 全局数据访问模块,所有窗体都通过它拿连接 Private mConn As ADODB.Connection Public Function OpenDB() As Boolean Dim sIni As String sIni = App.Path & "\db.ini" ' 程序目录,不依赖盘符 ' 连接串从 ini 的 [DB] 段读,切换服务器只改配置不改代码 mConn = New ADODB.Connection mConn.ConnectionTimeout = 5 ' 连不上 5 秒就报错,别让界面卡死 mConn.CommandTimeout = 10 mConn.Open ReadIni(sIni, "DB", "ConnStr") OpenDB = (mConn.State = adStateOpen) End Function Public Function QueryParam(ByVal sSQL As String, ParamArray vArgs() As Variant) As ADODB.Recordset Dim cmd As ADODB.Command Set cmd = New ADODB.Command Set cmd.ActiveConnection = mConn cmd.CommandType = adCmdText cmd.CommandText = sSQL AppendParams cmd, vArgs ' 把参数按顺序追加成 adVarChar 参数 Set QueryParam = cmd.Execute End FunctionOpenDB里两个超时参数是有意义的:ConnectionTimeout设 5 秒,数据库服务没启动时界面不会假死几分钟;CommandTimeout设 10 秒,防止某条统计 SQL 拖住整个窗体。QueryParam用ADODB.Command而不是字符串拼接,参数化之后单引号、日期格式这些老问题基本就消掉了,后面登录和借书的代码全部走这条通道。
借书这条业务在库层面是两条语句,一条改状态,一条写记录,必须放在同一个事务里:
-- 借书:条件更新 + 插入借阅记录,两条语句同一事务 UPDATE book SET state = '借出' WHERE bannercode = ? -- 参数 1:图书编号 AND state = '在馆'; -- 只有还在馆的才更新得动 INSERT INTO borrow (user_cardno, bannercode, borrowdate, receivedate, renew) VALUES (?, ?, ?, NULL, '否'); -- 参数 2、3、4:证件号、条码号、借书日期第一条语句的AND state = '在馆'是整个借书逻辑的安全阀。如果两个管理员同时给同一本书办借出手续,第二条执行时更新影响行数会是 0,程序据此回滚并提示「该书已被借出」,不需要加锁也不用担心并发。这个技巧在后面排查章节还会提到,它比「先查再写」可靠得多。
4. 系统实现:VB6 工程结构、登录窗体与借还书事务
实现这一章如果只贴界面截图,文档价值会掉一半。评委真正想知道的是:代码有没有分层,窗体里是不是塞满了 SQL,业务规则写在哪。VB6 虽然没有现代框架,但用标准模块加类模块,照样能把三层的意思做出来。
4.1 工程结构与模块划分:窗体、类模块、标准模块各管一摊
工程建的是一个标准 EXE,按职责拆成三块,和三层架构大致对应:
| 文件 | 类型 | 职责 |
|---|---|---|
| frmLogin.frm | 窗体 | 登录界面,只做输入采集和跳转 |
| frmMain.frm | 窗体 | 主框架,按角色挂不同菜单 |
| frmBook.frm | 窗体 | 图书信息维护,增删改查 |
| frmBorrow.frm | 窗体 | 借书、还书窗口 |
| frmReader.frm | 窗体 | 读者信息维护 |
| clsReader.cls | 类模块 | 读者属性与 CanBorrow 等自身规则 |
| clsBook.cls | 类模块 | 图书属性与状态流转 |
| clsLoan.cls | 类模块 | 借阅记录,含逾期天数计算 |
| modDB.bas | 标准模块 | 连接、参数化查询、事务封装 |
| modCommon.bas | 标准模块 | 日期格式化、字符串校验、密码哈希 |
窗体层只做三件事:取值、调业务函数、显示结果。任何一条 SQL 都不允许出现在窗体里,全部走 modDB。这条规矩看起来死板,但它的好处在改需求的时候会立刻体现——借期从 30 天改成 60 天,只需要改 clsLoan 里的一个常量,不用去翻十几个窗体找硬编码的数字。
4.2 以登录窗体为例的详细设计思路
登录看着简单,其实是整个系统里分支最多的一个界面:三类角色共用一个入口,登录成功后要跳到不同主界面,还要把当前用户信息存到全局变量供后续窗体使用。校验顺序也有讲究,先空值、再账号、再密码、最后分流,顺序错了会泄露「哪些账号存在」这种信息。
' frmLogin.frm —— 登录按钮 Private Sub cmdLogin_Click() Dim rs As ADODB.Recordset Dim sUser As String, sPwd As String sUser = Trim(txtUser.Text) sPwd = Trim(txtPwd.Text) ' 1. 空值校验,别把空串丢给数据库 If Len(sUser) = 0 Or Len(sPwd) = 0 Then MsgBox "用户名和密码不能为空", vbExclamation Exit Sub End If ' 2. 参数化查询,用户名带单引号也不会把 SQL 拼坏 Set rs = QueryParam("SELECT user_name, psw, role FROM login WHERE user_name = ?", sUser) If rs.EOF Then MsgBox "账号或密码错误", vbExclamation ' 不区分「账号不存在」和「密码错」 rs.Close: Exit Sub End If ' 3. 密码比对走哈希,库里不存明文 If StrComp(rs("psw"), HashPwd(sPwd), vbBinaryCompare) <> 0 Then MsgBox "账号或密码错误", vbExclamation rs.Close: Exit Sub End If ' 4. 记下当前身份,按角色分流 gUser = rs("user_name") gRole = rs("role") rs.Close Unload Me Select Case gRole Case "reader": frmReaderMain.Show Case "librarian": frmLibMain.Show Case "admin": frmAdminMain.Show Case Else: MsgBox "账号角色配置异常,请联系管理员", vbCritical End Select End SubHashPwd在 modCommon 里实现,登录表里存的是哈希值而不是明文,这一点在文档里写一句就够,但在答辩现场被问到「密码怎么存的」时能直接接住。gUser、gRole是标准模块里的全局变量,后续窗体靠它们判断当前是谁在操作,借还书窗口的经办人字段就是从gUser取的。vbBinaryCompare保证密码比对区分大小写,默认的文本比较在某些区域设置下会把大小写抹平。
4.3 借书与还书:条件更新、事务和逾期计算
借书的核心不是插入一条记录,而是「确保这本书在插入的瞬间还在馆」。前面 SQL 里那句AND state = '在馆'就是这个保证,落到 VB 代码里要配合事务使用:
' clsLoan.cls —— 借书,返回空串表示成功,否则返回失败原因 Public Function Borrow(ByVal sCard As String, ByVal sBookNo As String) As String Dim cmd As ADODB.Command Dim lAffected As Long Dim dDue As Date ' 读者资格校验放在事务外,读操作不需要占锁 If Not GetReaderByCard(sCard).CanBorrow() Then Borrow = "读者状态异常或已达借阅上限" Exit Function End If On Error GoTo Rollback ' 任何一步出错都回滚 mConn.BeginTrans ' 条件更新:只有仍在馆的书才更新得动,影响行数为 0 说明已被借走 Set cmd = New ADODB.Command Set cmd.ActiveConnection = mConn cmd.CommandText = "UPDATE book SET state='借出' WHERE bannercode=? AND state='在馆'" cmd.Parameters.Append cmd.CreateParameter("p1", adVarChar, adParamInput, 30, sBookNo) cmd.Execute lAffected If lAffected = 0 Then mConn.RollbackTrans Borrow = "该书已被借出或已下架" Exit Function End If ' 写借阅记录,应还日期 = 借书日期 + 借期 30 天 dDue = DateAdd("d", 30, Date) Set cmd = New ADODB.Command Set cmd.ActiveConnection = mConn cmd.CommandText = "INSERT INTO borrow(user_cardno,bannercode,borrowdate,receivedate,renew) " & _ "VALUES(?,?,?,NULL,'否')" cmd.Parameters.Append cmd.CreateParameter("p1", adVarChar, adParamInput, 20, sCard) cmd.Parameters.Append cmd.CreateParameter("p2", adVarChar, adParamInput, 30, sBookNo) cmd.Parameters.Append cmd.CreateParameter("p3", adDate, adParamInput, , Date) cmd.Execute mConn.CommitTrans Borrow = "" Exit Function Rollback: mConn.RollbackTrans Borrow = "借阅失败:" & Err.Description End Function参数说明一下:sCard是读者证件号,sBookNo是图书条码号,两者都不允许为空;借期 30 天写成DateAdd里的常量,实际项目会从 bookkind 表按类别取,不同类别借期不同;lAffected是Execute返回的影响行数,它是判断并发冲突的唯一依据,不能省。
还书反过来,先更新借阅记录的还书日期,再把图书状态改回在馆,同时算逾期:
' 还书时计算逾期天数,超过借期按天计罚 lOverdue = DateDiff("d", rs("borrowdate"), Date) - 30 If lOverdue > 0 Then lFine = lOverdue * 0.2 ' 每天 0.2 元,按各自馆的规定改 mConn.Execute "UPDATE punishment SET sum_account = sum_account + " & lFine & _ " WHERE user_cardnumber = '" & sCard & "'" End If这段里的 0.2 是演示参数,写文档时把它标成「可配置项」就行。逾期计算用buyDate到当前日期的天数差减借期,而不是去比应还日期,因为应还日期在库里根本没存——它是算出来的。这个设计选择也要在文档里提一句:应还日期属于派生数据,不入库,避免借期调整后历史记录全部失真。
5. 常见问题排查:这套老技术栈最容易翻车的五个点
VB6 加 SQL Server 2000 这套组合,出问题的位置高度集中。下面五条是我见过最多的,每条按现象、原因、解决写,照着排查能省掉大半天。
5.1 数据库与连接层
连接串写死盘符,换台机器就起不来。现象是程序在自己电脑上好好的,拷到别人机器或者答辩现场的电脑上,一启动就报「未找到提供程序」或者直接闪退。原因就是连接串放在F://conn.txt这类绝对路径里,那个盘符在别的机器上根本不存在。解决方式是改成程序目录下的 ini,用App.Path拼相对路径,并且在OpenDB里加一个文件存在性判断,读不到配置就弹一个明确的提示框,而不是让程序静默退出。
字段名冒出两套写法,SQL 报「列名无效」。现象是某条查询在开发时通过,换一个窗体调用就报列名不存在。原因是设计阶段同一张表在文档里写user_cardnumber,代码里写成user_cardno,borrow 表又用了user_cardno,三处不一致。解决办法是建一份字段字典,主键统一用xxx_no后缀,外键和主键同名,写完立刻用 grep 把所有出现的位置过一遍。这个坑我踩过一次,改到凌晨两点,血泪经验就是字段字典要在建表之前定,不是建完之后补。
日期在中文区域设置下变成 1900-01-01。现象是借书日期存进去变成 1900 年,或者插入时报「将 varchar 转换为 datetime 时出错」。原因是 VB 的日期字面量和 SQL 的日期格式在区域设置不同时解析不一致,#2024/3/5#这种写法换个环境就不认。解决办法是所有日期一律走参数化,参数类型用adDate而不是拼字符串;实在要拼,格式固定成yyyy-mm-dd。
5.2 业务逻辑与文档一致性
同一条码被两个人同时借走。现象是借阅记录里出现两条同一本书、还书日期都为空的记录,书架上只有一本。原因是代码写成了「先 SELECT 查状态,判断在馆,再 UPDATE」,两步之间有空隙。解决办法就是 4.3 里那种条件更新,UPDATE ... WHERE state='在馆',看影响行数决定成败,必要时再给 borrow 表加一个「未归还记录唯一」的约束兜底。
用例图和类图对不上,答辩被追着问。现象是评委指着用例图问「这个续借用例,你类图里哪个方法实现的」,翻半天找不到。原因是需求分析和系统设计是分两次写的,中间没有对照。解决办法是做一张追溯矩阵,用例编号一列,对应的类和方法一列,UC-05 续借对应clsLoan.Renew(),写不出来就说明设计漏了。这张表在文档末尾放一页,答辩时能救命。
还有一条不算坑但值得提:密码明文存 login 表。这在课程设计里很常见,改起来也就十几行代码,加个哈希函数,登录时比对哈希值。这一点被问到的时候,答「知道应该哈希,演示环境为了便于查看数据暂时保留明文」也行,但代码里有哈希会更有说服力。
6. 验收与答辩:用三条主流程和一页类图讲完整套系统
验收这件事,很多人理解成「功能点跑一遍」,其实评委看的是系统的一致性。我给自己的验收清单是这样的,每一条都有明确的判定方式:
| 验收项 | 判定标准 | 检查方式 |
|---|---|---|
| 需求覆盖 | 九个用例至少八条能在界面上走通 | 按用例编号逐个点 |
| 模型一致 | 类图里每个类在代码中有对应文件 | 对照类图数文件 |
| 表结构完整 | 八张表全部建好,主键唯一约束齐全 | 打开企业管理器逐表看 |
| 借书主流程 | 正常借书成功,图书状态变为借出 | 新读者 + 在馆图书 |
| 借书异常流 | 已借出的书再次借阅被拒绝 | 同一本书连借两次 |
| 还书与逾期 | 逾期记录能算出天数并写罚款表 | 手工把借书日期改早 |
| 权限隔离 | 读者登录看不到维护菜单 | 三类账号各登一次 |
| 数据一致性 | 还书后图书状态回到在馆 | 还书后查 book.state |
答辩的技巧,说到底就一句话:别按界面上有什么讲,按数据怎么流讲。我一般准备三条主线,第一条借书,从读者点借阅开始,经过资格校验、条件更新、写借阅记录,最后落到 book.state 变成借出;第二条还书与逾期,从管理员确认还书,到算天数、写罚款、状态复位;第三条管理员维护,新增书目、加复本、下架,讲清楚 title 和 item 为什么分开。三条线讲完,系统的骨架就出来了。
讲的时候把类图打印成一页 A4 拿在手上,讲到借书就用手指从 reader 划到 loan,再划到 item,嘴里说「这条记录关联的是具体某一本,不是书名」。评委看到你的模型和代码是同一套东西,后面基本不会再为难你。反过来,如果类图只是论文里的一张插图,讲的时候完全不提,那它就成了摆设,问一句就露馅。
还有个小细节:答辩前把数据库里的演示数据清一遍,留三五个读者、十来本书、两条历史借阅记录。数据太干净显得没跑过,数据太乱自己讲的时候都找不到重点。我吃过一次亏,演示库里有一百多条乱七八糟的测试记录,讲借书讲到一半翻不到那本目标书,场面很尴尬。从那以后我每次答辩前都强制走一遍「清库、灌演示数据、三条主线各跑一次」的流程,跑通了才敢上台。
这套图书管理系统软件工程的文档结构,从需求到数据库到实现再到验收,每一层都有可以对照检查的落点,照着改改字段和业务规则就能用在自己的题目上。希望帮到你。
本文还有配套的精品资源,点击获取