毕业设计——基于SSM+shiro+maven+bootstrap的图书馆管理系统设计与实现

基于SSM+shiro+maven+bootstrap的图书馆管理系统设计与实现

完整项目地址:https://download.csdn.net/download/lijunhcn/88430554

1. 设计题目

图书管理系统

2. 设计目的

通过对图书管理系统的系统分析、系统设计、编码和调试等工作的实践,熟悉管理信息系统的开发过程、设计方法及相关编程技术,熟练掌握数据库设计的基本理论及方法。

3. 设计任务

要求完成一个具有一定实用价值的图书管理系统,主要任务包括:
在Microsoft SQL Server 2000/2005/2008环境下建立图书管理系统所使用的数据库,利用企业管理器或查询分析器建立各种数据库对象,包括:数据表、视图、约束、存储过程和触发器等;
掌握ADO.NET编程技术,对MS SQL Server数据库进行连接和操纵;
掌握使用C#语言开发一个数据库应用系统的基本方法和步骤,熟悉一些基础功能的实现方法,如:数据维护(插删改等操作),数据查询、浏览和Excel导出,统计与报表,用户登录和权限管理等。
了解C/S或B/S应用程序的多层体系结构及三层架构方案设计思想,了解迭代式开发,熟悉面向对象设计方法及其分析与设计过程,了解UML文档及其开发过程中的作用。
指导书说明:
(1)开发环境与目标:微软 C#、SQL Server,基于C/S结构的Windows应用程序。
(2)仅给出了部分功能的设计与实现,以说明面向对象分析与设计的一般方法以及关键编程技术,其它功能部分需要自己完成。
(3)为减少篇幅和降低阅读门槛,没有追求使用标准的UML设计文档和术语。

4. 设计准备

4.1 系统准备
操作系统:Windows xp/7/8
数据库系统:SQL Server 2005/2008/2012
客户端开发工具:Visual Studio 2005/2008/2010/2012
4.2 知识准备
熟悉SQL Server 2005/2008/2012的使用;
熟悉C#、ASP.NET语言及其数据库编程技术。
了解:迭代式开发过程、UML设计文档、设计模式;以及图书馆相关业务知识
4.3 迭代式开发
迭代式开发(统一过程UP) 系统开发被组织成一系列固定的短期(一段为2-6周)小项目,称为迭代;每次迭代都产生可执行的系统。每次迭代都包括计划、需求、分析、设计、编码、测试等过程以及文档编写工作;第一次迭代考虑系统的核心功能,随后的迭代逐步扩展系统功能;每次迭代的成果(含需求、分析、设计、代码和文档等)均为下一次迭代的工作基础,直至满足最终需求。这种开发过程是基于面向对象方法的。

5. 系统分析

系统边界与约定
(1)系统限定在实体书库的借阅和管理等业务范围;
(2)不考虑图书馆的电子书库、订购、情报、人事管理等业务;
(3)不考虑图书馆的跨区分布情况,如长江大学图书馆包括多个校区图书馆;
(4)不考虑图书的通借通还,如长江大学读者可在湖北省高校任何一家图书馆借还图书;
(5)不考虑珍藏图书的借阅业务;
(6)暂不考虑与校园一卡通系统的外部接口。一卡通系统为外部系统(外部参与者),卡内记录有身份及相关信息,该系统负责身份验证工作。
(7)期刊库和论文库的借阅和管理等业务可作为二期项目目标,视本系统使用情况而定。
需求概要
(1) 图书管理系统的基本功能需求包括:读者管理、图书管理、借阅管理、用户登录与用户管理等;其它功能需求包括:读者查询与预约借书*、统计与报表*、数据备份*、书架管理*、期刊管理*、期刊借阅*、论文管理*、论文借阅_等。(_ 表示留待以后的迭代周期完成,下同)
(2) 相关领域概念:借书证(读者)、图书、借还书记录。
(3) 系统外部参与者:读者、借书证管理员、图书管理员、借阅管理员、系统管理员。将图书馆工作人员划分为借书证管理、图书管理、借阅管理等三类人员;系统管理员负责数据库和软件系统管理,包括各类管理员用户的创建和授权、数据库备份等工作。

