分类

课内:
不限
类型:
不限 毕业设计 课程设计 小学期 大作业
汇编语言 C语言 C++ JAVA C# JSP PYTHON PHP
数据结构与算法 操作系统 编译原理 数据库 计算机网络 软件工程 VC++程序设计
游戏 PC程序 APP 网站 其他
评分:
不限 10 9 8 7 6 5 4 3 2 1
年份:
不限 2018 2019 2020

资源列表

  • 基于C#的可视化进程调度算法

    一、目的要求用C#语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解。
    二、准备知识2.1 基本概念
    进程的概念
    进程的状态和进程控制块
    进程调度算法

    2.2 进程调度2.2.1 进程的状态
    2.2.2 进程的结构——PCB进程都是由一系列操作(动作)所组成,通过这些操作来完成其任务。因此,不同的进程,其内部操作也不相同。在操作系统中,描述一个进程除了需要程序和私有数据之外,最主要的是需要一个与动态过程相联系的数据结构,该数据结构用来描述进程的外部特性(名字、状态等)以及与其它进程的联系(通信关系)等信息,该数据结构称为进程控制块(PCB,Process Control Block)。
    进程控制块PCB与进程一一对应,PCB中记录了系统所需的全部信息、用于描述进程情况所需的全部信息和控制进程运行所需的全部信息。因此,系统可以通过进程的PCB来对进程进行管理。
    三、实验内容设计一个有 N个进程并发执行的进程调度程序。
    进程调度算法:采用最高优先数优先的调度算法(即把处理机分配给优先数最高的进程)和先来先服务算法。
    每个进程由一个进程控制块( PCB)表示。进程控制块可以包含如下信息:进程名、优先数、到达时间、需要运行时间、已用CPU时间、进程状态等。

    进程的优先数(0~10)及需要的运行时间(可用一个整数表示)可以在进程创建时人为指定(也可以由随机数产生)
    进程的到达时间为进程输入的时间
    进程的运行时间以时间片为单位进行计算
    每个进程的状态可以是就绪 (Ready)、运行(Run)两种状态之一。本实验不考虑进程的资源问题,因此暂不包括进程的阻塞状态
    就绪进程获得CPU后都只能运行一个时间片。用已占用CPU时间加1来表示。如果运行一个时间片后,进程的已占用 CPU时间已达到所需要的运行时间,则撤消该进程,如果运行一个时间片后进程的已占用CPU时间还未达所需要的运行时间,也就是进程还需要继续运行,此时应将进程的优先数减1(即降低一级),然后把它插入就绪队列等待CPU
    每进行一次CPU调度,需要输出当前运行进程和就绪队列各个进程的 PCB,以便进行检查
    重复以上过程,直到所要进程都完成为止

    程序要求模块化设计,采用自定义函数实现各个所需功能,例如main(主函数)、create(进程创建函数)、display(进程信息输出函数)、schedule(进程调度函数)、destroy(进程销毁函数)等,以及其他按照功能分解出的自定义函数。
    调度算法的流程图参考如下:

    四、实验结果随机生成数据

    单步执行加入进程1

    单步执行运行进程2

    所有进程到达完成
    0 评论 1 下载 2020-07-06 09:57:03 下载需要11点积分
  • 基于SMTP协议和POP3协议实现的邮件收发客户端

    一、概要设计1.1 抽象数据类型定义主要定义了三个抽象数据类型:

    Base64

    功能:用于发送邮件时进行编码,以及接收邮件时进行解码数据部分:无操作部分:编码(encode)、解码(decode)
    SMTP

    功能:简单邮件传输协议类。用于实现SMTP协议中各种命令调用,发送邮件数据部分:套接字操作部分:创建套接字、释放套接字、连接SMTP服务器、状态码检测、发送数据
    POP3

    功能:实现POP3协议中各种命令调用,接收邮件数据部分:套接字、邮件类属性(包括邮件大小、主题、发送方等信息)操作部分:创建套接字、释放套接字、用户名密码检测、POP3协议中相关操作命令(包括STAT、LIST、TOP、NOOP、RETR、QUIT等)

    1.2 主程序流程图
    1.3 各个模块关系按功能上可以从总体上大致分为登陆模块、发送模块、接收模块和显示模块,其所对应的模块层次结构如下图所示:

    1.4 技术开发思路1.4.1 明确设计目标和要求关于要求:编程实现通过用户界面,用户登录信箱认证过程(含base64方式编码)、发送信息及附件(常用格式)、邮件信息验证、伪造邮件地址黑名单。
    其实前三点都是比较正常的功能需求,但是对于第四点,实在是难以理解,为什么发送器会有黑白名单?但是既然要求,那就做吧,按我个人的理解是这样的:显然黑白名单的功能不是发送器的,而是接收器的。虽然题目清清楚楚写着发送器设计,但在功能上却要求实现接收器的功能。这意味着除了使用SMTP协议发送邮件外,还需设计使用POP3协议接收邮件,在接收的时候采用黑白名单过滤的功能。
    1.4.2 开发环境选择采用VC6.0,使用MFC框架进行开发。
    1.4.3 开发流程准备先进行发送模块和登陆模块以及部分显示模块的开发,完成之后进行接收模块的开发,并最终完善显示模块。
    二、详细设计抽象数据类型的实现
    2.1 Base64类包括两个成员函数:

    Encode

    参数:包括待编码的字符串、该字符串长度返回值:编码后的字符串实际定义:string Base64::Encode(const unsigned char *str, int length)具体实现(伪代码):Dim EncodeTable[0…63] as charDim strEncode as stringFor i=0 to length/3 strEncode+=EncodeTable[str[i]>>2] strEncode+=EncodeTable[((str[i]<<4)|(str[i+1]>>4))&0x3F] strEncode+=EncodeTable[((str[i+1]<<2)|(str[i+2]>>6))&0x3F] strEncode+=EncodeTable[str[i+2]&0x3F]EndFor

    Decode

    参数:包括待解码的字符串、该字符串长度、解码后的字符串长度返回值:解码后的字符串实际定义:string Base64::Decode(const char *str, int length, int &outlength)具体实现(伪代码):Dim DecodeTabe[] as charDim strDecode as stringDim val as intWhile i<length Val=DecodeTable[str[i]]<<18 Val+=DecodeTable[str[i+1]]<<12 strDecode+=(val&0x00FF00000)>>16 outlength++ if str[i+2]!=’=’ then val+=DecodeTable[str[i+2]|<<6 strDecode+=(val&0x0000FF00)>>8 outlength++ if str[i+3]!=’=’ then val+=DecodeTable[str[i+3]] str+=(val&0x000000FF) outlength++ end if end if i+=4


    2.2 SMTP类2.2.1 数据定义SOCKET m_socket; //套接字WSADATA m_wsadata; //存放SOCKET的初始化信息HOSTENT* m_hostent; //存放主机以及地址SOCKADDR_IN m_sockaddr_in; //存放地址协议、ip、端口
    2.2.2 函数bool SMTP::CheckResponse(const char *code) //检查返回的状态码与期望结果code是否一致bool SMTP::Connect(const string addr, const int port) //连接到服务器,参数为服务器名称以及端口bool SMTP::CreateSocket() //创建套接字void SMTP::ReleaseSocket() //释放套接字bool SMTP::isvalid(const string username, const string password)//验证用户名和密码是否正确然后是发送函数:bool Send(const string sendaddr, //发送方邮箱 const vector<string> rcvlist, //接收方地址 const string sendname, //发送方姓名 const string rcvname, //接收方姓名 const string subject, //主题 const string content,//内容 const vector<string> file, //文件 int ishtml); //是否以html格式发送
    2.2.3 流程图以及关键技术伪代码发送函数send

    连接服务器Connect

    检查账户信息isvalid

    发送函数伪代码:
    Str=”MAIL FROM:”+”发送地址”If send(str)==TRUE then If CheckResponse(“250”) then Str=”RCPT TO”+”接收方地址” If Send(str)==TRUE then If CheckResponse(“250”) then Str=”DATA” If Send(str)==TRUE then If CheckResponse(“354”) then Str=”邮件信息”+”附件” If Send(str)==TRUE then If CheckResponse(“250”) then ReleaseSocket() Return TRUE End if End if End if End if End if End if End ifEnd ifReleaseSocket()Return FALSE
    2.3 POP3类2.3.1 数据定义SOCKET m_socket; //套接字WSADATA m_wsadata; //存放SOCKET的初始化信息HOSTENT* m_hostent; //存放主机以及地址SOCKADDR_IN m_sockaddr_in; //存放地址协议、ip、端口unsigned int mailnum,mailsize; //邮件总数、总大小CString m_response; //存放响应信息CStringArray m_subject; //CString数组存放各个邮件主题CStringArray m_size; //存放各个邮件大小CStringArray m_sender; //存放发送方CStringArray m_date; //存放发送时间
    2.3.2 主要函数bool CheckResponse(bool bDouble); //检查响应,参数用于识别响应末尾是一个回车换行还是2个void ReleaseSocket();//释放套接字bool CreateSocket();//创建套接字bool isvalid(const string username,const string password);//用户名密码检测bool Connect(const string addr,const int port);//连接POP服务器bool STAT(); //STAT命令,获取邮件总数及总大小bool RETR(UINT nIndex,CString &strMsg);//获取序号为nIndex的邮件内容存放于strMsg中bool Noop(); //NOOP命令,确认连接bool TOP(); //TOP命令,返回邮件头信息bool LIST(); //列出邮件序号及大小bool QUIT(); //断开连接
    2.3.3 流程图及关键函数伪代码*接收响应(CheckResponse)

    LIST函数

    TOP函数

    接收响应函数源码:
    TCHAR pChar[100005]; CString strTemp; // 读取回应信息 BOOL bEnd = FALSE; UINT nReceived = 0; DWORD dwStart = ::GetTickCount(); while (!bEnd) { // 尝试时间到 if ((::GetTickCount() - dwStart) > 2000) { pChar[nReceived] = '\0'; // 保存当前回应的消息 m_response = pChar; AfxMessageBox("接收响应消息超时"); return FALSE; } // 看套接字是否可读 timeval timeout = {0, 0}; fd_set fds; FD_ZERO(&fds); FD_SET(m_socket,&fds); Int nStatus = select(0,&fds,NULL,NULL,&timeout); if (nStatus == SOCKET_ERROR) { // 套接字不可读 AfxMessageBox("套接字不可达"); return FALSE; } else if (!nStatus) { // 没有接收到数据 ::Sleep(688); continue; } // 从套接字中接收数据 ::Sleep(288); nStatus=recv(m_socket,pChar + nReceived,sizeof(pChar),0); if (nStatus == SOCKET_ERROR) { pChar[nReceived] = '\0'; // 套接字错误 // 保存当前回应信息 m_response = pChar; AfxMessageBox("未能从套接字中收到数据"); return FALSE; } else if (nStatus) { // 重置计时器 dwStart = ::GetTickCount(); // 已收到的数据又增加了 nReceived += nStatus; } // 将pChar设为字符串,并赋给CString型的变量 pChar[nReceived] = '\0'; strTemp = pChar; // 检查是否收到了结束标志 LPCTSTR lpszComp = bDouble ? "\r\n.\r\n" : "\r\n"; bEnd = (strTemp.Find(lpszComp) != -1); } // 去掉结束标志 nReceived -= bDouble ? 3 : 0; pChar[nReceived] = '\0'; // 检查回应信息是否有效 strTemp = pChar; strTemp.MakeUpper(); int nStart = strTemp.Find("+OK"); if (nStart == -1) { // 收到无效信息 AfxMessageBox("回应消息无效"); return FALSE; } // 提取有效信息 strTemp = pChar; m_response = strTemp.Right(strTemp.GetLength() - nStart - 3);
    三、调试分析3.1 遇到的问题及解决办法
    问题一:一开始使用的是126邮箱进行测试,没有问题。到后面换成了QQ邮箱,发现无法连接服务器。原因是QQ的POP服务器名不是以POP3开始的,而是POP,即:pop.qq.com,而126和163的都是以pop3开头。

    解决办法:对不同的服务器采用不同的处理方式。
    问题二:测试邮箱事先没有开启SMTP/POP服务,导致登陆失败。

    解决办法:开启SMTP/POP服务。
    问题三:发送大附件的问题。

    解决办法:采取分段发送。开设一定的缓冲区,缓存分段,一个附件分为多个段经多次发送。
    问题四:部分邮件的主题是经过base64加密的。一开始没有考虑,导致部分邮件主题没有得到解析。如下图所示。

    解决办法:根据字段”=?GBK?B?”和”=?UTF-8?B”识别邮件主题是否被加密,对加密的邮件主题进行base64解密。



    问题五:部分邮件内容是html格式的,不能直接解码显示。

    解决办法:若发现Content-type字段值为text/html,则直接显示其html文本。(或许应该在网页中打开??)
    问题六:一开始在pop3检查响应时,采用和SMTP检查响应一样的函数进行处理。导致无法识别接收响应消息和邮件。其原因在于:对于长文本内容可能会分段发送并且具有延时现象。

    解决办法:这个问题比较麻烦。找了很多资料,最终采用了计时处理的方式。代码已经在前面列出,可以参考。虽然接收速度比较慢(需等待),但是响应信息的准确性得到了保证。
    问题七:黑白名单。

    解决办法:设定两个数组分别存放当前用户的黑白名单成员,同时使用文件操作维护之。当用户登录的时候,检查相关目录中是否存在该用户信息,若存在,则加载该用户黑白名单到指定数组中。当用户接收邮件时,检查黑名单,看是否存在当前邮件发送者,若不存在,则接收邮件,否则不接收。

    3.2 尚存在的问题和改进设想时间紧迫,个人能力有限,尚存如下问题,待解决。(实际上,均是和邮件接收有关的问题,好像跟题目没什么关系。)

    问题一:对于html格式的邮件内容无法解析

    改进设想:将获取的内容存放到一个html文件中,然后通过调用打开浏览器在浏览器中查看该邮件内容。
    问题二:无法接收附件。

    改进设想:这个,我想需要研究一下各种文件的格式。
    问题三:邮件编码问题。不同服务器编码方式不一样,无法用同一种解码方式对邮件内容进行解码显示。

    改进设想:研究编码方式,对不同编码的邮件,分别解码处理。
    问题四:当账号中邮件数量较多时,接收缓慢。这个问题主要是由于上面提到的检查响应的函数造成的。

    改进设想:寻找更好的检查响应算法。

    3.3 经验和体会经过这次计网课设,对SMTP协议和POP3协议有了更加深刻的理解,在实践中碰到了许多问题,通过不断解决这些问题,使得自己在编程能力、理解能力、学习能力等各方面能力都得到了有效的锻炼。虽然时间很紧迫,进行课设的同时还得上课,课余时间基本上都花在了课设上,经过努力,完成了所有的基本要求,感觉很开心。但还是有一些问题没有得到解决,希望能够在今后的学习中将这些问题解决掉。
    四、操作说明

    登陆:输入账号密码,在下拉列表中选择对应服务器,点击登陆邮箱按钮即可
    发送邮件:输入发送方姓名(可省)、接收方地址(发送到),主题(可选),附件(可选),填写邮件内容。确认无误之后,点击发送邮件
    添加附件:点击添加按钮,弹出对话框,选择需要添加的文件(可以多选,最多20个),确定之后返回主界面,在附件列表中可以查看到添加的附件名称
    删除附件:点击下拉列表,选中需要删除的附件名称之后,点击删除按钮,即可删除当前选择的附件
    接收邮件:需要先进行登陆才可。登陆之后,点击列出邮件,如果邮箱中邮件数目较多,请耐心等待。(中途可能有些邮件无法正确接收,会弹出提示框,点击确定即可)一段时间后,邮件列表中将显示出成功接收到的邮件信息
    设置黑白名单:点击设置黑/白名单,弹出设置框,输入账号,点击添加,完成添加。选择列表中已经添加的账号,然后点击删除,可将账号信息从名单中删除
    2 评论 71 下载 2019-02-09 17:07:18 下载需要13点积分
  • 利用哈希表实现电话号码查询系统

    第一章 需求分析1.1 问题描述设计一个电话号码查询系统,为来访的客⼈提供各种信息查询服务。
    1.2 基本要求
    设计每个记录有下列数据项:电话号码、用户名、地址
    从键盘输入个记录,分别以电话号码和用户名为关键字建立不同散列表存储
    采用一定的方法解决冲突
    查找并显示给定电话号码的记录
    查找并显示给定用户名的记录

    1.3 实现提示
    设计不同的散列函数,尝试不同类型冲突解决方案,考察平均查找长度的变化
    记录与散列表分开,达到不同关键字散列表可共享记录

    1.4 补充内容
    自动读入硬盘中的记录,并可以选择存储更新后的记录
    提供信息检测机制,以学号作为唯一关键字,对重复学号的记录不允许插入
    提供删除功能
    提供空⽩检测机制,输入信息任意一项为空则不允许插入
    提供格式检测机制,输入信息的格式不正确则不允许插入(如年龄不允许输入字符或字符串)
    采用不同的hash函数构建方法和不同的冲突处理方式
    实现用户界面

    第二章 系统描述2.1 开发语言及主要功能实现方法本程序基于java语言写成,配置java所需环境变量。 本程序中链表和hash函数均未使用java库中已有函数,链表和hash函数都 是使用java语言自⼰编写实现。 Java 语言实现链表和 C 语言类似,但由于 java 没有指针功能,因此可以将 节点作为单独的类,用引用的方法实现链式链接。 Hash函数分别采用除留取余法和伪随机数法,其中伪随机数用于字符串构造 hash函数,可根据不同的字符串生成不同的随机数。 冲突处理分别采用线性探测法、再哈希法和链地址法。
    2.2 单条记录所含内容结合学生电子号码本的需求情况,选出本部周围的8项内容,作为一条记录:



    学号
    姓名
    性别
    年龄
    电话号码
    住址
    学院
    专业




    123456789
    张三

    19
    1357924680
    学3-236
    计算机学院
    计算机科学与技术



    (其余记录与此格式相同,不做重复)
    2.3 Hash 函数及处理冲突方法本系统分别对学号、姓名、电话号码三项构建 hash 函数,并采用不同的冲突处理方法,具体如下:

    学号散列表:采用除留取余法构建hash函数,采用线性探测法处理冲突
    姓名散列表:采用伪随机数法构建hash函数,采用链地址法处理冲突
    电话号码散列表:采用除留取余法构建hash函数,采用再哈希法处理冲突

    除留余数法
    m是散列表表长。
    f(key) = key mod p (p<=m)
    随机数法
    注意random的随机种子需要是固定的,以便查询的时候能够根据key重新找到,适用于关键字长度不等的情况。
    f(key) = random(key)
    再哈希法
    遇到冲突就重新采用一个散列函数计算新的存储位置,可以使关键字不产生聚集。
    f i (key)=RH i (key) (i=1,2,...k)
    链地址法(拉链)
    将所有关键字的同义词记录在一个单链表中,在散列表中只存储所有同义词表的头指针。
    第三章 功能模块结构3.1 信息插入模块
    功能:插入单条记录,依次输入单条记录中的信息
    输入要求:学号不允许重复、每项信息不能有空值、性别只允许男/女,年龄只允许输入数字等等
    输出结果:将该记录保存在链表中备份,依次采用三种不同的 hash 函数构建散列表索引项,并处理冲突,实现记录与散列表分开,达到不同关键字散列表可共享记录

    3.2 信息修改模块
    功能:按照输入学号修改相应记录,在屏幕上显示对应记录的所有信息并允许修改
    输入要求:学号不允许重复、每项信息不能有空值、性别只允许男/女,年龄只允许输入数字等等
    输出结果:将原记录在链表中的内容更新备份,同时更新三种不同的 hash 函数构建的散列表索引项

    3.3 信息删除模块
    功能:删除单条记录,同时删除链表中的记录和各散列表中的索引
    输入要求:相应记录的学号必须存在
    输出结果:同时删除链表中的记录和各散列表中的索引

    3.4 信息查询模块——按照学号查找
    功能:根据学号的散列值查找单条记录,实际上为查找学号散列表中的索引并获取对应的完整记录
    输入要求:相应记录的学号必须存在
    输出结果:在屏幕上显示相关记录

    3.5 信息查询模块——按照电话查找
    功能:根据电话号码的散列值查找单条记录,实际上为查找电话号码散列表中的索引并获取对应的完整记录
    输入要求:相应记录的电话号码必须存在
    输出结果:在屏幕上显示相关记录

    3.6 信息查询模块——按照姓名查找
    功能:根据姓名的散列值查找单条记录,实际上为查找姓名散列表中的索引并获取对应的完整记录
    输入要求:相应记录的姓名必须存在
    输出结果:在屏幕上显示相关记录(由于姓名可能重复,所以可能会显示多条记录)

    3.7 信息保存
    功能:将已有记录保存在本地
    输入要求:无
    输出结果:在本地保存所有信息


    第四章 主要模块算法说明4.1 学号散列表设计
    hash函数构建方法:通过除留取余法构建散列表
    处理冲突方法:采用线性探测法,一次一步

    4.2 电话号码散列表设计
    hash函数构建方法:通过伪随机数法构建散列表处理冲突方法:采用再哈希法
    4.3 姓名散列表设计
    hash函数构建方法:通过伪随机数法构建散列表
    处理冲突方法:采用链地址法(插入、删除、更新、查询全部包含在内)

    4.4 记录插入模块设计从界面上⽂本框中读取字符串,并进⾏判断:

    首先各项都必须按 照要求,⽐如年龄不能为字符,学号不能为字符等等
    然后判断是否有某项为空,有空则不允许插入
    最后检测学号是否重复, 重复则不允许插入。 然后在链表中添加完整记录,同时建⽴学号、电话号码、姓名的索引

    4.5 记录修改模块设计首先根据给定的学号选择相应记录,显示在屏幕上,允许用户自⾏修改。从界面上⽂本框中读取字符串,并进⾏判断:

    首先各项都必须按 照要求,⽐如年龄不能为字符,学号不能为字符等等
    然后判断是否有某项为空,有空则不允许插入
    最后检测学号是否重复, 重复则不允许插入。 然后在链表中更新完整记录,同时更新学号、电话号码、姓名的索引

    4.6 记录删除模块设计删除输入学号对应的记录,同时删除链表中的节点和各索引表中的索引。
    第五章 运行结果主界面

    添加纪录

    通过学号查找记录并修改

    查询界面

    查询信息如下所示:

    保存信息到本地

    第六章 课程设计总结
    ⼈机交互的问题,用户界面如何设计得美观且易于使用,在此使用java UI设计,设计友好美观的界面,方便用户使用
    怎样能利用合理的哈希函数构建算法和冲突处理算法
    如何实现记录与散列表分开,达到不同关键字散列表可共享记录
    3 评论 173 下载 2018-11-05 12:19:45 下载需要13点积分
  • 基于PHP和MySql的学生成绩管理系统

    摘 要随着学校向全国及至世界范围的持续扩张,学生人数的增加,对于学生的信 息管理也越来越复杂,要求也越来越高,因此需要一个全面、详细的信息管理系 统,以便完成对学生信息的管理。无纸化的环境是技术时代的一个梦想,也是许 多学校和公司越来越意识到的一个真实世界。以前是由学生档案和公告栏来提供 各种信息及通告新的变化,而现在这个繁杂的工作已被网站和内部计算机网络所 取代。使得学生信息的管理更方便、安全。 根据调查得知,现在广大学生进行信息提交的主要方式是基于文件、表格等 纸介质的手工处理,学生信息管理部门信息处理工作量大,容易出错,且管理方 面因人而异。然而学校网上学生信息管理系统应该覆盖各个所需功能,使各级管 理人员和广大教职工在信息系统的辅助下进行工作,提高管理的整体水平。使得 学生信息管理更方便。 学生信息管理系统,可以用集中的数据库将与人力资源管理相关的信息全 面、有机地联系起来,有效地减少了信息更新和查找中的重复劳动,保证了信息 的相容性,从而大大地提高了工作效率,还能使原来不可能提供的分析报告成了 可能。在采用和实施学生信息管理系统之后,就会将依赖于人的过程改为依赖于 计算机系统的过程。学校管理人员只要获取了相应的权限,就可以随时进入系统, 直接查阅相应的信息。采用和实施学生信息管理系统不仅仅是为了提高工作效 率。为了除掉手工记录的低效率工作方式,运用信息化管理,提高工作效率,开 发本系统。 应该看到,在实施学生信息管理系统后,经过整合的、较为全面、准确、一 致和相容的信息不仅可以让学校领导对本学校学生资源的现状有一个比较全面 和准确的认识,同时也可以生成综合的分析报表供学校领导人在决策时参考。
    1 绪论1.1 课题简介随着时代的发展,成绩管理 成了每个教育部门不可或缺的一部分,它的内容对于学校 的有效管理显得尤为重要,作为计算机的一部分,用计算机进行成绩管理无疑会把这个过程 变得尤为简单。 学生管理系统为学生提供了简易的操作和方便的查询,以及更好的被管理。
    1.2 系统背景随着社会信息量的与日俱增,学校需要有一个学生成绩管理系统,以方便对学生的成绩 进行有效的管理。学生成绩管理系统是一个学校不可缺少的重要部分,它的内容对于学校的 决策者和管理者来说都至关重要,所以学生成绩管理系统应该为用户提供充足的信息和快捷 的查询手段。当前成教学院没有一个完善的成绩信息管理平台,计算机使用主要基于 Microsoft Office,不能发挥有效的作用。而且随着我国教育改革的不断深入以及自学教育 的不断扩招,参加考试的人越来越多,考试科目的多样化,使得成教学院对自学考试成绩的 管理越趋繁琐、复杂,工作业务繁杂,工作量大,这种传统的学生管理模式已经暴露出种种 弊端:难以统一调配和处理,效率极低,缺乏科学性以及合理性。随着计算机应用的普及与 深入,利用计算机能够对所有自学考试成绩进行统一管理,并进行分析,大大减少教学秘书 的工作量,提高工作效率,为教学办公带来了极大的方便。通过操作手册,使用者可以了解 本软件的基本工作原理及使用说明。操作人员只需输入一些简单的汉字、数字,就可以存储、 查找、修改、打印学生成绩信息等。本系统开发的总体任务是实现学生成绩管理的系统化、 规范化、自动化、达到提高学生成绩管理效率的目的,本系统本着实用性、通用、开放和安 全的原则,使数据库开发软件开发制作,实现了学生信息管理、课程信息管理、学生成绩管 理、成绩查询等功能。该设计方法易于推广至其它信息化管理系统的设计,充分利用计算机 作为辅助工具,实现学生考试成绩从传统的手工管理到计算机管理,对提高管理效率和节约 大量的人力、物力有一定的推动作用。本系统一切从实际出发,充分考虑了成绩的内部管理、信息交流等方面的复杂需求,实现成绩的有效管理,真正为学生成绩管理提供一个电子平台。 合理的数据库结构设计可以提高数据存储的效率,保证数据的完整性和一致性。同时,合理 的数据库结构也有利于程序的实现。
    1.3 系统开发运行环境
    操作系统:win10
    软件:AppServ(php+apache+mysql),nginx(代理)

    2 需求分析2.1 系统需求当今社会,计算机的使用已经深入到日常生活和工作的方方面面,它逐渐成 为人们学习和工作时必不可少的工具。虽然目前为止已经开发出了成千上万的软 件系统,但它们并不能满足用户的各种特殊需要,因此人们不得不开发属于自己 的软件,能够满足自己的特殊需求。学生管理系统是教育事业单位必不可少的。 它的内容对学校的管理者来说至关重要,学生成绩管理系统应该能够提供快捷的 查询功能以及能够及时修改、增添、删除信息等功能。传统的人工管理文件档案 的方式存在很多缺点,例如:效率低、保密性差、另外时间一长,信息量的不断 扩增,都给查找、更新何维护带来很大困难。使用计算机对学生成绩进行管理, 具有手工管理不可比拟的优点。例如:检索迅速、查找方便、存储信息量大、保 密性好、及时更新并进行维护等。计算机管理学生成绩能够提高学校的管理效率, 是科学化、正规化管理的重要途径,型心计算机管理将不断深入到学校的各项事 务的管理当中。
    2.2 功能要求2.2.1 教职工对学生成绩有一个整体的了解,在今后的教学中能有所改进。同时可 以对自己教授的课程进行修改,进一步了解学生的个人情况,便于因材施教。 当学生的个人信息发生改变时,老师能够及时进行修改。例如学生转校、后来转 到本系、或者毕业生离开学校等,老师能够根据具体情况对学生信息进行添加、 修改、删除等。能够管理课程信息,合理安排老师教授的课程,及时为学生提供 选课信息。老师能够对课程名、课程编号、学分等进行修改和更新。能够对学生 成绩进行发布、修改、删除,清晰地了解学生的成绩情况,以便做出总结和改进。
    2.2.2 学生能够查询个人的学习成绩和总体学生的成绩,以便做出新的定位。

    成绩查询:成绩修改、成绩添加、成绩删除等
    课程查询:课程修改、课程添加、课程删除等
    学生查询:学生信息修改、学生信息添加、学生信息删除等

    2.3 可行性分析为了使系统在学院的管理中发挥更大的作用,实现工作过程的计算机化,提高工作效率 和工作质量,现提出如下的系统开发目标:

    提供了成绩查询的平台,可以用来发布成绩
    任何学生都能上去查看自己的成绩
    学生可以凭借自己的学号进行查询
    管理员可以进行数据的添加

    可行性研究的目的是用最小的代价在尽可能短的时间内确定问题是否能够解决。也就是说 可行性研究的目的不是解决问题,而是确定问题是否值得去解,研究在当前的具体条件下, 开发新系统是否具备必要的资源和其它条件。
    2.3.1 经济可行性主要从对项目的经济上进行分析评价,一方面是支出的费用,包括设备购置费、管理 和维护费用、人员工资和培训费等,另一个是取得的收益。这是个超小型的管理系统,从投 入的人力,财力与物力来讲是非常之小的,只要一台电脑,一台打印机,这个系统就可以搞 起来,考虑到学校里有电脑,现只要购置一台打印机就可以了。从节省人力方面,可以让管 理人员从繁与复杂的工作中解脱出来,做更多的工作,可以给教学管理提高一个层次。
    2.3.2 管理性学生成绩管理系统是对学生成绩进行管理的一个简单系统,主要又成绩的输入、输出、 浏览、打印、数据备份等组合而成,因此可适用于任何学校用作成绩管理。该系统管理方法 科学,相应的管理制度成熟,所记录的原始数据准确,且操作简单、快速,对管理人员的计算级应用技术要求不高,可被一般管理人员所接受,所以在管理上具备一定的可行性,便与普遍采用。
    2.3.3 技术性在开发本应用软件时,我是按照软件周期进行开发的。而我所设计的学生成绩管理系统 是一个用php 和 Mysql 加前端js框架实现的前后端分离开发的应用系统。
    2.4 安全与完整性要求建立数据库用户,对其权限进行设置。确定各表主键、索引、参照完整性、 用户定义完整性。
    2.5 数据字典学生表(学号,姓名,性别,系别,学生年龄)
    课程表(课程号,课程名,课时,学分)
    成绩表(课程号,学生号,成绩。)
    老师表(老师姓名,老师编号,所授课程,联系电话)

    名字:老师信息描述:学生成绩管理系统中存储的所有老师的信息定义:老师信息=老师姓名+所授课程+教师编号+联系电话
    名字:学生信息描述:学生成绩管理中存储的所有学生信息定义:学生信息=学生学号+学生姓名+学生性别+学生系别+学生年龄位置:存储 输出供查询
    名字:课程信息描述:多个必要课程信息组成定义:课程信息=课程号+课程名+课时+学分位置:存储 输出供查询
    名字:用户表信息描述:用户个人的信息定义:用户信息=用户名位置:存储 输出供查询
    名字:学生成绩信息输入:学生姓名输出:相应的学生成绩信息
    名字:查询信息描述:用户提出的具体查询请求定义:查询信息=[课程查询信息]+[学生查询信息]位置:课程表 学生表 成绩表
    名字:添加信息输入:学号、学生姓名、学生性别、系别、学生年龄输出:新输入的学生信息
    名字:删除信息输入:选中所要删除的学生信息输出:删除完成系统的实体与联系

    3 概念结构设计3.1 系统与实体的联系由需求分析的结果可知,本系统设计的实体包括:

    学生基本信息:学号,姓名,学院,班级,年龄,性别
    课程基本信息:课程名,课程号,学时
    教师基本信息:教师号,教师姓名,职称,年龄,性别,学院
    学院基本信息:学院名、学院号、院长姓名

    这些实体间的联系包括:

    每位学生可以学习多门课程,每门课程可供多位学生学习
    每门课可以由多个老师教,每个老师可以教多门课程
    学生每选一门课就可以得到一个成绩,不选此课就不能取得该课程成绩

    3.2 各个实体 E-R 图3.2.1 学生表
    3.2.2 教师表
    3.2.3 课程表
    3.2.4 成绩表
    3.2.5 总体实体练习图
    3.3 E-R图转实为关系模型3.3.1 学生表


    属性名
    数据描述
    数据类型
    是否为空
    备注




    sno
    学号
    Char(8)
    不允许为空
    主键


    sname
    姓名
    Char(10)
    不允许为空



    Ssex
    性别
    Char(2)
    不允许为空



    Ssex
    性别
    C har(2)
    不允许为空



    sbirth
    出生日期
    atetime(8)
    允许为空



    class
    所在班级
    Char(4)
    不允许为空



    type

    Char(7)
    允许为空



    3.3.2 教师表


    属性名
    数据描述
    数据类型
    是否为空
    备注




    tno
    教师编号
    char(5)
    不允许为空
    主键


    tname
    姓名
    varchar(10)
    不允许为空



    depart
    部门
    varchar(8)
    不允许为空



    Tsex
    性别
    char(2)
    不允许为空



    Tbirth
    出生日期
    datetime ,
    允许为空



    prof
    职称
    char(6)
    允许为空



    3.3.3 课程表


    属性名
    数据描述
    数据类型
    是否为空
    备注




    cno
    课程号
    Char(5)
    不允许为空
    主键



    cname
    课程名称
    varchar(10)
    不允许为空


    tno
    教师编号
    char(3)
    不允许为空



    3.3.4 成绩表


    属性名
    数据描述
    数据类型
    是否为空
    备注




    sno
    学号
    Char(8)
    不允许为空
    主键


    cno
    课程号
    Char(5)
    不允许为空
    主键


    degree
    成绩
    Float(8)
    不允许为空



    5 物理结构设计4.1 确定关系模型的存取方法在将概念模型转换成物理模型之后,我们可以对物理模型进行设计,双击 物理模型的关系,可以对该关系的名称、注释等信息进行查询。可对该关系的属 性列进行设计,可分别设置其名称、码、数据类型以及主码、是否为空等。在实 际设计中最常用的存取方法是索引发,使用索引可以大大减少数据的查询时间, 在建立索引时应遵循:在经常需要搜索的列上建立索引; 在主关键字上建立 索引;在经常用于连接的列上建立索引,即在外键上建立索引;在经常需要根据 范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的等规 则。才能充分利用索引的作用避免因索引引起的负面作用。
    4.2 数据流图该数据流图主要体现教职工对学生信息、课程信息和学生成绩的管理,然后 存储的信息作用于查询系统。在学生能够操作的只有成绩查询,如图所示:

    5 效果图5.1 登录5.1.1 学生
    5.1.2 教师
    5.1.3 管理员
    5.2.学生界面5.2.1 首页
    5.2.2 个人信息
    5.2.3 成绩查询默认当前学期

    选择学期

    5.2.4 本学期课表
    5.3 教师界面5.3.1 欢迎界面
    5.3.2 查询教授的课程
    5.3.3 录入成绩
    5.3.4 已录警告
    5.3.5 录入
    5.3.6 选择查看教授的课程已录入的成绩
    5.4 管理员界面5.4.1 学生管理界面查询所有

    分类模糊查询

    添加学生

    编辑信息

    删除学生

    5.4.2 教师管理查询所有

    分类模糊查询

    添加教师

    编辑信息

    删除学生

    5.4.3 课程管理
    5.4.4 排课管理
    5.5 其他5.5.1 退出登录
    5.5.2 修改密码
    6 主要代码6.1 database.php<?phpreturn [ // 数据库类型 'type' => 'mysql', // 服务器地址 'hostname' => '127.0.0.1', // 数据库名 'database' => 'grademanager', // 用户名 'username' => 'root', // 密码 'password' => '123456', // 端口 'hostport' => '3306', // 连接dsn 'dsn' => '', // 数据库连接参数 'params' => [], // 数据库编码默认采用utf8 'charset' => 'utf8', // 数据库表前缀 'prefix' => '', // 数据库调试模式 'debug' => true, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) 'deploy' => 0, // 数据库读写是否分离 主从式有效 'rw_separate' => false, // 读写分离后 主服务器数量 'master_num' => 1, // 指定从服务器序号 'slave_no' => '', // 是否严格检查字段是否存在 'fields_strict' => true, // 数据集返回类型 'resultset_type' => 'array', // 自动写入时间戳字段 'auto_timestamp' => false, // 时间字段取出后的默认时间格式 'datetime_format' => 'Y-m-d H:i:s', // 是否需要进行SQL性能分析 'sql_explain' => false,];
    6.2 登录代码 // 登录 public function login() { $t = model('CommonResData'); if (input('post.username') && input('post.password')) { $username = input('post.username'); $password = input('post.password'); $identity = input('post.identity'); if ($identity == 0) { $t->data = Db::query("select admin_name from admin where admin_id=$username and admin_password='$password'"); if ($t->data) { $t->code = 0; $t->data = $t->data[0]['admin_name']; // return JSON($t->resData($t->code,$t->data)); } else { $t->code = 3; $t->data = '没有该用户或密码错误'; } } else if ($identity == 1) { $t->data = Db::query("select teacher_name from teacher where teacher_id=$username and teacher_password='$password'"); if ($t->data) { $t->code = 0; $t->data = $t->data[0]['teacher_name']; // return JSON($t->resData($t->code,$t->data)); } else { $t->code = 3; $t->data = '没有该用户或密码错误'; } } else if ($identity == 2) { $t->data = Db::query("select student_name from student where student_id = $username and student_password='$password'"); if ($t->data) { $t->code = 0; $t->data = $t->data[0]['student_name']; } else { $t->code = 3; $t->data = '没有该用户或密码错误'; } } else { $t->code = 2; $t->data = '登录失败'; } Session::set('islogin',$username); Session::set('identity',$identity); return JSON($t->resData($t->code,$t->data)); } else { $t->code = 2; $t->data = "用户名密码不能为空"; return JSON($t->resData($t->code,$t->data)); }}
    6.3 判断是否登录 public function isLogin() { $isLogin = Session::get('islogin'); $t = model('CommonResData'); if (!$isLogin) { $t->code = 1; $t->data = '未登录'; return; } else { $t->code = 0; session('islogin', $isLogin); } }
    7 总结在此次的学生成绩管理系统程序设计的过程中,我充分认识到了做计划的重要性,只要实现把整体方案规划好,才能保证以后设计的顺利进行,才能应对出现的突发事件,达到系统设计的目标。在开始进行系统设计时,我对管理信息系统的认识比较少,对系统的开发 缺乏本质和深入地研究调查,以至与在着手设计的过程中,困难接踵而至。然而又不知道怎样解决,直到后来重新对此次的设计做了认真细致的规划调查,最终才使整个程序的设计工作完成,当爱系统还是有很多不足。然而,本次程序设计的收获不仅仅让我了解了 php与 appServ,使我对系统开发有了初步的了解,提高了编写程序的兴趣,如果今后有机会的话,我希望能够对编程有更深入的学习。
    5 评论 116 下载 2019-09-25 17:04:50 下载需要15点积分
  • 基于JSP的在线调查问卷系统

    一、系统架构图用户登入功能,由login.jsp页面和LoginServlet.java组成,页面用于填写用户名和密码;Servlet用于验证是否可以登入,如果能够登入,则将用户登入时间记录到数据库表中,并转向main.jsp;不能登入给出提示,并转向login.jsp。
    用户注册功能,由register.jsp页面和RegsiterServlet.java组成。页面用于设计输入表单;Servlet用来将数据插入数据库表中,需要调用JavaBean。
    main.jsp中显示所有调查问卷的信息(来自LogInfo表)和一个用户注销按钮。如果身份是问卷调查人,能够通过发布问卷按钮发布问卷。如果是管理员则有一个用户管理按钮,可以管理用户。点击用户注销按钮时,将退出时间存入数据库表中,并转向 login.jsp;如果session超时或用户直接关闭浏览器也要将退出时间存入数据库表,使用session监听器实现这个功能。
    管理员点击首页的用户管理按钮后,进入userManagement.jsp,页面中显示所有用户的登入或退出系统的信息(来自LogInfo表)和一个返回首页按钮。还显示用户信息的列表,能够通过删除用户按钮通过AdminServlet.java删除指定用户,通过升级为问卷调查人问卷将普通用户的权限提高为2,使得用户能够出问卷。点击添加用户按键,跳转到adduser.jsp界面,能够添加用户,成功后返回用户管理页面。
    问卷调查人和管理员点击首页的发布问卷按键后,进入问卷发布页AddPaper.java,添加问卷后经过QuestionServlet.java处理后跳转到addChoiceQuestion.jsp,通过标签 单选题addChoiceQuestion.jsp、问答题addAnswerQuestion.jsp、多选题addMultiChoiceQt.jsp能够出问卷,出一题后会跳转到addQuestionSuccess.jsp提示继续出题或预览问卷preScanSurvey.jsp,预览问卷时能发布问卷和继续出题。
    首页点击查看问卷按钮后,通过ShowResult.java能查看问卷调查的统计结果信息showresult.jsp。
    当用户没有登录并在浏览器中直接访问main.jsp页面,则要求其登录。
    所有用户都能够参与问卷调查,在首页点击相应的问卷名字后打开surveypage.jsp,填写完整后提交问卷SurveySubmit.java把数据插入到数据库中保存。
    系统用例图如下所示:

    总体架构图如下所示:

    二、系统主要文件的名称和功能简介系统中所有的JSP、Servlet、JavaBean、Listener、Filter的名称和功能简介。
    ├─com│ │ LoginInfo.java 用户登录退出信息│ │ Paper.java 问卷信息│ │ Question.java 问卷问题信息│ │ UserInfo.java 用户基本信息│ ││ ├─dao│ │ │ PaperDao.java 问卷数据访问对象接口│ │ │ QuestionDao.jav 问题数据访问对象接口│ │ ││ │ └─mysqlimpl│ │ BaseDao.java mysql基本数据访问对象 │ │ PaperDaoImpl.java 问卷数据访问对象实现│ │ QuestionDaoImpl.java 问题数据访问对象实现│ ││ └─service│ │ PaperService.java 问卷类服务接口│ │ QuestionService.java 问题类服务接口│ ││ └─impl│ PaperServiceImpl.java 问卷类服务实现│ QuestionServiceImpl.java 问题类服务实现│├─db│ DB.java 数据库连接│├─filter│ LoginFilter.java 当用户没有登录并在浏览器中直接访问main.jsp页面,则要求其登录│├─listener│ LogoutListener.java 监听用户注销 注销时间记录在数据库中│└─servlet AddPaper.java 添加问卷信息Servlet AdminServlet.java 管理员管理用户信息Servlet LoginServlet.java 用户登录Servlet QuestionServlet.java 添加问题Servlet RegisterServlet.java 用户注册Servlet ShowResult.java 显示问卷统计信息Servlet SurveyPage.java 访问指定编号问卷Servlet SurveySubmit.java 提交问卷调查信息Servletjsp页面
    │ addAnswerQuestion.jsp 添加问答题页面│ addChoiceQuestion.jsp 添加单选题页面│ addMultiChoiceQt.jsp 添加多选题页面│ addpaper.jsp 添加问卷页面│ addQuestionSuccess.jsp 添加问题成功后的提示页面│ adduser.jsp 添加用户页面│ login.jsp 用户登录页面│ main.jsp 系统主界面│ MysqlTest.jsp mysql连接测试页面│ preScanSurvey.jsp 预览问卷 做问卷中途查看效果页面│ register.jsp 用户注册页面│ showpaper.jsp 查看问卷 输入问卷编号后跳转到指定问卷页面│ showresult.jsp 显示问卷调查结果页面│ showResultAfterAnswer.jsp 回答问卷后显示问卷调查结果页面│ surveypage.jsp 问卷调查主页面│ temp.jsp 用户未登录临时跳转页面│ userManagement.jsp 管理员用户管理页面三、数据库表设计Userinfo表
    示例值:

    Logininfo表
    示例值:

    Questions表
    示例值:

    Papers表
    示例值:

    四、程序运行效果用户登录界面

    用户注册

    系统主界面,根据用户的身份不同,会有不同的欢迎提示消息,如果为管理员,还可以管理用户,右上角可以注销登录。点击问卷名可以参与问卷调查,点击查看结果可以查看问卷调查结果。最新添加的问卷排在前面。

    管理员用户管理界面,显示用户的登录和注销时间信息。管理员能够添加删除用户,将用户升级为问卷调查人,即指定问卷调查人。

    发布问卷页面

    单选题、问答题、多选题各种题型添加

    填写问卷示例

    以图表的形式显示问卷调查结果

    五、实验总结通过本次试验,我对用JSP编写网站的过程熟悉了很多。对JSP、Servlet、JavaBean、Listener、Filter有了更加深的了解。
    本次试验是在上一个JDBC的实验基础上继续做的,又因为通过实习前两周培训,上了软件体系结构这门课,把DAO(Data Access Object)的编程思想马上运用到实验中来,学以致用。DAO模式是标准的J2EE设计模式之一,开发人员使用这个模式把底层的数据访问操作和上层的商务逻辑分开。在本次试验过程中,同样不可避免的遇到了很多的问题,有时候文件改太多不知道错了哪里很不好解决,还好我有通过svn来进行代码版本管理,存在问题的文件返回到正常的版本。编程过程中遇到的问题,通过和同学讨论,基本能解决问题。数据库的设计是参考大型问卷管理系统的,具体有些字段还没有实现,不过对于系统的扩充有很重要的意义。
    2 评论 23 下载 2020-01-15 22:51:47 下载需要13点积分
  • 基于Qt实现的旅行模拟器

    一、设计任务的描述城市之间有三种交通工具(汽车、火车和飞机)相连,某旅客于某一时刻向系统提出旅行要求,系统根据该旅客的要求为其设计一条旅行线路并输出;系统能查询当前时刻旅客所处的地点和状态(停留城市/所在交通工具)。
    二、功能需求说明及分析
    城市总数不少于10个(13个)
    建立汽车、火车和飞机的时刻表(航班表)

    有沿途到站及票价信息不能太简单(不能总只是1班车次相连)
    旅客的要求包括:起点、终点、途经某些城市和旅行策略
    旅行策略有:

    最少费用策略:无时间限制,费用最少即可最少时间策略:无费用限制,时间最少即可限时最少费用策略:在规定的时间内所需费用最省

    三、总体方案设计说明软件开发环境、总体结构和模块划分等。
    Windows下开发,使用Qt Creator作为IDE,MySQL数据库进行时刻表调用,C++语言编程。
    目前为单一窗口,如果需要显示地图,可以增加一个窗口。
    模块:

    Main:调用其他各个模块
    Widget:主窗口,其上有输入信息和输出信息
    Route:地图窗口,可以显示地图以及当前的位置,预计路径行程等
    Passenger:储存输入的信息,当前状态,计算后的预计行程等
    LogFile:记录日志
    TimeTable:进行数据库的访问,将访问数据库封装成该类的方法

    应该还有一个计时器来模拟时间流动。


    四、数据结构说明和数据字典struct Status//保存当前状态{ char transport;//当前交通工具 QString curCity;//当前城市 QString nextMove;//下一步};class Passenger//当前乘客的信息{public: Passenger(); enum POLICY{minTime,minCost,timeLimitCost}; void setStart(QString s); QString getStart(); void setEnd(QString e); QString getEnd(); void setPolicy(int p); int getPolicy(); void setLimitTime(double L); double getLimitTime(); void setWayCities(QList<QPair<QString, double>> W); QList<QPair<QString, double>> getWayCities(); void setSequence(bool checked); bool isSequence();private: QString start;//起点 QString end;//终点 int policy;//策略 double limitTime;//限时最低价格的限制时间 QList<QPair<QString, double>> wayCities;//途经城市 bool sequence;//是否有顺序 Status curStatus;//暂时打算用作储存当前状态};struct EdgeType { int cost = A_BIG_INT;};//邻接矩阵class Graph //{public: Graph(); void CreateGraph_MinCost();//根据数据库建立最低价格的矩阵 int Dijkstra(QString start_city, QString end_city, vector<QString> &out); //迪杰斯特拉求最短路径 int LeastCost(QString start_city, QString end_city, vector<QString> &mid_city, int isOrdered, vector<QString> &rout); //求总路径private: vector<QString> vertex;//城市名表 EdgeType arc_MinCost[100][100];//邻接矩阵,可看作边表 int numVertex;//图中当前的顶点数 int numEdge; //图中当前的边数};struct Info//数据库中一条数据{ QString trainnumber; QString departcity; QString arrivecity; QTime departtime; QTime arrivetime; int price; int id;};class TimeTable{public: TimeTable(); ~TimeTable(); static int getMinPrice(QString start, QString goal); //根据起点终点从数据库中寻找最少价格 static Info getInfo_MinCost(QString start, QString goal); //根据起点终点从数据库中提取最少价格的那一条数据private: QSqlDatabase db; static QMap<QString,QString> full2Short; //全名映射到简称};
    五、各模块设计说明在widget窗口中输入,即时设定好passenger的成员变量,点击开始后,执行算法。
    最少费用:价格作为有向网的权值,利用迪杰斯特拉算法设计出路线。
    3 评论 38 下载 2019-06-30 10:37:48 下载需要12点积分
  • 基于C语言的外卖派单模拟系统

    一、课题任务概述你运行一家外卖快递服务店,负责一个区域内的外卖订单接收和餐食快递。你有一笔启动资金,可以招募外卖骑手帮你送餐,来赚取快递费。但你也会面临风险,本区域的订单你都有义务接收,不能拒绝,若拒单就会被工商部门吊销营业执照;但如果接收多个订单后,因为骑手来不及送达,导致某个订单超时未送达,客户会投诉,你会被罚款。
    因此,你的任务就是制定聪明的调度策略,避免拒单被吊销营业执照(人工调度在订单高峰期可能会来不及接收),避免因为罚款而破产,并且尽可能赚更多的钱。
    二、规则2.1 规则一:负责的区域
    约束1-1:你的区域必须是一个9*9的方格,每格是一个房间,既可以是下订单的食客家,也可以是接单的餐馆
    约束1-2:方格之间的8*8条街道是骑手唯一可走的道路;骑手停在方格的上下左右街道,即算抵达
    约束1-3:每个方格的宽高都一样,即骑手走过每个方格的距离一样,速度也一样,约定为骑手每走过一个方格花费1个时间单位,骑手从最左边直达最右边花费时间8个时间单位,即拐弯不花时间,经过路口不花时间。每个时间单位暂定为20秒,后续可能会统一修改
    约束1-4:为了记录房间和骑手位置,坐标系定为17*17,约定左上角的房间逻辑坐标为(0, 0),右下角房间的逻辑坐标为(16, 16)。横纵坐标一奇一偶的都是路,坐标都是偶数的是房间,坐标都是奇数的是路口

    2.2 规则二:外卖订单格式和输入方式
    约束2-1:你负责的外卖派送区域内,发起的任何订单都必须接收;如果订单发起后,3个时间单位内没有派单给现有骑手,则视为拒单,你将被吊销营业执照,运营终止
    约束2-2:外卖订单的信息格式是一个四元组(n序号,t下单时间,餐馆坐标,食客坐标);具体格式规范如下,必须按此规范执行。(注:/表示前后数据分隔的含义,实际中不出现)。序号/分隔符空格 /下单时间/分隔符空格/餐馆坐标x/分隔符空格/餐馆坐标y/分隔符空格/食客坐标x/分隔符空格/食客坐标y/回车符/n。约束2-3:外卖订单的输入方式,要求一套程序支持以文本文件格式的输入方式,和鼠标操作的输入方式两种。两种方式不会同时生效。

    文件输入方式:系统启动后检查当前目录下是否有标准文件名“sales.txt”,若有则自动进入订单强制文件输入方式。sales.txt文件必须遵从约束2-2规定的文件格式。
    鼠标操作方式:系统启动后检查当前目录找不到标准文件“sales.txt”,则自动进入订单强制鼠标输入方式。系统运行期间,鼠标点中任意方格再拖拽至另一方格,即算完成从餐馆到食客的订单发起动作,系统必须实时记录并进行派单。
    2.3 规则三:运营规则
    约束3-1:系统开始运营时,你有1000$作为运营资本
    约束3-2:你必须有骑手才能接单,招聘一位骑手需投资300$; 只要你有钱,骑手数量不限;在系统运营的整个期间,你都可以随时招聘骑手,但必须有足够的钱,不能拖欠
    约束3-3:招聘骑手的发起方式只能是两种方式,一种是你的调度程序自动发起,另一种是做成输入按钮,鼠标点击的方式发起。你可以只实现一种,也可以两种都实现,两种都实现的好处是人工调度比自动调度聪明
    约束3-4:接单的方式只能是将其按顺序派给指定骑手。接单的操作可以是人工接单,也可以是程序按调度策略自动接单。人工接单的操作比较复杂,需要用鼠标逐个选中现有未处理订单,将其分配给某个骑手
    约束3-5:所有骑手的初始位置必须是同一位置;但起始位置需要在你的程序中自行设定。骑手初始位置的设定可以在程序中写死,也可以在系统启动时修改设置,两种均可。注意:如果骑手初始在左上角,那么立刻接到一个(右下角>左上角)的订单时,可能超时
    约束3-6:每个订单从下单时间开始,要求在30个时间点内完成服务(先后抵达餐馆和食客家),否则算超时。满30个时间点订单若没有完成结单,客户会投诉导致立刻罚款50$; 满60个时间点订单若没有完成结单,属于恶意废单立刻破产
    约束3-7:每完成一单且不超时,可收入10$
    约束3-8:无须考虑骑手负载限制,一位骑手可以带无限外卖;但超时未达要按约束3-6条处罚
    约束3-9:负债即破产!一旦破产,即刻停止运营,系统盘点每位骑手的接单数、完成数、超时数
    约束3-10:系统运营期间,至少每个时间单位更新一次,显示当前钱数、每位骑手的位置、接单数、完成数、超时数

    2.4 规则四:技术框架
    约束4-1:程序代码主体必须是C语言编写。
    约束4-2:界面部分,允许使用C++的动画包。
    约束4-3:主干代码不允许抄袭,无论是来自互联网或者其他设计人员

    2.5 建议:派单的基础策略
    策略x-1:首先按下单时间顺序,将新订单放入待处理队列
    策略x-2:根据骑手数量,将区域划分为几块,分给每个骑手,注意预先保留一个跨区域订单骑手
    策略x-3:派单时,从待处理队列取出队首订单,判断属于哪个区域,就分给哪个骑手,分派后此单出待处理队列,加入对应骑手的待送达队列;餐馆和食客不在一个区域的订单,分给跨区域骑手
    策略x-4:当跨区域骑手的待派送队列中元素超过预警值时(例如10个),再分出一个骑手作跨区域骑手,剩下骑手重新划分区域,更改仅对后续订单生效,已分配订单受影响。注意:预警值是你自己在程序中设定的,根据经验设置
    策略x-5:所有单派完后,开始轮流对所有骑手的待派送队列进行优化。优化策略是:取出队首订单,作为当前目标点;计算骑手当前位置和当前目标点的区域范围,然后扫描队列后续订单中的所有可达目标点(见后续解释),筛选出属于此区域内的,设计出合理的行走路线,只要按此路线当前目标点不超时,即可插入到队首目标点之前。

    为了完成上述优化策略,骑手的待派送队列要把每个订单拆成A、B两个任务,每个元素都包含订单号、A或B标志,坐标位置点,下单时间,是否可达,这五个数据。A任务没有约束条件,任何时间都属于可达目标点;B任务,默认不可达,只有在A任务完成时,扫描队列将A任务对应订单号的B任务改为可达。

    策略x-5附加动作:当骑手的当前位置抵达待派送队列队首元素,队首元素出队,执行任务撤销处理,若是A任务,修改队列中对应B任务为可达; 若是B任务,计算是否超时,超时罚款,最后将该骑手的完成订单数+1
    三、模块划分3.1 输入模块
    接单(sales.txt)(按照订单中的时间匹配上clock()/CLOCKS_PER_SEC使用)
    信息格式是一个四元组(n序号,t下单时间,餐馆坐标,食客坐标)
    准备使用二元数组存储

    3.2 控制模块
    分区:为每一位骑手划分指定的派送区域
    分单:遍历订单,根据区域分给骑手(注:要分别设定本区预警值,和跨区预警值,达到预警值,返回第一步,重新分区)(还是需要一个时间预警值,比如超过2.5个时间单位,订单还没有被分配,需要优先被分配给订单少的骑手)(三个判断)
    聘骑手:每聘请一名新的骑手,执行第一步分区(初始化是3个)(每多一个要分配一个数组)(但是要考虑预留一部分罚款金额:(n-2)*100)/*n为骑手数目*/
    派单:需要考虑路线和时间,目标是不拒单,少罚款,路线设计上争取时间最短

    3.3 输出模块每个时间单位输出一次:骑手位置,接单数,完成数,超时数,钱。
    模块调用关系

    四、关键数据类型订单:二元数组(目前想法10000*6)(非静态全局变量)



    序号
    时间
    餐馆x
    餐馆y
    食客x
    食客y













    每一位骑手的派送区域:二元数组(例 0 5 0 5 表示派送区域0<=x<=5,0<=y<=5)



    骑手序号
    横坐标x范围
    横坐标x范围
    纵坐标y范围
    纵坐标y范围



















    每一位骑手的订单:二维数组



    序号
    接单时间
    餐馆坐标x
    餐馆坐标y
    食客坐标x
    食客坐标y





















    骑手位置



    骑手序号
    骑手位置x
    骑手位置y















    待分配订单二元数组



    序号
    时间
    餐馆x
    餐馆y
    食客x
    食客y





















    五、关键全局变量
    接单数 task
    完成数 finish
    超时数 overtime
    钱 money
    时间单位数 time unit
    骑手数 rider

    六、关键常量
    订单预警值
    时间预警值
    时间单位常量(0.05秒)
    超时时间(30个时间单位)
    拒单时间1(3个时间单位)
    拒单时间2(60个时间单位)

    七、关键算法7.1 分区对于3-10个骑手使用枚举算法:

    3个人:左半边,右半边,以及一个跨区
    4个人:左半边,右半边,两个跨区(随机分配)
    5个人:左半边,右半边,三个跨区(随机分配)
    6个人:三个区:左边,中间,右边,三个跨区(左和中,左和右,中和右)
    7个人:三个区:左边,中间,右边,四个跨区(左和中,左和右,左和右,中和右)
    8个人:三个区:左边,中间,右边,五个跨区(左和右,左和右,左和中,右和中,第五个要判断左和中,右和中那个订单压力大就分给哪个)
    9个人:三个区:左边,中间,右边,六个跨区(左和右,左和右,左和中,左和中,右和中,右和中)
    10个人:四个区:a和b, a和c, a和d, b和c, b和d, c和d, a和a,b和b, c和c, d和d

    往后当骑手增加的时候,判断哪个区域订单压力最大,就分配到哪个区域。
    7.2 分单根据时间单位来读取订单进入待处理订单中,然后依次进行if判断,来确定该订单位于哪一个区域中,从而分配到对应骑手的派送订单中,在进行判断的同时,要用当前时间单位减去待处理订单中的所有订单来判断是否有订单要超时(预警值暂定为2.5个时间单位)(如果存在这样的订单,立刻对各个骑手的派送订单数做统计,将这个订单派给订单最少的骑手),将订单分给骑手的同时,要记录每个骑手的接单数,当接单数等于订单预警值,就要重新分区(区数减一,跨区骑手加一)。
    7.3 聘骑手骑手数加一,需要设定一个预留的罚款金额(要随骑手数目增加而线性增加),当骑手数目加一,则需要调用分区算法来决定新的分区。
    7.4 派单先取区域内所有的餐馆的餐(以横坐标为基准,用骑手的横坐标分别减去区域内各餐馆的横坐标,正值即餐馆在骑手左侧,负值即餐馆在骑手右侧;比较最大正值和最小负值的绝对值的大小,若正值更小,则骑手先往左侧取餐,若负值绝对值更小,则骑手先往右侧取餐,然后凑y值趋势。)(注:当某一列的餐馆与当前骑手位置的纵坐标差值>=6时,先放弃取餐,延后处理)。后送区域中所有食客的餐,(方法与送餐一样)并更新各订单状态(超时或送达),同时更新超时数,完成数,资金,并把送达的订单从配送队列中。
    7.5 删除当时间等于29个时间单位时,遍历一遍待配送队列是否有订单还未从餐馆取走,若有,则抛弃之后要送给食客的订单,回去取未取订单,再继续送给食客。
    八、用户界面设计左侧订单状态中第一栏是骑手编号和位置坐标,第二栏是订单中餐馆位置和食客位置,第三栏是每一个订单的完成状况:超时或完成。

    初始界面

    运行界面
    0 评论 2 下载 2020-07-04 20:51:02 下载需要15点积分
  • 基于Java和Mysql的学生成绩管理系统

    一、相关技术介绍
    开发环境:Windows 10
    数据库管理系统:Mysql
    开发工具:Intel IDEA
    运行环境:Windows 10以及更高版本
    系统结构:C/S

    二、系统需求分析2.1 业务流程用户登陆到系统后,在本系统中可以选择进行考试成绩录入、补考成绩录入、重修成绩录入,或查看总评成绩单、补考通知单、补考成绩单、重修通知单、重修成绩单、优秀学生名单等…
    2.2 功能需求
    用户能够登入本系统
    用户可以在系统中录入考试成绩
    用户可以在系统中录入补考成绩
    用户可以在系统中录入重修成绩
    用户可以在系统中查看总评成绩单
    用户可以在系统中查看补考通知单
    用户可以在系统中查看补考成绩单
    用户可以在系统中查看重修通知单
    用户可以在系统中查看重修成绩单
    用户可以在系统中查看优秀学生名单

    2.3 信息需求
    进行成绩录入时不允许存在列值为空
    进行成绩录入时需保证学生学号、姓名、选课的一致性

    2.4 安全性与完整性需求数据库上信息的安全性由数据库管理系统进行保证,完整性则主要由编程语句来体现。
    2.5 数据字典


    数据项名称
    别名
    类型
    含义说明




    学号
    s_no
    Char(8)
    学生的唯一标识


    姓名
    s_name
    Char(8)
    学生的姓名


    性别
    s_sex
    Char(2)
    学生的性别


    班级
    s_class
    Char(8)
    学生的专业


    专业
    s_spec
    Char(8)
    学生的专业


    课程号
    c_no
    Char(8)
    课程的唯一标识


    课程名
    c_name
    Char(8)
    课程的名字


    课程学分
    c_point
    Smallint
    课程的学分


    上课时间
    c_time
    Smallint
    上课时间


    平时成绩
    ord_score
    Int
    学生某课程的平时成绩


    考试成绩
    exam_score
    Int
    学生某课程的考试成绩


    补考成绩
    makeup_score
    Int
    学生某课程的补考成绩


    重修成绩
    renovate_score
    Int
    学生某课程的重修成绩


    总评成绩
    final_score
    Int
    学生某课程的总评成绩



    2.6 系统结构
    各模块功能说明:

    系统登录:该系统使用时需登录
    成绩录入:用于录入各类成绩
    考试成绩录入:用于登录入考试成绩及平时成绩
    补考成绩录入:用于录入补考成绩
    重修成绩录入:用于录入重修成绩
    信息查询:用于查询各种信息
    总评成绩:用于输出总评成绩。其中:总评成绩=30%*平时成绩+70*考试成绩
    补考通知单:用于输出补考名单,即总评成绩不到60分的学生
    补考成绩单:用于输出补考学生的成绩
    重修通知单:用于输出重修名单,及总评成绩 < 60且补考成绩也 < 60的学生
    重修成绩单:用于输出重修学生的成绩
    优秀学生名单:用于输出优秀学生。及该学生每科总评成绩均大于60
    退出系统:退出系统

    三、概念模型设计E-R图

    四、逻辑结构设计学生信息表(学号,姓名,性别,班级,专业)


    主键:学号
    外键:无
    非空:学号、姓名

    选课表(学号,课程号,课程名)


    主键:无
    外键:学号、课程号
    非空:学号、课程号

    课程表(课程号,课程名,课程学分,上课时间)


    主键:课程号
    外键:无
    非空:课程号,课程名

    成绩表(学号,课程号,课程名,平时成绩,考试成绩,补考成绩,重修成绩,总评成绩)


    主键:无
    外键:学号、课程号
    非空:无

    五、物理结构设计建立数据库表
    下面使用Mysql可视化工具Navicate进行建库、建表操作。

    六、数据库连接与应用6.1 Java中通过JDBC连接数据库关键代码如下:
    static { try { if (conn == null) { Class.forName(driver).newInstance(); conn = DriverManager.getConnection(dbUrl, dbUser, dbPwd); } } catch (ClassNotFoundException e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "数据库连接异常!"); System.exit(0); } catch (Exception e) { e.printStackTrace(); }}
    6.2 数据库的运行与维护登录界面

    主界面

    选择界面

    信息查询界面

    查询的SQL语句如下:
    String sql = "select student.s_no,student.s_name,score.c_name " + "from student,score " + "where student.s_no=score.s_no and score.final_score<60";
    考试成绩录入

    录入的SQL语句如下:
    String sql = "Insert " + "into score(s_no, c_no, c_name, ord_score, exam_score, final_score) " + "values(?, ?, ?, ?, ?, ?)";
    七、收获与体会通过本次的数据库课程设计,我进一步的了解了数据库的开发和使用,与看课本学习不同的是,这次是动手实践去做,而不仅仅局限于课本上的理论知识,更加进一步加深了对数据库的理解,同时也对Java语法、JDBC使用更加熟练。
    3 评论 206 下载 2019-06-16 12:48:24 下载需要13点积分
  • C++实现的基于α-β剪枝算法的井字棋游戏

    一、井字棋游戏规则“井字棋”游戏(又叫“三子棋”),是一款十分经典的益智小游戏,操作简单,娱乐性强。两个玩家,一个打圈(O),一个打叉(X),轮流在3乘3的格上打自己的符号,最先以横、直、斜连成一线则为胜。
    如果双方都下得正确无误,将得和局。
    这种游戏实际上是由第一位玩家所控制,第一位玩家是攻,第二位玩家是守。
    X方取胜的情况

    和局的情况

    第一位玩家在角位行第一子的话赢面最大,只要第二位玩家不是在中间下子,第一位玩家就可以以两粒连线牵制着第二位玩家,然后制造“两头蛇”。

    二、井字棋与人工智能这种游戏的变化简单,常成为博弈论和赛局树搜寻的教学例子。这个游戏只有765个可能局面,26830个棋局。如果将对称的棋局视作不同,则有255168个棋局。
    由于这种游戏的结构简单,这游戏就成为了人工智能的一个好题目。学生都要从既有的玩法中,归纳出游戏的致胜之道,并将策略演绎成为程式,让电脑与用户对奕。
    世界上第一个电脑游戏,1952年为EDSAC电脑制作的OXO游戏,就是以该游戏为题材,可以正确无误地与人类对手下棋。
    三、设计方案将井字棋游戏设计为人机对弈系统,分别用X代替人(玩家)的棋子,用O代替机(电脑)的棋子。玩家可以选择自己或电脑先下(游戏实际上是由先下的一方所控制),电脑一方是由程序选择对自己最有利的棋局决定下一步,程序利用Minimax算法结合α-β剪枝算法实现电脑的走步。结局有三种情况:玩家赢,电脑赢或平局。
    用一个3×3的井字格来显示用户与电脑下的界面,使用提示信息要求用户输入数据。当用户与计算机分出了胜负后,机器会显示出比赛的结果,并由用户选择是否重玩游戏。
    四、算法实现4.1 Minimax(极大极小法)算法思想设博弈双方中一方为MAX,另一方为MIN。然后为其中的一方(计算机)找一个最佳走法。
    为了找到当前棋局的最优走法,需要对各个可能的走法所产生的后续棋局进行比较,同时也要考虑对方可能的走法,并对后续棋局赋予一定的权值(或者称之为分数)。也就是说,以当前棋局为根节点生成一棵博弈树,N步后的棋局作为树的叶子节点。同时从树根开始轮流给每层结点赋予Max和Min的称号。
    用一个评估函数来分析计算各个后续棋局(即叶子节点)的权值,估算出来的分数为静态估值。要注意将某方获胜的状态节点的评估函数值设为计算机能表示的最大数(无穷大)或最小数(无穷小)以表明在该状态下有一方获胜。
    当端节点的估值计算出来后,再推算出父节点的得分。推算的方法是:对于处于MAX层的节点,选其子节点中一个最大的得分作为父节点的得分,这是为了使自己在可供选择的方案中选一个对自己最有利的方案;对处于MIN层的节点,选其子节点中一个最小的得分作为父节点的得分,这是为了立足于最坏的情况,这样计算出的父节点的得分为倒推值。
    如此反推至根节点下的第一层孩子,如果其中某个孩子能获得较大的倒推值,则它就是当前棋局最好的走法。
    不过在极大极小法中,必须求出所有端点的评估值,当预先考虑的棋步比较多时,计算量会大大增加。因此,α-β剪枝方法是一种效率比较高的方法。在α-β剪枝方法中,采用了两个变量a和β,它们是最终可以获得的对最大评估值和最小评估值的估计值。
    α-β剪枝的方法如下:

    max节点的α值为当前子节点的最大倒推值
    min节点的β值为当前子节点的最小倒推值
    α-β剪枝的规则如下:

    任何max节点n的α值大于或等于它先辈节点的β值,则n以下的分枝可停止搜索,并令节点n的倒推值为α。这种剪枝称为β剪枝任何min节点n的β值小于或等于它先辈节点的α值,则n 以下的分支可停止搜索,并令节点n的倒推值为β。这种剪枝技术称为α剪枝

    算法流程图

    五、程序模块分析
    程序用一个二维数组chess[3][3]表示一个棋盘
    IsWin()函数:判断某一状态是否胜负已决。返回0表示没有人赢,返回-1表示玩家赢了,返回1表示电脑赢了
    Evaluation()函数:评估函数,主要思想是计算每一行、每一列、斜线中连成3个棋子的有多少个
    AlphaBeta()函数:α-β剪枝算法的实现。获胜的状态节点的评估函数值设为计算机能表示的最大数(无穷大)或最小数(无穷小)以表明在该状态下有一方获胜
    PlayerInput()函数:提示玩家输入,用户通过此函数来选择落子的位置,并提示不正确的输入
    PrintChess()函数:将棋盘以界面的形式显示出来,棋盘的信息存储在一个二维数组chess[3][3]中
    PlayChess()函数:人机对弈模拟过程的实现

    六、结果演示X代替玩家的棋子,用O代替电脑的棋子,口代表空位置

    玩家选择谁先走,这里我们让玩家先走:

    两者交替走步,直到分出胜负:

    结果分析
    上述情况事实上是玩家唯一可以赢电脑的情况,除此之外,玩家至多平局。赢电脑的情况是因为当玩家两个棋子占据棋盘对角的时候,电脑还预测不到玩家的意图,当第三个棋子占据棋盘一角三个棋子成掎角之势时,出现了两种赢的情况,电脑已经守不住了。
    3 评论 117 下载 2018-11-04 22:40:48 下载需要12点积分
  • 基于Java和Sql Server的C/S架构图书管理系统

    1 系统设计目标1.1 应用背景图书管理系统是各图书馆都需要使用的系统,它能帮助图书管理员更好地管理海量图书,尤其是在图书馆藏数量和读者数量都很大的图书馆,我们无法用手写的方式录入、管理图书信息和借阅信息,必须借助图书管理系统来完成这些工作。
    1.2 总体目标系统的使用者分为管理员和读者。管理员负责新书的录入、旧书的清理、借书审核、还书审核,以及日常的维护,有权限增删图书的信息;读者要能够根据书名查找图书,并选择中意的图书进行借阅,读完以后还可以还书;读者没有权限修改图书的信息,他对图书的操作仅限于借、还。这就是一个简单的图书管理系统的大致功能。
    2 需求分析系统总体功能需求列表如下表所示。



    功能编号
    功能名称
    功能描述
    权限




    1
    录入图书信息
    将新的书籍信息录入系统
    管理员


    2
    删除图书信息
    将损坏的图书从系统删除
    管理员


    3
    修改图书信息
    更新图书信息
    管理员


    4
    审核还书申请
    审核读者的还书请求,检查图书损坏情况并开出罚单
    管理员


    5
    审核借书申请
    审核读者是否有罚金未交,确定读者是否可借阅书籍
    管理员


    6
    查找书籍
    通过书名查找书籍信息
    读者


    7
    查询个人信息
    读者查询个人信息
    读者


    8
    查询借书记录
    读者查询借书记录
    读者


    9
    借书
    读者选择书籍进行借阅
    读者


    10
    还书
    归还借阅的书籍
    读者


    11
    续借
    继续借阅到期的书籍
    读者


    12
    交款
    缴纳罚金
    读者



    性能需求上,要求所有的操作都没有明显的延迟,这对于现在的计算机来说不算难事,所以是不用刻意考虑性能方面的因素的。
    数据完整性,具体在数据库设计中说明。
    系统的数据流图如下图所示。

    3 总体设计系统采用C/S模式实现,没有为服务器设计专门的客户端,实际上服务器就是数据库,用户是读者和管理员。主要分为两大功能板块:管理员和读者。
    实际的图书管理系统要配合扫描仪等设备进行使用,我们的系统显然不能连接外设,适当信息需要手动输入。
    系统的总体结构图如下图所示。

    3.1 管理员3.1.1 图书信息管理具体又分为两个部分:新书上架,也就是将新书的各项信息录入到数据库;查询维护,通过索书号、书名、作者等信息进行查询,得到查询结果后,可以选中并删除图书,这主要是方便管理员查找图书,找到以后还可以精准地删除图书。
    3.1.2 读者信息管理与图书信息管理类似,可以录入、查找并修改或注销读者信息。
    3.1.3 借阅管理分为借书和还书两部分。读者想要借书时,发出一个借书请求,管理员收到该请求后,查看该读者是否还存在有罚金未交的情况,若是,则拒绝读者的借书请求;否则,同意借书。读者还书时也发出还书请求,管理员收到后,查看该读者是否延期还书,或者图书损坏,若是,则开出罚单,等待读者缴费,若图书损坏,则将图书标记为损坏,否则,进行还书登记。
    3.2 读者3.2.1 借阅分为借书、还书和续借。借书时,可以根据关键字在数据库中进行查找,选择借书,此时发出借书申请,等图书管理员审核通过后才能成功借书;还书时,从借阅列表中选择尚未归还的书籍,发出还书请求,等待管理员审核,若审核发现图书有损坏,则会收到罚单;续借是将当前正在借阅的书籍再延长一个借书周期。
    3.2.2 查看报表读者可以查看个人信息、借阅信息、罚单。
    4 数据库设计4.1 ER图用Microsoft Visio2010与SQL server连接,生成的实体关系图如下图所示。

    4.2 权限控制图书馆的访问者主要是管理员和读者,所以设置两个用户。管理员有所有表的所有权限,读者的权限则要受到限制。
    在上图的6个表中,读者有权限访问馆藏表、图书表和作者表,因为读者需要查询图书;读者有权限访问读者信息表,因为他需要查看自己的个人信息;读者有权限查询和更新借阅表,因为他需要查看自己的借书记录,此外,发起借书请求时会向借阅表中增加一条记录,所以需要更新权限;读者有权限查询和更新罚单表,与前者同理,读者需要查看罚单,并且缴纳罚金时会修改罚单状态,所以需要更新权限。读者没有删除任何一个表的权限,有查询所有表的权限和修改部分表的权限。
    4.3 数据库逻辑结构设计数据库主要分成三大部分:图书信息、借阅信息和读者信息,其中借阅信息和读者信息分别可用一个表实现,但是图书信息相对较复杂。在了解了学校图书馆的图书管理系统以后,发现每一本书都有一个索书号,一个索书号可以对应该书的多本实体,每个实体只用索书号是无法区分的,图书馆采用条码进行区分,所以需要增设馆藏信息表来存放每本实体书的条码号和馆藏地点、馆藏状态等。
    同样的,一本书也可能有多个作者,所以也需要用一个单独的表来存放作者,这里我们暂不考虑作者同名的情况,所以没有给作者设置编号。出版社在一般情况下不会同名,也不设置单独的表。
    借阅信息用于存放读者的借阅记录,由于借阅过程存在罚款,所以还有一个罚款表。
    最终图书管理系统的数据库共有6个表:图书信息表、作者信息表、馆藏信息表、借阅信息表、罚款信息表、读者信息表和罚单表,表项分别如下:

    图书信息表:题名,索书号,出版社,发行时间,版本。主码为索书号,题名也不能为空
    馆藏信息表:条码,索书号,馆藏地点,状态。主码为条码,索书号为外码,来自图书信息表,馆藏状态不能为空
    作者信息表:索书号,作者。索书号为外码,来自图书信息表
    借阅信息表:条码,读者编号,借阅日期,归还日期,借阅编号,状态。主码为借阅编号,条码为来自馆藏信息表的外码,读者编号为来自读者信息表的外码
    读者信息表:编号,姓名。编号为主码
    罚款信息表:罚单号,罚金,罚款原因,状态,借阅编号。主码为罚单号,借阅编号为来自借阅信息表的外码

    除了基本表外,还需要若干个视图来实现系统的功能。

    图书视图:题名,索书号,作者,出版社,发行时间,版次,条码,馆藏地点,状态。该视图用于管理员和读者查询图书的结果显示,是图书信息表、馆藏信息表和作者表三者的连接
    借阅记录视图:借阅编号,条码,书名,读者编号,读者姓名,借阅时间。该视图用于管理员对读者的借书请求进行处理,视图中包含所有读者的所有借阅记录,是借阅信息表、图书信息表和读者信息表的连接
    借阅统计:借阅申请次数、借阅成功次数、还书申请次数、还书破损册数。该视图用于管理员的统计查询,对一段时间内的借书、还书信息进行统计
    借阅排行:索书号,书名,借阅次数。用于管理员统计一段时间内借阅次数排名前列的书籍,了解图书馆最受欢迎的书籍情况

    4.4 数据库物理设计图书表设计如下表所示:



    字段名
    类型
    主键/外键
    为空
    索引
    取值
    备注




    索书号
    char(20)
    主键






    书名
    char(100)







    出版社
    char(30)







    发行时间
    date



    合法日期



    版本
    tinyint



    正整数



    馆藏信息表设计如下表所示:



    字段名
    类型
    主键/外键
    为空
    索引
    取值
    备注




    条码
    int
    主键


    从1起自增



    索书号
    char(20)
    外键


    来自图书表



    馆藏地点
    char(100)







    状态
    tinyint



    0、1、2
    1-在馆 2-借出 0-损坏



    著作表设计如下表所示:



    字段名
    类型
    主键/外键
    为空
    索引
    取值
    备注




    索书号
    char(20)
    外键


    来自图书表



    作者
    char(20)







    读者表设计如下表所示:



    字段名
    类型
    主键/外键
    为空
    索引
    取值
    备注




    编号
    int
    主键


    从1自增



    姓名
    char(10)







    密码
    char(20)







    借阅表设计如下表所示:



    字段名
    类型
    主键/外键
    为空
    索引
    取值
    备注




    借阅编号
    int
    主键


    从1自增



    条码
    int
    外键


    来自馆藏表



    读者编号
    int
    外键


    来自读者表



    借阅日期
    datetime







    归还日期
    datetime







    状态
    tinyint



    0-4
    1-申请借阅 2-在借 3-申请归还 4-已归还 0-失效



    罚单表设计如下表所示:



    字段名
    类型
    主键/外键
    为空
    索引
    取值
    备注




    罚单号
    int
    主键


    从1自增



    借阅编号
    int
    外键


    来自借阅表



    罚金
    int







    罚款原因
    bit



    0、1
    0-过期归还罚款 1-损坏图书罚款


    状态
    bit



    0、1
    0-用户未交罚金 1-罚金已付



    5 详细设计与实现系统用Java语言实现,通过jdbc与SQL server进行连接,获取数据库中的数据。对管理员和用户分别提供了客户端,图形界面用Javafx实现。
    5.1 读者-搜索图书5.1.1 流程图算法的业务流程图如下图所示。借书功能与搜索功能是密不可分的,一般都是先搜索再借书。程序初始化时就从数据库中查找出所有的图书信息,并显示到表格上,用户可以直接选择从表中选取某一项,然后进行借阅;如果图书信息过多,直接选取较为困难,可以在输入框中输入关键字搜索,再选择图书进行操作。

    5.1.2 算法说明图书的状态,如在馆、借出等,在数据库中是用int型存储的,所以向管理员展示时,必须用汉字直观地打出,所以要将int转换成字符串;
    由于每本书都可能有多个作者,所以要对作者进行特别处理,当多条记录的索书号相同而作者不同时,要合并为一条记录,把各个作者拼接成一个字符串,中间用分号隔开;
    此外,在数据库中,如果某个字段是长度为20的字符类型,而实际只用了8个字符,那么后面12个字符会用空格填充,这虽然不影响查询的结果,但是在表格中显示时,空格也会占用空间,所以需要用Java中String.trin()去除多余的空格。
    5.1.3 数据库实现sql语句如下,其中index是搜索的关键字,关键字可以是图书的索书号的一部分、书名的一部分或者图书作者的一部分,即只要有部分字段匹配即可搜索处结果,所以where子句中用“like”进行匹配。
    sql = "select * from dbo.图书 t,dbo.馆藏 t2,dbo.著作 t3 where t.索书号=t2.索书号 " + " and t3.索书号=t.索书号 and (t.索书号='"+index +"' or t.题名 like '%"+index+"%' or t2.条码='"+index+"' or t3.作者 like " + "'%"+index+"%') order by t2.条码,t.索书号,t3.作者";
    5.2 读者-借书5.2.1 流程图图书搜索功能中,在选中了图书并申请借阅以后,要进行一系列判断审核,流程图如下图所示。

    5.2.2 算法说明从选中表项中获取该的条码号,实际上从表中可以直接获取图书的馆藏状态,但是考虑到表中数据可能未及时更新,该书在数据库中可能已经改变状态,所以不能用表中的状态。
    根据条码号从数据库中查询该书状态,如果已经借出或者已经损坏,则提示用户借书失败;否则,可以生成借阅信息,插入到借阅信息表中,并提示用户借书请求成功。这不意味着真正地借书成功,还要等待管理员审核。
    5.2.3 数据库实现插入借阅信息sql语句如下,借阅时间是当前时间,借阅编号自动生成。
    sql = "insert into dbo.借阅(条码,读者编号,借阅时间,状态," + "借阅编号) values("+barcode+",'"+Main.getUser()+"'," + "'"+df.format(new Date())+"',1,"+(count+1)+")";
    5.3 读者-续借/还书5.3.1 流程图算法流程图如下图所示。续借和还书都是以借阅记录表为基础的。虽然在需求分析中,这些功能是相互独立的,但在实际实现时,我们要把他们充分联系起来,这也是为了用户的使用方便。
    从数据库中获取该读者所有的借阅记录,读者可以选中任意一条记录,选择续借或者归还该书籍。

    5.3.2 算法说明读者查看借阅记录时,借阅记录表已经初始化好,从数据库中选取了该读者的所有历史借阅记录,记录的状态分为在借、已归还。
    读者选中某条记录后,若选择续借,则首先要判断是不是在借记录,不是则无法续借,然后还要判断该书是否过期未还,借书期限为一个月,超过期限的书是不可以续借的,若上述条件都满足,则续借成功,将数据库中的借阅时间更新为当前时间,还书期限重新计时。
    若读者选择归还,则先判断该记录是否为在借记录,若不是,则无法归还,若是,则直接申请归还,这不需要新增一条借阅记录,只需要将借阅记录中的状态从在借修改为申请还书,管理员看到以后会进行审核。
    5.4 读者-查看个人信息该选项只能查看信息,不可进行其他操作,功能简单。
    获取读者在借册数的sql语句如下:
    sql = "select count(*) total from dbo.借阅 t where t.读者编号" + "='"+usernum+"' and t.状态=2";
    获取读者总罚金数的sql语句如下:
    sql = "select sum(t.罚金) total from dbo.罚单 t,dbo.借阅 t2 " + "where t.借阅编号=t2.借阅编号 and t2.读者编号='"+usernum+"' and t.状态=1";
    5.5 读者-查看罚单该选项只能查看信息,功能简单。获取罚单的sql语句如下:
    sql = "select t.罚单号,t.罚金,t.罚款原因,t.状态,t.借阅编号,t4.题名," + "t3.借阅时间,t3.归还时间" + " from dbo.罚单 t,dbo.馆藏 t2,dbo.借阅 t3,dbo.图书 t4 " + "where t.借阅编号=t3.借阅编号 and t3.条码=t2.条码 and " + "t2.索书号=t4.索书号 and t3.读者编号='"+Main.getUser()+"'";
    5.6 管理员-查询图书管理员查询图书与读者查询图书的流程基本相同,不再赘述。
    5.7 管理员-下架旧书
    5.7.1 流程图算法流程图如上图所示。
    5.7.2 算法说明由于管理员看到的图书信息实际上是由图书信息表和馆藏信息表连接生成的,所以在进行图书下架时,既涉及到馆藏信息的删除,又有图书信息的删除。有些书籍没有馆藏信息,只有图书信息,则只需要删除图书信息表,否则只要删除馆藏信息表,不能删除图书信息表,因为该图书可能存在其他实体,我们只能一次删除馆藏信息中的一个实体,如果把图书信息也一并删除,则馆藏信息的外键引用会出错。
    5.8 管理员-录入图书5.8.1 流程图算法流程图如下图所示。

    5.8.2 算法说明录入图书时,索书号和条码号绝对不能为空,须在所有操作之前检查。录入的情况分两种:首先是索书号已经存在的,也就是说,这本书以前就在图书馆中存在,现在又购置了该种书的一批新书,所以图书信息不需要再插入,直接插入馆藏表即可;
    第二种是该书原本不存在的情况,图书馆第一次购置该种书,则需要先插入图书信息表,然后再插入馆藏信息表,不可改变插入顺序,否则外键引用出错。
    5.8.3 数据库实现插入图书信息:
    sql = "insert into dbo.图书(题名,索书号,出版社," + "发行时间,版本) " + "values ("+bname+","+isbn+","+press+","+ymd+","+version+")";
    插入馆藏信息:
    sql = "insert into dbo.馆藏(条码,索书号,馆藏地点," + "状态) " + "values ("+barcode+","+isbn+","+store+",1)";
    5.9 管理员-查询读者5.9.1 流程图算法流程图如下图所示:

    5.9.2 算法说明搜索框的输入可以是读者编号、读者姓名的一部分,在数据库中的读者信息表中查找符合要求的项,这样的项可能有多个,循环取出,依次查找他们的在借册数和罚金数额,都添加到结果表格中显示。
    5.10 管理员-修改读者5.10.1 算法说明管理员选中读者表中的某个以后,选择修改该读者的信息,由于Javafx中的表格直接修改不太方便,所以用弹窗的方式修改。将原来的读者信息在弹窗中显示,管理员选择修改,点击确认以后,将修改后的信息写入到数据库中该读者对应的条目。
    5.11 管理员-注销读者
    5.11.1 流程图算法流程图如上图所示。
    5.11.2 算法说明管理员选中某个读者,选择注销该读者,先判断读者是否有在借书籍,如果有,则不能注销,否则该读者无法还书;再判断该读者是否有罚金未交,如果有,则不可注销,否则会造成图书馆的亏损。若上述情况都没有,则直接将其从读者信息表中删除,其他在外键中引用了该读者的表项也会被触发器一并删除。
    5.12 管理员-审核借书5.12.1 流程图算法流程图如下图所示:

    5.12.2 算法说明审核读者的借书申请时,首先要检查读者已经借了多少册书,若达到上限,则不允许继续借书;然后检查该读者的罚单,如果有罚金未交,也不允许借书;再检查该读者在借记录,若有书过期未还,不允许借书。
    以上情况均不存在,则读者有借书资格,然后检查该书是否在馆,因为该书可能被前面的读者借走了,若在馆则允许借书,审核通过,否则失败。
    5.13 管理员-审核还书5.13.1 流程图算法流程图如下图所示:

    5.13.2 算法说明管理员审核还书时,先要看图书是否损坏,判断以后填写,如果损坏,则需要生成书籍损坏的罚单,还要将该图书的馆藏信息状态修改为损坏。然后再判断读者是否未按时归还该书籍,若是,则需要生成延期的罚单。最后将归还日期写入数据库,审核完成。
    5.14 数据库事务实现在进行书籍的录入时,先要向图书信息表添加数据,然后再向馆藏信息表添加数据,这两者是分两步进行的。在一般情况下,两步都会成功。但是,特殊情况下,可能插入图书信息成功,而插入馆藏信息失败,这是不应该的。为此我们要添加数据库事务,目的是,对于连续的几个数据库操作,要使其成为原子操作,也就是,要么全都执行成功,要么全都不执行。假如第一条成功了,而第二条失败了,那么要将第一条的结果回滚,部分代码如下所示:
    stmt.executeUpdate(sql_1);stmt.execteUpdate(sql_2);conn.commit();//若所有结果执行完成,则执行提交事务ps.close();conn.close()catch(ClassNotFoundException e){ e.printStackTrace();}catch(SQLException e){ e.printStackTrace(); try{ //只要有一个sql语句错误,则事务回滚 conn.rollback(); }catch(SQLException e){ e.printStackTrace(); } }
    5.15 触发器-删除空白书籍5.15.1 触发器说明书籍的信息是存放在图书信息、馆藏信息两个表中的,在录入某种书籍时,先在图书信息表种录入一条数据,再在馆藏信息表中录入多条数据,表示该种书的多个实体。假如该种书全都损坏,则馆藏表中关于该书的条目全都被删除,此时图书信息表中还残留有该书的信息,这条信息已经无效了,需要删除。为了避免手动删除,使用触发器来实现,每次更新或者删除馆藏信息后,检测图书信息表中是否有某条记录已经没有馆藏书籍,将它从图书信息表中删除。
    5.15.2 触发器实现触发器功能部分如下:
    ALTER TRIGGER [dbo].[delete_emptybook] ON [dbo].[馆藏] AFTER DELETE,UPDATEAS BEGIN SET NOCOUNT ON; delete from 图书 where 0=(select count(*) from 馆藏 where 馆藏.索书号=图书.索书号)END
    15.16 触发器-设置图书损坏5.16.1 触发器说明当读者还书时,管理员需要判定该书是否损坏,如果鉴定为损坏,则需要开具罚单,罚单中有一项表示罚款的原因是书籍损坏还是迟还,如果该项填写为书籍损坏,则自动将馆藏表中对应的书籍馆藏状态设置为损坏,省去了手动设置。
    5.16.2 触发器实现触发器功能部分实现如下:
    ALTER TRIGGER [dbo].[set_bookbroken] ON [dbo].[罚单] AFTER INSERT,DELETE,UPDATEAS BEGIN update 馆藏 set 状态=0 where exists (select * from inserted,(select * from 借阅)t where inserted.罚款原因=1 and inserted.借阅编号=t.借阅编号 and t.条码=馆藏.条码)END
    5.17 触发器-设置罚金5.17.1 触发器说明在开具罚单时,管理员只需要填写罚款原因,而罚款金额有数据库生成,规定过期还书罚款1元,书籍损坏罚款5元,自动设置罚款的触发器根据罚款原因进行罚金的设置。
    5.17.2 触发器实现触发器功能部分实现如下:
    ALTER TRIGGER [dbo].[set_fine] ON [dbo].[罚单] AFTER INSERT,DELETE,UPDATEAS declare @sake bit;BEGIN select @sake = 罚款原因 from 罚单; if @sake=0 begin update 罚单 set 罚金=1 where exists(select * from inserted where 罚单.罚单号=inserted.罚单号) end else begin update 罚单 set 罚金=5 where exists(select * from inserted where 罚单.罚单号=inserted.罚单号) endEND
    5.18 触发器-修改读者信息5.18.1 触发器说明管理员有一项功能是修改读者的信息,如果只是修改了读者姓名、密码等,那么只需要修改读者表这一个表,而如果修改了读者编号,即修改了主码,那么与该读者有关的借阅信息表中存有的该读者的编号也要进行修改,这一操作不能让管理员执行,需要用触发器实现。
    5.18.2 触发器实现触发器功能部分实现如下:
    ALTER TRIGGER [dbo].[update_aboutuser] ON [dbo].[读者] AFTER UPDATEAS declare @old char(10) declare @newuser char(10)BEGIN select @old=t.编号 from deleted t select @newuser =t.编号 from inserted t update dbo.借阅 set 读者编号=@newuser where 借阅.读者编号=@oldEND
    6 系统测试6.1 管理员-图书查询测试6.1.1 测试说明可以在选择框输入索书号、作者或者是书名,均可查询出结果。
    6.1.2 测试过程管理员的图书查询维护界面如下图所示,未执行查询时会显示所有的图书信息。

    查询可以根据索书号、书名、作者这三个关键字的全部或者部分进行查询,根据索书号查询结果如下图所示。

    根据书名查找结果如下图所示。

    根据作者查询结果如下图所示。

    查询失败结果如下图所示,书库中暂无该书。

    若输入框为空,则查询结果为所有书籍。
    6.2 管理员-图书下架测试6.2.1 测试说明任务书中要求管理员可以进行旧书下架,旧这个概念比较模糊,没法严格定义,所以我们把一本书是否已经“旧”了的决策权交给管理员,也就是说,管理员可以删除任何他认为算作旧书的书籍,所以管理员可以选择任何书籍进行删除,除非该书已借出,不在馆。
    6.2.2 测试过程选中已经借出的书籍《大卫•科波菲尔》,选择下架,弹出窗口警告该书已借出,不可删除,如下图所示。

    选择在馆图书《夏洛的网》,点击下架,结果如下图所示,删除成功。

    《夏洛的网》只有一本实体书,删除以后,馆藏信息表中已经没有该书,而图书信息表中还有该书,此时触发器检测到该书没有馆藏信息,在图书信息表中将其自动删除。
    6.3 管理员-新书上架测试6.3.1 测试说明新书上架界面如下图所示,其中索书号一栏用的是下拉框,既可以选择又可以输入,这样设计是因为,录入图书时,有两种情况:其一,图书馆购置了一批最新的书籍,馆中没有这种书,那么索书号必须要新分配,所以要输入索书号;其二,馆中已经有的书,最近又增购了一些,录入这些书籍时,就可以直接从列表中选择索书号了,我们的测试也分这两种情况进行。书籍的条码号不需要手动填写,数据库会自增生成。

    6.3.2 测试过程首先选择录入已经存在的书籍,从索书号列表中选择一个索书号,如下图所示,书名、作者等项会自动填充,且不可编辑,只有条码号和馆藏地点可以填写。

    填写好以后,点击录入,录入成功,结果如下图所示,最后一行是《兄弟》新录入的馆藏本,条码号为168。

    再测试录入馆中没有的书籍,我们录入一本计算机丛书《编译原理》,索书号为cs3,其他各项信息如下图所示。

    确定录入,录入成功,结果如下图所示,最后一行是刚录入的书籍。

    测试异常情况,不填写索书号直接录入,弹出窗口警告;不填写馆藏地点直接录入,也提示错误。
    6.4 管理员-读者查询6.4.1 测试说明读者信息查询可以根据读者编号、读者姓名的一部分或全部进行,但不能通过用户密码进行查询,因为涉及到密码的操作不太安全,实际上这里将用户密码直接显示也是不太好的,只不过我们认为管理员有一切权限,所以可以查看用户密码。
    6.4.2 测试过程读者查询维护界面初始化如下图所示,表中显示了所有的读者。

    根据读者姓名查询,在搜索框输入“张”,查询结果如下图所示。

    根据读者编号进行查询,结果如下图所示。

    查询异常情况,输入的关键字不匹配,查询结果为空,如下图所示。

    6.5 管理员-录入读者信息6.5.1 测试说明读者录入分为正常录入、读者编号重复异常、信息不全异常。
    6.5.2 测试过程录入一名读者,如下图所示。

    录入以后,在读者列表中可以看到刚刚录入的读者信息;将读者姓名、密码之中的任意一项空缺,点击录入,将提示信息填写不全
    6.6 管理员-修改读者信息6.6.1 测试说明管理员可以选择一条用户信息,选择修改。修改后点击确定,即可修改成功。不允许修改主码读者编号,因为该项是自增的,不可编辑,可以任意修改读者姓名和登录密码。
    6.6.2 测试过程选择读者“张三”,点击修改,弹出窗口如图 4 36所示。将读者姓名修改为“李四”,密码改为“lisi”,点击确定。

    6.7 管理员-注销用户6.7.1 测试说明管理员有权限删除任何一个用户,只是也要受一些限制。如果读者有借书还未归还,则不能删除;如果读者有罚金未交,则不能删除。只有读者与图书馆不存在利益关系时才可注销账户。
    6.7.2 测试过程选择3号用户蔡韬,点击删除,注销成功。
    6.8 管理员-查看报表统计报表的功能较为简单,如下图所示是借阅统计报表,可以选择开始时间和结束时间,统计该段时间内的总借阅申请、借阅成功、还书申请、还书成功数目。

    如下图所示是借阅排行榜,可以选择开始时间和结束时间,统计该段时间内,图书馆的书籍借出次数,降序排列,便于管理员掌握受欢迎的书籍种类。

    6.9 借书/还书综合测试6.9.1 测试说明由于读者的借书和管理员的借书审核、读者的还书和管理员的还书审核,互相之间是密不可分的,所以测试也不能孤立地进行,我们将读者和管理员的借书、还书操作混合交替进行,以达到测试借书、还书的目的。
    管理员审核读者的借出请求时,首先要判断读者在借册数是否超标,再判断是否有在借的书过期未还,最后判断是否有罚金还未交,以上三种情况都拒绝借书,否则审核通过,借书成功。
    借书测试计划是,先让一个用户连续申请借书4次,管理员进行审核,由于用户借书上限是3本,所以该用户的前三次请求均能通过,属于正常情况,第4次被拒绝,属于异常中的借书册数超标。然后读者申请还书,管理员很合还书时将该书鉴定为损坏,对读者开罚单,读者收到罚单后再次借书会失败,这是借书异常中的罚款未交异常。再将读者借书日期修改为超过1个月以前,这样读者再次借书也会失败,属于借书异常中的有书过期未还异常。
    6.9.2 测试过程读者请求借书,连续申请4次。在管理员一端可以看到读者“张鑫”的4次借书请求,如下图所示。

    管理员进行借书审核,读者借书成功;审核到第4本书时,系统检测到该读者已经借书3本,不可继续借书,所以弹窗警告,借书失败;紧接着,读者申请还书;管理员审核还书,管理员填写鉴定图书是否损坏,默认为正常,可以下拉选择损坏;选择损坏并点击确定,图书损坏需要罚款5元。
    由于该读者还书时被鉴定为损坏图书,所以他已经被取消了借阅资格,只有缴纳了罚金以后才会被取消限制,现在该读者再次尝试借书,管理员审核时检测到他有罚金未交,拒绝了借书请求。要恢复还书资格,读者必须缴纳罚款,读者成功缴纳5元罚金,重获借书资格并再次申请借书。管理员再次审核读者的借书请求,借书成功。
    最后一种异常情况,就是读者借书过期未还时,不可继续借书。我们设置的借书期限是一个月,考虑到测试时生成的借阅记录都是今天的,所以短时间内不会超过借书期限,为了完成测试,我们直接到SQL server中将借阅事件修改到两个月以前,这样一来,这条借阅记录就一定过期了。如下图所示,最后一条借阅记录时间为4月12日。

    该读者有书过期未还,现在再次申请借书,管理员审核借书信息时,检测到他有书过期未还,拒绝借书。读者将过期未还的书申请还书,管理员审核时,系统检测到该书过期,收取1元罚金,该读者被取消借书资格,只有缴纳罚金以后才会取消限制。
    6.9.3 结果分析以上测试过程涵盖了读者借书、读者还书、管理员审核借书、管理员审核还书。读者不管有没有借书资格,都是可以发出借书申请的,最终借书是否通过,在管理员一方决定。读者所借书籍不管是不是已经过期、是不是损坏,都是可以申请还书的,最终是否罚款,在管理员一方判断。所以说,读者借书、还书都没有异常情况。
    管理员审核借书,有三种异常情况:该读者已经有3本书在借未还;该读者有罚金未交;该读者有至少一本书过期未还。这三种情况在测试都进行了处理。
    管理员审核还书,有正常情况和两种异常情况。不论如何,都会弹出窗口要求管理员填写图书是否损坏,如果填写正常,那么直接审核通过;如果填写损坏,那么罚款5元;如果读者还书时已经超过借书期限,则罚款1元。在测试用例中上述情况都进行了测试。
    综上,读者、管理员的借书、还书综合测试成功,系统功能达到设计目标。
    6.10 读者-图书查询6.10.1 测试说明读者的图书查询与管理员稍有不同,管理员的查询是单条件查询,而为了使读者的使用体验更好,向读者提供了多条件查询。
    6.10.2 测试过程可以根据书名、作者或者出版社进行单项查找,不需要的条件直接不填即可。

    6.11 读者-查看借书记录6.11.1 测试过程如下图所示是该读者的借书记录,最后一列“在借”表示当前正在读者手中的书籍,“借阅失败”可能是因为读者有罚金未交等异常情况引起的,“已还”表示读者已经成功归还书籍。

    6.12 读者-查看基本信息6.12.1 测试过程如下图所示是当前读者的基本信息。

    6.13 读者-续借6.13.1 测试说明一本书籍在借,且为过期时,读者可以选择续借,续借成功后,借阅时间更新为当前时间,借阅期限重新计算。当书籍过期未还时不可续借,不是在借的书籍也不可续借。以下测试将对上述三种情况进行测试。
    6.13.2 测试过程当前读者的借阅记录如下图所示,有两本在借书籍,一本是4月12日借阅的,已经过期,另一本是6月13日借阅的,还未过期。

    选择续借6月13日借阅的书籍,如下图所示,续借成功。

    续借成功后,书籍的借阅时间进行了更新。选择续借4月12日借阅的书籍,系统检测到该书已过期,拒绝了续借。选择一条借阅失败的记录进行续借,系统提示该条信息不可续借。
    7 课程总结主要熟悉了SQL server的使用,学会了新增用户并设置用户权限;掌握了sql查询语句的多种用法以及较为复杂的查询逻辑的实现;掌握了触发器的简单使用;将数据库知识和实际结合,实现了一个功能比较完备的管理系统。
    实验过程中使用了MySQL和SQL server两个数据库,两者各有优劣,基本的操作都已经掌握,在以后的使用了可以灵活选择。只是对于命令行下操作数据库还不够熟悉。
    触发器的实现花费了较多时间,因为触发器的语句写法很灵活,而且Oracle、SQL server等不同数据库的触发器语法还大不相同。在编程的过程中发现,很多能够在高级语言中实现的功能,其实也可以在数据库中用触发器实现,两者对比,选择用触发器实现更好,可以减少编码量。
    在系统生成报表时,是用sql语句对多个表进行连接生成的,而没有使用视图,这方面还有待改进,用视图生成报表更加方便。
    软件功能学习部分的选做题没有完成,有时间还需要实现,加深对数据库的理解和操作的熟练程度。
    5 评论 152 下载 2019-03-14 10:31:00 下载需要15点积分
  • 基于JSP的图书馆管理系统设计与实现

    摘 要随着科学技术的进步,计算机行业的迅速发展,大大提高人们的工作效率。计算机信息处理系统的引进已彻底改变了许多系统的经营管理 。
    图书管理系统是学校管理机制中的重要组成部分,通过对图书管理系统的运行管理机制进行调查研究,开发了此图书系统。本系统中解决了学校图书管理事务中的常用基本问题以及相关统计工作。本系统中包含6个功能模块:系统设置,读者管理,图书管理,图书借还,系统查询和更改口令。
    本系统使有jsp进行网页界面的设计,使用MVC设计模式,采用了开源框架Struts,它采用了当今软件设计的最新技术,具有开发效率高、设计灵活、生成的软件界面友好美观等特点。本系统中通过JDBC驱动和数据库进行无缝连接,后端的数据库是mysql,也是一个开源的数据库系统,该数据库具有较高的完整性,一致性和安全性。
    关键词:图书管理;信息管理;jsp;struts
    AbstractWith the progress of science and technology, the astonishing rapid development of the computer industry has been improving people’s working efficiency greatly.The introduction of computerized information system has sharply changed the management in many systems in many fields.
    The management system of the library takes an important role in the administration of school organization. I desigen the system after the thorough investigations about the library management system’s mechanism. This system contains with reader informantion management model, book information management model, books borrowing and returning including system information query and password setting.
    The system is contrived with Java Server Pages Techonolege as well as Struts,the software design mode of MVC with open source framework techonolege, which makes this system have the advantages of efficiently designed with beauteous and friendly interface . This system use jdbc driver to connect the mysql database server,which is also an open source database system for its users. The batabase was desigend with highly integrity, security, and consistency.
    Key words: book management, management of information ,jsp,struts
    1.绪论1.1 毕业设计主要任务
    实现图书馆对所藏图书的按类别、书名等多方面的查询,最大的方便读者和图书馆工作人员对所需图书的查询
    建立图书馆外借读者数据库,方便工作人员对读者进行有效管理
    建立图书馆工作人员数据库,限定每个工作人员对软件操作的权限,最大限度的保护数据库
    实现图书馆对新书入库,旧书注销的简单处理,并且建立书籍档案,方便进货
    实现图书馆

    1.2 目前图书管理系统存在的问题1.2.1 检索速度慢、效率低因为图书馆的藏书种类多、数量多,将藏书准确地分门别类,快速检索,手工进行非常困难往往是终于查到了二伟的信息,馆中没有此书或已被别人借走。图书馆的规模越大,这个问题越突出。
    1.2.2 借书、还书工作量大借书、还书频率越大,说明图书馆的作用越大,然而随之而来的大量的借书、还书登记、实存图书的更新以及借出图书超期、遗失等的处理,其工作量之大,往往是人工操作所难以胜任的。而且经常会出现这样那样的差错。
    1.2.3 图书统计工作难、藏书更新不能及时完成。图书馆的图书应根据科学技术的发展和教学工作的需要及时添加和更新,然而由于藏书数量及图书种类越来越多,加上自然损耗,人为破坏,使图书的统计工作难以及时完成,藏书的更新也就很难有针对性地进行,藏书的知识结构得不到良好地控制。
    我校也是一所发展中的高校,近儿年的发展速度很快,图书馆的规模和藏书数量也不断的扩大,为了解决海量图书的管理问题,改变传统的管理方式也是迫在眉睫了。
    1.3 课题意义随着计算机的广泛应用,其逐步成为现代化的标志。图书馆或者一些企业内部,甚至是书店,在正常运行过程中总是面对大量的读者信息,书籍信息以及两者相互作用产生的借书信息、还书信息。因此需要对读者资源、书籍资源、借书信息、还书信息进行管理,及时了解各个环节中信息的变更,要对因此而产生的单据进行及时的处理,为了提高图书馆或者企业内部对图书存销的自动化的管理,能够更快速的满足读者的要求,提高各种工作的效率,现对其设计相应的系统,以达到上述的目的[1]。
    图书管理系统的主要功能是实现图书馆图书借阅和归还的管理的自动化。围绕这一主要功能,本系统涉及到以下核心功能:借阅管理,归还管理。除了这些核心功能外,还包括一些基本和辅助功能,它们是:用户管理、图书馆参数管理、图书管理、统计查询。
    1.4 论文的工作和安排本次设计的目标是,开发一个图书馆借阅管理系统。借助该系统,管理员通过快捷可靠的数据库管理,方便的管理图书馆的信息资料,规范化的管理读者用户,设定不同用户权限,并能通过互联网向读者提供更为方便的在线查询服务,方便读者的使用,最终达到提高图书馆资源利用效率的目的。
    论文设计和实现了图书借阅管理系统系统,可以根据用户的不同权限,对图书馆的的各种信息进行添加、删除、修改或查询操作。论文分为五个部分:

    第一章即本章绪论,简述图书馆借阅管理系统这个课题的背景情况以及开发本系统的意义
    第二章为需求分析,本章中明确了系统需要实现的功能,分析了系统的用例,并介绍根据系统的需求选择的开发工具和技术的概况
    第三章是总体设计,详细描述了本系统中数据库的设计情况,并给出了系统总体界面的设计方案
    第四章为程序设计与编码各主要功能模块的实现方法和部分关键代码,同时提供了个主要界面运行的参考图片,以更直观了解系统的实现情况
    第五章是软件测试,测试系统功能实现并对测试结果进行记录分析
    第六章为结束语,为此次毕业设计做一个总结,总结所获得的经验和体会

    2.图书借阅管理需求分析2.1 可行性分析采用现代化统一的计算机信息网站系统,能够有效优化图书馆管理系统,使其高效的发挥最大作用,能够迅捷的为读者提供相应的服务。开发本系统的可行性研究如下:
    2.1.1 技术可行性技术上的可行性分析主要分析技术条件能否顺利完成开发工作,软、硬件能否满足需要。本系统采用JSP开发出友好美观的人机界面,便于用户理解、操作。数据库管理系统采用MySQL,它能够处理大量数据,同时保持数据的完整性、安全性。因此本系统的开发平台已成熟可行。硬件方面,在科技飞速发展的今天,硬件更新速度越来越快,容量越来越大,可靠性越来越高,价格越来越便宜,因此硬件平台也能够满足本系统所需[2]。
    2.1.2 经济可行性鉴于计算机技术发展异常迅猛,在硬件软件配置以及开发技术均以可行的情况下开发这样一个管理系统成本不会很高,但其可以大大提高图书馆的工作效率,也是图书馆管理发展的必然趋势,其必将有比较宽阔的市场,因此改性统在经济可行性上时可行的[2]。
    2.2 图书借阅管理系统需求概述2.2.1 系统目标该系统主要建立一个基于B/S模式的图书馆借阅管理系统,面对当起很多小型图书管理仍是人工管理带来的检索速度慢,效率低,借阅归还图书量大,图书统计工作量大,藏书不能完成及时更新的问题,该系统可以对跟系统的三个用户类型的使用实现:

    对于读者在本系统的应用下可实现按照各种方式(如:书名,编号,作者)查询图书馆的藏书请客,方便的借阅图书,续借图书,归还图书,能够查询自己的借阅图书情况
    对于图书馆工作人员能够实现方便的对图书进行查询,方便的进行读者借阅情况查询,方便的进行借书还书处理等,便捷的对图书信息进行添加、修改、删除,分类管理等操作,对读者信息进行相关添加,修改,分类管理等操作
    对于系统管理员可以对图书馆信息进行修改更新操作,对系统用户进行添加、修改、删除、权限设置等操作,对图书馆的办证参数进行修改维护等操作功能

    2.2.2 用户类和用户特性图书借阅管理系统是一个基于B/S模式的对图书馆进行高效率管理的应用系统,它的用户主要是读者和图书管理员,学生通过该系统进行图书查询进而对自己需要的图书进行借阅及自己的借阅情况进行查询,图书管理员则通过本系统实现对图书及读者的高效管理,除此之外,还需要一个系统管理员对不同的用户进行权限的设置等操作[2]。
    三类用户的具体描述如下表所示:



    用户类
    描述




    读者
    读者是该系统的重要的使用角色,他们通过该系统查询自己需要的图书信息,并像图书管理员提出借阅图书的申请进而借阅自己所需的图书,还可以通过对自己借阅情况进行查询。


    图书管理员
    图书管理员是该系统的另一个重要使用者,图书管理员通过该系统进行图书的增加,修改,删除,分类管理等操作,实现对读者借阅归还续接图书的方便操作,实现对系统中图书,读者,读者借阅情况的查询,信息更改维护等操作,管理读者类型,对不同类型读者可借阅的图书数量进行设置等图书馆的基本操作。


    系统员
    系统管理员主要是图书管理系统中用户的管理,实现用户添加修改删除以及用户权限设置等操作,实现对图书馆基本信息的修改维护等操作,还包括对图书馆书架的设置操作,以及校外读者办证所需费用、证件有效期等参数的设置。



    2.3 图书借阅管理系统需求模型2.3.1 功能描述图书借阅管理系统的主要任务是实现读者迅速检索查询,方便借阅归还图书,图书管理员高效的完成系统的各项基本操作,系统管理员是管理用户设置权限等操作[3],从图2.1可以看出图书借阅管理系统要完成一下功能:

    登录:读者、图书管理员,系统管理员进入该系统必须登录,身份验证正确了才可以进入该系统,以不同身份进入该系统所对应的系统使用权限是不同的
    系统设置功能:系统管理员可以设置图书馆相关的参数信息
    用户管理功能:对系统用户进行添加,修改,删除,权限设置等操作
    查询功能:对图书馆的馆藏图书,借阅历史,读者用户等信息进行查询
    其他功能:系统管理员可以修改自己的密码,并且拥有其他用户所拥有的所有功能

    下面的系统用例图描述了整个系统用户之间的动作联系及功能模块的概述[4]。

    2.3.2 图书管理员详细功能描述
    读者管理功能:对读者的类型和读者档案进行管理,包括添加,修改,删除读者类型和读者用户的相关信息,管理不同类型读者借阅图书的数量
    图书管理功能:包括对图书类型和具体图书信息的管理,可以增加,修改,删除图书,丰富具体图书的信息,对不同图书进行分类操作
    图书借阅功能:可以完成对读者借阅,续接和还书的操作
    系统查询功能:查询图书相关资料,借阅历史和借阅到期题型
    修改密码功能:可以修改自己的登录密码

    2.3.3 读者详细功能描述
    修改登陆密码:修改自己的登录密码
    查询功能:对图书馆图书信息进行查询,对自己当前借阅书籍进行查询,对图书规划到期题型进行查看

    2.3.4 主要用例的用例描述图书借阅借阅管理系统涉及到的用例包括:图书借阅,图书归还,读书查询,读者信息管理,图书信息管理,用户管理等,现就系统的主要用例图书借阅,图书归还,图书查询进行详细分析。
    用例“图书借阅”



    用例名称
    图书借阅




    标识符
    UC-1


    参与者
    读者,图书管理员


    描述
    读书可以通过查询等方式获得自己想借阅的图书的名称,编号,等其他可唯一识别的信息,向图书管理员提出借阅请求,管理员在系统中记录相应信息,将图书交给读者,借阅成功。


    前置条件
    1. 登录;2. 进入图书借阅的页面


    后置条件
    1. 更新图书借阅列表;


    主干过程
    1.0 借阅图书 1. 读者请求借阅新地图书,并提供自己的编号 2. 系统显示读者借阅情况的表单 3. 读者提供想借阅的图书的标号 4. 系统存储读者和借阅的图书,并将之存储到数据库中 5. 系统更新借阅列表


    分支过程
    1.1 选择重置(第3步后分支出来) 1. 读者选择重置 2. 系统刷新该页面


    异常
    1.0.E.1 读者借阅已满(第2步) 1.读者借阅的数目已经到达自己借阅的上线 2. 系统将错误信息显示在借阅页面 3. 系统重新启动该用例


    被包含用例



    被扩展用例



    优先级




    用例“图书归还”



    用例名称
    图书归还




    标识符
    UC-1


    参与者
    读者,图书管理员


    描述
    读者将自己借阅的图书归还图书馆。


    前置条件
    1. 登录;2. 进入图书归还页面


    后置条件
    1. 更新图书归还列表;


    主干过程
    1.0 图书归还 1. 读者请求归还借阅的图书并提供自己的编号 2. 系统显示该读者的借阅信息表 3. 使用者填将要归还的图书交给管理员 4. 管理员输入图书编号,系统存储归还信息,并将之存储到数据库中 5. 系统更图书归还列表


    分支过程
    1.1 选择重置(第3步后分支出来) 1. 读者选择重置 2. 系统刷新该页面


    异常
    1.0.E.1 读者借阅超时(第4步) 1.该书超出了应该归还的时间范围 2. 系统将罚款信息显示在归还页面 3. 需要缴纳罚金


    被包含用例



    被扩展用例



    优先级




    用例“图书查询”



    用例名称
    图书查询




    标识符
    UC-3


    参与者
    读者,图书管理员


    描述
    读者通过图书的标号,名称等信息对相应的图书进行查询。


    前置条件
    1. 登录; 2. 转到图书查询页面


    后置条件
    1. 查询页面显示相应的图书的信息


    主干过程
    图书查询 1. 读者输入想要查询的图书信息 2. 系统显示相应的图书信息 3. 读者点击读书名称,跳转到图书详细信息链接页面


    分支过程
    输入信息时(第2步后) 1. 系统显示:请选择查询依据 2. 用户进行相应选择 重新查询(第2步后) 1. 系统已经显示了相应图书信息 2. 读者想查询其他图书


    异常
    5.0.E.1 查询的图书不存在(第2步后) 1. 读者输入的图书信息不能在数据库中查询到 2. 系统显示暂时无该图书信息 3. 重新启动该用例


    被包含用例



    被扩展用例



    优先级




    3.总体设计3.1 数据库设计3.1.1 数据库设计概述数据库是整个系统的基石,数据库的设计优劣直接影响到整个系统的设计成败,本节对数据库的设计进行专门阐述[5]。
    数据库是数据管理的最新技术。十多年来数据库管理系统已从专用的应用程序发展成为通用的系统软件。由于数据库具有数据结构化,最低冗余度,较高的程序与数据独立性,易于扩充,易于编制应用程序等优点,较大的信息系统都是建立在数据库设计之上的。因此不仅大型计算机及中小型计算机,甚至微型机都配有数据库管理系统[6]。
    数据库系统的出现使信息系统从以加工数据的程序为中心转向围绕共享的数据库为中心的新阶段。这样既便于数据的集中管理,又有利于应用程序的研制和维护,提高了数据的利用性和相容性,提高了决策的可靠性。目前,数据库已经成为现代信息系统不可分割的重要组成部分。数据库技术也是计算机领域中发展最快的技术之一。
    数据库设计是把现实世界的实体模型与需求转换成数据库的模型的过程,它是建立数据库应用系统的核心问题。数据库及其应用的性能都建立在良好的数据库设计的基础之上,数据库的数据是一切操作的基础,如果数据库设计不好,那么其它一切用于提高数据库性能的方法收效都是有限的。数据库设计的关键是如何使设计的数据库能合理地存储用户的数据,方便用户进行数据处理[6]。
    设计数据库必须遵循一定的规则,在关系型数据库中,这种规则就是范式,范式是符合某一种级别的关系模式的集合。一般人们设计数据库遵循第三范式。即:数据库表中不包含已在其他表中包含的非主关键字信息。采用范式减少了数据冗余,节约了存储空间,同时加快了增、删、改的速度[6]。
    整个系统所包括的信息有图书信息、读者信息、留言信息、图书借阅信息、图书归还信息、系统用户信息、读者类型信息。可将这些信息抽象为下列系统所需要的数据项和数据结构:

    图书信息(编号,图书名称,图书类型,作者,译者,ISBN号,价格,出版社,所在书架,入库时间,操作员)
    图书类型(编号,名称,可借阅天数)
    读者信息(编号,姓名,性别,条形码,读者类型,出生年月,有效证件,证件号码,登记日期,电话,邮箱,操作员)
    读者类型(名称,可借阅图书本数)
    图书借阅信息(图书编号,读者ID,借出时间,应还时间,是否归还,操作员)
    图书归还信息(图书编号,读者ID,归还时间,操作员)
    用户(编号,用户名称,密码)
    图书馆信息(编号,名称,馆长,电话,地址,邮箱,创建日期,简介)
    图书馆参数信息(编号,办证费用,有效期限)

    在这里使用E-R图描述了图书借阅管理系统的数据模型。图3.1图书借阅管理系统E-R图描述了该系统所涉及到的实体以及他们之间的关系。具体结构如下图所示:

    3.1.2 图书信息表结构设计图书信息表主要用于存储图书馆中所藏图书的相关信息,其中的相关信息是在图书入库时由操作员进行添加完善,此表主要用于读者和图书管理员对馆中图书的查询,系统用户根据图书的某个属性进行查询,便可得知图书的其他相关信息,其中图书所在书架属性是便于读者借阅时对图书的寻找,图书价格是在读者不慎将图书遗失时对遗失图书进行赔偿的依据。表的具体结果如下:
    图书信息表tb_bookinfo



    字段名称
    数据类型
    字段长度
    是否为空
    说明




    barcode
    varchar
    30
    No
    Key


    bookname
    varchar
    70
    No



    author
    varchar
    30
    Yes
    作者


    translator
    varchar
    30
    Yes
    译者


    ISBN
    varchar
    20
    No



    price
    float
    8,2
    No
    图书价格


    bookcase
    varchar
    10
    No
    图书所在书架


    press
    varchar
    70
    No
    出版社


    intime
    date

    No
    图书入库时间


    operator
    varchar
    30
    No
    操作员


    page
    int
    10
    Yes
    图书页码



    3.1.3 图书类型信息表结构设计该表的设计主要是方便对图书的分类,和对图书的查询,在实际应用中图书管理员就是根据图书类型的不同将之分列在不同的书架,以方便读者的借阅寻找,其中可借阅天数项设置了不同类型图书的借阅期限,可根据图书的具体情况进行不同的维护管理,表的具体结构设计如下:
    图书类型信息表tb_booktype



    字段名称
    数据类型
    字段长度
    是否为空
    说明




    ID
    int
    10
    No
    Key


    bookname
    varchar
    30
    No



    days
    int
    10
    No
    可借阅天数



    3.1.4 读者信息表结构设计读者信息表的设计是为了图书馆管理员对读者进行管理,其中读者ID,不同类型证件的号码都是唯一的,是读者在借阅图书时需要输入对读者身份进行识别的信息,读者邮件电话等信息室为了与读者进行联系,读者类型信息决定了读者一次性可借阅的图书的数量,注册时间可用于查询计算读者身份有效的期限,操作员是为了便于对信息才操作的查询。表的具体结构设计如下:
    读者信息表tb_reader



    字段名称
    数据类型
    字段长度
    是否为空
    说明




    Id
    int
    10
    No
    Key


    name
    varchar
    20
    No



    sex
    varchar
    4
    No



    barcode
    varchar
    30
    No



    readertype
    varchar
    11
    No
    读者类型


    tel
    varchar
    20
    Yes
    电话


    e-mail
    varchar
    100
    Yes



    paperType
    varchar
    10
    No
    证件类型


    PaperNO.
    Varchar
    20
    No
    证件号码


    birthday
    date

    Yes



    intime
    date

    No
    登记时间


    operator
    varchar
    30
    No
    操作员



    3.1.5 读者类型信息表结构设计此表的设计是为了对不同身份的读者进行分类方便读者的管理,其中可借阅图书数量的属性设定,是根据读者需求的不同对起权限进行的设置,用于规定不同类型读者一次可借阅的图书数量,表的具体结构设计如下:
    读者类型信息表tb_readertype



    字段名称
    数据类型
    字段长度
    是否为空
    说明




    ID
    int
    10
    No
    Key


    readername
    varchar
    50
    No



    number
    int
    4
    No
    可借图书本数



    3.1.6 图书借阅信息表结构设计该表的设计是用于对读者借阅图书进行管理,表中图书ID属性是对借阅图书的唯一性识别标识,读者ID号记录借阅的相应读者,结出时间记录了相应的归还时间,以及归还时是否超时,操作员是对借阅进行操作的人员的记录方便日后的查询,是否归还标识可查询当起读书是否被归还,表的具体结构设计如下:
    图书借阅信息表 tb_borrow



    字段名称
    数据类型
    字段长度
    是否为空
    说明




    ID
    int
    10
    No
    Key


    readerID
    varchar
    10
    No



    bookID
    int
    10
    No



    borrowTime
    date

    No
    结出时间


    backTime
    date

    No
    应归还时间


    operator
    varchar
    30
    No
    操作员


    ifback
    tinyint
    1
    No
    是否归还



    3.1.7 图书归还信息表结构设计与图书借阅信息表形成对照的是图书归还信息表,该表的设计除了像上表一样把借阅的图书与相应的借阅者进行对应的联系以外还记录了读者应归还图书的时间,以此判断读者的借阅是否超时,表的具体结构设计如下:
    图书归还信息表tb_giveback



    字段名称
    数据类型
    字段长度
    是否为空
    说明




    ID
    int
    10
    No
    Key


    readerID
    varchar
    11
    No



    bookID
    int
    11
    No



    backTime
    date

    No
    归还时间


    operator
    varchar
    30
    No
    操作员



    3.1.8 用户信息表结构设计该表的设计用于记录图书管理系统用户的信息,方便对用户的管理,表中包括用户ID 和用户的登录密码,表的具体结构设计如下:
    系统用户信息表tb_user



    字段名称
    数据类型
    字段长度
    是否为空
    说明




    ID
    int
    10
    No
    Key


    name
    varchar
    30
    No



    password
    varchar
    30
    No



    3.1.9 图书馆信息表结构设计该表包含了图书馆的名称,地址,联系方式,建馆时间,简介等信息,是对图书馆基本属性信息的描述,方便外界读者对图书馆的了解,表的具体结构设计如下:
    图书馆信息表 tb_library



    字段名称
    数据类型
    字段长度
    是否为空
    说明




    ID
    int
    10
    No
    Key


    libraryname
    varchar
    50
    No



    curator
    varchar
    10
    No



    tel
    varchar
    20
    Yes
    结出时间


    address
    varchar
    100
    No
    应归还时间


    e-mail
    varchar
    100
    No



    url
    varchar
    100
    No
    图书馆网站


    createDate
    varchar

    No
    创馆时间


    introduce
    text

    Yes
    图书馆简介



    3.1.10 办证参数信息表结构设计该表是为校外人员设计的,对于需要到图书馆进行借阅的读者可办理临时的借阅证用于对图书的借阅凭证,表中包含了办证所需费用以及证件的有效期限,表的具体结果设计如下:
    图书证参数信息表tb_parameter



    字段名称
    数据类型
    字段长度
    是否为空
    说明




    ID
    int
    10
    No
    Key


    Cost
    int
    10
    No
    办证费用


    validity
    int
    10
    No
    有效时间



    3.2 系统总体结构设计该系统在Windows98/2000/XP环境下,主要采用JSP开发工具,MySQL数据库来设计,开发过程与成果应符合GB/T 11457-1995软件工程术语,GB/T 8567-1988计算机软件产品开发文件编制指南等[7]。
    3.2.1 图书管理系统总体结构图绘制系统结构图的过程,实际上就是对系统功能模块进行分解设计的过程,即合理地将数据流程图转变为所需要的系统结构图[8]。
    系统结构图将会使读者和用户能直观的了解系统的结构模式,理解系统的各个功能的结构,能很好地方便用户使用和理解整个系统。
    本系统的结构图如下:

    根据需求分析的结果,按照“低耦合、高内聚”的原则,本系统将划分为以下主要功能模块:系统管理员功能模块,读者管理功能模块,图书管理功能模块,图书借还功能模块;系统查询功能模块[8]。
    3.2.2 系统管理员模块功能该模块主要包括图书馆信息设置,用户管理,参数设置,书架设置。

    图书馆信息设置:该功能选项用于系统管理员对图书馆名称,地址,联系方式,简介等信息的管理更新,以便于读者和外界人士对图书馆的了解。该功能是对td_library表进行维护修改等操作,修改后的信息将被保存在该表中
    用户设置:该功能子模块主要是系统管理员对系统用户的管理,通过此子模块的功能实现可以对用户进行添加、修改、删除、权限设置等操作,该子模块能将图书馆的不同工作细化到不同的相关人员,极大地提高了图书馆的工作效率。该操作是对tb_users表进行操作,在对用户进行了相关的操作后把操作后的最新信息存放在该表中
    图书馆参数设置:通过该子模块设置在图书馆办理临时读者证的费用及证件有效期限。该操作是对于tb_parameter表进行,并把操作后的最新数据存放在该表中

    3.2.3 读者管理模块功能该模块主要包含读者类型管理和读者信息管理两个子模块:

    读者类型管理:该子模块是对图书馆系统用户读者的类型进行维护,修改等操作,在此模块中主要设置不同类型读者一次性可借阅的图书的数量,该操作是对于tb_resderType表进行,并将操作结果保存在该表中
    读者信息管理:该子模块是对读者的基本信息进行管理,可以对读者的基本信息进行添加,修改,删除操作,这下操作均是对tb_resder表进行的,并将操作后的结果保存在该表中

    3.2.4 图书管理模块功能图书管理功能模块可分为图书类型管理和图书信息管理两个子模块,其各自的实现分别如下面表中所示:
    图书类型管理描述




    图书类型管理




    功能描述
    对图书进行类型设置分类,并对不同类型图书可被借阅的天数进行设置


    访问的数据库表
    图书类型表:tb_bookType


    进行的操作
    添加、修改、删除图书类型,对不同类型图书可被借阅的天数进行设置


    产生的结果
    对图书类型进行管理,对不同类型图书参数进行设置


    结果存储位置或输出
    结果存储在图书类型表(tb_bookType)中,结果在图书类型查询页面输出



    图书信息管理描述




    图书信息管理




    功能描述
    对图书进行基本操作和信息管理


    访问的数据库表
    图书类型表:tb_bookType


    进行的操作
    添加、修改、删除图书,对图书的编号、所在书架、价格、出版社等基本信息进行管理


    产生的结果
    对图书基本操作管理,对不同图书参数进行各自信息的设置管理


    结果存储位置或输出
    结果存储在图书类型表(tb_book)中,结果在图书查询页面输出



    3.2.5 图书借还模块功能该功能模块主要实现对读者借阅、续接、归还图书的操作,其中子模块各自的描述如下各表所列:
    图书借阅描述




    图书借阅管理




    功能描述
    对读者借阅图书进行基本操作和信息管理


    访问的数据库表
    图书信息表: tb_bookinfo 读者信息表:tb_reader 读者类型信息表:tb_resderType


    进行的操作
    对读者借阅图书进行管理


    产生的结果
    读者借阅成功,系统对借阅信息进行记录


    结果存储位置或输出
    结果存储在图书借阅表(tb_borrow)中,结果在图书借阅查询页面输出



    图书续借描述




    图书续接管理




    功能描述
    对读者借阅图书进行提续接操作


    访问的数据库表
    图书借阅表: tb_borrow


    进行的操作
    对借阅的图书进行续接


    产生的结果
    读者归还日期延后一个月


    结果存储位置或输出
    结果存储在图书借阅表(tb_borrow)中



    图书归还描述




    图书归还管理




    功能描述
    对读者归还图书进行基本操作和信息管理


    访问的数据库表
    图书借阅信息表: tb_borrow 读者类型信息表:tb_resderType


    进行的操作
    对读者借阅图书进行管理


    产生的结果
    读者借阅成功,系统对借阅信息进行记录


    结果存储位置或输出
    结果存储在图书归还表(tb_giveback)中



    3.2.6 系统查询模块功能该模块包括对图书馆藏书进行查询,对读者借阅情况进行查询,以及对借阅到期和超期的读者进行提醒的信息,其中三个子模块的各自实习如下所示:
    图书查询描述




    图书查询




    功能描述
    系统用户对馆藏图书信息进行查询操作


    访问的数据库表
    图书信息表: tb_book


    进行的操作
    用户通过图书的编号,作者,出版社等信息对图书进行相关查询


    产生的结果
    读者查询到相应的图书或系统提醒查询的图书不存在


    结果存储位置或输出
    结果在图书查询页面输出



    图书借阅查询描述




    图书借阅查询




    功能描述
    系统用户对读者借阅图书信息进行查询操作


    访问的数据库表
    图书借阅表: tb_borrow


    进行的操作
    用户通过图书的编号,读者编号等信息对摸个读者或某本图书的借阅情况进行相关查询


    产生的结果
    查询到相应的读者或图书得借阅情况


    结果存储位置或输出
    结果在图书查询页面输出



    图书借阅到期提醒描述




    图书借阅到期提醒管理




    功能描述
    对读者借阅的到期图书进行提醒


    访问的数据库表
    图书借阅表: tb_borrow 图书归还表:tb_giveback 读者信息表:tb_reader 读者类型信息表:tb_resderType


    进行的操作
    对借阅到期和超期的读者进行提醒


    产生的结果
    向借阅到期和借阅超期的读者发送邮件等提醒信息


    结果存储位置或输出
    结果存储在图书借阅到期提醒表



    4.程序设计与编码4.1 开发平台与工具4.1.1 J2EE平台J2EE ,即是Java2平台企业版(Java 2 Platform Enterprise Edition),是原Sun公司(现已被甲骨文公司收购)为企业级应用推出的标准平台。它简化了企业解决方案的开发、部署和管理相关复杂问题的体系结构,J2EE技术的基础就是核心Java平台或Java 2平台的标准版,J2EE不仅巩固了标准版中的许多优点,例如”编写一次、随处运行”的特性、方便存取数据库的JDBC API、CORBA技术以及能够在Internet应用中保护数据的安全模式等等,同时还提供了对 EJB(Enterprise JavaBeans)、Java Servlets API、JSP(Java Server Pages)以及XML技术的全面支持。其最终目的就是成为一个能够使企业开发者大幅缩短投放市场时间的体系结构。J2EE体系结构提供中间层集成框架用来满足无需太多费用而又需要高可用性、高可靠性以及可扩展性的应用的需求。通过提供统一的开发平台,J2EE降低了开发多层应用的费用和复杂性,同时提供对现有应用程序集成强有力支持,完全支持Enterprise JavaBeans,有良好的向导支持打包和部署应用,添加目录支持,增强了安全机制,提高了性能[9]。
    在开发图书馆借阅管理系统的过程中,应用Myeclipse6.0.1,它可以在数据库和J2EE的开发、发布,以及应用程序服务器的整合方面极大的提高工作效率。Myeclipse是功能丰富的J2EE集成开发环境,包括了完备的编码、调试、测试和发布功能,完整支持HTML, Struts, JSF, CSS, Javascript, SQL[10]。
    4.1.2 WEB服务器和数据库在系统的开发过程中使用的Web应用服务器是Tomcat,是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、SUN和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现。Tomcat是一个小型的轻量级应用服务器,它运行时占用的系统资源小、扩展性好、支持负载平衡和邮件服务等开发应用系统常用的功能,因此在中小型系统和并发访问用户不是很多的时候,经常被使用[11]。
    使用MySQL作为数据库开发工具。MySQL是一个小型关系型数据库管理系统,开发者为瑞典MySQL AB公司。在2008年1月16号被Sun公司收购。目前MySQL被广泛地应用在Internet上的中小型网站中。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库[11]。
    为了开发的便捷快速,使用struts第三方插件。Struts是一个全新的MVC框架,实在WebWork基础上发展起来的[12]。
    开发系统用的系统工具如表4.1所示:



    工具名称
    用途




    JDK 1.6.0_11
    Java 开发工具包


    MyEclipse
    J2EE集成开发环境


    MySQL 5.0
    小型关系数据库管理系统


    SQLYog 6.1
    MySQL图形化数据库管理工具


    Tomcat 6.0
    Web应用服务器


    Struts 1.0
    第三方插件,可扩展的Java EE Web框架



    4.2 程序设计4.2.1 程序设计概述在设计的Web层应用了著名的MVC模式,V有JSP来实现,为了业务逻辑和表示的分离.它是基于Web应用系统,它的客户端使用Broswer,然后是Web层的应用,业务逻辑层(有EJB实现),资源管理层。客户请求浏览页面,一般Web层的View有JSP组成,并且使用了大量Taglib。把每个请求映射到某个HTMLAction类来响应它。HTML Action类是一个标准的类,执行选择的HTML Action。使用MVC模式减少了代码的复制,即减少了代码的维护,由于模型返回的格式不带任何显示格式,因而模型可以直接应用于接口的使用,还因为MVC模型把不同的模型和不同的视图组合在一起完成不同的请求,因此,控制层可以说包含了用户请求权限的概念[13]。
    在设计中还因应用了Struts框架,Struts跟Tomcat、Turbine等诸多Apache项目一样,是开源软件,这是它的一大优点。使开发者能更深入的了解其内部实现机制[11]。
    除此之外,Struts的优点主要集中体现在Taglib和页面导航。Taglib是Struts的标记库,灵活动用,能大大提高开发效率。页面导航使系统的脉络更加清晰。通过一个配置文件,即可把握整个系统各部分之间的联系,这对于后期的维护有着莫大的好处[11]。
    4.2.2 数据库与Web服务器的连接数据库连接时采用连接池技术链接MySQL,具体代码实现如下:
    public ConnDB(){ try { InputStream in=getClass().getResourceAsStream(propFileName); prop.load(in); //通过输入流对象加载Properties文件 dbClassName = prop.getProperty("DB_CLASS_NAME"); //获取数据库驱动 dbUrl = prop.getProperty("DB_URL", "jdbc:mysql://127.0.0.1:3306/db_librarySys?user=root&password=123&useUnicode=true"); } catch (Exception e) { e.printStackTrace(); //输出异常信息 } } public static Connection getConnection() { Connection conn = null; try { Class.forName(dbClassName).newInstance(); conn = DriverManager.getConnection(dbUrl); } catch (Exception ee) { ee.printStackTrace(); } if (conn == null) { System.err.println( "警告: DbConnectionManager.getConnection() 获得数据库链接失败.\r\n\r\n链接类型:" + dbClassName + "\r\n链接位置:" + dbUrl); } return conn; } /* * 功能:执行查询语句 */ public ResultSet executeQuery(String sql) { try { conn = getConnection(); stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); rs = stmt.executeQuery(sql); } catch (SQLException ex) { System.err.println(ex.getMessage()); } return rs; } /* * 功能:执行更新操作 */ public int executeUpdate(String sql) { int result = 0; try { conn = getConnection(); //调用getConnection()方法构造Connection对象的一个实例conn stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); result = stmt.executeUpdate(sql); //执行更新操作 } catch (SQLException ex) { result = 0; } return result; } /* * 功能:关闭数据库的连接 */ public void close() { try { if (rs != null) { rs.close(); } if (stmt != null) { stmt.close(); } if (conn != null) { conn.close(); } } catch (Exception e) { e.printStackTrace(System.err); } }}
    4.2.3 登录模块程序设计本模块主要是用户通过图书管理系统的首页登录进入该系统。用户输入正确的用户名和密码,系统会根据用户的身份进行相应权限划分;如果登录信息有错误,则系统提示登入错误的信息,并且禁止系统用户进行任何操作。图书借阅管理系统的登录主页面如图4.1所示。

    用户在登录页面写好用户名和密码,选择登录,登录成功则跳转到系统的首页,否则提示错误信息[14]。在服务器端进行用户身份验证的程序流程图如图4.2程序流程图所示。

    4.2.4 系统管理员功能模块的实现本模块中最主要的是管理系统用户,设置图书馆信息等操作,其中管理系统用户包括对他们进行添加,修改,删除及权限划分操作。
    其中系统管理员读系统用户进行管理的操作页面如下图所示:

    其中对系统用户权限的设置是该操作的重要部分也是系统提高效率的关键所在,起具体实现代码为:
    private ActionForward managerModify(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { ManagerForm managerForm = (ManagerForm) form; managerForm.setId(managerForm.getId()); //获取并设置管理员ID号 managerForm.setName(managerForm.getName()); //获取并设置管理员名称 managerForm.setPwd(managerForm.getPwd()); //获取并设置管理员密码 managerForm.setSysset(managerForm.getSysset()); //获取并设置系统设置权限 managerForm.setReaderset(managerForm.getReaderset()); //获取并设置读者管理权限 managerForm.setBookset(managerForm.getBookset()); //获取并设置图书管理权限 managerForm.setBorrowback(managerForm.getBorrowback()); //获取并设置图书借还权限 managerForm.setSysquery(managerForm.getSysquery()); //获取并设置系统查询权限 int ret = managerDAO.update(managerForm); //调用设置管理员权限的方法 if (ret == 0) { request.setAttribute("error", "设置管理员权限失败!");//保存错误提示信息到error参数中 return mapping.findForward("error"); //转到错误提示页面 } else { return mapping.findForward("managerModify"); //转到权限设置成功页面 } }
    4.2.5 读者管理功能模块的实现读者管理主要实现对读者的类型管理和信息管理两个功能子模块,其中读者类型管理中需要设置不同类型读者一次性可借阅的图书数量,读者信息管理则主要管理维护读者的基本信息,其各自操作界面如下所示:
    读者类型管理功能界面

    读者信息管理功能界面

    该管理功能在设置读者信息时需要输入读者姓名,性别,条形码,选择读者类别,有效证件,证件号码,电话,e-mail等信息。其中的姓名,性别,条形码,证件号码是必填选项。
    4.2.6 查询功能模块的实现查询功能模块包括图书查询,读者借阅查询和借阅到期提醒三个子功能模块。
    图书查询可根据图书的条形码,书名,作者,出版社等不同信息进行查询,其操作界面图下图所示:

    实现该功能中根据读者不同需求的按条件查询实现语句如下:
    public Collection query(String strif){BookForm bookForm=null;Collection bookColl=new ArrayList();String sql="";if(strif!="all" && strif!=null && strif!=""){ sql="select * from (select b.*,c.name as bookcaseName,p.pubname as publishing,t.typename from tb_bookinfo b left join tb_bookcase c on b.bookcase=c.id join tb_publishing p on b.ISBN=p.ISBN join tb_booktype t on b.typeid=t.id where b.del=0) as book where book."+strif+"'";}else{ sql="select b.*,c.name as bookcaseName,p.pubname as publishing,t.typename from tb_bookinfo b left join tb_bookcase c on b.bookcase=c.id join tb_publishing p on b.ISBN=p.ISBN join tb_booktype t on b.typeid=t.id where b.del=0";}System.out.println("图书查询时的SQL:"+sql);ResultSet rs=conn.executeQuery(sql);try { while (rs.next()) { bookForm=new BookForm(); bookForm.setBarcode(rs.getString(1)); bookForm.setBookName(rs.getString(2)); bookForm.setTypeId(rs.getInt(3)); bookForm.setAuthor(rs.getString(4)); bookForm.setTranslator(rs.getString(5)); bookForm.setIsbn(rs.getString(6)); bookForm.setPrice(Float.valueOf(rs.getString(7))); //此处必须进行类型转换 bookForm.setPage(rs.getInt(8)); bookForm.setBookcaseid(rs.getInt(9)); bookForm.setInTime(rs.getString(10)); bookForm.setOperator(rs.getString(11)); bookForm.setDel(rs.getInt(12)); bookForm.setId(Integer.valueOf(rs.getString(13))); bookForm.setBookcaseName(rs.getString(14)); bookForm.setPublishing(rs.getString(15)); bookForm.setTypeName(rs.getString(16)); bookColl.add(bookForm); }} catch (SQLException ex) { ex.printStackTrace();}conn.close();return bookColl;}
    借阅查询子模块是对图书当前状态和读者当前的借阅情况进行查询,具有此权限的用户登录并进入该操作界面后选中相应的查询条件,并输入相应的查询信息,系统即可在页面显示被查询的图书的状态,或相应读者的当起借阅情况,此外,还可以输入相应时间段内的所有借阅清单,或选择某个读者查询他在某个时间段内的借阅情况,查询某个时间段内的此子功能操作界面为:

    系统中同时选中日期和限制条件进行查询时,程序是在条件查询的基础上选中符合时间条件限制的内容,其实现代码为:
    if (flag.length == 2) { if (request.getParameter("f") != null) { str = request.getParameter("f") + " like '%" + request.getParameter("key") + "%'"; } System.out.println("日期和条件"); String sdate = request.getParameter("sdate"); String edate = request.getParameter("edate"); String str1 = null; if (sdate != null && edate != null) { str1 = "borrowTime between '" + sdate + "' and '" + edate + "'"; } str = str + " and borr." + str1; System.out.println("条件和日期:" + str);}
    借阅到期提醒子模块是将系统当前时间与应归还的时间进行比较,如果系统当前时间以超过图书应归还时间,相应的读者借阅信息便会被显示在借阅到期提醒界面,其界面为:

    4.2.7 图书管理功能模块的实现与读者管理模块类似,图书管理模块也分为图书类型管理和图书档案管理两个子模块,其中图书类型管理功能处理将图书分类提高管理效率外还设置了不同类型图书可借阅的天数,对不同类型图书进行区别管理,图书档案管理是管理维护图书馆藏书的基本信息。这两个子模块的操作界面为:
    图书类型管理界面

    图书档案管理界面

    图书档案中包含图书的条形码,图书名称,图书类型,作者,译者,价格,出版社,所在书架等图书基本信息,其中作者,译者,页码是备选信息,可以不填。
    4.2.8 图书借还功能模块的实现该功能模块可分为图书借阅,图书归还,图书续借三个子模块.
    图书借阅该子模块实现系统的借阅功能,读者向图书管理员提供自己的编号会显示出读者当起的借阅情况,再提供要借阅的图书标号,图书管理员将信息记录在系统中,借阅成功,其操作界面如下图:

    如果在借阅时所要借阅的图书不存在或者读者借阅已达借阅图书的上线,则读者不能接续借阅图书,系统将给出相应提示,此功能的实现代码为:
    private ActionForward bookborrow(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){ //查询读者信息 //此处一定不能使用该语句进行转换 readerForm.setBarcode(request.getParameter("barcode")); ReaderForm reader = (ReaderForm) readerDAO.queryM(readerForm); request.setAttribute("readerinfo", reader); //查询读者的借阅信息request.setAttribute("borrowinfo",borrowDAO.borrowinfo(request.getParameter("barcode"))); //完成借阅 String f = request.getParameter("f"); String key = request.getParameter("inputkey"); if (key != null && !key.equals("")) { String operator = request.getParameter("operator"); BookForm bookForm=bookDAO.queryB(f, key); if (bookForm!=null){ int ret = borrowDAO.insertBorrow(reader, bookDAO.queryB(f, key), operator); if (ret == 1) { request.setAttribute("bar", request.getParameter("barcode")); return mapping.findForward("bookborrowok"); } else { request.setAttribute("error", "添加借阅信息失败!"); return mapping.findForward("error"); } }else{ request.setAttribute("error", "没有该图书!"); return mapping.findForward("error"); } } return mapping.findForward("bookborrow");}
    图书归还该子模块实现系统的图书归还功能,读者向图书管理员提供自己的编号会显示出读者当起的借阅情况,再提供要归还的图书标号,图书管理员将信息记录在系统中,归还成功,其操作界面如下图:

    5.软件测试5.1 软件测试的方法与步骤该系统在本地服务器上进行运行和调试,鉴于对系统的内部结构和处理算法的完全了解以及对系统功能的全面掌握对系统进行白盒测试和黑盒测试。
    在开发软件系统的过程中,需要面对错综复杂的问题,因此,在软件生存周期的每个阶段都不可避免地会产生错误。测试目的在于:发现错误而执行一个程序的过程,测试重要发现一个发现其中尚未发现的错误。
    本系统的测试阶段信息流程下图所示[15]。

    为了设计出有效地测试方案按照下面准则进行测试:所有测试都应追溯到用户需求;在完成了需求模型就要着手制定测试计划,在编码之前最所有测试工作进行计划和设计;运用Pareto原理着重对占出现错误80%的容易出错的20%的模块进行测试,从小规模开始逐步进行大规模测试,通常先重点测试单个程序模块再转向集成的模块簇;精心设计测试方案,尽可能充分覆盖程序逻辑使之达到要求的可靠性[15]。
    按照软件工程的观点,软件测试(主要是指多模块程序的测试)共包括4个层次。

    单元测试。单元测试的用例从单元详细设计中导出。在单元测试中可以采用功能性测试和结构性测试两种
    集成测试和确认测试。这一阶段的任务,是通过了单元测试的模块逐步组装起来,通过测试与纠错,最终得到一个满足需求的目标软件
    验证测试。在这个测试步骤中所发现的往往是需求规格说明的错误。一般来说,系统测试是功能性测试,不是结构性测试[15]

    在整个测试中,采用了白盒测试和黑盒测试相结合的方法。
    5.2 测试用例设计与测试用例的运行过程及测试结果分析5.2.1模块测试登录模块测试


    用例
    测试数据
    预期结果




    UC1:输入正确的用户名和密码
    用户名:admin密码:admin
    系统跳转到登陆成功页面


    UC2:输入空用户名
    用户名:
    请输入用户名


    UC3:输入用户名和空密码
    用户名:admin 密码:
    请输入密码


    UC4:输入用户名和错误的密码
    用户名:admin 密码:321ff
    您输入的用户名或密码错误



    当用户输入的用户名或密码错误是系统会跳转到出错页面并提示“您输入的用户名或密码错误”,用户点击确定,系统会重新返回登陆页面,其中错误信息提示页面如图5.1所示:

    更改密码模块测试用户登录系统后可对自己的登录密码进行更改,更改过程要求用户提供原始密码,输入新密码,重新输入新密码进行确认,如果用户输入的原始密码错误,或两次输入的新密码不一致将无法执行密码更新操作,系统会给出相应的提示,起显示页面为:

    5.2.2集成测试把经过单元测试的模块放在一起形成一个子系统并对它进行测试用于检验模块相互间的协调和通信,这里主要对图书管理员功能系统进行了测试,经过检验其功能均得以顺利实现,下图为管理员操作的读者借阅模块成功运行界面:

    把经过测试的子系统装配成一个完整的系统进行测试,经过黑盒测试于白盒测试相结合的方式,对整个系统的各个功能模块进行了测试,并调试改正其中的设计和编码错误,经过这个环节的操作整个系统的功能基本实现成功运行。
    5.2.3 验收测试在进行了以上的测试工作后,将整个软件系统作为单一的实体进行测试,测试内容与系统测试基本类似,但它是在用户积极参与下进行的,此测试过程主要使用实际数据,进行测试,验证测试的目的是验证系统确实能够满足用户的需求,经过这个环节的实际数据测试,系统的各个功能实现都达到了系统需求设计的要求。
    5.3 评价测试过程严格按照测试的流程,经过单元测试、子系统测试和系统测试。通过单元测试,查找出了系统各模块内部的错误;通过子系统测试,发现了模块间相互协调和通信上的错误;通过系统的集成测试,发现了软件设计过程中存在的错误。通过改正错误的设计和实现部分,保证了图书借阅管理系统可以完成需求分析中制定的需求[16]。
    从上面的测试中可以看出,此系统可以完成用户登录、系统设置、图书管理、读者管理管理、借阅管理和系统查询等功能。读者在本系统的应用下可实现按照各种方式(如:书名,编号,作者)查询图书馆的藏书请客,方便的借阅图书,续借图书,归还图书,能够查询自己的借阅图书情况。图书馆工作人员能够实现方便的对图书进行查询,方便的进行读者借阅情况查询,方便的进行借书还书处理等,便捷的对图书信息进行添加、修改、删除,分类管理等操作,对读者信息进行相关添加,修改,分类管理等操作。系统管理员可以对图书馆信息进行修改更新操作,对系统用户进行添加、修改、删除、权限设置等操作,对图书馆的办证参数进行修改维护等操作功能。测试阶段的工作一方面发现了系统的各种错误,另外一方面也验证了修改后的系统能够实现提高图书馆工作效率的预期目的。
    6.结束语6.1 工作成果在MyEclipse开发环境下,以J2EE为平台,运用JSP网络编程语言和Struts框架和MySQL数据库完成了B/S模式的图书馆借阅管理系统。系统基本上实现了预期的各项功能,达到了任务书中的主要设计内容的各项任务,整个系统也在经过测试和不断地改正之后能够顺利运行。基本上实现了开题报告中的需求设计在程序编写,该系统能够实现:

    读者在本系统的应用下可实现按照各种方式(如:书名,编号,作者)查询图书馆的藏书请客,方便的借阅图书,续借图书,归还图书,能够查询自己的借阅图书情况
    图书馆工作人员能够实现方便的对图书进行查询,方便的进行读者借阅情况查询,方便的进行借书还书处理等,便捷的对图书信息进行添加、修改、删除,分类管理等操作,对读者信息进行相关添加,修改,分类管理等操作
    系统管理员可以对图书馆信息进行修改更新操作,对系统用户进行添加、修改、删除、权限设置等操作,对图书馆的办证参数进行修改维护等操作功能

    6.2 改进意见该系统在使用第三方插件Strusts时采用的是1.0版本的,若使用更新的2.0版本会更大的改进系统的开发便捷性和可维护性,系统在数据库与Web服务器的连接时采用的是连接池技术,若在数据库连接时使用现在流行的第三方插件Hibernate3.0,会使系统有更强的数据库映射关系,进而极大简化开发过程,还有就是系统在一些信息设置的细节上还存在不足,可以对系统的相关字段进行格式设置和异常处理,使数据更加规范化[11]。
    其次,本系统只对传统书籍进行了最基本的管理,随着计算机技术的飞速发展,应将各个图书馆的图书进行联网交流,使读者可以远程查询图书馆的藏书等信息,还应开发对电子书的管理,形成网上图书资源共享平台,使读者可以在线阅读电子书资料,并设置用户权限,使管理员可以上传图书资料信息,高级用户可以下载网上电子书资源,从而实现信息资源最大化被共享。
    2 评论 50 下载 2019-10-11 12:27:37 下载需要20点积分
  • 基于Java和Sql Server 2000实现的学生选课管理系统

    一、课程设计任务完成学生选课管理系统的开发。
    二、需求描述本系统是一个单机版的小型的学生选课管理系统,在本系统中,开发了一个面向管理员、学生和教师这三个对象的教务平台,对学生提供的服务有登录、选课、、修改登录密码、和查询成绩这几个服务,所选课程总数不能超过3门;对教师提供的服务有登录、修改登录密码和登录成绩;对管理员提供的服务有登录开设学生和教师帐号、删除学生和教师帐号的服务。
    三、系统总体设计3.1 系统架构设计
    架构

    单机
    运行软件环境

    windows XP SP3jdk1.6
    开发环境

    硬件平台
    CPU:P41.8GHz内存:256MB以上
    软件平台:windows XP SP3 、jdk1.6
    操作系统:WindowsXP数据库:SQL Server 2000、SQLServer SP4补丁开发工具:Eclipse 3.3分辨率:1024*768


    3.2 功能模块设计
    各模块功能:

    登录界面:登录界面是有帐号,密码两个JTextField,管理员帐号一字母A开头,教师帐号一字母T开头,学生帐号以字母S开头,登录帐号或密码输入错误会弹出相应的提示对话框
    学生信息管理模块:管理员用于添加和删除学生信息的模块
    教师信息管理模块:管理员用于添加和删除教师信息的模块
    教师密码修改模块和学生密码修改模块:管理员添加的用户帐号的初始密码与用户的帐号相同,用户通过密码修改模块可以自己需改密码
    教师录入成绩模块:教师可以浏览选修自己课程的学生的信息并且录入该学生的成绩
    学生选择选修课模块:该模块通过表格的形式将所有课程列出来,学生可以根据个人兴趣选择不同的课程,每个学生选择的课程数目不能超过3门,而且不能重复选课,否则会弹出对话框,提示用户查看已经选择了的课程
    学生查询成绩模块:通过表格的形式将该学生选择了的课程列出来,如果教师有录入成绩,则可以看到自己的课程成绩

    3.3 数据库设计E-R图

    关系模式

    学生(学生学号,学生姓名,教师性别,教师生日,所在班级)
    教师(教师编号,教师姓名,教师性别,教师生日,教师职称,所在院系)
    课程(课程号,课程名,学分,选课人数)
    选课(课程号,学生学号,成绩)
    授课(课程号,教师编号,上课地点)

    数据库管理系统
    Microsoft SQL Server 2000
    数据库命名
    StudentManager
    数据库表
    Logon(登录帐号密码),主要用来保存用户登录信息。



    字段名
    数据类型
    长度
    是否为空
    是否主键




    UserID
    char
    10
    不为空
    主键


    Passwordr
    charr
    10




    StudentTable1(学生信息表),主要用来保存学生信息。



    字段名
    数据类型
    长度
    主键否
    是否为空
    描述




    StudentID
    Char
    10
    主键
    不为空
    学生学号


    StudentName
    Char
    10

    不为空
    学生姓名


    StudentSex
    Char
    2

    不为空
    学生性别


    StudentBirthday
    Datetime
    8


    学生生日


    Class
    char
    16


    所在班级



    TeacherTable1(教师信息表),用来储存教师的基本信息。



    字段名
    数据类型
    长度
    主键否
    是否为空
    描述




    TeacherID
    Char
    10
    主键
    不为空
    教师编号


    TeacherName
    Char
    10

    不为空
    教师姓名


    TeacherSex
    Char
    2

    不为空
    教师性别


    TeacherBirthday
    Datetime
    8


    教师生日


    Post
    char
    10


    教师职称


    Department
    char
    20


    所在院系



    CourseTable(课程信息表)



    字段名
    数据类型
    长度
    主键否
    是否为空
    描述




    CourseID
    Char
    16
    主键
    不为空
    课程编号


    CourseName
    Char
    16

    不为空
    课程名


    Point
    Char
    8

    不为空
    学分


    StuNumber
    Datetime
    4

    不为空
    选课人数



    ScoreTable(学生成绩表),用于存储学生成绩。



    字段名
    数据类型
    长度
    是否为空
    是否主键




    CourseID
    char
    16
    不为空
    主键


    StudentID
    char
    10
    不为空
    主键


    Score
    int
    4




    TeachTable(j教师授课表)



    字段名
    数据类型
    长度
    是否为空
    是否主键




    CourseID
    char
    16
    不为空
    主键


    TeacherID
    char
    10
    不为空
    主键


    Location
    int
    10




    数据库账户及权限 (截图)
    学生账户表

    教师账户表

    用户登录表

    数据库存储过程
    AllCourse
    create proc AllCourseasbegin select x.CourseID,x.CourseName,x.Point ,y.TeacherName,y.Post,z.Location,x.StuNumber from Course x,TeacherTable1 y,TeachTable z where x.CourseID=z.CourseID and y.TeacherID=z.TeacherIDend
    DeleteLogon
    create proc DeleteLogon(@id char(10))asbegin delete from Logon where UserID=@idend
    DeleteStudent
    create proc DeleteStudent(@id char(10))asbegin delete from StudentTable1 where StudentID=@idend
    DeleteTeacher
    create proc DeleteTeacher(@id char(10))asbegin delete from TeacherTable1 where TeacherID=@idend
    InsertLogon
    create proc InsertLogon(@id char(10))asbegin insert into Logon values(@id,@id)end
    InsertStudent
    create proc InsertStudent(@userid char(10),@username char(10),@sex char(2),@birth datetime,@class char(10))asbegin insert into StudentTable1 values(@userid ,@username,@sex,@birth,@class)endreturn
    InsertTeacher
    create proc InsertTeacher(@userid char(10),@username char(10),@sex char(2),@birth datetime,@post char(10),@department char(10))asbegin insert into TeacherTable1 values(@userid ,@username,@sex,@birth,@post,@department)endreturn
    IsExistsStu
    create proc IsExistsStu(@id char(10))asbegin select * from StudentTable1 where StudentID=@idend
    IsExistsTea
    create proc IsExistsTea(@id char(10))asbegin select * from Teachertable1 where TeacherID=@idend
    ProcAllStu
    create proc ProcAllStuasbegin select * from StudentTable1end
    ProcAllTea
    create proc ProcAllTeaasbegin select * from TeacherTable1end
    ProcLogon
    create proc ProcLogon(@userid char(16),@password char(10))asbegin select * from Logon where UserID=@userid and Password=@passwordendreturn
    ProcModify
    create proc ProcModify(@id char(10),@password char(16))asbegin update Logon set Password=@password where UserID=@idend
    ProcStudent
    create proc ProcStudent(@id char(10))asbegin select * from StudentTable1 where StudentID=@idend
    SelectCourse
    create proc SelectCourse(@id char(10),@courseid char(16))asbegin insert into ScoreTable values(@courseid,@id,null)end
    SelectedCourse
    create proc SelectedCourse(@id char(10))asbegin select * from ScoreTable where @id=StudentIDend
    SelectedCourseNum
    create proc SelectedCourseNum(@id char(10))asbegin select COUNT(*) from Scoretable where StudentID=@idend
    SelectedDetail
    create proc SelectedDetail(@id char(10))asbegin select x.CourseID,x.CourseName,x.Point ,y.TeacherName,y.Post,z.Location,s.Score from Course x,TeacherTable1 y,TeachTable z,ScoreTable s where @id=s.StudentID and x.CourseID=z.CourseID and z.TeacherID=y.TeacherID and x.CourseID=s.CourseIDend
    3.4 系统界面设计3.4.1 窗体功能描述登录界面Logon.java

    管理员以帐号Admin密码123登录成功进入管理员的信息管理界面,通过点击“学生信息管理”和“教师信息管理”进入不同的管理界面,学生信息管理界面如下:

    教师信息管理界面如下:

    以学生帐号(如:帐号:S001001,密码:S001001)登陆成功后进入如下界面,首先显示的 是学生的基本信息:

    点击“课程列表”按钮进入如下界面:

    根据自己的跟人兴趣选择课程,选择的课程数目不能超过3门否则弹出对话框如下:

    点击“确定”跳转到已选课程列表。
    在主界面点击“已选课程”按钮也可以进入下面的界面查看已经选择的课程:

    以教师帐号(如:帐号:T01001,密码:T01001)登陆成功后进入如下界面,首先显示的是教师的基本信息:

    点击“录入成绩”可以通过表格来录入学生的成绩,界面如下图所示:

    3.4.2 页面/窗体关系结构图
    四、系统实现技术小结为了方便管理,将数据库的封装分成两部分,数据库资源配置文件和封装数据库操作的类SqlManager.java。
    数据库资源配置文件sysConfig.properties
    #Sepecify the system type: window or unixsystem-type=windows#specify the database's typedatabase-type=sqlserver#specify some parametersDBhost=localhostDBport=1433DBname=StudentManagerDBuser=saDBpassword=
    封装数据库操作的类:SqlManager.java
    import java.sql.*;import java.util.*;import javax.swing.JOptionPane;public class SqlManager { private static SqlManager p=null; private PropertyResourceBundle bundle; private static String jdbcDriver=null; private static String split=null; private String DBType=null; private String DBhost="localhost"; private String DBname=""; private String DBport=""; private String DBuser=""; private String DBpassword=""; private Connection Sqlconn=null; private Statement Sqlstmt=null; private String strCon=null; private SqlManager(){ try{ bundle=new PropertyResourceBundle(SqlManager.class. getResourceAsStream("/sysConfig.properties")); this.DBhost=getString("DBhost"); this.DBname=getString("DBname"); this.DBport=getString("DBport"); this.DBuser=getString("DBuser"); this.DBpassword=getString("DBpassword"); String system_type=getString("system-type"); if(system_type!=null){ if(system_type!=null){ if(system_type.toLowerCase().equals("widows")) split=";"; else if(system_type.toLowerCase().equals("unix")) split=":"; } String database_type=getString("database-type"); this.DBType=database_type; if(database_type!=null){ if(database_type.toLowerCase().equals("mysql")){ jdbcDriver="com.mysql.jdbc.Driver"; strCon="jdbc:mysql://"+DBhost+":"+DBport+"/"+DBname; } else if(database_type.toLowerCase().equals("oracle")){ jdbcDriver="oracle.jdbc.driver.OracleDriver"; strCon="jdbc:oracle:thin:@"+DBhost+":"+DBport+":"+DBname; } else if(database_type.toLowerCase().equals("sqlserver")){ jdbcDriver="com.microsoft.jdbc.sqlserver.SQLServerDriver"; strCon="jdbc:microsoft:sqlserver://"+DBhost+":"+DBport+";DatabaseName="+DBname; } } } }catch(Exception e){ e.printStackTrace(); } } public static SqlManager createInstance(){ if(p==null) { p=new SqlManager(); p.initDB(); } return p; } private String getString(String s) { return this.bundle.getString(s); } public void initDB(){ System.out.println(strCon); System.out.println(jdbcDriver); try{ Class.forName(jdbcDriver); }catch(Exception ex){ System.err.println("Can't Find Database Driver."); } } public void connectDB(){ try{ System.out.println("SqlManager:Connecting to database..."); Sqlconn=DriverManager.getConnection(strCon,DBuser,DBpassword); Sqlstmt=Sqlconn.createStatement(); }catch(SQLException ex){ System.err.println("connectDB"+ex.getMessage()); } System.out.println("SqlManager:Connect to database successful."); } public void closeDB(){ try{ System.out.println("SqlManager:Close connection to database..."); Sqlstmt.close(); Sqlconn.close(); }catch(SQLException ex){ System.err.println("closeDB:"+ex.getMessage()); } System.out.println("Sqlmanager:Close connection successful."); } public int executeUpdate(String sql){ int ret=0; try{ ret=Sqlstmt.executeUpdate(sql); }catch(SQLException ex) { System.out.println("executeUpdate:"+ex.getMessage()); } return ret; } public ResultSet executeQuery(String sql){ ResultSet rs=null; try{ rs=Sqlstmt.executeQuery(sql); }catch(SQLException ex){ System.err.println("executeQuery:"+ex.getMessage()); } return rs; } public static void main(String args[]){ SqlManager.createInstance().connectDB(); SqlManager.createInstance().closeDB(); }}
    五、课程设计体会该系统主要实现了学生选课的功能,这个系统是我独立完成,从需求分析,界面的搭建,到数据库的连接,表格,存储过程和存储过程等的建立,在这段时间的摸索中,我确实学到了很多东西,特别是对以前不太了解的Java Swing组件有了更深刻的了解。比如JTable,对于它的用法我在网上找了很多资料,JTable的建立有各种不同的方法,可以使用DefaultTableModel类来实现,如DefaultTableModel dtm=new DefaultTableModel(new Object [] {“”,”课程编号”,”课程名称”,”学分”,”任课教师”,”教师职称”,”上课地点”,”以选人数”},0));然后再table.setModel(dtm); 或者继承AbstractTableModel类,还有对于如何在JTable中添加Swing组件,原本我是直接新建一个JcheckBox对象直接添加到表格的单元格里,结果发现只能显示出一串字符串,上网查找后才知道,要用DefaultCellEditor来添加Swing组件,再设置setCellRenderer(new MyTableRenderer()) 这是一个实现了TableCellRenderer接口的JCheckBox。TableCellRenderer可以看做是Swing组件的呈现器,这样Table就会把内容显示绘制交给JCheckBox了。
    对于数据库,我尽量将对数据库的操作放在存储过程中,这样的抽象和封装使得源程序代码更加容易理解,而且在web应用系统中也可以避免发生不安全的状况,我想这是一个号的程序员应当要养成的习惯,在这次的课程设计中,层次化,模块化,抽象化也是我学到的一个重要的经验,参考一些资料后发现模块化能使程序设计更加简单,设计代码时目标更加明确,效率更高,以前虽然也知道这些道理,但自己真正实施起来却感到无从下手,比如前面的数据库操作和数据库资源配置文件,就是我从书中看来的,这样做的好处是,在程序中操作数据库的时候避免了使用很多try和catch语句,是代码更加简洁,更容易理解,此外需要连接不同的数据库时只要修改数据库的资源配置文件sysConfig.properties就可以了。原本我是想用jsp 做一个web应用程序的,因为对于学生选课系统做成单版的确实没什么实用性,但是我对jsp还不太熟悉,所以这次先做个单机版的,以后我会尝试用jsp来做这个系统。
    6 评论 150 下载 2019-04-29 20:07:05 下载需要13点积分
  • 基于Java和Mysql的图书管理系统

    一、设计题目图书管理系统设计
    二、问题描述完成一个学校图书管理系统的设计,用户有以下需求:建立读者档案;建立图书档案;完成日常的图书检索、借还以及新书订购和系统维护工作。
    三、需求分析3.1 功能需求3.1.1 读者档案数据包括:借书证号、姓名、性别、专业,读者类型(不同读者类型具有不同的最多借书册数)、证件类型,证件号码,联系电话、办证日期、允许最多借书册数等。
    实现办证、修改、注销、和读者信息检索(显示所有读者信息和按条件查询)等功能;
    3.1.2 图书档案数据包括:书号、书名、图书类别(不同图书类型具有不同的借阅天数)、可借天数、作者、出版单位、单价、藏书册数、书架编号、入库日期等。
    实现对图书和图书类别的管理:包括图书的添加和修改功能,图书类型的添加和修改功能。
    3.1.3 图书订阅数据包括:图书编号、书名、作者、出版社、单价、订购日期、订购数量、操作员、是否验收等。
    实现新书订购和验收新书功能。
    3.1.4 借阅管理图书借阅:根据借书证号判断该读者借书是否超出最大允许借书册数,是否有逾期未换的图书,满足借阅条件的进行借书登记,应记录借阅日期、应还日期,不满足借阅条件的给出提示信息。
    图书归还:执行图书归还操作。
    读者借阅搜索:对读者借阅记录进行检索。
    3.1.5 系统维护实现对管理员的添加和删除操作,以及修改密码的操作。
    3.2 数据需求需要管理员信息的数据、读者信息的数据、图书信息的数据,以及在借阅和归还图书过程中产生的借阅记录数据。
    3.3 系统模块的划分3.3.1 管理员用户登录采用菜单形式,菜单项设计如下:

    3.3.2 完成读者信息管理模块
    3.3.3 完成图书信息管理模块

    3.3.4 完成借阅管理模块
    四、概念模型的设计 (E/R图设计)4.1 E-R图
    4.2 属性的说明关于各个实体的属性的特性的说明
    Admini



    属性名
    属性的类型
    长度
    属性的约束等说明
    属性的特性说明




    教职工号
    char
    6
    主键,不为空
    6位都是0-9的数字


    姓名
    Varchar
    20




    性别
    Char
    2
    男或女



    账号
    int

    唯一
    账号>99999 账号<1000000


    密码
    Varchar
    10




    联系电话
    varchar
    15








    属性名
    属性的类型
    长度
    属性的约束等说明
    属性的特性说明




    图书编号
    Char
    14
    主键,不为空
    14位都是0-9的数字


    图书名称
    Varchar
    20




    出版社
    Varchar
    30




    作者
    Varchar
    10




    单价
    Float


    单价>0


    藏书册数
    Int


    藏书册数>0


    书架编号
    Char
    2

    2位0-9的数字


    入库日期
    Datetime





    图书类别



    属性名
    属性的类型
    长度
    属性的约束等说明
    属性的特性说明




    类别编号
    Char
    2
    主键,不为空
    2位都是0-9的数字


    类别名称
    Varchar
    20
    唯一



    可借天数
    Int

    唯一
    可借天数>0



    读者信息



    属性名
    属性的类型
    长度
    属性的约束等说明
    属性的特性说明




    借书证号
    Char
    6
    主键,唯一不为空
    6位都是0-9的数字


    姓名
    Varchar
    10




    性别
    Char
    2

    男或女


    专业
    Varchar
    20




    证件类型
    Varchar
    20




    证件号码
    Varchar
    15




    联系电话
    Varchar
    15




    办证日期
    Datetime





    借阅册数
    Int


    借阅册数>=0



    读者类型



    属性名
    属性的类型
    长度
    属性的约束等说明
    属性的特性说明




    借书证号
    Char
    6
    主键,唯一不为空
    6位都是0-9的数字


    读者类型
    Varchar
    10




    允许最多借书册数
    Int


    允许最多借书册数>0



    4.3 依赖关系说明
    书所属类别表,borrow_relationship表中的图书编号依赖书表中的图书编号
    读者类型表,borrow_relationship表,借阅记录表中的借书证号依赖读者信息表中的借书证号
    解约记录表中的管理员编号依赖admini表中的教职工号
    图书所属类别表中的类别编号依赖图书类别中的类别编号

    五、关系模型的逻辑设计5.1 完整的关系图
    5.2 关系的模式描述图书所属类别

    函数依赖:图书编号依赖书表中的图书编号,类别编号依赖图书类别中的类别编号
    范式级别:第二范式




    属性名
    属性的描述
    属性的类型
    约束
    备注




    图书编号
    14位
    char
    参照书表



    类别编号
    2位
    char
    参照图书类别



    可借天数
    不同类别不同
    Int
    可借天数 >0




    借阅关系

    函数依赖:借阅证号依赖读者信息表中的借阅证号,图书编号依赖书表中的图书编号
    范式级别:第二范式




    属性名
    属性的描述
    属性的类型
    约束
    备注




    图书编号
    14位
    char
    参照书表



    借书证号
    6位
    char
    参照读者信息表




    六、关系数据库创建6.1 数据库物理模型的设计数据文件的文件名:BookManagePro
    日志物理文件的文件名:BookManagePro_log
    建立数据库的T-SQL语句
    create database BookMangeProgo
    建立关系模型的T-SQL语句
    create table admini( 教职工号 char(6) not null primary key check(教职工号 like'[0-9][0-9][0-9][0-9][0-9][0-9]') , 姓名 varchar(20), 性别 char(2) check(性别 ='男' or 性别='女'), 账号 int check(账号>99999 and 账号<1000000) unique , 密码 varchar(10), 联系电话 varchar(15));create table 书( 图书编号 char(14)not null primary key check(图书编号 like'[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'), 图书名称 varchar(20), 出版社 varchar(30), 作者 varchar(10), 单价 float,check (单价>0), 藏书册数 int,check (藏书册数>0), 书架编号 char(2) check(书架编号 like'[0-9][0-9]'), 入库日期 datetime);create table 图书类别( 类别编号 char(2) not null primary key check(类别编号 like'[0-9][0-9]'), 类别名称 varchar(20) unique, 可借天数 int check(可借天数 >0) unique);create table 图书所属类别( 图书编号 char(14) not null primary key references 书(图书编号), 类别编号 char(2) references 图书类别(类别编号), 可借天数 int,check(可借天数 >0));create table 读者信息( 借书证号 char(6)not null primary key check(借书证号 like'[0-9][0-9][0-9][0-9][0-9][0-9]'), 姓名 varchar(10), 性别 char (2) check(性别 ='男' or 性别='女'), 专业 varchar(20), 证件类型 varchar(20), 证件号码 varchar(15), 联系电话 varchar(15), 办证日期 datetime , 借阅册数 int,check(借阅册数>0));create table 读者类型( 借书证号 char(6)not null primary key references 读者信息(借书证号), 读者类型 varchar(10), 允许最多借书册数 int,check(允许最多借书册数>0));create table 借阅记录( 借书证号 char(6) references 读者信息(借书证号), 图书编号 varchar(14), 借阅日期 datetime, 应还日期 datetime, 归还日期 datetime, 管理员编号 char(6)references admini(教职工号), primary key(借书证号,图书编号,借阅日期));create table borrow_relationship( 借书证号 char(6) references 读者信息(借书证号), 图书编号 char(14) references 书(图书编号), primary key(借书证号,图书编号));insert into admini values('000000','斌','男',666666,'bin','151****9377')insert into admini values('000001','罗','男',888888,'luo','173****5269')
    七、视图的设计7.1 用户角色用户角色为图书馆管理员,管理员操作本系统实现一系列功能。
    7.2 功能模块读者信息修改、、图书信息查询、图书信息修改图书借阅、读者借阅记录查询这几个功能模块需要用到视图方便操作。
    7.3 用户视图的需求需要所有图书信息的视图、可借图书信息的视图、读者借阅图书信息的视图、读者所有信息的视图。
    所有图书信息的视图
    create view bookifoas( select a.图书编号,图书名称,类别名称,b.可借天数,c.类别编号,出版社,作者,单价,书架编号,入库日期 from 书 a,图书所属类别 b,图书类别 c where a.图书编号=b.图书编号 and c.类别编号=b.类别编号)
    可借图书信息的视图
    create view loanable_bookasselect 书.图书编号,书.图书名称,书.出版社,类别名称,书.作者,书.单价,书.藏书册数,书.书架编号,书.入库日期,图书所属类别.可借天数from 书,图书所属类别,图书类别where 书.图书编号=图书所属类别.图书编号 and 图书类别.类别编号=图书所属类别.类别编号 and 书.图书编号 not in(select borrow_relationship.图书编号 from borrow_relationship)
    读者借阅图书信息的视图
    create view bookborrowasselect 读者信息.借书证号,姓名,允许最多借书册数,书.图书编号,书.图书名称,借阅日期,应还日期,归还日期from 读者类型 ,读者信息,书,借阅记录where 读者信息.借书证号=读者类型.借书证号 and 读者信息.借书证号=借阅记录.借书证号 and 书.图书编号=借阅记录.图书编号
    读者所有信息的视图
    create view readerasselect 读者信息.借书证号,姓名,性别,专业,证件类型,证件号码,联系电话,办证日期,借阅册数,读者类型,允许最多借书册数from 读者信息,读者类型where 读者信息.借书证号=读者类型.借书证号
    八、存储过程/触发器的建立没有使用到存储过程与自建的触发器。
    九、系统实现9.1 系统功能结构框架图
    9.2 功能模块实现9.2.1 管理员注册模块实现了普通管理员和超级管理员的登录,输入正确的账号密码即可登陆到主界面。并且可用键盘的回车键直接登陆;注册按钮可以进到普通管理员的注册界面;重置按钮可以清空已经输入的账号和密码内容。

    该界面是通过继承JFrame利用windowsbulider插件进行合理的布局完成的。
    键盘的监听,实际是对文本域的监听:
    KeyListener key_Listener = new KeyListener() { public void keyTyped(KeyEvent e) {} public void keyReleased(KeyEvent e){} public void keyPressed(KeyEvent e){ if(e.getKeyChar() == KeyEvent.VK_ENTER ) { enterloginActionPerformed(e);//键盘监听,按回车进入主界面,可与鼠标点击同时使用 } } }; userNameTxt.addKeyListener(key_Listener); passwordTxt.addKeyListener(key_Listener);
    登录的sql操作方法
    public Admini login(Connection con,Admini admin)throws SQLException{ Admini ad1=null; String sql = "select * from Admini where 账号=? and 密码=?"; PreparedStatement pstmt = (PreparedStatement) con.prepareStatement(sql); pstmt.setInt(1,admin.getAccnumber()); pstmt.setString(2,admin.getPassword()); ResultSet rs = pstmt.executeQuery(); if(rs.next()){ ad1 = new Admini(); ad1.setAccnumber(rs.getInt("账号")); ad1.setPassword(rs.getString("密码")); } return ad1;}
    9.2.2 管理员登录模块通过输入一系列的信息,进行普通管理员的注册,注册普通管理员时必须输入超级管理员的账号和密码,这样即表示只有在超管的允许下才可以注册普通管理员。不能随便一个人就可以注册。点击确认按钮即可注册,清空按钮可清空所有已填信息,返回按钮可返回到登录界面。

    该界面是通过继承JFrame通过windowsbulider插件进行合理的布局完成的。
    注册的sql 操作方法,通过传入一个连接数据库的参数,以及Admini类的一个对象,方法内写入相应的sql语句。
    public int register(Connection con,Admini admin)throws SQLException{ String sql="insert into Admini"+"(教职工号,姓名,性别,账号,密码,联系电话)"+"values(?,?,?,?,?,?)"; PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sql); pstmt.setString(1, admin.getTeanumber()); pstmt.setString(2, admin.getName()); pstmt.setString(3, admin.getSex()); pstmt.setInt(4, admin.getAccnumber()); pstmt.setString(5, admin.getPassword()); pstmt.setString(6, admin.getPhone()); return pstmt.executeUpdate(); }
    9.2.3 读者信息添加模块通过输入读者的相关信息(不可输入的办证日期和最多借书都是系统自动生成),点击确认按钮从而完成一个新读者的信息的添加。若点击清空按钮即可清空已填入的读者信息。

    该界面实在主界面的基础上继承JInternalframe实现的主界面下的子界面,同样是通过windowbulider插件进行合理的布局完成的。
    两个add方法,分别插入数据库的两个表,只有两个方法返回都为一条记录是,才算插入数据库成功,即添加一位新的读者信息成功。
    public int add1(Connection con,Readertype readertype)throws SQLException{ String sql="insert into 读者类型"+"(借书证号,读者类型,允许最多借书册数)"+"values(?,?,?)"; PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sql); pstmt.setString(1,readertype.getReadernumber()); pstmt.setString(2,readertype.getReadertype()); pstmt.setInt(3,readertype.getMax_borrownumber()); return pstmt.executeUpdate();}public int add2(Connection con,Reader reader)throws Exception{ Date date = new Date(); Timestamp dateStr =new java.sql.Timestamp(System.currentTimeMillis()); String sql="insert into 读者信息"+"(借书证号,姓名,性别,专业,证件类型,证件号码,联系电话,办证日期)"+"values(?,?,?,?,?,?,?,?)"; PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sql); pstmt.setString(1,reader.getReadnumber()); pstmt.setString(2,reader.getName()); pstmt.setString(3,reader.getSex()); pstmt.setString(4,reader.getMajor()); pstmt.setString(5,reader.getDocumenttype()); pstmt.setString(6,reader.getDocumentnumber()); pstmt.setString(7,reader.getPhone()); pstmt.setTimestamp(8,dateStr); return pstmt.executeUpdate(); }
    9.2.4 读者信息维护模块在搜索条件是空时,将会显示所有的读者的信息,点击每一条,下方各个文本域就会显示该读者的所有信息,供管理员修改或删除,不可编辑的文本域即为不可修改,修改信息时先编辑文本域以及下拉框的内容,修改的信息都写好后,点击修改按钮即刻修改读者的信息。点击删除按钮即可删除该读者的所有信息。搜索时只要输入借书证号的个别位即可,支持模糊查询。

    该界面实在主界面的基础上继承JInternalframe实现的主界面下的子界面,同样是通过windowbulider插件进行合理的布局完成的。
    list方法是查询的函数,返回一个结果集,从而将数据库的读者信息显示到界面上。两个delete方法是删除数据库中两个表中选中的读者信息,先删除后建立的表,再删除先建立的表,顺序不能乱。两个update方法是修改数据库的读者信息,然后再显示到界面上。
    public ResultSet list(Connection con,Reader reader,Readertype readertype)throws Exception{ StringBuffer sb = new StringBuffer("select * from reader"); if(StringUtil.isNotEmpty(reader.getReadnumber())) { sb.append(" where 借书证号 like '%"+reader.getReadnumber()+"%'"); } PreparedStatement pst =con.prepareStatement(sb.toString()); return pst.executeQuery();}public int update2(Connection con,Readertype readertype)throws Exception{ String sql="update 读者类型 set 读者类型=?,允许最多借书册数=? where 借书证号=?"; PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sql); pstmt.setString(1, readertype.getReadertype()); pstmt.setInt(2, readertype.getMax_borrownumber()); pstmt.setString(3, readertype.getReadernumber()); return pstmt.executeUpdate(); }public int update1(Connection con,Reader reader)throws Exception{ String sql="update 读者信息 set 姓名=?,性别=?,专业=?,证件类型=?,证件号码=?,联系电话=?,办证日期=? where 借书证号=?"; PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sql); pstmt.setString(1, reader.getName()); pstmt.setString(2, reader.getSex()); pstmt.setString(3, reader.getMajor()); pstmt.setString(4, reader.getDocumenttype()); pstmt.setString(5, reader.getDocumentnumber()); pstmt.setString(6, reader.getPhone()); pstmt.setString(7, reader.getReadertime()); pstmt.setString (8, reader.getReadnumber()); return pstmt.executeUpdate(); }public int delete1(Connection con,Reader reader)throws Exception{ String sql="delete from 读者信息 where 借书证号=?"; PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sql); pstmt.setString(1, reader.getReadnumber()); return pstmt.executeUpdate(); }public int delete2(Connection con,Readertype readertype)throws Exception{ String sql="delete from 读者类型 where 借书证号=?"; PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sql); pstmt.setString(1, readertype.getReadernumber()); return pstmt.executeUpdate(); }
    9.2.5 图书类别添加模块通过输入信息,完成对新类别的添加,每个类别的可借天数和编码都是不一样的,点击添加按钮即可加入一个新的图书类别,重置按钮可清空已填的所有信息。

    该界面实在主界面的基础上继承JInternalframe实现的主界面下的子界面,同样是通过windowbulider插件进行合理的布局完成的。
    public int add(Connection con,BookType bookType)throws Exception{ //操作的记录数,影响的记录条数 String sql="insert into 图书类别 values(?,?,?)"; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setString(1, bookType.getId()); pstmt.setString(2, bookType.getBookTypeName()); pstmt.setInt(3, bookType.getTypeday()); //执行,返回影响的记录条数 return pstmt.executeUpdate(); }
    9.2.6 图书类别管理模块通过数图书类别名称从而搜索该类别的信息(支持模糊查询),搜索条件为空时显示所有的类别的信息。点击表单的没一个类别的信息,即可将信息显示在下方文本域,可供管理员进行类别的修改和删除(不可编辑的文本框即为不可修改的内容)。

    该界面实在主界面的基础上继承JInternalframe实现的主界面下的子界面,同样是通过windowbulider插件进行合理的布局完成的。
    public ResultSet list(Connection con,BookType bookType)throws Exception{ StringBuffer sb = new StringBuffer("select * from 图书类别"); if(StringUtil.isNotEmpty(bookType.getBookTypeName())) { sb.append(" and 类别名称 like '%"+bookType.getBookTypeName()+"%'"); } //把第一个and换成where PreparedStatement pst =con.prepareStatement(sb.toString().replace("and", "where")); return pst.executeQuery();}public int delete(Connection con,String id)throws Exception{ String sql="delete from 图书类别 where 类别编号=?"; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setString(1, id); return pstmt.executeUpdate();}public int update(Connection con,BookType bookType)throws Exception{ String sql="update 图书类别 set 类别名称=?,可借天数=? where 类别编号=?"; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setString(1, bookType.getBookTypeName()); pstmt.setInt(2,bookType.getTypeday()); pstmt.setString(3, bookType.getId()); return pstmt.executeUpdate();}
    9.2.7 添加模块图书编号是当前的系统的时间,一共十四位,精确到秒,在填入图书信息后,根据藏书册数借助线程暂停的方法有延迟的连续添加相应的本数,这样可使图书编号唯一,入库日期也是当前系统时间。重置按钮可重置所有填入的图书信息。

    该界面实在主界面的基础上继承JInternalframe实现的主界面下的子界面,同样是通过windowbulider插件进行合理的布局完成的。
    public int add(Connection con,Book book)throws SQLException{ Book bk1=null; String sql = "insert into 书 values(?,?,?,?,?,?,?,?)"; PreparedStatement pstmt = (PreparedStatement) con.prepareStatement(sql); pstmt.setString(1,book.getBookid()); pstmt.setString(2,book.getBookname()); pstmt.setString(3,book.getBookpublish()); pstmt.setString(4,book.getAuthor()); pstmt.setFloat(5, book.getPrice()); pstmt.setInt(6,book.getNumber()); pstmt.setString(7,book.getShelfnum()); pstmt.setTimestamp(8,book.getArrivedate()); return pstmt.executeUpdate(); }
    9.2.8 图书信息修改删除模块通过图书编号 图书名称 作者 出版社 图书类别都可以模糊查询图书的信息,若搜索条件为空时,将会显示所有的图书信息。选择一条信息,该图书信息将会在下方的文本域显示,供管理员修改和删除。

    该界面实在主界面的基础上继承JInternalframe实现的主界面下的子界面,同样是通过windowbulider插件进行合理的布局完成的。
    public ResultSet list(Connection con,Book book)throws Exception{ StringBuffer sb=new StringBuffer("select 图书编号,图书名称,类别名称,出版社,作者,单价,书架编号,入库日期" + " from bookifo"); if(StringUtil.isNotEmpty(book.getBookid())){ sb.append(" and 图书编号 like '%"+book.getBookid()+"%'"); } if(StringUtil.isNotEmpty(book.getBookname())){ sb.append(" and 图书名称 like '%"+book.getBookname()+"%'"); } if(StringUtil.isNotEmpty(book.getAuthor())){ sb.append(" and 作者 like '%"+book.getAuthor()+"%'"); } if(StringUtil.isNotEmpty(book.getBookpublish())){ sb.append(" and 出版社 like '%"+book.getBookpublish()+"%'"); } if(StringUtil.isNotEmpty(book.getType())){ sb.append(" and 类别名称 like '%"+book.getType()+"%'"); } PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sb.toString().replaceFirst("and", "where")); return pstmt.executeQuery();}public int delete(Connection con,String id)throws Exception{ //关联删除,同时删除书表和图书所属类别表中的所有信息 String sql="delete from 图书所属类别 where 图书编号 =?;delete from 书 where 图书编号 =?"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setString(1,id); pstmt.setString(2,id); return pstmt.executeUpdate();}public int update(Connection con,Book book,BookType booktype)throws Exception{ String sql="update 书 set 图书名称=?,出版社=?,作者=?,单价=?,书架编号=? where 图书编号=?;" + "update 图书所属类别 set 类别编号=?,可借天数=? where 图书编号=?"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setString(1,book.getBookname()); pstmt.setString(2,book.getBookpublish()); pstmt.setString(3,book.getAuthor()); pstmt.setFloat(4, book.getPrice()); pstmt.setString(5,book.getShelfnum()); //书架编号,两位字符 pstmt.setString(6,book.getBookid()); pstmt.setString(7,booktype.getId()); pstmt.setInt(8,booktype.getTypeday()); pstmt.setString(9,book.getBookid()); return pstmt.executeUpdate();}public int update(Connection con,Book book,BookType bookType)throws Exception{ String sql="update 图书所属类别 set 类别编号=?,可借天数=? where 图书编号=?"; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setString(1, bookType.getBookTypeName()); pstmt.setInt(2,bookType.getTypeday()); pstmt.setString(3, book.getBookid()); return pstmt.executeUpdate();}public int delete(Connection con,Book book)throws Exception{ String sql="delete from 图书所属类别 where 图书编号=?"; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setString(1, book.getBookid()); return pstmt.executeUpdate();}
    9.2.9 图书借阅模块通过图书编号 图书名称 作者 出版社 图书类别都可以模糊查询图书的信息,若搜索条件为空时,将会显示所有的图书信息。点击该图书信息,即可在下方表格显示该图书的编号,在手动输入借书证号以及操作管理员的教职工号,即可进行借书。应还日期和借阅日期都会自动生成。

    该界面实在主界面的基础上继承JInternalframe实现的主界面下的子界面,同样是通过windowbulider插件进行合理的布局完成的。
    public int borrowbook(Connection con,Book book,String readerid,String adminid) throws SQLException{ String sql ="insert into 借阅记录 (借书证号,图书编号,借阅日期,应还日期,管理员编号)values(?,?,?,?,?);" + "insert into borrow_relationship values(?,?)"; PreparedStatement pstmt = (PreparedStatement) con.prepareStatement(sql); Timestamp nowtime =new java.sql.Timestamp(System.currentTimeMillis()); pstmt.setString(1,readerid); pstmt.setString(2,book.getBookid()); pstmt.setTimestamp(3,nowtime); //借阅日期 pstmt.setTimestamp(4,plusDay2(book.getTypeday())); //应还日期,sql设置时间戳 pstmt.setString(5,adminid); pstmt.setString(6,readerid); pstmt.setString(7,book.getBookid()); return pstmt.executeUpdate();}
    9.2.10 图书归还模块输入要归还的图书编号,点击归还按钮,即可归还图书。

    该界面实在主界面的基础上继承JInternalframe实现的主界面下的子界面,同样是通过windowbulider插件进行合理的布局完成的。
    public int returnbook(Connection con,Book book) throws SQLException{ String sql ="update 借阅记录 set 归还日期=? where 图书编号=? and 归还日期 is null;" + "delete from borrow_relationship where 图书编号=?"; PreparedStatement pstmt = (PreparedStatement) con.prepareStatement(sql); Timestamp nowtime =new java.sql.Timestamp(System.currentTimeMillis()); pstmt.setTimestamp(1,nowtime); //当前归还日期,sql设置时间戳 pstmt.setString(2,book.getBookid()); //加借阅日期限制不行 pstmt.setString(3,book.getBookid()); return pstmt.executeUpdate();}
    9.2.11 图书借阅信息搜索通过对借书证号的搜索(支持模糊查询),搜索想要查询的读者的借书记录,若搜索条件为空,则显示所有的读者的借阅记录。

    该界面实在主界面的基础上继承JInternalframe实现的主界面下的子界面,同样是通过windowbulider插件进行合理的布局完成的。
    public ResultSet list(Connection con,Reader reader,Book book,Readertype readertype)throws Exception{ StringBuffer sb = new StringBuffer("select * from bookborrow"); if(StringUtil.isNotEmpty(reader.getReadnumber())) { sb.append(" where 借书证号 like '%"+reader.getReadnumber()+"%'"); } PreparedStatement pst =con.prepareStatement(sb.toString()); return pst.executeQuery();}
    9.2.12 系统维护模块(只有超级管理员登录的界面才有)通过输入管理员的教职工号进行查询(可支持模糊查询),即可在下方表格显示查询的普通管理员信息,点击信息,将会显示在下方的文本域内,可供超级管理员修改删除普通管理员的信息。

    该界面实在主界面的基础上继承JInternalframe实现的主界面下的子界面,同样是通过windowbulider插件进行合理的布局完成的。
    public int update(Connection con,Admini admini)throws Exception{ String sql="" +"update admini set 姓名=?,性别=?,密码=?,联系电话=? where 教职工号=? and 账号=?"; PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sql); pstmt.setString(1, admini.getName()); pstmt.setString(2, admini.getSex()); pstmt.setString(3, admini.getPassword()); pstmt.setString(4, admini.getPhone()); pstmt.setString(5, admini.getTeanumber()); pstmt.setInt(6, admini.getAccnumber()); return pstmt.executeUpdate();}public int delete(Connection con ,Admini admini)throws Exception{ String sql="delete from admini where 教职工号=?"; PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sql); pstmt.setString(1, admini.getTeanumber()); return pstmt.executeUpdate();}public ResultSet list(Connection con,Admini admini)throws Exception{ StringBuffer sb = new StringBuffer("select * from admini where 账号<>666666 and 账号<>888888"); if(StringUtil.isNotEmpty(admini.getTeanumber())) { sb.append(" where 教职工号 like '%"+admini.getTeanumber()+"%'"); } PreparedStatement pst =con.prepareStatement(sb.toString()); return pst.executeQuery();}
    十、设计总结在设计的过程中我们先后遇到了数据库设计,JDBC数据可访问,Java图形用户界面实现,数据库实现借还书sql语句如何书写等一系列问题。
    我们解决数据库设计问题的方法是两人共同商量探讨,先给出数据库关系模型的1.0版本,在经过不断的推理论证,在结合实际的测试操作,不断更新迭代多次,最终形成健壮可靠的数据库关系模型。
    解决JDBC数据库访问的方法是先在本地sql server服务器上进行操作实验,后来发现组员南绍斌电脑上没有安装数据库,结合两个人连接一个数据库会很不方便,于是我想到了在我自己的云主机上架设数据库,这样就可以两个人同时使用云主机上的数据库,经过一系列操作结合网上的资料,这一大胆的设想变成了现实,从而解决了这个问题。
    在Java图形用户界面方面,由于我们之前都没有接触过,所以这方面显得很欠缺,于是我们广泛收集资料,找寻到了一些目前比较前沿并且很方便操作的技术windowbuilder插件制作GUI,我们于是从零开始学习如何使用该插件,一步一个脚印,最终成功解决了GUI的问题。
    最容易出现问题的还是JavaDAO中的SQL语句的问题,因为它需要的思维逻辑性很强,并且错误不容易被发现,我们只能一边用eclipse调试程序,一边用与主机上的数据库测试SQL语句,在不断的测试与改正之后,最终我们成功的解决了这个问题。
    通过做数据库课程设计,巩固了数据库和Java的知识,还在实践的过程当中学习到了许多课本上没有的知识,提高了我们的动手能力,和程序设计实现能力,以及团队协作配合的能力。
    4 评论 39 下载 2020-03-12 13:17:47 下载需要16点积分
  • 基于JAVA和SQL SERVER数据库实现的医院病房信息管理系统

    1 系统设计1.1 设计目标医院病房管理系统是一种以窗体界面为基础的多功能平台,本系统最根本的目的是让使用者与数据库能够通过系统达到交互,以此来进行医院病房的管理等相关操作。管理员可以通过该平台对医生、病人、科室、病房、病床进行增加、删除、修改、查询操作,普通用户可以通过该平台查看修改自己的个人信息、进行病人住院登记、查询病人和床位信息、根据病人的住院日期、出院日期和所住病房的收费标准进行出院结算,然后删除该病人的信息。本系统在全面提高医院的整体工作效率、为病人提供快捷的服务、为医生提供人性化的管理、减轻医院工作人员的负担等方面发挥着重要作用。
    1.2 需求分析信息要求:医生基本信息包括工作证号、密码、姓名、性别、职称、年龄、联系电话、所属科室,病人基本信息包括病历号、姓名、性别、诊断结果、病房号、病床号、主治医生工作证号、联系电话、入院日期、出院日期,科室基本信息包括科室名称、科室地址、科室电话,病房基本信息包括病房号、所属科室、收费标准,病床基本信息包括病房号、病床号、目前状态。
    处理要求:一名医生可以诊治多名病人,一名病人只能被一名医生诊治。一个病房可以住多名病人,一名病人只能住在一个病房。一个科室有多名医生,一个医生只属于一个科室。一个科室包含多个病房,一个病房只属于一个科室。一个病房拥有多张病床,一个病床只能位于一个科室。
    安全性与完整性要求:管理员和医生只有输入正确的工作证号和密码才能登录系统,如果还没有注册,先输入相关信息进行注册。对于管理员,管理主页列出了管理员所能实现的功能,包括对医生、病人、科室、病房、病床的增加、删除、修改、查询,管理员根据需要选择对应的项目。对于用户,即医生,管理主页列出了医生所能实现的功能,包括查看修改自己的个人信息、登记病人基本信息、查询病人和床位信息、根据病人的住院日期、出院日期和所住病房的收费标准进行出院结算,然后删除该病人的信息。为了保证系统的安全性,系统提供对工作证号和旧密码的验证,来修改登录密码。
    1.3 开发和运行环境选择
    开发工具:前台开发语言为Java编程语言
    后台数据库为SQL Server 2014
    运行环境:Windows 10

    2 数据库设计2.1 数据库概念设计根据需求分析,可以确定该系统中的实体、属性和联系之间的关系,并画出如下所示的E-R图。
    实体及属性如图2.1所示。

    病人实体及属性如图2.2所示。

    科室实体及属性如图2.3所示。

    病房实体及属性如图2.4所示。

    病床实体及属性如图2.5所示。

    由该项目的处理需求可知,“医生”和“病人”之间的“治疗”联系为1:n,即一名医生可以诊治多名病人,一名病人只能被一名医生诊治。“病房”和“病人”之间的“入住”联系为1:n,即一个病房可以住多名病人,一名病人只能住在一个病房。“科室”和“医生”之间的“属于”联系为1:n,即一个科室有多名医生,一个医生只属于一个科室。“科室”和“病房”之间的“包含”联系为1:n,即一个科室包含多个病房,一个病房只属于一个科室。“病房”和“病床”之间的“拥有”联系为1:n,即一个病房拥有多张病床,一个病床只能位于一个科室。系统的实体联系图,如图2.6所示。

    2.2 数据库逻辑结构设计2.2.1 关系模式根据转换规则和医院病房管理系统E-R图,可以得到医院病房管理系统的关系模式如下。
    医生(工作证号、密码、姓名、性别、职称、年龄、联系电话、所属科室)为医生实体对应的关系模式,其中工作证号是主码,科室的主码科室名称是医生的外码。
    病人(病历号、姓名、性别、诊断结果、病房号、病床号、主治医生工作证号、联系电话、入院日期、出院日期)为病人实体对应的关系模式,其中病历号是主码,医生的主码工作证号是病人的外码属性,病床的主码病房号、病床号是病人的外码属性。
    科室(科室名称、科室地址、科室电话)为科室实体对应的关系模式,其中科室名称是主码。
    病房(病房号、所属科室、收费标准)为病房实体对应的关系模式,其中病房号是主码,科室的主码科室名称是病房的外码。
    病床(病房号、病床号、目前状态)为病床实体对应的关系模式,其中病房号、病床号是主码。
    2.2.2 结构设计表医生结构设计表如表2.1所示。

    病人结构设计表如表2.2所示。

    科室结构设计表如表2.3所示。

    病房结构设计表如表2.4所示。

    病床结构设计表如表2.5所示。

    2.2.3 数据字典数据项描述如表2.3所示。

    数据结构描述如表2.4所示。

    3 医院病房管理系统详细设计3.1 系统功能医院病房管理系统主要分为用户模块和管理员模块(分为医生、病人、科室、病房、病床信息增删改查功能)。其中用户模块包括查看修改自己的个人信息、进行病人住院登记、查询病人和床位信息、根据病人的住院日期、出院日期和所住病房的收费标准进行出院结算,然后删除该病人的信息。管理员模块包括对医生、病人、科室、病房、病床进行增加、删除、修改、查询操作。
    3.2 数据库以及表的建立医院病房管理系统数据库中包含五张表,分别为医生(Doctor)、病人(Patient)、科室(Department)、病房(Ward)、病床(Bed),相关代码如下。
    CREATE TABLE Doctor (Dno CHAR(10) PRIMARY KEY, Dpassword VARCHAR(15) NOT NULL, Dname CHAR(20) NOT NULL, Dsex CHAR(2) NOT NULL, Dtitle CHAR(10) NOT NULL, Dage SMALLINT NOT NULL, Dtel CHAR(11) NOT NULL, Deptname CHAR(20) NOT NULL, FOREIGN KEY(Deptname) REFERENCES Department(Deptname) );CREATE TABLE Department (Deptname CHAR(20) PRIMARY KEY, Deptaddress CHAR(20) NOT NULL, Depttel CHAR(11) NOT NULL );CREATE TABLE Ward (Wno CHAR(9) PRIMARY KEY, Deptname CHAR(20) NOT NULL, Wcharge INT NOT NULL, FOREIGN KEY(Deptname) REFERENCES Department(Deptname) );CREATE TABLE Bed (Wno CHAR(9), Bno CHAR(9), Bstate CHAR(20) , PRIMARY KEY(Wno,Bno), FOREIGN KEY(Wno) REFERENCES Ward(Wno) );CREATE TABLE Patient (Pno CHAR(10) PRIMARY KEY, Pname CHAR(20) NOT NULL, Psex CHAR(2) NOT NULL, Pdiagnose CHAR(20) NOT NULL, Wno CHAR(9) NOT NULL, Bno CHAR(9) NOT NULL, Dno CHAR(10) NOT NULL, Ptel CHAR(11) NOT NULL, Pindate DATE NOT NULL, Poutdate DATE , FOREIGN KEY(Wno,Bno) REFERENCES Bed(Wno,Bno), FOREIGN KEY(Dno) REFERENCES Doctor(Dno) );
    3.3 连接数据库连接数据库的代码及设置和连接操作的相关代码如下。
    package linkdatabase;package linkdatabase;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;public class linkdatabase { static Connection connection; public linkdatabase(){ //数据库驱动 String driverName="com.microsoft.sqlserver.jdbc.SQLServerDriver"; //连接的数据库 String url="jdbc:sqlserver://localhost:1433;DatabaseName=HWMS"; String user="sa"; String password="yyl13593519418"; //加载JDBC-MySQL数据库驱动 try { Class.forName(driverName); connection = (Connection) DriverManager.getConnection(url,user,password); System.out.println("数据库连接成功"); } catch(Exception e) { e.printStackTrace(); System.out.println("数据库连接失败:"+e.getMessage()); } } public static Connection getConnection(){ new linkdatabase(); return connection; } public void setConnection(Connection connection){ this.connection = connection; } public static void closeAll(ResultSet rs,PreparedStatement ps,Connection con){ if(rs != null){ try{ rs.close(); }catch(SQLException e){ e.printStackTrace(); } } if(ps != null){ try{ ps.close(); }catch(SQLException e) { e.printStackTrace(); } } if(con != null){ try{ con.close(); }catch(SQLException e){ e.printStackTrace(); } } }}
    3.4 登录系统登录系统为进入系统的首要操作,相关代码如下。
    package Hospitallogin;import java.awt.Button;import java.awt.Color;import java.awt.Cursor;import java.awt.Font;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import javax.swing.ImageIcon;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JOptionPane;import javax.swing.JPanel;import javax.swing.JTextField;import Doctorfunction.Main;import Hospitaladmin.admin_frame;import Hospitalresponse.Alter;import Hospitalresponse.Register;import geng.handle.HandleLogin;import geng.model.Login;import linkdatabase.linkdatabase;public class LoginFrame extends JFrame implements ActionListener{ String sql; Login login = new Login(); HandleLogin handleLogin = new HandleLogin(); JLabel l1 = new JLabel("欢迎登陆医院病房管理系统"); JLabel l2 = new JLabel("账号:"); JLabel l3 = new JLabel("密码:"); JLabel l4 = new JLabel("账号不存在!"); JLabel l5 = new JLabel("<HTML><U>"+"注册账号"+"</U></HTML>"); JLabel l6 = new JLabel("<HTML><U>"+"修改密码"+"</U></HTML>"); JTextField t1 = new JTextField(); JTextField t2 = new JTextField(); Button b1 = new Button("登陆"); Button b2 = new Button("取消"); public LoginFrame() { // TODO Auto-generated constructor stub //设置标题 super("欢迎登陆医院病房管理系统");//创建标题为欢迎登陆医院病房管理系统的窗口 setBounds(300,100,910,500);//设置窗口在屏幕上的位置及大小 String path = "lib/login.jpeg"; ImageIcon backgroundimage=new ImageIcon(path);//使标签有图片,用此创建背景图片 JLabel jLabel = new JLabel(backgroundimage);//标签为用户提示信息 jLabel.setBounds(0, 0, this.getWidth(), this.getHeight());//标签在窗口上的位置及大小 JPanel jPanel1 = (JPanel) this.getContentPane();//初始化一个内容面板,这样才可以把内容面板设置成透明的 jPanel1下面是我们要添加的图片,上面是我们的组件 jPanel1.setOpaque(false);//使组件不会显示其中的某些像素,允许组件下面的像素显现出来,即设置透明 jPanel1.setLayout(null); this.getLayeredPane().add(jLabel,new Integer(Integer.MIN_VALUE)); setVisible(true); // 登陆界面配置 l1.setBounds(450, 70, 450, 35); l1.setFont(new Font("宋体", Font.BOLD, 30)); l2.setBounds(470, 140, 70, 25); l2.setFont(new Font("宋体",Font.BOLD,23)); l3.setBounds(470, 200, 70, 25); l3.setFont(new Font("宋体",Font.BOLD,23)); l4.setBounds(120, 200, 150, 20); l4.setFont(new Font("宋体",Font.BOLD,23)); l5.setBounds(730,140,70,25); l5.setFont(new Font("微软雅黑",Font.BOLD,15)); l5.setForeground(Color.blue); l5.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); l5.addMouseListener(new Register()); l6.setBounds(730,200,70,25); l6.setFont(new Font("微软雅黑",Font.BOLD,15)); l6.setForeground(Color.blue); l6.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); l6.addMouseListener(new Alter()); t1.setBounds(540, 140, 160, 25); t1.setFont(new Font("宋体",0,18)); t2.setBounds(540, 200, 160, 25); t2.setFont(new Font("宋体",0,18)); b1.setBounds(540, 260, 70, 30); b1.setFont(new Font("宋体",0,15)); b1.addActionListener(this); b2.setBounds(660, 260, 70, 30); b2.setFont(new Font("宋体",0,15)); b2.addActionListener(this); super.add(l1); super.add(l2); super.add(l3); super.add(l5); super.add(l6); super.add(t1); super.add(t2); super.add(b1); super.add(b2); super.setLayout(null); super.setVisible(true); //当单击窗口右上方的关闭图标时,监视器调用windowClosing方法,如果在该方法中使用System.exit(0)退出程序的运行 super.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { // TODO Auto-generated method stub super.windowClosing(e); System.exit(0); } }); super.setResizable(false); } public static void main(String[] args) { // TODO Auto-generated method stub new LoginFrame(); } @Override //事件源触发ActionEvent事件后,监视器调用接口中的此方法对发生的事件做出处理 public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub Object source = e.getSource();//返回添加事件监听的对象 Connection con = null; PreparedStatement ps = null; ResultSet rs = null; if(source == b1) { String name = t1.getText(); String pass = t2.getText(); Login login = new Login(); login.setDno(name); try { con = linkdatabase.getConnection(); if("".equals(name.trim()) || "".equals(pass.trim())) { JOptionPane.showMessageDialog(null, "请输入完整的登陆信息!","系统提示",JOptionPane.ERROR_MESSAGE); }else if(name.equals("admin") && pass.equals("123456")) { new admin_frame(); super.dispose(); }else { login.setDno(name); login.setDpassword(pass); login = handleLogin.queryVerify(login); if(login.getLoginSuccess() == true) { System.out.println("登录成功了!"); new Main(login); super.dispose(); }else { System.out.println("登录失败了!"); JOptionPane.showMessageDialog(null, "登录失败,请重新登录","系统提示",JOptionPane.WARNING_MESSAGE); } } } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); }finally { linkdatabase.closeAll(rs, ps, con); } } if(source == b2) { System.exit(0); } }}
    4 系统测试以及界面4.1 订书单位信息查询测试测试注册账号,界面如图4.1所示。

    注册账号成功,结果如图4.2所示。

    4.2 病人出院结算测试进入病人出院结算界面,点击查询与结算,得出病人出院费用,结果如图4.3所示。

    结算出院成功,结果如图4.4所示。

    5 总结在本次数据库课程设计中,我设计开发了一个小型的医院病房管理系统,实现了对病人的住院登记、出院结算、信息查询,对医生信息、病人信息、科室信息、病房信息、病床信息的增加、删除、修改、查询的功能。设计过程中曾经遇到了不少难点和问题,如:将界面和后台数据库连接起来时出错;对数据库中信息操作时有时忽略了参照完整性;病人出院结算时无法调用数据库中存储的信息;页面间参数传递实现不了;还出现了一个语法错误,对一些控件的属性及方法不熟悉等。对于上述这些难点,我花了很多时间去解决,查阅数据库教材和理论课的课件、并借来相关书籍辅助学习,注意数据库中各个所建表的主外键约束,上网搜索也让我学到很多知识,还有些问题是与同学之间的相互讨论,最终将难点一一克服。
    13 评论 416 下载 2018-11-06 15:43:53 下载需要16点积分
  • 基于深度学习的图像识别

    介 绍随着计算机理论、技术和应用的快速发展,视频图像处理和计算能力得到了极大的提高,使得计算机视觉成为了计算机领域与人工智能领域中最热门的研究课题之一。计算机视觉(CV),通俗地说,是一门研究如何使机器“看”的科学,更进一步的说,是指用摄影机和电脑代替人眼对目标进行识别、跟踪和测量等机器视觉,并进一步做图形处理,使电脑处理成为更适合人眼观察或传送给仪器检测的图像。
    本小组研究的课题是基于深度学习的图像识别,最终实现的是对海量图片数据的学习和准确的识别,不仅如此,我们测试了几种不同的分类模型,并比较预测结果,计算预测准确率,对预测方法进行优化,希望得到一种最高效的预测方法,从而实现真正的机器智能化识别。
    本小组课设主要基于python开发环境下的scikit-learn标准库以及PIL图像处理库,并采用matplotlib实现最终结果的比对,PIL库用于图像的特征值批量读取,scikit-learn标准库用于分类模型的构建,matplotlib则用于显示最终结果。
    这是这两个基本库的homepage以及参考网页:

    PIL

    http://www.pythonware.com/products/pil/http://blog.csdn.net/u013467442/article/details/41827085http://blog.csdn.net/passball/article/details/5204132
    scikit-learn

    http://scikit-learn.org/stable/index.html

    下面是本小组的方案流程以及说明:

    1 图像特征向量的提取特征提取是计算机视觉和图像处理中的一个概念。它指的是使用计算机提取图像信息,决定每个图像的点是否属于一个图像特征。特征提取的结果是把图像上的点分为不同的子集,这些子集往往属于孤立的点、连续的曲线或者连续的区域。
    特征的精确定义往往由问题或者应用类型决定。特征是一个数字图像中“有趣”的部分,它是许多计算机图像分析算法的起点。因此一个算法是否成功往往由它使用和定义的特征决定。因此特征提取最重要的一个特性是“可重复性”:同一场景的不同图像所提取的特征应该是相同的。
    常用的特征提取方法有方向梯度直方图(Histogram of Oriented Gradient, HOG)特征,主要思想是在一副图像中,局部目标的表象和形状(appearance and shape)能够被梯度或边缘的方向密度分布很好地描述;LBP(Local Binary Pattern,局部二值模式)特征,一种用来描述图像局部纹理特征的算子;Haar-like特征,最早由Papageorgiou等应用于人脸表示。
    我们采用HOG方法进行图像特征的提取,特别的,HOG+SVM方法进行图像识别已经被广泛用于图像识别领域中。
    通过调用PIL库中的Image模块可以实现上述功能。

    img = Image.open(j)

    j为图片所在路径,采用open方法描述图片。进行灰度化:

    Gray = (R^2.2 0.2973 + G^2.2 0.6274 + B^2.2 * 0.0753)^(1/2.2)

    通过相关算法对图片的特征进行处理,最终可得到想要的特征向量。此外,需要保存每张图像对应的目标值以及图像的三原色信息。(详细的容器说明见代码)
    2 训练集、测试集的分离调用sklearn中的train_test_split方法:

    self.x_train0, self.x_test0, self.y_train0, self.y_test0 = train_test_split(self.pic_data_gray, self.target, test_size=0.25, random_state=42)

    3 图像主成分的析取及灰度化通过第一步图片的特征向量提取,我们得到一组特征向量的列表集,但由于特征向量的维度过高,一来提高了计算的复杂度,占用内存资源,不利于大规模开发,二来特征描述过分详细,相关性不大的维度会对分类器的分类造成负面影响,所以接下来对图片的特征向量进行降维处理。
    这里采用PCA(Principal Component Analysis)降维方法,PCA又称主成分分析法,是一种常用的数据分析方法。PCA通过线性变换将原始数据变换为一组各维度线性无关的表示,可用于提取数据的主要特征分量,常用于高维数据的降维。
    对于一个k维的特征来说,相当于它的每一维特征与其他维都是正交的(相当于在多维坐标系中,坐标轴都是垂直的),那么我们可以变化这些维的坐标系,从而使这个特征在某些维上方差大,而在某些维上方差很小。例如,一个45度倾斜的椭圆,在第一坐标系,如果按照x,y坐标来投影,这些点的x和y的属性很难用于区分他们,因为他们在x,y轴上坐标变化的方差都差不多,我们无法根据这个点的某个x属性来判断这个点是哪个,而如果将坐标轴旋转,以椭圆长轴为x轴,则椭圆在长轴上的分布比较长,方差大,而在短轴上的分布短,方差小,所以可以考虑只保留这些点的长轴属性,来区分椭圆上的点,这样,区分性比x,y轴的方法要好!
    所以我们的做法就是求得一个k维特征的投影矩阵,这个投影矩阵可以将特征从高维降到低维。投影矩阵也可以叫做变换矩阵。新的低维特征必须每个维都正交,特征向量都是正交的。通过求样本矩阵的协方差矩阵,然后求出协方差矩阵的特征向量,这些特征向量就可以构成这个投影矩阵了。特征向量的选择取决于协方差矩阵的特征值的大小。
    举一个例子:
    对于一个训练集,100个对象模板,特征是10维,那么它可以建立一个100*10的矩阵,作为样本。求这个样本的协方差矩阵,得到一个10*10的协方差矩阵,然后求出这个协方差矩阵的特征值和特征向量,应该有10个特征值和特征向量,我们根据特征值的大小,取前四个特征值所对应的特征向量,构成一个10*4的矩阵,这个矩阵就是我们要求的特征矩阵,100*10的样本矩阵乘以这个10*4的特征矩阵,就得到了一个100*4的新的降维之后的样本矩阵,每个特征的维数下降了。
    总结一下PCA的算法步骤:
    设有m条n维数据。

    将原始数据按列组成n行m列矩阵X
    将X的每一行(代表一个属性字段)进行零均值化,即减去这一行的均值
    求出协方差矩阵
    求出协方差矩阵的特征值及对应的特征向量
    将特征向量按对应特征值大小从上到下按行排列成矩阵,取前k行组成矩阵P
    即为降维到k维后的数据

    具体的原理:

    http://blog.csdn.net/xiaojidan2011/article/details/11595869
    http://www.cnblogs.com/549294286/archive/2013/11/11/3417702.html

    算法实现为:

    pca = PCA(n_components = n_components, svd_solver=’auto’,whiten=True).fit(self.x_train0)x_train_pca = pca.transform(self.x_train0)

    4 分类器的构造与训练学习这是整个课设的核心部分,即构造建模合理的分类器。我们采用支持向量机(Support Vector Machine)进行分类。

    SVM是Cortes和Vapnik于1995年首先提出的,它在解决小样本、非线性及高维模式识别中表现出许多特有的优势,并能够推广应用到函数拟合等其他机器学习问题中。
    机器学习本质上就是一种对问题真实模型的逼近(我们选择一个我们认为比较好的近似模型,这个近似模型就叫做一个假设),但毫无疑问,真实模型一定是不知道的(如果知道了,我们干吗还要机器学习?直接用真实模型解决问题不就可以了?对吧,哈哈)既然真实模型不知道,那么我们选择的假设与问题真实解之间究竟有多大差距,我们就没法得知。比如说我们认为宇宙诞生于150亿年前的一场大爆炸,这个假设能够描述很多我们观察到的现象,但它与真实的宇宙模型之间还相差多少?谁也说不清,因为我们压根就不知道真实的宇宙模型到底是什么。
    这个与问题真实解之间的误差,就叫做风险(更严格的说,误差的累积叫做风险)。我们选择了一个假设之后(更直观点说,我们得到了一个分类器以后),真实误差无从得知,但我们可以用某些可以掌握的量来逼近它。最直观的想法就是使用分类器在样本数据上的分类的结果与真实结果(因为样本是已经标注过的数据,是准确的数据)之间的差值来表示。这个差值叫做经验风险Remp(w)。以前的机器学习方法都把经验风险最小化作为努力的目标,但后来发现很多分类函数能够在样本集上轻易达到100%的正确率,在真实分类时却一塌糊涂(即所谓的推广能力差,或泛化能力差)。此时的情况便是选择了一个足够复杂的分类函数(它的VC维很高),能够精确的记住每一个样本,但对样本之外的数据一律分类错误。回头看看经验风险最小化原则我们就会发现,此原则适用的大前提是经验风险要确实能够逼近真实风险才行(行话叫一致),但实际上能逼近么?答案是不能,因为样本数相对于现实世界要分类的文本数来说简直九牛一毛,经验风险最小化原则只在这占很小比例的样本上做到没有误差,当然不能保证在更大比例的真实文本上也没有误差。
    统计学习因此而引入了泛化误差界的概念,就是指真实风险应该由两部分内容刻画,一是经验风险,代表了分类器在给定样本上的误差;二是置信风险,代表了我们在多大程度上可以信任分类器在未知文本上分类的结果。很显然,第二部分是没有办法精确计算的,因此只能给出一个估计的区间,也使得整个误差只能计算上界,而无法计算准确的值(所以叫做泛化误差界,而不叫泛化误差)。
    置信风险与两个量有关,一是样本数量,显然给定的样本数量越大,我们的学习结果越有可能正确,此时置信风险越小;二是分类函数的VC维,显然VC维越大,推广能力越差,置信风险会变大。泛化误差界的公式为:

    R(w)≤Remp(w)+Ф(n/h)

    公式中R(w)就是真实风险,Remp(w)就是经验风险,Ф(n/h)就是置信风险。统计学习的目标从经验风险最小化变为了寻求经验风险与置信风险的和最小,即结构风险最小。
    SVM正是这样一种努力最小化结构风险的算法。
    下面举例简述基本原理:
    首先是线性SVM向量机,如图所示二维平面有两类点,我们要做的便是找到一条分类线将整个平面分为两部分,一部分属于蓝色五角星,一部分属于红色点,如过新加入的点落在五角星一侧便判定他为五角星类。

    这些分类线可能有很多,现需要找到最优的分类线。

    通俗地理解,只需要使得如图所示的Gap达到最大即可。同样的方法适用于多维多类的问题,此时分类线即分类超平面。

    设w为这个超平面的法向量,中间具体的数学推导过程不再详述,总之我们要实现的优化是:

    yI为正确的分类结果,xi为特征向量。一个更简单的例子,要对苹果和香蕉进行分类:


    SVM支持向量机则引入了非线性的神经网络,从而更好地解决非线性问题:
    我们将使用一种叫做核函数(kernel)的工具,将数据从一个空间转换到另一个空间,使其变成易于分类器理解的形式。但要确保核函数可以很快速的进行计算,否则影响效率。
    常用的核函数有:

    多项式核函数(Polynomial Kernel),其形式如下:
    Kernel(X,X′)=(ξ+γXTX′)Q
    径向基函数(Radial Basis Function,RBF),其形式如下:
    Kernel(X,X′)=e(−||X−X′||22σ2)上述高斯核函数将数据从特征空间映射到更高维的空间,具体来说这里是映射到一个无穷维的空间。
    将核函数(kernel)引入到 SVM 中也就是替换 SVM 中的 XTY 为 Kernel(X,Y),也就是将第3部份第2步的二次规划规划问题中的 XTX 为 Kernel(X,X),例如二次项核函数的 (1+XT∗X)2,将
    b=ys−wTxs=ys−(∑Nn=1αnynxn)xs替换为:
    b=ys−∑Nn=1αnynKernel(xn,xs)其中 s 表示某个支持向量。
    最后,将:
    gsvm(x)=sign(wTx+b)=sign((∑Nn=1αnynxn)x+b)替换为:
    gsvm(x)=sign(∑Nn=1αnynKernel(xn,x)+b)之后进行神经网络的建模,其中K(x1,x)为上述核函数:

    详见:

    http://blog.csdn.net/passball/article/details/7661887/
    http://blog.csdn.net/macyang/article/details/38782399/
    https://www.zhihu.com/question/21094489

    5 预测测试图片集,分析结果首先,对预测结果,采用matplotlib简单地绘制了预测结果和真实图片的比较:

    这里比较了12组预测结果,其中只有第7组预测有误,其他均预测正确!下面是程序在沙盒下的运行结果:

    Python 3.5.3 (v3.5.3:1880cb95a742, Jan 16 2017, 16:02:32) [MSC v.1900 64 bit (AMD64)] on win32Type “copyright”, “credits” or “license()” for more information.


    ====== RESTART: C:\Users\76947\Desktop\machine learning\plot_gallary.py ======正在采集图像数据…图片信息采集完毕!花费了9.126秒总数据库的规模如下:样本数: 1110特征数: 80000分类数: 5正在进行降维处理…完成!花费了 28.129秒数据分类降维完毕!正在进行训练…完成,共计 8.308秒最优分类向量机找到:SVC(C=1000.0, cache_size=200, class_weight=’balanced’, coef0=0.0, decision_function_shape=None, degree=3, gamma=0.1, kernel=’rbf’, max_iter=-1, probability=False, random_state=None, shrinking=True, tol=0.001, verbose=False)正在预测图片…完成预测,共计 0.016秒预测结果如下:precision recall f1-score supportairplanes 0.93 0.99 0.95 213brain 0.77 0.81 0.79 21chair 0.18 0.20 0.19 10dolphin 0.80 0.42 0.55 19sunflower 0.75 0.40 0.52 15avg / total 0.87 0.87 0.86 278[[210 1 1 1 0] [ 2 17 2 0 0] [ 7 0 2 0 1] [ 4 1 5 8 1] [ 4 3 1 1 6]]预测的准确率为: 0.8741007194244604{‘target:’: ‘brain’, ‘predict:’: ‘brain’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘dolphin’, ‘predict:’: ‘brain’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘brain’, ‘predict:’: ‘brain’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘dolphin’, ‘predict:’: ‘chair’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘sunflower’, ‘predict:’: ‘brain’}{‘target:’: ‘dolphin’, ‘predict:’: ‘airplanes’}{‘target:’: ‘dolphin’, ‘predict:’: ‘sunflower’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘dolphin’, ‘predict:’: ‘airplanes’}{‘target:’: ‘brain’, ‘predict:’: ‘brain’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘brain’, ‘predict:’: ‘brain’}{‘target:’: ‘brain’, ‘predict:’: ‘brain’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘brain’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘sunflower’, ‘predict:’: ‘sunflower’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘sunflower’, ‘predict:’: ‘sunflower’}{‘target:’: ‘dolphin’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘chair’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘dolphin’, ‘predict:’: ‘dolphin’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘sunflower’, ‘predict:’: ‘sunflower’}{‘target:’: ‘airplanes’, ‘predict:’: ‘chair’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘brain’, ‘predict:’: ‘brain’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘brain’, ‘predict:’: ‘brain’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘dolphin’, ‘predict:’: ‘dolphin’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘chair’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘chair’, ‘predict:’: ‘sunflower’}{‘target:’: ‘dolphin’, ‘predict:’: ‘chair’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘sunflower’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘brain’, ‘predict:’: ‘brain’}



    预测准确率有可观的0.8741007194244604,对飞机的预测更是达到了0.93的准确率,这里的预测准确度和学习的样本数有关,如果样本数足够多,相信我们会得到更可观的结果。下面是采用不同核函数的预测准确率比较:

    可以看到采用rbf径向基函数可达到很高的预测准确度。
    3 评论 42 下载 2019-03-04 10:48:16 下载需要15点积分
显示 30 到 45 ,共 15 条
eject