系统分析目标
找出系统用例,书写用例文档,建立领域模型(概念模型)。
[用例] use case,或译为使用案例、用况。是指为了完成一个领域目标或任务,提供一个或多个场景来说明其在系统内部与外部(人员或外部系统等)之间的交互过程。如办理借书证、借书、还书、用户登录等均为用例;而借阅管理不是用例,因为它包括多个任务;读者可否借书也不是用例,因为它不是一个领域任务或业务目标。参见“参考资料01 用例.doc”。
用例是一个事件流,一个事件对应一个系统操作;如借书用例中的“根据借书证号查询读者信息”、“根据借书证号查询超期未归还图书”、“判断读者可否借书”、“判断图书是否在馆”、“确认借书”等均为事件或系统操作。
找出系统用例后,对每个用例的交互操作过程进行描述(即书写用例),通过用例发现领域概念及其属性,并建立领域模型(即概念模型)。用例与领域模型的建立过程一般是交互进行的,并相互参考、印证和补充完善。
通过用例发现事件或系统操作,可进行下一步的设计和实现工作,是系统设计主要内容。
在面向对象方法的开发过程中,分析与设计没有明显的界限,只是侧重面不同而已。
5.1 读者管理
读者管理即借书证管理,包括的业务(即用例)有:办理借书证、借书证变更、借书证挂失、解除挂失、补办借书证、注销借书证、批量办理新生借书证*等。(*表示留待迭代2及以后完成,下同。完成此类用例文档并实现其功能者,教师可酌情加分)
借书证(读者)可分为2种类别:教师、学生。
借书证(教师)=借书证号、姓名、性别、所在单位、办证日期、照片等。
借书证(学生)=借书证号、学号、姓名、性别、专业、班级、办证日期、有效期、照片等。其中,有效期由学生类别决定,本科生4年、专科生3年、硕士生3年等。
相关业务规则:(1)读者凭借书证借书;(2)教师最多借书12本,借书期限最长为60天,可续借2次;学生最多借书8本,借书期限最长为30天,可续借1次;(3)处于挂失、注销状态的读者不能借书;(4)未归还图书者不能注销其借书证。
分析:增加读者类别概念,统一并简化读者信息,采用教师属性项,而学生可在所在单位填写班级,学生特有读者信息可留待以后的开发周期处理。可得到2个概念:读者、读者类别。
读者=借书证号、姓名、性别、所在单位、读者类别、办证日期、照片等。(另可加:电话、邮箱等)
读者类别=读者类别号、类别名称、可借书本数、可借书天数、可续借次数。
思考:学生借书证的有效期如何处理?

  1. 办理借书证
    用例名称:办理借书证
    迭 代:1 (说明:第1次迭代期间的用例文档)
    参 与 者:借书证管理员(或系统管理员)、读者
    综 述:用例起始于读者来到借书证管理办公室,管理员给读者办理新借书证。
    触 发 器: (说明该用例的触发条件)
    前置条件:登录用户具备读者管理权限。
    过程描述: (标题名或为:基本流程、基本事件流、主要成功场景等)
  2. 管理员输入:读者类别、所在单位、姓名。
  3. 点击“查询”。
  4. 系统查询读者信息,并显示查询结果。
  5. 管理员判断该读者是否已办理借书证,若是,则可取消办证过程。(人工操作)
  6. 管理员输入读者信息:读者类别、姓名、性别、所在单位、办证日期、照片等。(类别、姓名、单位等可预置为过程1中输入值,办证日期可预置为系统日期)
  7. 确认办证。
    后置条件:创建新的读者对象,并具有新的借书证号;系统记录读者信息。
    业务规则:借书证号应具有唯一性。
    待解决问题:
  8. 打印借书证;
    注 释:未考虑校园一卡通做为借书证使用的情况
    作者与日期: 2013-7-24日,LSH,版本号1.0
    思考:读者分成教师和学生2个概念时,用例有何不同?
  9. 变更借书证
    变更借书证类别、有效期、所在单位等,以及其它信息;借书证号不可更改。
    用例(略 要求自己完成)
  10. 挂失借书证
    用例名称:挂失借书证
    参 与 者:借书证管理员、读者
    综 述:用例起始于读者来到借书证管理办公室,管理员给读者办理借书证挂失。
    前置条件:登录用户具备读者管理权限,且读者已经存在
    过程描述:
  11. 输入借书证号,或输入读者的类别、单位、姓名。
  12. 点击“查询”。
  13. 系统查询并显示读者信息。
  14. 找到其借书证,且读者状态为有效。
  15. 确认挂失。系统修改读者状态为挂失。
    后置条件:系统记录读者信息。
    业务规则:借书证挂失后禁止读者借书。
    分析:修改读者概念,增加属性“借书证状态”;并修改办理借书证用例。
  16. 解除挂失
    用例名称:解除挂失
    参 与 者:借书证管理员、读者
    综 述:用例起始于读者来到借书证管理办公室,管理员给读者办理解除借书证挂失。
    前置条件:登录用户具备读者管理权限,且读者已经存在
    过程描述:
  17. 输入借书证号,或输入读者的类别、单位、姓名。
  18. 点击“查询”。
  19. 系统查询并显示读者信息。
  20. 找到其借书证。
  21. 确认解除挂失。(前提:读者状态为挂失)
  22. 系统修改读者状态为有效。
    后置条件:系统记录读者信息。
  23. 补办借书证
    补办借书证过程:创建新借书证(复制原读者信息,但借书证需取新号,其它信息不变),并将原借书证的借阅记录转移到新证上,原借书证注销。
    用例(略 自己完成)
  24. 注销借书证
    相关规则:有未归还图书者不能办理注销。
    用例(略 自己完成)
  25. 批量办理新生借书证*
    从教务管理系统导入新生信息,系统生成借书证信息,管理员核实后办理借书证。
    用例(略,思考:联机在线导入,离线导入)
  26. 读者类型管理
    从系统的功能完整性来看,还存在一个隐性的功能需求:读者类型管理,即读者类型信息的插、删、改、查等数据维护操作。
    用例(略 要求自己完成)
    5.2 图书管理
    包括业务(用例):图书编目*、新书入库、图书信息维护、图书变卖与销毁处理*等。
    图书信息=书号、书名、作者、出版社、出版日期、ISBN、分类号、语言、页数、单价、内容简介、图书封面、图书状态等;(图书状态包括:在馆、借出、遗失、变卖、销毁)
  27. 图书编目*
    新书入库前,图书管理员对图书进行图书编目工作,即根据该馆的现有图书分类目录信息编写新书的分类号,需要时根据图书分类法增加新的图书分类条目。
    图书信息= … 、分类号、…
    图书分类目录=分类号、分类名。图书分类信息主要用于统计,如中文图书分类条目:

分类号 分类名
TP 自动化技术、计算机技术
TP3 计算技术、计算机技术
TP31 计算机软件
TP311 程序设计、软件工程
TP312 程序语言、算法语言
TP311.13 数据库理论与系统
TP311.131 数据库理论
新书分类号,如图书“C#高级编程(第7版)”可编为:TP312/3033.2
图书分类概念暂不考虑, 可留待以后开发周期处理。
用例名称:图书编目(略)
2. 新书入库
用例名称:新书入库
参 与 者:图书管理员
前置条件:登录用户具备图书管理身份和权限
过程描述:

  1. 输入或系统生成起始书号(BkNO)。
  2. 输入:图书信息(书名、作者、出版社、出版日期、语言、页数、单价、ISBN、分类号、内容简介等)、入库数量(N,N>=1)、入馆日期。
  3. 确认图书入库。
  4. 图书馆工作人员对图书进行贴书签(分类号)、印书号(或条形码)、盖图书馆印章。
  5. 图书上架。
    后置条件:创建N个图书对象,书号分别为BkNO、BkNO+1、…、BkNO+N-1,这N本图书的状态均修改为在馆;系统记录图书信息。
    注 释:BkNO+N可作为下一次新书入库的起始书号。
    思考:图书信息划分为2个概念是否更为合理?
    馆藏图书目录=书名、作者、出版社、出版日期、ISBN、分类号、语言、页数、单价、内容简介、图书封面、入库数量、入馆日期
    图书=书号、分类号、图书状态
  6. 图书信息维护
    图书信息的查、删、改等信息维护操作。
    用例名称:图书信息维护(略 自己完成,提示:先查找,再删改)
  7. 在馆图书变卖与销毁处理*
    长期没有借阅记录且失去保存价值的图书可以进行变卖或销毁处理。
    用例名称:在馆图书销毁和变卖处理(略)
    5.3 借阅管理
    包括业务用例:借书、续借、还书等。还书过程涉及超期罚款、遗失图书罚款等业务规则。
    罚款规则:(1)超期罚款规则 应罚款金额=超期天数_罚款率,罚款率=0.05元/天,罚款率可能随时间或读者类别而变化;实际罚款金额<=应罚款金额,根据实际情况可以进行减免。(2)遗失罚款规则 遗失图书应罚款金额=3_图书单价;实际罚款金额在(1_图书单价,3_图书单价)之间。(3)遗失罚款规则优先于超期罚款规则。
    借书记录=借书证号、书号、借书操作员、借书日期、应还日期
    续借记录=借书证号、书号、续借操作员、续借日期、应还日期,续借次数
    还书记录=借书证号、书号、还书操作员、还书日期、应还日期,超期天数、应罚款金额,实际罚款金额
    分析:借书记录、续借记录、还书记录等信息可合并为借阅记录,续借可舍去部分信息。借阅历史记录应该长期保存在数据库中,以便于统计分析,另外,读者对一本书可能多次借阅,故借阅信息应该增加一个标识项:借书顺序号。
    借阅信息=借书顺序号、借书证号、书号、借书操作员、借书日期、应还日期,续借次数、还书操作员、还书日期,超期天数、应罚款金额,实际罚款金额
  8. 借书
    用例名称:借书
    参 与 者:借阅管理员、读者
    综 述:用例起始于读者带着图书来到图书借阅大厅,管理员给读者办理借书手续。
    前置条件:登录用户具备借阅管理权限。
    过程描述:
  9. 管理员输入借书证号,点击“查询读者”。
  10. 系统查询读者信息、未归还图书信息(含超期),并进行显示。
  11. 系统判断读者可否借书(借书证状态为有效,已借书数量小于可借书数量,不存在超期未归还图书)。若不可借书,则禁止借书。
  12. 管理员输入待借图书的书号,点击“查询图书”。
  13. 系统查询,并显示图书信息。
  14. 系统判断图书是否在馆,若不在馆,则禁止借书。
  15. 管理员点击“借书”。
  16. 系统完成以下操作:
    8.a 创建借阅记录对象(借书顺序号由系统自动产生,借书证号和书号为上述输入值,借书操作员=登录用户,借书日期=系统日期,应还日期=系统日期+可借书天数,续借次数=0,还书日期=NULL,还书操作员=NULL),并标记为未归还;
    8.b 修改读者对象的已借书数量+1;
    8.c 修改图书状态为借出;
    后置条件:系统记录借阅对象、读者对象、图书对象。
    业务规则:(1)借书证状态为挂失、注销者不能借书;(2)借书数量不能超过可借书数量;(3)有超期未归还图书者不能借书。
    注 释:未归还图书状态可采用还书日期为空(NULL)来标记,或另加属性表示是否还书。
    修改读者信息:增加“已借书数量”;修改用例办理借书证:后置条件中,已借书数量=0。
    练习:修改用例以满足读者携带多本图书进行借书的要求。
  17. 续借
    用例名称:续借
    参 与 者:借阅管理员、读者
    前置条件:登录用户具备借阅管理权限、图书状态为借出
    过程描述:
  18. 输入待续借图书书号。
  19. 系统查询并获取图书对象、未归还状态的借阅记录对象、及其读者对象,并进行显示。
  20. 系统判断可否续借(续借次数<可续借次数, 读者状态为有效)。
  21. 点击“续借”。
    后置条件:修改借阅记录对象(续借次数+1,应还日期+=可借书天数),图书状态为借出,并保存到数据库中。
    业务规则:(1)借书证状态为挂失、注销者不能续借;(2)续借次数不能超过可续借次数。
    注 释:续借前后图书状态应为借出
  22. 还书
    还书用例需要处理超期罚款、遗失图书罚款处理2种情况。
    用例名称:归还图书(略 要求自己完成,完成罚款处理者,教师可酌情加分)
    5.4 用户登录与用户管理
    包括用例:用户登录、密码修改、用户管理*,为本系统的基础和主要功能。
    用户包括2类:读者、管理员。其中,管理员用户权限是4种角色的组合:借书证管理、图书管理、借阅管理、系统管理;系统管理员负责所有管理员用户及其权限的管理,借书证管理员负责读者管理(即借书证管理)。
    管理员是读者,但读者不一定是管理员;读者与管理员间存在(1对0…1)联系。
    读者信息+=密码。
    管理员信息=用户号、用户名、密码、管理角色
    管理角色设计:可采用4位二进制,借书证管理(0001)2=1、图书管理(0010)2=2、借阅管理(0100)2=4、系统管理(1000)2=8。如表示图书管理和借阅管理权限:2+4=6;判断7是否具备图书管理权限:7位与2,即(0111)2位与(0010)2=(0010)2,表示有此权限。
    分析:将管理员信息合并到读者中,可简化概念,此时,非管理员的管理角色(0000)2=0。好处:简化用户登录用例;坏处:概念不够清晰,给用户管理带来不便。第1个迭代周期采用简化概念设计。另外也可用4个逻辑数据项分别表示4个管理角色。
    读者信息+=密码、管理角色。需修改用例办理借书证(自己完成)。
  23. 用户登录
    用例名称:用户登录
    参 与 者:读者或管理员
    前置条件:无
    过程描述:
  24. 输入用户号(即借书证号)、密码;密码采用掩码“*”号显示。
  25. 点击“登录”。
  26. 系统根据借书证号获取读者对象。
    3a. 未获取读者对象时,显示无此用户,转入1;
    3b. 密码未匹配时,显示密码错误,并清空密码,转入1;
  27. 进入系统主程序界面。
    后置条件:根据登录用户权限显示或隐藏相应的系统功能(菜单等)。
    待解决问题:
  28. 挂失或注销借书证者不能登录。
    注 释:该登录用户(读者)对象应为全局可见
    系统功能与用户角色之间的关系参见“表1 系统功能与用户角色关系表”。
  29. 密码修改
    用例名称:修改密码
    参 与 者:用户
    综 述:用户登录后修改自己的登录密码。
    …(略)
  30. 用户管理*
    用例名称:用户管理
    参 与 者:系统管理员、图书馆工作人员
    综 述:系统管理员对图书馆工作人员进行权限管理。
    前置条件:登录用户为系统管理员,图书馆工作人员需先办理借书证
    过程描述:
  31. 输入借书证号,或输入读者的类别、单位、姓名。
  32. 点击“查询”。
  33. 系统查询,并显示读者信息。
  34. 找到借书证后,设置该读者的管理角色。
  35. 确认完成。
    后置条件:修改读者的管理员角色,系统记录读者信息。
    注 释: 管理角色有4种:借书证管理、图书管理、借阅管理、系统管理
    5.5 读者查询与预约借书*
    读者(非管理员用户)的功能需求,包括用例:未归还图书查询与续借*(含超期、即将到期查询操作)、预约借书*(含在馆图书查询操作)等。
    该类读者所使用的功能最好是采用web程序实现,Web程序功能可包括:读者登录、密码修改、未归还图书查询与续借*、预约借书_等。
    用例名称:未归还图书查询与续借(略,思考:与续借用例有不同吗?)
    用例名称:预约借书(略,思考:对借书用例有何影响?可在迭代2完善借书用例)
    5.6 统计与报表_
    包括:馆藏图书统计、借阅情况统计、借阅时段统计等等。
    馆藏图书统计可按图书类别、入馆时间统计图书数量、金额等,可得图书分布情况;
    借阅情况统计可按单位(含专业、年级)、图书类别、借阅时间(年、学期、月份)等统计借阅次数和天数,统计结果可作为订购新书的参考依据;
    借阅时段统计按工作日(星期一、二、、、)和时段(8:00-8:30、8:30-9:00、、、)统计借还书次数,可得各时段的借阅工作量,并可依此安排借阅管理人员。
    注:涉及OLAP(联机分析处理)技术,开发者需理解“多维数据模型”及相关概念。
    用例(略)
    5.7 数据备份*
    用户备份是对SQL Server数据库进行备份,由系统管理员操作。
    5.8 系统功能与用户角色
    表1 系统功能与用户角色关系表
    序号 系统功能 借书证管理 图书管理 借阅管理 系统管理 读者
    1 读者管理 √ (√)
    2 图书管理 √
    3 借阅管理 √
    4 用户登录 √ √ √ √ √
    5 密码修改 √ √ √ √ √
    6 用户管理 √
    7 读者预约 √ √ √ √ √
    8 统计与报表 √ √ √ √
    9 数据备份 √
    10
    5.9 领域模型
    领域概念小结
    读者=读者号(借书证号)、姓名、性别、所在单位、电话、邮箱地址、办证日期、照片、借书证状态、已借书数量、密码、管理角色。(借书证状态:有效、挂失、注销)
    读者类别=读者类别号、读者类别名称、可借书数量、可借书天数、可续借次数,罚款率,证件有效期。
    图书=书号、书名、作者、出版社、出版日期、ISBN、分类号、语言、页数、单价、内容简介、图书封面、图书状态。(图书状态包括:在馆、借出、遗失、销毁、卖出)
    借阅信息=借书顺序号、读者号、书号、借书操作员、借书日期、应还日期、续借次数、还书操作员、还书日期,超期天数、应罚款金额、实际罚款金额。
    领域模型

图1 图书管理系统概念模型(V1)

重要提示:在领域模型建立后、以及数据库设计完成后,均应检查所有的用例文档(检查重点:事件流、前置条件和后置条件),检查两者的一致性,发现缺漏点及矛盾之处,并进行修正。

6.系统设计与实现
6.1 数据库设计与实现

  1. 读者类别表(TB_ReaderType)
    序号 字段名 数据类型 说明
    1 rdType SmallInt 读者类别【主键】
    2 rdTypeName Nvarchar(20) 读者类别名称【唯一、非空】
    3 CanLendQty Int 可借书数量
    4 CanLendDay Int 可借书天数
    5 CanContinueTimes Int 可续借的次数
    6 PunishRate Float 罚款率(元/天)
    7 DateValid SmallInt 证书有效期(年)【非空,0表示永久有效】
  2. 读者信息表(TB_Reader)
    序号 字段名 数据类型 说明
    1 rdID Int 读者编号/借书证号【主键】
    2 rdName nvarchar(20) 读者姓名
    3 rdSex nchar(1) 性别,男/女
    4 rdType SmallInt 读者类别【外键TB_ReaderType】【非空】
    5 rdDept nvarchar (20) 单位代码/单位名称
    6 rdPhone nvarchar(25) 电话号码
    7 rdEmail nvarchar(25) 电子邮箱
    8 rdDateReg datetime 读者登记日期/办证日期
    9 rdPhoto image 读者照片
    10 rdStatus nchar(2) 证件状态,3个:有效、挂失、注销
    11 rdBorrowQty Int 已借书数量(缺省值0)
    12 rdPwd nvarchar (20) 读者密码(初值123),可加密存储
    13 rdAdminRoles SmallInt 管理角色,0-读者、1-借书证管理、2-图书管理、4-借阅管理、8-系统管理,可组合
    分析提示:(1)可将管理员另外建表,与读者信息分开单独进行设计。(2)单位rdType可以采用名称,若采用代码则需另建一张表:单位代码与名称对照表,这样便于按单位统计。(3)管理角色(rdAdminRoles)也可设计为4个bit类型字段。
  3. 图书信息表(TB_Book)
    序号 字段名 数据类型 说明
    1 bkID Int 图书序号【标识列,主键】
    2 bkCode Nvarchar (20) 图书编号或条码号(前文中的书号)
    3 bkName Nvarchar(50) 书名
    4 bkAuthor Nvarchar(30) 作者
    5 bkPress Nvarchar(50) 出版社
    6 bkDatePress datetime 出版日期
    7 bkISBN Nvarchar (15) ISBN书号
    8 bkCatalog Nvarchar(30) 分类号(如:TP316-21/123)
    9 bkLanguage SmallInt 语言,0-中文,1-英文,2-日文,3-俄文,
    4-德文,5-法文
    10 bkPages Int 页数
    11 bkPrice Money 价格
    12 bkDateIn DateTime 入馆日期
    13 bkBrief Text 内容简介
    14 bkCover image 图书封面照片
    15 bkStatus NChar(2) 图书状态,在馆、借出、遗失、变卖、销毁
    说明:bkCode为前文中的书号,这里没有设计为关键字,而增加bkID字段作为表关键字,其原因为:防止新书入库时起始书号输入错误时,因关键字而不易修改。
  4. 借阅信息表(TB_Borrow)
    序号 字段名 数据类型 说明
    1 BorrowID Numeric(12,0) 借书顺序号【主键】
    2 rdID Int 读者序号【外键TB_Reader】
    3 bkID Int 图书序号【外键TB_Book】
    4 ldContinueTimes Int 续借次数(第一次借时,记为0)
    5 ldDateOut DateTime 借书日期
    6 ldDateRetPlan DateTime 应还日期
    7 ldDateRetAct DateTime 实际还书日期
    8 ldOverDay Int 超期天数
    9 ldOverMoney Money 超期金额(应罚款金额)
    10 ldPunishMoney Money 罚款金额
    11 lsHasReturn Bit 是否已经还书,缺省为0-未还
    12 OperatorLend Nvarchar(20) 借书操作员
    13 OperatorRet Nvarchar(20) 还书操作员
    分析提示:借阅信息即用于图书的借还管理,同时又是统计分析的主要信息来源,故要求保持其历史信息。设计时不能以(读者序号+图书序号)为关键字,否则读者不能第二次借阅同一本书了。
  5. 数据库实现
    内容:
    (1) 创建数据库:Library;
    (2) 创建登录名:LibAdmin,密码:123;并设置为数据库Library的dbo;
    (3) 创建上述4张数据表及约束;
    实现方法:
    (1) 采用SQL Server企业管理器手工操作方法完成创建工作;(自己完成)
    (2) 编写SQL脚本文件,并在查询窗口工具中运行并创建;如创建TB_ReaderType表:
    CREATE TABLE [dbo].[TB_ReaderType](
    [rdType] smallint NOT NULL,
    [rdTypeName] nvarchar(20) NOT NULL,
    [CanLendQty] int NULL,
    [CanLendDay] int NULL,
    [CanContinueTimes] int NULL,
    [PunishRate] float NULL,
    [DateValid] smallint NULL DEFAULT ((0)),
    PRIMARY KEY ([rdType]),
    UNIQUE ([rdTypeName])
    )
    GO
    insert into [TB_ReaderType] values(10,‘教师’,12,60,2,0.05,0);
    insert into [TB_ReaderType] values(20,‘本科生’,8,30,1,0.05,4);
    insert into [TB_ReaderType] values(21,‘专科生’,8,30,1,0.05,3);
    insert into [TB_ReaderType] values(30,‘硕士研究生’,8,30,1,0.05,3);
    insert into [TB_ReaderType] values(31,‘博士研究生’,8,30,1,0.05,4);
    GO
    6.2 三层架构简介
    采用三层体系结构,即表示层、业务逻辑层和数据访问层,如图2所示,图中箭头表示调用和依赖关系。

图2 三层架构示意图
表示层(USL):也称UI,提供交互式界面,形式:WinForm或HTML Web界面。
业务逻辑层(BLL):实现业务功能,为表示层提供服务,形式:类库。
数据访问层(DAL):实现数据访问功能(如数据库、文件等数据的读取、保存和更新),为业务逻辑层提供服务,形式:类库。微软公布的SQLHelper类提供了对SQL Server数据库的一般访问方法(JAVA有类似的类或组件)。
实体类(Model):描述一个业务实体的类,也即应用系统所涉及的业务对象。对数据库来讲,每个数据表对应于一个实体类,数据表的每个字段对应于类的一个属性。
表示层、业务逻辑层、数据访问层都依赖于业务实体。各层之间数据的传递主要是实体对象,业务信息封装在实体对象中。
6.3 搭建三层架构解决方案
创建C#应用程序解决方案,包括4个项目:BookManage(Windows窗口应用程序)、BookManage.Model(类库)、BookManage.DAL(类库)、BookManage.BLL(类库)。

  1. 新建项目BookManage(启动项目)
    MS VS菜单:“文件”->“新建”->“项目”,在新建项目窗口中,选择“C#”->“Windows”->“Windows窗口应用程序”,选择项目文件的存储位置,并输入项目名称:BookManage,如图3。
    项目BookManage即为UI层,该项目在VS .NET编译后产生BookManage.exe文件。

图3 新建项目BookManage
2. 添加新项目BookManage.Model
MS VS菜单:“文件”->“添加”->“新建项目”,选择“类库”,输入项目名称,如图4。VS .NET编译后产生BookManage.Model.dll文件(.DLL后缀文件称为动态链接库)。

图4 添加新建项目BookManage.Model
3. 添加新项目BookManage.DAL
操作与BookManage.Model类似,项目名称设置为:BookManage.DAL。VS .NET编译后产生BookManage.DAL.dll文件。
4. 添加新项目BookManage.BLL
操作与BookManage.Model类似,项目名称设置为:BookManage.BLL。VS .NET编译后产生BookManage.BLL.dll文件。至此,解决方案参见图5。

图5 图书管理项目解决方案
5. 设置启动项目和项目引用关系
在解决方案中设置BookManage为启动项目(“BookManage”右键菜单“设为启动项目”)。
项目引用关系如表2所示。如BookManage.BLL项目引用DAL和Model,其设置方法:解决方案中项目“BookManage.BLL”的右键菜单“添加引用”,并按图6进行设置。
表2 项目引用关系。
BookManage BookManage.BLL BookManage.DAL BookManage.Model
BookManage - √ × √
BookManage.BLL - √ √
BookManage.DAL - √
BookManage.Model -

图6 给BookManage.BLL项目添加引用
6.4 类总体设计(迭代1)
实体类、数据访问层类、业务逻辑层类、表示层窗口类的初步设计如表3。
表3 实体类、数据访问层、业务逻辑层的类设计
层 类名 说明
实体类模块
(Model) ReaderType 读者类型实体类
Reader 读者实体类
Book 图书实体类
Borrow 借阅记录实体类
数据访问层
(DAL) ReaderTypeDAL 读者类型数据表访问类(插、删、改、查、存储过程等)
ReaderDAL 读者数据表访问类(插、删、改、查、存储过程等)
BookDAL 图书数据表访问类(插、删、改、查、存储过程等)
BorrowDAL 借阅数据表访问类(插、删、改、查、存储过程等)
SQLHelper 微软提供的对SQL Server数据库进行访问的通用类
业务逻辑层
(BLL) ReaderTypeAdmin 读者类型管理类,实现插、删、改、查等信息维护操作。
ReaderAdmin 读者管理类,实现借书证办理、变更、补办、挂失、解除挂失、注销等用例中的各种系统操作。
BookAdmin 图书管理类,实现图书管理各用例中的系统操作
BorrowAdmin 借阅管理类,实现借书、还书、续借等用例中的系统操作。
UserAdmin 用户管理类,
表示层
(UI) frmLogin 登录窗口类
frmMain 程序主窗口类,含菜单、工具栏、状态栏等
frmReader 读者管理窗口类

6.5 Model层实体类设计
在BookManage.Model项目中添加4个实体类:ReaderType、Reader、Book、Borrow,分别对应4个数据库表。实体类的属性与数据库表结构保持一致(名称、类型);实体类应尽量简单,除了实体对象的复制与比较等方法外,不宜添加过多方法。
其实实体类就是实现ORM。
ORM Object Relational Mapping 对象关系映射,是为了解决面向对象的类,与关系数据库的表之间,存在的不匹配的现象,通过使用描述对象和关系之间映射的元数据,在程序中的类对象,与关系数据库的表之间建立持久的关系,用于在程序中描述数据库表。本质上就是将数据从一种形式转换到另外一种形式。
ORM是一个广义的概念,适应于关系数据库与应用程序之间的各类数据转换,目前有许多自动转换工具可用,如codesmith 等,也可手工书写实体类代码来实现ORM。

  1. ReaderType类
    在Model项目中添加新建项:C#代码类ReaderType.cs,如图7所示。

图7 添加C#代码类文件ReaderType.cs
表字段映射为实体类属性的基本方法(VS 2005及以上版本)如下:
private string _rdTypeName;
public string rdTypeName
{
get { return _rdTypeName; }
set { _rdTypeName = value; }
}
而在VS 2008及以上版本中可简化为:
public string rdTypeName { get; set; }
表4 SQL字段类型与实体类属性类型的映射关系
SQL Server字段类型 DataTable中类型 C#实体类设计属性
nchar, nvarchar, text System.String string
int, smallint System.Int32, System.Int16 int
numeric(12,0) System.Decimal long
datetime System.DateTime DateTime
Float, money System.Single, System.Decimal float
bit System.Boolean bool
image System.Byte[] Byte[]
在VS 2008及以上版本中ReaderType类的实现代码如下:

在VS 2005(含2008及以上版本)中ReaderType类的实现代码如下:

另外,可添加复制构造函数,如下:
public ReaderType(ReaderType rt)
{
this.rdType = rt.rdType;
this.rdTypeName = rt.rdTypeName;
this.CanLendQty = rt.CanLendQty;
this.CanLendDay = rt.CanLendDay;
this.CanContinueTimes = rt.CanContinueTimes;
this.PunishRate = rt.PunishRate;
this.DateValid = rt.DateValid;
}
2. Reader类(略)
3. Book类(略)
4. Borrow类(略)
6.6 DAL层类设计
除SqlHelper外,每个数据库表对应一个DAL层类,主要实现该表的插删改查操作。

  1. SqlHelper类
    在BookManage.DAL项目中添加SqlHelper.cs文件,该类是微软SqlHelper类(参见文件“参考资料03 微软的SQLHelper类(含完整中文注释).cs”)的简化版(有源码提供)。
    SqlHelper类主要包括的成员函数有:打开数据库连接、关闭数据库连接、执行SQL语句、执行存储过程等。
    表5 SqlHelper类(简化版)成员
    1# private static string _strConnection = @“Data Source=LSH-SL400\SQLSERVER; Initial Catalog=Library;User ID=BookManage;Password=123;”;
    <成员属性> -连接SQL Server的字符串(常量)。
    – LSH-SL400\SQLSERVER为服务器名称,可在SQL Server Management Studio的“已注册服务器”中查看(菜单:“视图”->“已注册服务器”)。
    – 需修改为自己的连接。可手动修改,或可采用MS VS的服务器资源管理器得到(菜单:“视图”->“服务器资源管理器”,“数据连接”->“添加连接”)。
    2# private static SqlConnection conn = new SqlConnection(_strConnection);
    <成员属性> -SQL Server数据库连接对象(常量);
    3# private static void OpenConn()
    <成员函数> -打开数据库连接
    4# private static void CloseConn()
    <成员函数> -关闭数据库连接
    5 public static int ExecuteNonQuery(string sql)
    <成员函数> -执行非查询的SQL语句,返回受影响的行数
    – sql指定要执行的SQL语句,
    – 例:sql = “delete from TB_ReaderType where rdType=12”;
    6# public static int ExecuteNonQuery(string sql, SqlParameter[] parameters)
    <成员函数> -执行非查询的SQL语句(带参数),返回受影响的行数
    – 参见:6.6-2中的ReaderTypeDAL.Add() 函数代码
    7 public static object ExecuteScalar(string sql)
    <成员函数> -执行查询语句,返回查询结果中的首行首列
    8# public static object ExecuteScalar(string sql, SqlParameter[] parameters)
    <成员函数> -执行查询语句(带参数),返回查询结果中的首行首列
    9# public static DataTable GetDataTable(string sql, SqlParameter[] parameters, string TableName)
    <成员函数> -执行查询语句(带参数),返回查询结果记录集(DataTable对象)
    – 参见:6.6-2中的ReaderTypeDAL.GetDRByID()函数代码
    10# public static SqlDataReader GetDataReader(string sql)
    <成员函数> -执行查询语句,返回查询结果记录集。SqlDataReader为只读对象,它占用的内存空间比DataTable小的多。
    11# public static int ExecuteStoredProc(string storedProcName, SqlParameter[] parameters)
    <成员函数> -执行非查询的存储过程,返回受影响的行数
    – parameters指定存储过程的函数实参
    – 参见:
    12# public static DataTable ExecuteStoredProc(string storedPrecName, SqlParameter[] parameters, string TableName)
    <成员函数> -执行查询的存储过程,返回查询结果记录集
    – 参见:
    表中标注#为必要的类成员,成员5、7可分别被6、8替代,大家可以试试将成员10改写为带参数的函数。ADO.NET类与相关组件的用法参见“参考资料02 ADO.NET用法.cs”。
  2. ReaderTypeDAL类
    DAL层的类主要实现对应数据表的插、删、改、查等操作,以及存储过程的调用。
    首先,在DAL项目中添加C#代码类文件-ReaderTypeDAL.cs,并在文件中添加引用:
    using System.Data.SqlClient;
    using System.Data;
    using BookManage.Model;
    然后,在ReaderTypeDAL类中添加对表TB_ReaderType记录的插入Add()、删除Delete()、修改Update()等3个方法。

注:带参数SqlParameter[] parameters的SqlHelper.ExecuteNonQuery(sql, parameters)方法,支持带image列的插入和修改SQL语句。

然后,在ReaderTypeDAL类中添加根据关键字查询ReaderType实体类对象的方法GetObjectByID(),这里提取出了另一个方法GetDRByID()。

有2个常用的通用转换方法,采用C#的泛型和反射技术分别实现DataTable和DataRow到实体类对象的转换;算法要求:表记录(DataTable或DataRow)包含了实体类T的所有属性,并且表字段名与T的属性名相同。
可以另建一个C#工程BookManage.Common(公用模块,可被DAL、BLL、UI各层引用,在三层架构图中地位如同Model模块),并将这2个方法放入其中;本例采用的是放入SqlHelper类中。这2个方法的代码如下:

而其它查询方法可在每个用例的UI层设计与实现过程中去发现和完成。
3. ReaderDAL类
在ReaderDAL类中添加对表TB_Reader记录的插入Add()、删除Delete()、修改Update()、根据关键字查询Reader实体类对象GetObjectByID()等方法。函数原型如下:
public static int Add(Reader reader)
public static int Update(Reader reader)
public static int Delete(Reader reader)
public static Reader GetObjectByID(int rdID)
而其它查询方法可在每个用例的UI层设计与实现过程中去发现和完成。
4. BookDAL类(略)
5. BorrowDAL类
添加表TB_Borrow的插入Add()、删除Delete()、修改Update()等3个方法;不必添加GetObjectByID()方法,该表的查询一般是通过书号或读者号(参看借还书等用例)。
6.7 BLL层类设计
BLL层类的成员函数设计,可在实现用例的过程中去发现和完成,用例实现主要包括UI层窗口类、BLL层类、DAL层类等方法的设计与实现。
参见6.8节。
6.8 UI层窗体设计与用例的实现
除主窗体要考虑整体功能结构外,其它功能都是按用例逐一进行设计和实现的。部分用例的事件流相似且相关,可集中在同一个窗体内实现,如:借书证挂失、解除、补办与注销。

  1. 用例:用户登录 - frmLogin窗体
    用例:用户登录,参见5.4(1)节。
    (1)登录窗体设计如下:

登录窗体控件如下:
序号 控件类型 控件(Name) 属性设置
1 label label1 Text = 用户编号
2 label Label2 Text = 用户密码
3 TextBox txtUserID
4 TextBox txtUserPwd PasswordChar = *
5 Button btnLogin Text = 登录
6 Button btnClose Text = 退出
7 label lblReaderInfo Text = 登录信息:
ForeColor = red
(2)在frmLogin.cs文件中添加引用:
using BookManage.BLL;
using BookManage.Model;
(3)在frmLogin类中添加成员;其中reader在窗体关闭后仍要求存在并可见(static)。
private int loginTimes = 0; //登录次数
private ReaderAdmin readerBLL = new ReaderAdmin();
public static Reader reader = null; //登录用户信息,可用于整个程序
(4)BLL层ReaderAdmin类添加方法:(登录用例之步骤:3. 系统根据借书证号获取读者对象。)

(5)添加“登录”和“退出”按钮的Click事件和方法:

(6)修改Program.cs程序:

(7) 测试 点击“登录”从数据库查询到某读者记录,但其照片为null时,程序在SqlHelper的成员函数DataRowToT(DataRow source)处发生错误,出错语句和原因:
value = Convert.ChangeType(source[pi.Name], ptype);
从“System.DBNull”到“System.Byte[]”的强制转换无效。
纠错:在出错语句前添加条件,语句如下:
if (!(pi.PropertyType.FullName == “System.Byte[]” && source[pi.Name] == DBNull.Value))
2. frmMain主窗体界面
(1)主窗体添加控件:菜单栏(MenuStrip)和状态栏(StatusStrip)。状态栏里添加一个标签(ToolStripStatusLabel),命名(Name)为: tssUser。菜单栏添加菜单项如下:
序号 菜单项 菜单(Name) 属性设置
1 图书管理 图书管理ToolStripMenuItem
1.1 新书入库 新书入库ToolStripMenuItem
1.2 图书信息维护 图书信息维护ToolStripMenuItem
2 读者管理 读者管理ToolStripMenuItem
2.1 办理借书证 办理借书证ToolStripMenuItem
2.2 借书证信息变更 借书证信息变更ToolStripMenuItem
2.3 借书证挂失与解除 借书证挂失与解除ToolStripMenuItem
2.4 注销借书证 注销借书证ToolStripMenuItem
2.5 读者类型管理 读者类型管理ToolStripMenuItem
3 借阅管理 借阅管理ToolStripMenuItem
3.1 借书 借书ToolStripMenuItem
3.2 续借 续借ToolStripMenuItem
3.3 还书 还书ToolStripMenuItem
4 用户管理 用户管理ToolStripMenuItem
4.1 权限管理 权限管理ToolStripMenuItem
4.2 密码修改 密码修改ToolStripMenuItem
(2)根据登录用户的权限,确定菜单是否可用,并显示登录用户信息,有3个问题:
A. 获取登录窗口frmLogin中的读者对象reader。而进入主窗口时,登录窗口对象已经释放,故只能通过类名(而不是类对象)访问,申明reader为静态public static。
在frmLogin类中:public static Reader reader = null;
在frmMain等其它类中的访问方法:frmLogin.reader
B. 读者对象reader权限的判断方法,分配在BLL层/Model层? Model层代码如下:

C. 根据登录用户权限,在frmMain类中初始化菜单。添加InitMenu()方法:

  1. 用例:借书证的办理、变更、挂失、解除、补办与注销 –frmReader窗体
    借书证相关用例有:办理借书证、变更借书证、挂失借书证、解除挂失、补办借书证、注销借书证等。分析发现第一个步骤都相同,即借书证查询操作;办理新借书证、变更借书证有界面操作,然后再分别做插入和修改操作;而其它的挂失、解除挂失、补办、注销等没有界面操作,可以直接进行各自的业务操作。
    方案一 设计3个窗口:
    (1)查询窗口,并设计6个按钮控件:办理新证、变更、挂失、解除挂失、补办、注销等。
    其中办理新证、变更在点击后分别转入下面2个窗口;另外4个按钮可调用相应业务逻辑方法直接完成。
    (2)办理新借书证窗口,从查询窗口传入相关的信息(参见其用例),完成读者表记录的插入操作。
    (3)变更借书证窗口,从查询窗口传入原借书证对象,完成读者表记录的修改操作。
    此方案的设计与实现比较简单,用户操作简易、流畅。

设计改变了系统主菜单,frmMain类及其窗体的修改工作如下:
将主窗体菜单(6.8.2节)中的4个菜单项“2.1办理借书证”至“2.4注销借书证”去掉3个,仅保留一个菜单项,改其名为“借书证管理”,并添加其点击事件,事件的实现代码为:

方案二 设计1个窗口,如下:

此操作界面的控制较复杂,下面详细介绍其设计思想与实现技术。
(1)窗口界面设计
将界面设计成3个部分:
查询条件 工具栏(ToolStrip toolStrip1),其中控件:查找(ToolStripButton btnQuery),Excel(ToolStripButton btnToExcel)。
查询结果 组控件(GroupBox groupBox1),其中控件:网格控件(DataGridView dgvReader,设置ReadOnly=true),办理借书证(Button btnNewDoc)、变更借书证(Button btnChangeDoc)、挂失(Button btnLossDoc)、解除挂失(Button btnUnlossDoc)、注销(Button btnCancelDoc)、退出(Button btnClose);另外,借阅信息(Label lblBorrowInfo)可用于显示读者的历史借阅记录数和未归还图书数量。
读者信息 组控件(GroupBox groupBox2),其中控件:确认办证(Button btnAddReader)、确认变更(Button btnUpdateReader)、撤销(Button btnCancelChange);另外,图片控件(PictureBox picboxPhoto,设置BorderStyle= FixedSingle,SizeMode= StretchImage)、打开图片文件(Button btnLoadPictureFile)。
(2)界面操作状态的控制
添加枚举类型opStatus,表示3种窗口操作状态,参见下列代码。并在frmReader类中添加成员对象,其中:
DataTable dt -存放查询结果,并给DataGridView dgvReader提供数据。
Reader reader –存放读者信息,与读者信息组控件内的各控件进行数据交换,并与BLL、Model层进行数据传递。
opStatus ops –记录当前操作状态。
代码如下:

然后添加窗口类成员函数SetStatus(),代码如下:

在几个需要进行状态切换的按钮Click点击事件中调用此函数,如下:
办理借书证(Button btnNewDoc) 调用 SetStatus(opStatus.inNew);
变更借书证(Button btnChangeDoc) 调用 SetStatus(opStatus.inChange);
撤销(Button btnCancelChange) 调用 SetStatus(opStatus.inSelect);
思考:确认办证、确认变更的Click事件该如何切换状态?
(3)窗口初始化
在窗口类frmReader的构造函数public frmReader()中添加代码:

在BLL类ReaderAdmin中添加成员函数:

在DAL类ReaderTypeDAL中添加成员函数:

在窗口类frmReader中添加成员函数:

在实体类Reader中添加成员函数:

(4)查询操作的实现

在BLL类ReaderAdmin中添加成员函数:

在DAL类ReaderDAL中添加成员函数:

(5)查询结果导入到Excel
在BookManage项目里添加C#代码类ExcelHelper,文件ExcelHelper.cs内容如下:

类ExcelHelper的3个成员函数如下:

在frmReader窗口工具栏中,给按钮“Excel”添加Click事件,其代码如下:

(6)给DataGridView dgvReader添加SelectionChanged事件,其代码如下:

(7)读者信息组内控件与实体类对象Reader reader之间的数据互换
在窗口类frmReader中添加成员函数:

(8)办理借书证操作与确认办证操作的实现(自己完成)
(9)变更借书证操作与确认变更操作的实现
在窗口类frmReader中添加成员函数(按钮“变更借书证”的点击事件):

在窗口类frmReader中添加成员函数(按钮“确认变更”的点击事件):

在BLL类ReaderAdmin中添加成员函数:

在窗口类frmReader中添加成员函数(按钮“图片文件…”的点击事件):

(10)挂失操作(自己完成)
(11)解除挂失操作(自己完成)
(12)注销操作(自己完成)
(13)补办借书证操作(自己完成)
4. 用例:读者类别管理
读者类别管理用例,主要功能是记录的插删改查等常规数据操作;由于类别记录少,仅设计查询全部记录这一个查询功能即可,界面可参考下图。

  1. 用例:新书入库、图书信息维护
    图书管理相关用例有:新书入库、图书信息维护、图书变卖与销毁处理*。下面介绍一种设计与实现方案:
    (1)新书入库窗口界面,可参考下图,其中不恰当之处请自行发现和修改。

(2)图书查询窗口界面,可参考下图。图中工具栏的设计存在明显的不妥之处,即不应该按数据库的数据插删改查进行功能设计,而应该按照用例中的操作进行,请自行修改。
界面中可以设计2个按钮,分别转入“新书入库”、“图书信息维护”窗口界面。

(3)图书信息维护窗口界面,可参考下图进行设计。该界面与新书入库窗口界面相似,设计时可以考虑将这2个窗口类进行合并。

  1. 用例:借书
    借书用例的窗口界面设计可参考如下图。

在此窗口的上半部分,可添加续借和还书按钮,以实现按照读者已借阅图书信息进行续借和还书的功能。实际上,续借和还书操作不需要知道读者编号信息,知道书号即可进行续借和还书。
借书可在BorrowAdmin类中设计实现,其设计思想和方法请同学们仔细体会,代码如下:
public bool BorrowBook(Reader reader, ReaderType readerType, Book book, Reader OperatorUser)
{
if (reader == null || readerType == null || book == null || OperatorUser == null)
return false;
if (reader.rdStatus != “有效” || (readerType.CanLendQty - reader.rdBorrowQty) <= 0)
return false;
if (book.bkStatus != “在馆”) return false;

reader.rdBorrowQty++;
ReaderDAL.Update(reader);

book.bkStatus = "借出";
BookDAL.Update(book);

Borrow borrow = new Borrow();
borrow.rdID = reader.rdID;
borrow.bkID = book.bkID;
borrow.ldContinueTimes = 0;
borrow.ldDateOut = DateTime.Now;
borrow.ldDateRetPlan = DateTime.Now.AddDays(readerType.CanLendDay);
borrow.lsHasReturn = false;
borrow.OperatorLend = OperatorUser.rdName;
BorrowDAL.Add(borrow);
return true;

}
7. 用例:续借、还书
可单独设计一个窗口,以实现按书号进行续借与还书功能。输入书号后,查询并显示(1)其借阅记录,未归还,(2)图书信息,(3)读者信息;然后进行续借或还书操作。
7. 提高篇
7.1 业务逻辑层的事务性操作与存储过程
对于事务性强的业务逻辑操作,也可以采用数据库的存储过程来实现。“借书”若采用存储过程,其实现方法如下:
(1) 在SQL Server的Library数据库中创建存储过程

(2)编写DAL层代码,BorrowDAL类成员函数如下:

(3) 编写BLL层代码,BorrowAdmin类成员函数如下:
public int BorrowBook(int rdID, int bkID, string OperatorLend)
{
return BorrowDAL.BorrowBook(rdID, bkID, OperatorLend);
}
7.2 关于用例中操作过程的控制问题
用例的实现往往需要过程与状态控制,这是一个普遍现象,例如6.8.3节frmReader窗体的“(2)界面操作状态的控制”设计案例,该案例存在着如下问题:
(1)将操作状态的控制放入frmReader窗体类,会使UI层变得庞大而复杂;
(2)增加了UI层的编程难度,程序员必须充分理解用例过程以及相关BLL层类;
我们可以有更好的设计,即在用例的UI层与BLL层之间增加一个控制类(称为“控制器”),将相关实体类以及过程与状态的控制放入其中。如在frmReader与ReaderAdmin之间增加一个ReaderController类(或取名为ReaderHandler),把Reader reader和opStatus ops以及状态变化方法迁移到其中,并根据当前状态来控制ReaderAdmin中方法的调用。将类ReaderAdmin更名为ReaderOperator更合适。
一般来说,可以将控制类放入BLL层,或成为单独的一层,即控制层(MVC软件体系结构)。
7.3 关于三层体系结构
一般在软件的三层体系结构中存在一个公用模块Common。另外,软件产品为了提供对多种不同数据库(如SQL Server、Oracle、DB2等)的支持,一般会在DAL层设计多套类库,分别实现对应数据库的数据访问。其三层体系结构图如下:

BookManage.DAL层变化如下:
类名 实现接口 原类名 说明
ReaderTypeDALSql IReaderTypeDAL ReaderTypeDAL 修改原类名,支持MS SQL Server
ReaderDALSql IReaderDAL ReaderDAL
BookDALSql IBookDAL BookDAL
BorrowDALSql IBorrowDAL BorrowDAL
SQLHelper SQLHelper
ReaderTypeDALOracle IReaderTypeDAL 新增类,与ReaderTypeDALSql实现的功能相同,但支持Oracle
ReaderDALOracle IReaderDAL
BookDALOracle IBookDAL
BorrowDALOracle IBorrowDAL
OracleHelper 与SQLHelper实现的功能相同,但支持Oracle
DALFactory 简单工厂类
OracleHelper类,可从SqlHelper方便地得到,步骤如下:
(1)BookManager.DAL项目中添加引用“System.Data.OracleClient”。
(2)复制文件SqlHelper.cs到OracleHelper.cs,然后对OracleHelper.cs内容做以下替换或修改操作
(3)using System.Data.SqlClient; 替换为:using System.Data.OracleClient;
(4)将类名SqlHelper替换为OracleHelper
(5)连接串修改为:
private static string _strConnection = @“Data Source=ORA92LSH;User ID=BookManage;Password=123;Unicode=True”;
说明:其中ORA92LSH为Oracle Net Manager配置的本地服务命名。创建Oracle数据库对象的SQL脚本,可参见文本文件“Library_ForOracle.sql”的内容。
(6)然后全文替换以下内容:
SqlConnection 替换为 OracleConnection
SqlCommand 替换为 OracleCommand
SqlException 替换为 OracleException
SqlParameter 替换为 OracleParameter
SqlDataAdapter替换为 OracleDataAdapter
(7)保存后,将它添加到BookManager.DAL项目中,至此,OracleHelper类修改完毕。

Oracle存取类(ReaderTypeDALOracle, ReaderDALOracle, BookDALOracle, BorrowDALOracle)可按上面相同方法得到,只是参数有一点不同,以ReaderTypeDALSql类成员函数Get_rdType()为例,如下:

Oracle参数使用“:”,而SQL Server参数使用“@”。对应ReaderTypeDALOracle类的成员函数如下:

另外,Oracle字段类型与SQL Server有较大的不同,Oracle查询结果存放到C#的DataTable中时,数据类型差别也比较大,编程时应该注意与实体类对象的类型转换问题。实体类属性类型按照SQL Server字段类型设计即可。Oracle字段类型与DataTable列类型对照关系,见下表:
Oracle字段类型 DataTable中类型
char, varchar2, long, clob
nchar, nvarchar2, nclob System.String
numeric(,) System.Decimal
Float System.Decimal
rowid System.Decimal
date System.DateTime
raw, long raw, blob System.Byte[]

建议:在DAL项目中建立2个目录SQL、Oracle,分别移入SQL Server和Oracle的DAL类文件;并分为2个命名空间,即BookManage.DAL.SQL和BookManage.DAL.Oracle

关于对多种数据库的支持见下节。
7.4 实现对多数据库的支持
修改DAL与BLL层代码。以原ReaderDAL类为例进行说明:
(1)新增接口类 IReaderDAL ,它包括原ReaderDAL类的所有public成员。

(2)ReaderDALSql及ReaderDALOracle均实现IReaderDAL接口,即2个类的外部访问接口完全相同。
public class ReaderDALSql : IReaderDAL
public class ReaderDALOracle : IReaderDAL
ReaderDALSql类的修改:从接口继承的函数不能采用静态成员函数,即去掉static
ReaderDALOracle类:新增类,它与ReaderDALSql类实现的public成员函数完全相同,但它引用的是OracleHelper类中的成员,而不是SqlHelper
(3)新增工厂类DALFactory。
public class DALFactory
{
private IReaderTypeDAL readerTypeDAL;
private IReaderDAL readerDAL;
public string GetDBSource()
{
return (“SQL”); //使用SQL Server
//return (“Oracle”); //使用Oracle
}
public IReaderTypeDAL GetReaderTypeDAL()
{
if (GetDBSource() == “SQL”)
readerTypeDAL = new ReaderTypeDALSql();
else
readerTypeDAL = new ReaderTypeDALOracle();
return readerTypeDAL;
}
public IReaderDAL GetReaderDAL()
{
if (GetDBSource() == “SQL”)
readerDAL = new ReaderDALSql();
else
readerDAL = new ReaderDALOracle();
return readerDAL;
}
}
(4)修改BLL层ReaderAdmin类

7.5 软件发布、部署与自动更新
作为产品,应该将使用SQL还是Oracle以及相应的连接字符串(在SqlHelper和OracleHelper类中)移出到程序外部,即将SQL或Oracle以及连接字符串加密后作为外部文件存放,程序运行时读取该文件并解密。
软件包括4个模块的版本升级与更新,即BookManage.Model.dll、BookManage.DAL.dll、BookManage.BLL.dll、BookManage.exe等文件。可将4个文件放在一个FTP服务器或Web服务器的固定目录上,在BookManage.exe程序中增加一个“检查更新”菜单及功能模块,用户启动或定时自动启动该功能。
当然使用VS .NET自身的部署功能,就更加方便了,如部署项目、ClickOnce等。

猜你喜欢

转载自blog.csdn.net/lijunhcn/article/details/135233926