分类

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

资源列表

  • 基于C语言实现的超市管理系统

    1 需求分析超市随着市场经济和现代信息技术的的发展,不可必要的要卷入信息现代化的大潮,如何使用现代化的工具,使企业和经营者个人在最小的投入下获取最大的回报,成为每一个人的梦想。因此,在超市管理中引进现代化的办公软件,就成为时下最好的解决办法。使用软件办公,不仅能使经营者的劳力资本减少,同时能使超市的管理更规范更合理,解决了超市中用于管理进出货以及购买、库存等众多繁琐、工作量巨大从而导致耗费人员过多,超市经营紊乱等众多问题。
    1.1 主要功能
    超级管理员模块:(需帐号登录)

    添加管理员删除管理员
    管理员模块:(需帐号登录)

    商品信息录入(编号、名称、单价、库存)商品信息修改(修改商品的各种信息)商品信息查询(根据所输入的商品名字,编码查询库存信息)商品信息删除(从商品文件中删除商品信息)商品信息排序(按编号,单价,库存3种模式进行排序)输出商品全部库存信息删除普通用户功能(管理员有权限删除普通用户帐号)
    普通用户模块:(需帐号登录)

    新用户注册用户登录:
    商品查询商品排序输出商品全部库存信息购买商品(通过用户余额来进行购买)充值(通过输入充值卡卡号对用户余额充值)修改用户密码


    1.2 运行环境
    操作系统:Windows NT/2000/XP/VISTA/WIN7/WIN8/WIN10
    开发平台:Microsoft Visual Studio 2012

    1.3 文件说明
    程序源代码(超市管理系统.cpp)
    程序运行文件(超市管理系统.exe)
    管理员信息(管理员信息.txt)
    普通用户信息(普通用户信息.txt)
    商品信息(商品信息.txt)

    2 总体方案设计2.1 设计方案整个超市管理系统分为3个模块,超级管理员+管理员+普通用户,其中:

    管理员可以实现商品信息的录入,修改,查询等管理操作,同时还拥有对普通用户帐号的管理
    超级管理员是最高执行者,拥有对管理员帐号的操作权限,可以对管理员帐号进行添加或删除
    普通用户模块,由于考虑到该程序的真实性,所以实现了普通用户的注册和登录功能,用户要进行购物,必须使用帐号(可自行注册,无须经过管理员),其中普通用户具有商品查询等一部分功能。特色功能是具有帐号余额功能,同时购物可以进行充值功能(输入充值卡卡号,类似于购买充值卡来充值)

    2.2 主要结构
    超级管理员模块:(需帐号登录)

    添加管理员删除管理员
    管理员模块:(需帐号登录)

    商品信息录入(编号、名称、单价、库存)商品信息修改(修改商品的各种信息)商品信息查询(根据所输入的商品名字,编码查询库存信息)商品信息删除(从商品文件中删除商品信息)商品信息排序(按编号,单价,库存3种模式进行排序)输出商品全部库存信息删除普通用户功能(管理员有权限删除普通用户帐号)
    普通用户模块:(需帐号登录)

    新用户注册用户登录:
    商品查询商品排序输出商品全部库存信息购买商品(通过用户余额来进行购买)充值(通过输入充值卡卡号对用户余额充值)修改用户密码


    2.3 程序功能和流程图由于本程序模块功能较多,有超级管理员,管理员和普通用户,共3个模式的功能,流程图较大,因此分为3个子图。
    超级管理员模块

    管理员模块

    普通用户模块

    2.4 数据结构和算法的设计说明本程序有3个数据结构:管理员,普通用户,商品共3个结构体。其中程序拥有超级管理员、管理员和普通用户共3种身份,运用链表来存储和读取所保存的信息。
    2.4.1 结构体类型一开始选择模块,输入帐号和密码,进行验证,是否正确。正确就进入功能模块。
    typedef struct custom* cpointer;//结点指针类型struct custom{ string custom_ID;//帐号 string custom_name;//姓名 string custom_mima;//密码 double money;//账户余额 cpointer next;};typedef cpointer clklist;//单链表类型,即头指针类型
    其中,管理员、普通用户、商品都是定义结构体,而后进入系统,一开始便定义相对应的链表进行存储和获取已保存的信息。
    2.4.2 算法设计排序算法
    for(int i=0;i<Goodnum;i++){ for(int j=Goodnum;j>=i+1;j--){ if(Go.Good[j].Good_ID<Go.Good[j-1].Good_ID) {//比较编号大小,小的在前面,大的在后面 flag=1; p=Go.Good[j]; Go.Good[j]=Go.Good[j-1]; Go.Good[j-1]=p; } }
    通过对相邻2个商品的编号不断比较,排序,运用2个for循环,比较编号大小,小的在前面,大的在后面。不断变换,最终排序完成。
    2.5 程序关键源代码说明程序中拥有3个身份:超级管理员,管理员,普通用户。不同身份之间函数都差不多,因此将函数直接展示,不说明为哪个身份的权限功能。
    custom_ender函数:登录验证函数。对输入的帐号和密码进行验证检索,正确就进入对应的身份模块。先定义一个普通用户结构体类型cpointer对象p,把包含普通用户全部信息的单链表head赋值给p,而后对p进行检索,如果p链表中的用户信息与输入的用户信息(帐号+密码)相同,就返回1;不同就显示“用户帐号不存在”,同时返回0。
    int custom_ender(clklist &head,string ID,string mima){ cpointer p; p=head; while(p!=NULL) { if(p->custom_ID==ID&&p->custom_mima==mima) return 1; else p=p->next; } cout<<"用户帐号不存在!"<<endl; return 0;}
    custom_creat函数:注册函数。先定义一个普通用户结构体类型cpointer对象p,把包含普通用户全部信息的单链表head赋值给p,而后输入注册用户的各种信息(帐号,密码,姓名),如果输入的帐号ID与已保存的用户帐号相同,就显示已存在,提示重新输入。最后将输入的新注册用户信息运用头插法插入,保存到”普通用户信息.txt”文件中保存
    void custom_creat(clklist &head){ cpointer s,p; string ID,name,mima; int sign=1,flat=1; while(sign!=0){ flat=1; cout<<"请输入用户帐号"<<endl; cin>>ID; p=head->next; while(p!=NULL){ if(p->custom_ID==ID) flat=0; p=p->next; } if(flat==0) { cout<<"用户帐号已存在,请重新输入"<<endl; continue; } cout<<"请输入用户密码"<<endl; cin>>mima; cout<<"请输入用户姓名"<<endl; cin>>name; s=new custom; s->custom_ID=ID; s->custom_name=name; s->custom_mima=mima; s->money=0; s->next=head->next;//使用头插法建表 head->next=s; buyernum++;//输入一个用户信息,buyernum自加1 custom_save(head); cout<<"是否继续注册?<继续>请按1 <结束>请按0"<<endl; cin>>sign;//while循环判断条件,所以不需要用if }}
    custom_get函数:从文件获取用户信息函数。先定义一个普通用户结构体类型cpointer对象p,把包含普通用户全部信息的单链表head赋值给p, 而后运用一个for循环,将用户信息从“普通用户信息.txt“全部导入到p链表中,返回给系统。
    clklist custom_get(clklist &buyer){ cpointer s,p;//s用于存储用户信息,p用于buyer的连接 string numname; string ID,name,mima; double money; buyer->next=NULL; p=buyer; ifstream ifile("C:\\普通用户信息.txt",ios::in); if(!ifile){ cerr<<"用户信息查询出错"<<endl;return 0; } ifile>>numname; ifile>>buyernum;//从文件中提取用户个数,用于for循环 for(int i=1;i<=buyernum;i++){ ifile>>ID; ifile>>name; ifile>>mima; ifile>>money; s=new custom; s->custom_ID=ID; s->custom_name=name; s->custom_mima=mima; s->money=money; s->next=p->next; p->next=s; } buyer=p; ifile.close(); return buyer;}
    Good_add函数:商品信息录入函数。把包含商品信息的链表Goods传入该函数,输入商品编号,if(Good_ender1(Goods,ID)==0)进行检索是否商品已存在,存在就提示重新输入,不存在就继续录入商品信息,导入到Goods链表中,最后运用Good_save(Goods)保存全部信息到“商品信息.txt”文件中。
    void Good_add(sqlist &Goods){ string ID,name; double piece; int last,sign,flat=1;//last为商品库存,sign用于判断选择 fstream ifile("C:\\商品信息.txt",ios::in); for(;flat!=0;) { cout<<"请输入商品编号:"; cin>>ID; if(Good_ender1(Goods,ID)==0) { cout<<"请输入商品名称:"; cin>>name; if(Good_ender2(Goods,name)==0) { cout<<"请输入商品单价:"; cin>>piece; cout<<"请输入商品数量:"; cin>>last; Goods.Good[Goodnum].Good_ID=ID; Goods.Good[Goodnum].Good_name=name; Goods.Good[Goodnum].piece=piece; Goods.Good[Goodnum].last=last; Goodnum++;//添加完信息就自加1 Good_save(Goods);//添加完就保存至商品信息.txt cout<<"是否继续录入?<继续>请按1 <结束>请按0"<<endl; cin>>sign; if(sign==0) break; } else {cout<<"商品名称已存在!<重新输入>请按1 <结束>请按0"<<endl; cin>>flat;} } else {cout<<"商品编号已存在!<重新输入>请按1 <结束>请按0"<<endl; cin>>flat;} }}
    Good_change函数:商品信息修改函数。把包含商品信息的链表Goods传入该函数,考虑到用户可能只记得商品编号或者商品名称,因此编写了2种修改模式(按编号检索修改,还是按名称检索修改)。如果选择按编号检索修改,同样对编号进行检索,如果在Goods链表中找到该商品编号,就运用 sign=Good_locate1(Goods,ID);定位记录下该商品在文件中的位置,而后输入修改后的商品信息,保存至文件中;按名称检索修改类似。最后修改完后,会提示是否继续修改,如果不继续就返回用户功能界面,执行其他功能。
    void Good_change(sqlist &Goods){ string ID,name; int sign;//sign用于定位要修改商品的位置 int a,flat=1;//a用于switch for(;flat!=0;){ cout<<"<输入要修改的商品编号>请按1 <输入要修改的商品名称>请按2"<<endl; cin>>a; if(a!=1&&a!=2) {cout<<"选择有误,请重新输入"<<endl;continue;} switch(a){ case 1: { cout<<"请输入商品编号:"; cin>>ID; if(Good_ender1(Goods,ID)==1) { sign=Good_locate1(Goods,ID); cout<<"商品编号:"<<Goods.Good[sign].Good_ID<<endl; cout<<"商品名称:"<<Goods.Good[sign].Good_name<<endl; cout<<"商品单价:"<<Goods.Good[sign].piece<<endl; cout<<"商品库存:"<<Goods.Good[sign].last<<endl; cout<<"请输入修改后的信息:"<<endl; cout<<"商品编号:"; cin>>Goods.Good[sign].Good_ID; cout<<"商品名称:"; cin>>Goods.Good[sign].Good_name; cout<<"商品单价:"; cin>>Goods.Good[sign].piece; cout<<"商品库存:"; cin>>Goods.Good[sign].last; Good_save(Goods);//保存信息 cout<<"修改成功"<<endl; } else cout<<"商品不存在!"<<endl; break; } case 2: 大致与编号模式相同 else cout<<"商品不存在!"<<endl; break; } }//switch的 cout<<"<继续修改>请按1 <退出>请按0"<<endl; cin>>flat; }//for循环的}
    Good_inquire函数:商品信息查询函数。把包含商品信息的链表Goods传入该函数,考虑到用户可能只记得商品编号或者商品名称,因此编写了2种查询方式(按编号检索查询,还是按名称检索查询)。如果选择按编号检索查询,同样对编号进行检索,如果在Goods链表中找到该商品编号,就运用 sign=Good_locate1(Goods,ID);定位记录下该商品在文件中的位置,而后输出该商品信息的全部信息;按名称检索查询类似。最后查询完后,会提示是否继续查询,如果不继续就返回用户功能界面,执行其他功能。
    void Good_inquire(sqlist &Goods){ string ID,name; int a,sign,flat=1; for(;flat!=0;){ cout<<"<按商品编号查询>请按1 <按商品名称查询>请按2"<<endl; cin>>a; if(a!=1&&a!=2) {cout<<"选择有误,请重新输入"<<endl;continue;} switch(a){ case 1: { cout<<"请输入商品编号:"; cin>>ID; if(Good_ender1(Goods,ID)==1) { sign=Good_locate1(Goods,ID); cout<<"商品编号:"<<Goods.Good[sign].Good_ID<<endl; cout<<"商品名称:"<<Goods.Good[sign].Good_name<<endl; cout<<"商品单价:"<<Goods.Good[sign].piece<<endl; cout<<"商品库存:"<<Goods.Good[sign].last<<endl; } else cout<<"商品不存在!"<<endl; break; } case 2: 大致与编号模式相同 else cout<<"商品不存在!"<<endl; break; } }//switch的 cout<<"是否继续查询?<继续>请按1 <结束>请按0"<<endl; cin>>flat; if(flat==0) break; }//for循环的}
    Good_delete函数:商品信息删除函数。把包含商品信息的链表Goods传入该函数,考虑到用户可能只记得商品编号或者商品名称,因此编写了2种删除方式(按编号检索删除,还是按名称检索删除)。如果选择按编号检索删除,同样对编号进行检索,如果在Goods链表中找到该商品编号,就运用 sign=Good_locate1(Goods,ID);定位记录下该商品在文件中的位置,而后使用for(int i=sign; i\<Goodnum; i++)将该位置后的商品全部前移1位,覆盖掉该位置,最后保存删除后的商品信息至“商品信息.txt”中;按名称检索删除类似。最后删除完后,会提示是否继续删除,如果不继续就返回用户功能界面,执行其他功能。
    void Good_delete(sqlist &Goods){ int a,sign,flat=1; string ID,name; for(;flat!=0;){ cout<<"<输入要删除的商品编号>请按1 <输入要删除的商品名称>请按2"<<endl; cin>>a; if(a!=1&&a!=2) {cout<<"选择有误,请重新输入"<<endl;continue;} switch(a){ case 1: { cout<<"请输入要删除的商品编号:"; cin>>ID; if(Good_ender1(Goods,ID)==1){ sign=Good_locate1(Goods,ID); for(int i=sign;i<Goodnum;i++){ Goods.Good[i]=Goods.Good[i+1]; } Goodnum--; Good_save(Goods); cout<<"删除成功!"<<endl; } else cout<<"商品不存在!"<<endl; break; } case 2: 大致与编号模式相同 else cout<<"商品不存在!"<<endl; break; } }//switch的 cout<<"是否继续删除?<继续>请按1 <结束>请按0"<<endl; cin>>sign; if(sign==0) break; }//for循环的}
    Good_range函数:商品信息排序函数。把包含商品信息的链表Go传入该函数,选择排序模式(按编号,单价,库存进行排序),运用2层for循环,使用冒泡法进行排序,从尾部向头部进行对比检索,小的放前面,大的放后面,排序完之后就将排序后的商品信息显示给用户;3种模式大致相同。最后排序完后,会提示是否继续执行,如果不继续就返回用户功能界面,执行其他功能。
    void Good_range(sqlist Go){ Goods p; p.piece=0; p.last=0; int a,flag=0,flat=1; for(;flat!=0;){ cout<<"<按商品编号排序>请按1 <按商品单价排序>请按2 <按库存数量排序>请按3 <退出>请按0"<<endl; cin>>a; if(a!=0&&a!=1&&a!=2&&a!=3) {cout<<"选择有误,请重新输入"<<endl;continue;} switch(a){ case 1: { for(int i=0;i<Goodnum;i++){ for(int j=Goodnum;j>=i+1;j--){ if(Go.Good[j].Good_ID<Go.Good[j-1].Good_ID){//比较编号大小,小的在前面,大的在后面 flag=1; p=Go.Good[j]; Go.Good[j]=Go.Good[j-1]; Go.Good[j-1]=p; } }//jfor的 if(!flag) break; }//ifor的 cout<<"商品编号"<<setw(10)<<"商品名称"<<setw(10)<<"商品单价"<<setw(10)<<"商品库存"<<endl; for(int i=1;i<=Goodnum;i++){ cout<<Go.Good[i].Good_ID<<setw(13)<<Go.Good[i].Good_name<<setw(8)<<Go.Good[i].piece<<setw(10)<<Go.Good[i].last<<endl; } break; } case 2: 大致与编号模式相同 case 3: 大致与编号模式相同 case 0:return; }//switch的 }//最外层for的
    Good_buy函数:购买商品函数。把包含商品信息的链表Goods以及包含用户信息的链表head传入该函数,选择购买模式(输入编号或名称进行购买),如果输入的商品编号与Goods中的商品信息相同,就提示购买数量,这时如果购买数量超过库存数量会提示“库存不足”,然后重新输入;如果购买商品所支付的钱超过用户的余额,则提示“余额不足”,是否前往充值页面进行充值。充值模块下面会展示。购买完商品后,用户可以继续购买,也可以返回用户功能界面。
    void Good_buy(sqlist &Goods,clklist &head,string cID){//cID为用户帐号 string ID,name; int a,shu,sign,flat=1; cpointer p; p=custom_locate(head,cID); for(;flat!=0;){ cout<<"<输入商品编号购买>请按1 <输入商品名称购买>请按2"<<endl; cin>>a; if(a!=1&&a!=2) {cout<<"输入有误,请重新输入"<<endl;continue;} switch (a) { case 1: { cout<<"请输入商品编号:"; cin>>ID; if(Good_ender1(Goods,ID)==1) { sign=Good_locate1(Goods,ID); cout<<"请输入购买数量:"; cin>>shu; if(shu<=Goods.Good[sign].last){ if(p->money<Goods.Good[sign].piece*shu) {cout<<"余额不足,请充值!"<<endl; cout<<"是否前往充值?<充值>请按1 <否>请按0"<<endl; cin>>flat; if(flat==0) break; if(flat==1) return;} Goods.Good[sign].last=Goods.Good[sign].last-shu; cout<<"购买成功"<<endl; p->money=p->money-Goods.Good[sign].piece*shu;//账户余额减少,扣费成功 custom_save(head); cout<<"账户余额:"<<p->money<<endl; Good_save(Goods); } else cout<<"库存不足!"<<endl; } else cout<<"找不到相应商品,购买失败"<<endl; break; } case 2:与编号模式类似 }//switch的 cout<<"是否继续购物?<继续>请按1 <结束>请按0"<<endl; cin>>flat; if(flat==0) break; }//for的}
    custom_addmoney函数:余额充值函数。余额是用户帐号中的一个成员,初始为0,用户在购物的时候余额会减少,如果余额不足就无法进行购物,需要进行充值,充值是输入系统给定的充值卡卡号进行充值,这是本系统的一大亮点。把包含用户信息的链表head传入该函数,运用 p=custom_locate(head,ID);定位是哪个用户的帐号要进行充值,其中,系统设定了2种充值卡“asd500”和“asd1000”分别可以充值500和1000元,这类似与用户购买不同的充值卡给自己的账户进行充值。用户输入充值卡卡号,进行检索是否与系统设定的充值卡卡号相同,如果相同就充值相应的金额;如果不同,就提示“充值卡无效”。最后充值后,用户可以选择继续充值或者返回用户功能界面进行购物等其他操作。
    void custom_addmoney(clklist &head,string ID){ cpointer p; int sign=1; p=custom_locate(head,ID); string acard,card1="asd500",card2="asd1000"; while(sign!=0){ cout<<"请输入您获得的充值卡卡号:"; cin>>acard;//acard是用户获得的充值卡 if(acard!=card1&&acard!=card2) cout<<"充值卡无效"<<endl; if(acard==card1) { p->money+=500; cout<<"充值成功!"<<endl; cout<<"账户余额:"<<p->money<<endl; }; if(acard==card2) { p->money+=1000; cout<<"充值成功!"<<endl; cout<<"账户余额:"<<p->money<<endl; }; custom_save(head);//充值成功 cout<<"是否继续充值?<继续>请按1 <结束>请按0"<<endl; cin>>sign;//while循环判断条件,所以不需要用if }
    3 程序功能测试一开始进入系统,初次使用会提示文件打开失败,是正常的,不影响功能。由于原本的“管理员信息.txt”“普通用户信息.txt”“商品信息.txt”是空的,当录入信息就不会有提示了。进入身份选择(都要帐号和密码)

    选择1进入超级管理员,(帐号:asd,密码123),先添加管理员。

    选择1,添加管理员信息(帐号+密码+姓名),添加完后可以选择继续添加或返回

    选择2,输入要删除的管理员帐号,直接删除管理员

    添加完管理员后,可返回主菜单,进入管理员模式,输入刚刚添加的管理员帐号+密码,进入管理员模式

    功能1,进入商品录入功能,输入商品的信息(编号,名称,单价,库存),当录入成功之后,管理员可以选择继续录入或返回(该模块当录入编号和名称和已录入的信息相同会提示出错,重新录入)

    功能2,可进行商品修改,有2种模式进行选择,输入商品编号101后,显示“商品信息.txt“文件中的商品信息,而后管理员可以输入修改后的信息

    功能3,可以进行商品信息查询,可以查询到刚刚修改的联想笔记本

    功能4,可以进行删除已录入的商品信息,例如,删除刚录入的联想笔记本

    删除后,进入查询功能查看联想笔记本,不存在,表明删除成功~ ~

    功能5,进行已录入商品信息排序,可选择(编号,单价,库存)进行从小到大排序,编号也是可以的

    功能6,输出全部商品信息

    功能7,删除普通用户,如果已经有普通用户,只需要输入普通用户的帐号就可以直接删除
    进入普通用户模块,如果没有帐号是无法查看和购物的,因此消费者可以自行注册

    注册完,就可以登录进入用户模块进行购物了

    其中,商品查询,排序,库存是和管理员一样的,就不展示了
    功能4,购买商品,一开始,由于没充值时,用户余额为0,余额不足,无法购买,用户可以返回,进行充值后购买。如果充值后,余额充足就可以购买了,购买后,余额相应减少

    这里我先前往充值2000元,后购买如下,主机单价50,购买后余额为1950,扣费成功

    功能5,用户可以随时修改自己的账户密码,保护自己的财产
    功能6,就是充值了,输入系统给定的充值卡卡号,有(asd500和asd1000)

    由于刚余额1950,现在输入卡号asd1000,成功充值1000,剩余2950
    4 总结这次选择了做“超市管理系统”,在完成基本功能之后,觉得要真正实现成功的超市管理系统,必须要有个人的帐号,因此增加了普通用户注册和帐号模式,同时管理员和超级管理员也都是用帐号+密码进入。普通用户可以自行注册,拥有自己的私人帐号。同时,超市管理系统普通用户在进行购买之后,应该是要有余额的,因此添加了余额成员。拥有余额成员之后,就想到,用户需要购买东西,余额不足就需要进行充值,为了实现真实性,就选定,用户需要输入充值卡卡号进行充值。最终完美实现。
    这个系统,是使用链表实现的,由于之前的大作业是使用文件流,不是使用链表,因此这次的大作业就决定说要使用链表来实现。在编程过程中,也发现了很多的bug,最终还是一一解决。感觉自己的编程能力在不断的提高,无论是什么bug都可以自行调试解决。
    同时,在思考程序的框架功能时,也逐渐重视用户体验,人机交互。编写大作业,不再只是仅仅满足基本功能,在基本功能上,还添加其余用户体验好的功能(比如帐号登录,充值等等功能),感觉大作业让我学会了很多。
    5 评论 225 下载 2018-10-31 11:28:48 下载需要7点积分
  • 基于MySql和JSP的题库管理系统

    第一章 选题意义及可行性1.1 背景及意义随着电脑网络的不断普及,计算机技术已经被越来越多地应用到各个行业管理当中,担当起高效、节能的操纵主角。在日常生活中也充当着重要的角色。
    随着疫情的发生,对于大学生的课程考核成为一个问题,该需求分析报告用于WEB的课程试题库管理系统这一课题的开发过程。明确了课题开发的目的与要求,介绍了该系统的所有功能以及适用范围。
    1.2 主要研究内容本次拟通过对题库管理有关理论著作和知识的学习,主要从使用者身份以及数据和信息两个方面着手去考虑,对题库管理的整个流程,从底层开始规划设计,针对不同角色的不同管理需求,制定相应的架构模块,实时跟进使用的需求变化,尽可能提高系统的操作性和灵活性。打下一个扎实的根基是非常必要的,否则系统将变得越发难以维护,复杂度也将增加。这就要求系统要有良好的模块化设计。当系统的信息量越大,复杂度越高的时候,用户体验显得尤为重要。对当前题库管理的新需求分析,根据这些新需求设计出一套合适但相对简化的管理模式的管理系统,并且完成该系统下的各子系统功能模块的设计与开发,以实现题库管理的自动化、及时化和系统化的目的。
    第二章 需求分析及系统设计2.1 需求分析2.1.1 系统描述本选题旨在设计一个可以对题库信息进行良好管理的系统。服务器端用于部署该系统并且储存用户提交的信息数据,所有的业务逻辑均在服务器端处理,而浏览器端仅仅是一个浏览器,使用者并不需要进行维护,只是需要进行数据访问,从而实现各项功能需求的定制。
    2.1.2 系统基本要求该课题研究的目的是为提高题库管理的效率,给需要进行题库管理的人提供方便、快捷的创建、编辑题库信息;提供方便、快捷的查询,提高题库调查工作的效率。
    系统主要完成内容包括管理员管理、教师管理、题库管理、题库导入管理、题库导出管理主要功能如下:

    管理员管理:包括管理员对管理员信息的增加、删除、修改等,对各类型的查询、统计等
    教师管理:对教师信息的增加、删除、修改、查询等
    题库管理:对题库信息的增加、删除、修改、查询等
    题库导出管理:对题库信息的导出成Excel
    题库导入管理:对题库信息的Excel导入mySQL

    2.1.3 功能需求分析系统的功能包括:管理员管理、教师管理、题库管理、题库导入管理、题库导出管理等。管理员负责对各项信息的管理等,具体功能如图3.1:

    管理员用例清单表



    模块
    用例编号
    用例名称
    用例描述




    管理员登入
    Admin-001
    管理员登入
    管理员根据账户名、密码登入系统


    教师管理
    Admin-002
    教师管理
    添加、修改、删除出题教师


    试卷组建
    Admin-003
    试卷组建
    在试题库中选择需求数量的题目组成试卷


    教师名单导入
    Admin-004
    教师名单导入
    在教师库中讲Excel文件中的教师名单导入


    试题导入
    Admin-005
    试题导入
    在试题库中讲Excel文件中的试题导入



    管理员登入的用例描述表




    描述




    描述
    管理员根据账户名、密码登入系统


    基本流程
    (1)根据登入界面选择“管理员”,输入用户名、密码 (2)核对数据库账号信息 (3)信息匹配登入成功,否则返回登入界面


    返回数据
    账户名



    教师管理的用例描述表




    描述




    描述
    添加、修改、删除出题教师


    基本流程
    (1)管理员点击“教师管理”,进入教师管理界面 (2)系统根据相应信息显示已存在的教师信息 (3)管理员根据需求,单击删除、修改、添加等按钮 (4)根据选择不同的需求弹出相应的窗口 (5)完成相应需求的操作


    返回数据
    NULL



    试卷组建用例描述表




    描述




    描述
    在试题库中选择需求数量的题目组成试卷


    基本流程
    (1) 管理员点击”组卷”,进入组卷界面 (2)系统根据相应信息显示已存在的题库信息 (3) 管理员根据需求选择相应的试题组成试卷 (4) 完成相应需求的组建操作


    返回数据
    试卷集



    用户负责个人信息、个人题库的管理,具体功能如图3.2:

    教师的用例清单表



    模块
    用例编号
    用例名称
    用例描述




    管理员登入
    Admin-001
    管理员登入
    管理员根据账户名、密码登入系统


    教师管理
    Admin-002
    教师管理
    添加、修改、删除出题教师


    试卷组建
    Admin-003
    试卷组建
    在试题库中选择需求数量的题目组成试卷


    教师名单导入
    Admin-004
    教师名单导入
    在教师库中讲Excel文件中的教师名单导入


    试题导入
    Admin-005
    试题导入
    在试题库中讲Excel文件中的试题导入



    教师登入用例描述表




    描述




    描述
    教师根据账户名、密码登入系统


    基本流程
    (1)根据登入界面选择“教师”,输入用户名、密码 (2)核对数据库账号信息 (3)信息匹配登入成功,否则返回登入界面


    返回数据
    账户名



    组建试题库用例描述表




    描述




    描述
    落实课程的授课知识点,完成试题库的组建


    基本流程
    (1) 教师点击“出题”,进入出题界面 (2) 向试题库中添加试题 (3) 完成相应需求的组建题库操作


    返回数据
    试题库



    试题维护用例描述表




    描述




    描述
    修改、删除试题库


    基本流程
    (1) 教师点击”搜索”,进入题库界面 (2) 填写相应的查询添加 (3) 编辑对应试题 (4) 完成相应需求的组试题维护操作


    返回数据
    改变的试题集



    2.1.4 运行需求分析系统服务器端配置需求信息表



    类型
    配置型号




    操作系统
    Window10


    Web服务器
    Tomcat9.0.3


    数据库管理系统
    MySQL5.6


    运行库
    JDK1.8



    系统客户端配置需求信息表



    类型
    配置型号




    浏览器
    Mozilla Firefox


    操作系统
    Windows10



    第三章 系统设计3.1 系统概要设计对于本系统的各子系统功能模块初步设想如下:

    系统登录模块:分别为教师和管理员的登录,进入不同页面
    管理员管理模块:教师信息题库数据的录入、维护、查询、删除管理工作
    教师管理模块:包括题库数据的录入、维护、查询、删除管理工作
    导入导出模块:对数据库数据的导出成excel和将excel数据导入excel中

    3.2 系统功能模块图系统主要功能模块图如图3.3所示,以使用角色来分,主要包括管理员模块、用户模块两大部分。其中管理员模块主要包括管理员信息管理,教师信息管理,题库管理;教师模块主要包括个人信息管理,题库管理,导入导出题库。

    3.3 系统总体业务流程管理员通过自己的用户名和密码登录管理系统,若输入不匹配则重新输入,进入系统后可以浏览所有管理员、教师、题库信息,可以对管理员、教师、题库信息进行增加、删除、修改与查询;教师登录系统后便列出该所教课程的所有试题,可以创建新的试题,可以对试题进行录入、维护、查询、删除管理工作,教师还可以修改个人的信息;管理员和教师都可以对题库的导入导出。

    管理员登录,如果帐号密码不匹配,重新输入
    系统验证登录信息,验证通过后进入管理系统首页
    管理员对管理员、教师、题库信息的查询或修改等管理操作
    退出系统


    3.4 系统开发体系结构设计本系统采用JSP技术,通过MVC三层设计模型实现基于B/S架构的《电路原理》重点课程网。用JSP+Servlet+JavaBean实现MVC设计模式的流程。

    MVC是三个单词的缩写:M,Model(模型);V,View(视图),C,Control(控制)。MVC模式的目的就是实现Web系统的职能分工,Model层:实现系统的业务逻辑,即javaBean部分。View层:负责与用户交互,即在界面上展示数据对象给用户,即html,jsp。Control层:Model与View之间沟通的桥梁,它可以分派用户的请求并选择恰当的视图以用于显示,同时它也可以解释用户的输入并将它们映射为模型层可执行的操作,当然就是Servlet的职责了。
    3.5 系统数据库设计数据库是信息管理的常规方法,它可以处理各种各样的数据信息。数据库的优势就在于它可以将庞大而复杂的信息以有序的方式组织起来,便于修改和查询, 管理人员手工处理这些枯燥的数据。数据库一般按照数据的组织和查询方式加以区分。目前使用最多的都是基于关系代数的关系数据管理系统(RDBMS)。在关系数据库关系系统中,数据按照表存放。一个数据库可以有多个表,每个表由行和列组成,每行是一个记录,每个记录的信息分为多段,一张表的每一行的段的组成都是相同的,而不同行中相同的列就称为字段。
    设计本系统,主要包括以下数据表,E-R图如下图所示:

    使用MySQL建立起数据库表如下:

    admin表:用于存储管理员信息
    class表:用于课程信息
    teacher表:用于存储教师信息
    test表:用于存储所有题库信息

    管理员信息表(admin)



    字段
    类型
    主键
    Null
    默认
    注释




    adminNumber
    varchar(20)
    Y
    N

    用户名


    adminPassword
    varchar(20)

    N

    密码



    用户信息表(class)



    字段
    类型
    主键
    Null
    默认
    注释




    classNumber
    varchar(20)
    Y
    N

    课程号


    className
    varchar(20)

    N

    课程名


    classCredit
    varchar(20)

    N

    学分



    题库信息表(teacher)



    字段
    类型
    主键
    Null
    默认
    注释




    teacherNumber
    varchar(20)
    Y
    N

    教师编号


    teacherPassword
    varchar(20)

    N

    登入密码


    teacherName
    varchar(20)

    Y

    教师姓名


    teacherSex
    varchar(20)

    Y
    0
    教师性别


    teacherTitle
    varchar(20)

    Y

    教师头衔


    teacherPhone
    varchar(20)

    Y

    教师电话



    问题信息表(test)



    字段
    类型
    主键
    Null
    默认
    注释




    questionNumber
    int(10)
    Y
    N

    试题编号


    classNumber
    varchar(20)
    Y
    N

    所属课程


    teacherNumber
    varchar(20)
    Y
    N

    教师姓名


    questionType
    varchar(20)

    N

    试题类型


    question
    varchar(500)

    N

    试题题目


    questionSelect
    varchar(500)

    Y
    NULL
    试题选项


    questionResult
    varchar(500)

    N

    试题答案


    questionPoint
    varchar(200)

    N

    试题考点



    第四章 系统功能实现4.1 系统的开发环境与开发工具开发工具对一个系统的成败具有决定性作用。我选用了IntelliJ IDEA开发软件,并用MySQL作为系统后台数据库,开发中将用到以下主要几款开发工具:
    开发工具、程序语言



    类型
    工具




    开发环境
    IntelliJ IDEA


    后台数据库管理
    MySQL 5.6


    数据库管理软件
    SQLyog


    功能模块设计及流程图绘制
    Microsoft Visio2013


    系统界面设计
    IntelliJ IDEA


    jQuery框架
    EasyUI


    程序设计语言
    JAVA


    浏览器
    Mozilla Firefox



    4.2 系统主要功能模块实现本套题库管理系统是基于当前流行的试题管理的新需求分析而开发的一套管理系统。通过对该管理系统的研究与相关开发,已达到如下目标:

    本系统主要完成上述六大子系统功能模块的设计与开发
    从管理人员的角度出发去人性化设计系统,方便使用者使用本系统
    系统开发完成后,能够提高工作效率,使得题库管理更加高效与便捷

    4.2.1 系统登录模块实现当使用本系统时,用户需要输入用户名和密码来进行安全验证登录。用户输入用户名密码后,系统会向后台登录模块发送请求,后台会调用方法来向数据库查询用户,若没有结果则返回错误状态,在界面向用户显示输入错误的提示。
    登录界面

    登录失败界面

    4.2.2 管理员管理模块实现当管理员输入正确的账号和密码时,系统登录成功跳转至admin.jsp。页面中,管理员可以进行对管理员信息的浏览,修改,增加,删除,查询等操作。
    管理员登录界面

    管理员增加界面

    管理员增加成功界面

    管理员编辑界面

    管理员编辑成功界面

    管理员删除界面

    管理员删除成功界面

    在管理员主界面中,上方有增加、删除、修改、查询等功能,管理员的信息一目了然。
    4.2.3 教师管理模块管理员可以点击左侧菜单中的“用户管理”,切换到用户管理的页面。页面中,管理员可以进行对用户信息的浏览,修改,增加,删除,查询,上传头像等操作。
    教师信息界面

    在用户管理主界面中,上方有增加、删除、修改、查询;
    4.2.4 题库管理模块管理员可以点击左侧菜单中的“题库管理”,切换到题库管理的页面。页面中,管理员可以进行对题库信息的浏览,修改,增加,删除,查询等操作。
    题库管理界面

    题库详情界面

    题库添加界面

    题库成功界面

    题库编辑界面

    题库编辑成功界面

    题库删除界面

    题库删除成功界面

    题库导入界面

    题库导入成功界面

    第五章 总结本次作业主要是对题库管理系统中学习到了以下几点:

    数据库的结构设计,数据库结构设计是继需求分析和确定开发工具后的重要阶段,是管理型软件开发设计的核心和重要组成部分。数据库结构设计的好坏与否将对应用系统的运行效率以及实现的效果产生很大影响。科学、合理的数据库结构设计可以提高数据访问的速度,有效保持数据的完整性、一致性和共享性,因此数据库结构设计对系统设计来说至关重要
    学习尝试了使用MVC结构完成JAVA的Web开发。并初次尝试使用了session的方式储存用户。学习到了许多JSP脚本的灵活使用。当然由于使用了MVC结构,大量运用了json的技术来传递数据。同时也使用了大量的jQuery中ajax的使用
    在开发过程中,大大小小的会遇到些问题,在询问老师或上网查找资料的过程中,对这项开发技术的一些细节也有了更深的理解和掌握。对于SQL语句也有了更深的理解,以及更好的运用;从刚开始每一条语句都要在数据库中执行一遍到能熟练掌握基本的增删改查语句
    对于各个界面有更深的理解以及完成过程,但也相对的会花费了更多的时间,很好的将程序进行分层管理,将各个模型的控制器,视图均放在一个界面中,便于后期管理

    总的来说,本次的作业对我是一次很好的锻炼,让我对系统开发的需求分析阶段有了更好的理解,在实践中去领会它的优势所在无疑是最好的办法。通过本次的课程设计,提升了我在数据库设计方面的能力熟练度。
    1 评论 3 下载 2020-07-06 10:02:24 下载需要12点积分
  • 基于C++的景区旅游信息管理系统

    1 问题描述如今生活水平提高,大家都喜欢在假期中到一个旅游景点参观,在旅游景区中经常听到游客打听从一个景点到另一个景点的最短路径和最短距离,这类不喜欢按照导游图来游览的游客常常需要一个景区管理系统来挑选自己喜欢的旅游景点,再规划一个最短路径和最短距离来游览,一边节省时间跟提高旅游效率。
    2 数据结构的设计
    建立一个景区旅游信息管理系统,实现如下功能:

    创建景区景点分布图

    通过一个邻接矩阵(实质是一个二维数组,m[i][j]表示从i到j的权值大小,为零表示没有直达的路径)记录景区景点的分布图
    输出景区景点分布图(邻接矩阵)

    通过扫描邻接矩阵输出景区景点分布图
    输出导游线路图:深度优先策略

    首先通过遍历景点,通过用户给出的一个入口景点c,建立一个导游线路图,导游线路图用有向图表示。遍历采用深度优先策略(递归),这个也是正常的游客的心理
    判断导游线路图有无回路:拓扑排序(查找入度大于1的景点)

    为了使导游线路图能够优化,可以通过拓扑排序判断图中有无回路,若有回路则打印输出回路中的景点,供人工优化
    求两个景点间的最短路径和最短距离:floyd算法

    在导游线路图中,还为一些不愿按线路走的游客提供信息服务,比如从一个景点到另一个景点的最短路径和最短距离。在本线路图中将输出任意景点间的最短路径和最短距离
    输出道路修建规划图:prime算法

    在景区建设中,道路建设是其中一个重要的内容。道路建设首先要保证能连通所有景点,但又要花最小的代价,可以通过求最小生成树来解决这个问题,通过prime算法来求最小生成树

    通过修改后添加的功能:

    将景区景点分布图安装指定的文件名(可以景区名字命名)保存到默认的目录file下

    在这里我遇到了路径格式问题,通过查询资料得以解决这个问题
    从默认目录file下读取指定文件名的景区景点分布图

    这样就减少了每次都要创建景区景点分布图,也方便从已有的景区景点分布图导入系统,不用手动新建,实际应用中更加的方便人性化
    为当前的景区添加景点道路

    一开始没有将景区景点的路径清零,以至于添加景点道路后,再从新导入景点较少的景区景点分布图,再添加景点道路的时候发现之前的道路依然存在,因此在添加景点道路之前要将道路景区清零

    3 算法设计(核心代码)//深度优先搜索导游线路int visited[M]={0};int np=0;//找到的景点个数int p[M];//表示各个景点的入度值void DFS(int c){ //c为景点编号 np++;//每递归调用一次就自加一次,作为判断是否到了最后一个景点 p[c]++; if(np==S.count){ //到了最后一个景点 cout<<S.mat.Pname[c]<<endl; returnMainFace(); }else{ cout<<S.mat.Pname[c]<<"-->"; } visited[c]=1; for(int i=0;i<S.count;i++){ if(S.mat.m[c][i]>0&&visited[i]==0){ DFS(i); if(S.count>np){ cout<<S.mat.Pname[c]<<"-->"; p[c]++; } } } if(np==S.count) returnMainFace();}void guide_line()//导游线路{ checked(); cout<<"\n*请输入起始景点的景点编号:"; int c; cin>>c; c--; for(int i=0;i<S.count;i++){ visited[i]=0; p[i]=0;//入度置初值为0 } np=0; cout<<"*形成的导游线路图(采取深度优先策略)如下所示:\n\n\t"; DFS(c);}//Floyd(佛洛依德)算法,A[M][M]表示最短距离,path[M][M]表示辅助数组,记住前驱void Floyd(int A[M][M],int path[M][M]){ int i,j,k; for(i=0;i<S.count;i++){ for(j=0;j<S.count;j++){ if(S.mat.m[i][j]==0&&i!=j){ //如果两点之间没有边相连,则权为无穷大 A[i][j]=INF;//INF=999666333 }else if(i==j){ A[i][j]=0; }else{ //S.mat.m[i][j]表示两个景点之间的道路长度 A[i][j]=S.mat.m[i][j]; } //给所有的path[i][j]赋值 if(i!=j&&S.mat.m[i][j]<INF){ path[i][j]=i; }else{ //(i==j&&S.mat.m[i][j]=INF path[i][j]=-1; } } } //k注意放到最外层,让A[i][j]检测都经过每一个k for(k=0;k<S.count;k++){ for(i=0;i<S.count;i++){ for(j=0;j<S.count;j++){ if(A[i][j]>A[i][k]+A[k][j]){//如果i->j的权值大于i->k->j的权值 A[i][j]=A[i][k]+A[k][j]; path[i][j]=path[k][j];//path[k][j]=k前驱?k是指向的下一个景点 } } } }}void min_distance()//最短路径、距离{ checked(); int A[M][M],path[M][M]; Floyd(A,path);//A是一个景点到另一个景点的最短路径的长度 while(true){ Num_Name();//编号对应的景点名称 int i,j,k,s; int apath[M],d;//apath[M]是记录路径的数组 bool flag=true; while(flag){ cout<<"\t-景点1:"; cin>>i; i--; if(i<0||i>S.count-1){ cout<<"*请输入合法的景点编号:\n"; }else{ flag=false; } } flag=true; while(flag){ cout<<"\t-景点2:"; cin>>j; j--; if(j<0||j>S.count-1){ cout<<"*请输入合法的景点编号:\n"; }else{ flag=false; } } if(A[i][j]<INF&&i!=j){ k=path[i][j];//k是指向的下一个景点 d=0;//路径有d+2个景点,是数组apath的下标 //将待输出的路径的点存放在栈apath中 apath[d]=j;//最后一个景点 while(k!=-1&&k!=i){ d++; apath[d]=k; //再继续判断还有没有景点 k=path[i][k]; } d++; apath[d]=i;//加上第一点 cout<<"\n*从 "<<S.mat.Pname[i]<<" 到"<<S.mat.Pname[j]<<" 最短路径为:"; cout<<S.mat.Pname[apath[d]];//apath[M]数组最后一个,就是第一个起点,相当于栈 for(s=d-1;s>=0;s--){//将剩下的景点(apath[M]数组剩下的元素)打印出来 cout<<"-->"<<S.mat.Pname[apath[s]]; } cout<<" ,最短距离为:"<<A[i][j]<<endl;//Floyd算法已经将最短路径算出来存放到了A[i][j](将INF的值用最短路径代替了) }else if(i==j){ cout<<"\n*景点输入不合法,输入的两个景点不能相同!\n"; }else{ cout<<"\n*这两个景点间不存在路径\n"; } cout<<"\n是否继续执行最短路径和最短距离的查询(Y/N)"; Y_N(); } returnMainFace();}//道路修建规划图、最小生成树(prime算法)void build_road(){ checked(); cout<<"\n*道路修建规划图(prime算法)规划如下:\n"; //Ai[M]表示待选边的权值,邻接矩阵的一行,closest[M]:点编号数组,记录下一条路的起点景点的编号 intAi[M],min,closest[M],i,j,k,sum=0,num=0;//num表示第几条路 int A[M][M]; //赋权值 for(i=0;i<S.count;i++){ for(j=0;j<S.count;j++){ if(S.mat.m[i][j]==0&&i!=j){ A[i][j]=INF; }else if(i==j){ A[i][j]=0; }else{ A[i][j]=S.mat.m[i][j]; } } } for(i=0;i<S.count;i++){ Ai[i]=A[0][i];//取第一行存四个Ai[i],就是一个景点到所有景点的权值 closest[i]=0;//0 } for(i=1;i<S.count;i++){ min=INF; //从Ai[j]中选出最小的值存放在min for(j=0;j<S.count;j++){ if(Ai[j]!=0&&Ai[j]<min){ min=Ai[j]; k=j;//记录最小的值的列j:k=j,为了下面标志此路已选 } } if(min<INF){ cout<<"\t-第 "<<++num<<" 条路: 从"<<S.mat.Pname[closest[k]]<<" 到"<<S.mat.Pname[k]<<" , 该道路长度为:"<<min<<endl; sum+=min;//sum累计道路长度,即是已选的权值 } Ai[k]=0;//标志为已选的边的权值,避免重复选择 //例子:对比a到c和b到c的权值,取最小存进Ai[j]中 for(j=0;j<S.count;j++){ if(A[k][j]!=0&&A[k][j]<Ai[j]){ Ai[j]=A[k][j]; closest[j]=k;//点编号数组,记录下一条路的起点景点的编号 } } } cout<<"*修建道路的总长度为:"<<sum<<endl; returnMainFace();}
    4 运行与测试通过创建不同的景区景点分布图来测试,测试结果正确无误,下面以一个例子演示运行测试的过程:
    创建景区景点分布图:


    输出景区景点分布图和各个编号对应的景点的名称:

    输入一个起始景点的景点编号来形成一个深度优先的导游线路图:

    通过检查景点的入度出度来判断是否重复走过景点:

    通过输入两个景点来查询最短路径和最短距离:

    通过prime算法规划道路,使道路的总长度最小,(实质生成的是最小生成树):

    将景区景点分布图按指定文件名保存到默认文件夹下:


    按文件名导入文件(符合存储景区景点格式的文件),导入景区景点分布图:


    为当前的景区添加景点和道路:

    添加后的景区景点分布图:

    退出系统:

    另外,当输入有不当的处理:


    5 总结与心得通过认真对待数据结构课程设计,认真思考如何用算法和代码来解决现实生活中的问题,认真参考优秀参考文献和优秀作品后,收获甚多。一开始,面对现实生活的问题,毫无头绪,不知如何入手来实现解决现实生活的问题,后来通过参考文献和别人的类似作品后,才发现原来数据结构算法是这样使用的,也因此解开之前在上数据结构课堂上的疑惑:数据结构如何运用在我们的工作代码上。总的来说,收获的东西确实不少,只要认真对待学习上的每一个环节,就一定会有收获。
    通过老师的指导,此系统优化了很大哦,并且让我学会了很多东西,很多实际问题都没有考虑周全,老师都可以指出并要求我修改,正是因为修改,才让我学到了更多的知识,使我明白了,做课程设计,不单单但是做课程设计,还要通过这次课程设计来考虑实际问题,不断优化。
    1 评论 101 下载 2018-11-07 15:17:54 下载需要7点积分
  • 基于QT实现的多人在线对战的五子棋游戏

    一、程序背景计算机网络的迅速发展,对游戏领域产生了巨大影响。尤其是随着信息时代的来临,人们越来越趋向于网络游戏来进行竞技,于是,各式各样的网络游戏应运而生,例如腾讯游戏,网易游戏。在这些平台上,五湖四海的玩家可以随意地竞争与合作,适当的娱乐可以很好地纾解生活压力,为家庭、事业都有巨大的积极作用。因此,开发和架构这种轻游戏平台符合时代发展的需要。
    二、设计原理及要求2.1 设计原理本系统主要由四个子模块组成:五子棋游戏、网络通信、用户系统、积分系统。
    2.2 设计要求
    采用C/S模式架构,能够同时支持至少40对玩家
    服务器端提供游戏大厅、游戏桌等
    对战平台提供的游戏:五子棋或其它等

    三、程序介绍此程序主要分为两个部分:服务端和客户端。
    游戏服务端用于存储和转发信息,收到用户的登录、准备、落子等主动信号,进行相关的数据运算,并发送回用户。
    游戏客户端可通过服务端的IP地址发送连接请求,然后登录到游戏大厅,没有账号则需要先注册。在服务端中会维护一个session列表,即在线用户名单,还有所有游戏桌状态数组,保存所有游戏桌的人数情况以及准备情况。有人进入游戏桌、开始准备游戏、开始游戏、落子、游戏结束、离开游戏桌等,服务端都会收到相应的数据,此时服务器作为一个存储器和转发站,保存所有用户的游戏状态,并转发消息给相关的用户。用户排名也会显示在对应的客户端上,可自行查看排行榜。本游戏人数理论上无上限,可修改宏定义的数值参数来设置人数上限。
    四、程序的功能描述4.1 开始会话启动客户端时,便会尝试连接至服务器。连接成功后会在服务器的会话列表中新增一个封装过的session类,这个session类保存会话用户的信息,包括用户ID、用户账号、用户排名、用户状态等。
    处理完成后向客户端发游戏大厅中所有桌子的游戏状态,将有人的桌子改变颜色。
    所有的传输的数据格式都是XML,以便于提取数据。服务端和客户端皆有特定的函数专门用来处理传输的XML数据,同时用递归的方式解决了Socket带来的数据缓冲区问题,即多条数据会合在一起发送给客户端,导致有一定的几率分析失败,产生逻辑上的错误。
    4.2 注册服务器收到用户的注册数据,便开始提取数据中的有用信息,包括用户名、密码,可注册的话则为其生成一个唯一的用户ID,确保此用户为本游戏平台中独一无二的玩家对象。接着向存储的数据中添加新用户的记录,初始化积分。客户端收到注册成功的信号,获取用户ID,开始正常游戏。注册后可通过点击游戏大厅的用户名按钮,来查看所有用户的数量(因为新账号的排名就是所有用户数量)。
    4.3 登录在客户端,用户输入其账号密码后,服务器收到用户的登录数据,提取中数据中的用户名和密码,和用户列表中的数据进行配对。如果失败则返回错误提示。如果匹配成功,则在session列表中逐一比较,避免同一用户多设备同时登录,扰乱游戏积分系统。登录后返回用户的ID、昵称、积分等个人信息。
    登录成功后可通过点击游戏大厅的用户名按钮,来查看自己所在的位置,以及所有用户的账号与排名。
    4.4 进入游戏桌这需要登录后才能进入游戏桌。每个游戏桌分为两个座位,分别为黑子、白子,先进来的玩家默认为黑棋,后进来的为白棋。玩家加入游戏桌后,对应位置上的区域将会出现头像,表示这个位置有人,状态文字也变成“未准备好”,出现“准备完毕”的按钮。
    大厅的桌子预览图列表中白色的座位图标会变成黑色,并且上面显示玩家昵称。
    4.5 离开游戏桌玩家离开桌子回到大厅时,游戏桌上的玩家头像消失,大厅中的游戏桌预览图列表的黑色座位变回白色,表示这个位置的玩家已经离开了,其他玩家随时可上去与其他玩家开始游戏。如果在激战中退出离开游戏桌,确认后即视为放弃比赛,主动认输,另一方无条件获胜。
    4.6 准备开始游戏刚开始加入游戏桌时皆为未准备状态,需要手动点击“准备完毕”表示自己已经准备好,随时可以开始游戏。双方玩家都能看到对方的准备状态,以便于自己是否确认开始进行对战。双方都准备完毕时,收到服务器发送的对战信号,将马上开始对战。
    4.7 开始游戏准备完毕时,客户端向服务端发送准备的信号,当同一桌双方玩家都准备完毕后,立即开始比赛。客户端发送start信号给游戏桌的双方客户端,客户端进行游戏初始化,包括棋盘数据清空、棋盘控件清空棋子和更新界面、设置黑子先手、五子棋AI初始化、确定各自棋子的颜色,开始进行五子棋对战。
    4.8 落子游戏双方的每一次落子都会向服务器发送落子的信号,传输的数据中同时含有自身的信息,比如桌子ID、座位ID等,避免在数据传输的过程中丢包而导致的一些逻辑问题。服务端判断收到的用户座位是不是与保存的用户状态的列表中的数据一致,如果不一致则是有错误,需要进行纠错;如果没有错误就转发落子的数据给另一方的客户端,在客户端中模拟玩家进行落子。遇到错误后服务端会进行处理,并返回尽量减少错误损失的数据,交给客户端处理。
    4.9 放弃游戏在对战中关闭棋盘窗口,则视为放弃本次比赛,对方无条件获胜。退出的一方将会警告扣除积分,但并不会真的扣除。胜利方也不会获得奖励,避免刷分操作。离开后失败方的头像将会消失,原来的头像下方的文字变为“对方已放弃”,并且字体变灰。
    判断双方处在对战中的逻辑是同一游戏桌的两名玩家都已经准备完毕,服务端中有一个维护所有桌子座位状态的数组,0为没有玩家, 1为有玩家但没有准备好,2为有玩家并且准备完毕。如果双方都已经准备,则会立即开始比赛,所以两边都准备的情况下必定是正在比赛。
    4.10 游戏胜利客户端落子时发送数据给服务端,接着调用五子棋的AI判断自己是不是胜利。如果是胜利,则发送胜利的信号给服务端,在服务端中分析对战的双方局势,判断是不是真的胜利。最后一颗棋子也会发送给失败方,以便于两边的棋谱同步。确定数据无误后在服务端通过落子数量获得胜利者应该获得的积分,转发给胜利的玩家客户端。失败者也会获得少量的积分奖励,积分约为胜利者的三分之一。游戏结束后双方的准备状态清空,胜利方状态变为金色,失败方状态变为灰色,同时需要重新点击“继续下一局”按钮来和对方继续下一句对战。
    4.11 积分奖励每胜利一局,都会获得大量的积分,计入自己的总积分。服务端会进行累加,并保存到用户数据中。失败者获得少量的积分,也会累加到用户数据中,并保存到文件,实时保存积分以便于下次启动服务端时重新读取数据,同时也是避免了数据丢失。
    4.12 用户排名在服务端中维护了一个用户列表,是从数据文件中读取的。每一个用户列表中都有封装好的用户信息,其中就包括了用户的积分。其中每一个积分都对应了一个用户ID,解决了修改用户昵称和密码后引起的后患。通过QT的qSort函数来对用户信息按照积分进行排序,通过简单的算法添加了对积分相同的用户的排名保护。遍历所有用户的排名、昵称、积分,用一个QString来保存XML格式的数据,然后传输到对应的客户端。接着在客户端使用自己编写的字符串提取函数提取出所有用户的排名、昵称、积分,使用制表符显示在一个小型对话框里面。客户端用户也可以在排行榜中看到自己所处的位置。
    五、系统的ER图下图是简易的ER图大纲:

    下图是完整的ER图以及各个子模块之间的联系:

    六、程序详细设计及主界面呈现6.1 游戏大厅界面启动程序后就建立了与服务端的连接,开启一个session,每个客户端被赋予一个独一无二的sessionID。服务器维护一个经过封装的会话list,通过sessionID来判断是哪个客户端。封装后的sessionInfo类,包含了sessionID、用户昵称、用户ID、游戏桌位置等,并且在和客户端进行通讯时判断用户的位置是否正确,如果有误则进行纠错处理,将系统损失降低到最小。
    启动时进入了游戏大厅,此时会显示所有游戏桌的状态。在客户端与服务端连接成功后,服务端就向客户端发送了特定的数据包。这段数据中涵盖了当前所有游戏桌的人数状态,采用简短的XML格式,包括每个游戏桌座位上的用户昵称、ID、准备状态等。

    如上图,每个游戏桌可分为桌子、两边的座位。每个座位默认是白色,表示没有人在这里。一旦有人进来,服务端会发送所有游戏桌的数据给所有在线的用户,客户端SocketUtil类收到数据,通过判断里面的kind关键字来分发数据给对应的窗口对象,游戏大厅窗口收到数据进行处理,座位变成黑色,表示已经有人了,同时在座位的上方打印玩家的昵称,用来辨认。上图中的第二张游戏桌的左边位置已经变黑,座位上面还显示了玩家的昵称helloLisa。
    如果没有登录,左上角只有一个“未登录”按钮,再进行任何操作例如点击登录按钮、点击游戏桌等,都会强制要求跳转到注册/登录界面,登录成功后才能继续操作。登录后的样子如下图所示。

    原先的“未登录”按钮变成了用户的昵称,而后面多了两条信息,分别表示用户的当前积分、个人排名。积分是在游戏后才能获得,而排名则是代表当前用户在所有用户之中的排行。相同积分的用户排名相同,而不是简单的按照名称排序。点击用户名按钮,可以看到所有用户的积分排名。

    点击用户名按钮,客户端发送查看排行榜的请求给服务端,服务端收到数据后访问所有用户,进行排序,并且将客户端需要的数据发送给客户端,包括排名、昵称、积分等,同样是封装成XML数据,客户端收到后弹出MessageBox对话框,读取所有用户排名,展示给用户看。
    点击任意一张桌子,都可以进入游戏等待界面。
    6.2 注册登录界面在游戏大厅中进行任何操作,如果没有登录的话,会强制要求跳转到注册登录界面。注册登录界面略显简陋,由两个垂直排列的对话框和两个水平排列的按钮组成,分别是账号、密码、注册、登录。

    注册时,如果用户昵称已经存在,则会提示注册失败,重新换个名字。因为用户名代表了这个用户的个性化,早点注册的用户有更多的可能获取到自己喜欢的用户名。

    登录时,如果用户已经在其他设备登录,则不允许再次登录。这是为了避免多人用同一个账号刷积分,保障积分系统的公平性与稳定性。

    如上图,一个客户端用helloLisa账号登录,而第二个客户端也尝试用同样的账号登录,这时就会返回登录错误,要求用户更换账号。
    注册成功后,通过MessageBox弹出“注册成功”的话语,并且提示用户牢记自己的账号和密码。

    登录成功后,通过MessageBox弹出“欢迎回来”字样的对话框,接着自动关闭登录窗口。

    登录后,游戏大厅会显示用户的信息,用户昵称、用户积分、用户排名。

    6.3 五子棋界面该界面由三部分横向的布局组成:左边是用户一的头像、状态、操作按钮,中间是五子棋棋盘的控件,右边是用户二的头像、状态、操作按钮。

    头像分为黑白两色,黑色表示该用户使用的是黑棋,白色则相反,代表白棋。头像下方的标签显示了用户的状态,刚进入游戏桌时默认为“未准备好”,而且状态标签下方的按钮会显示“准备完毕”。点击准备完毕后,“未准备好”标签变成醒目的红色,文字也变为“等待开始”。而原先的按钮文字变成“取消准备”。在游戏开始之前随时都可以取消准备,变成原先的状态,不会有任何影响。

    同一个游戏桌对面用户,不会显示准备按钮,因为无法干预对方的准备状态。而对面如果没有人,则不会显示头像,直至对手进入游戏桌,自动显示头像。


    当对手进入游戏桌后,黑色的“未准备好”字样变成了暗黄色的“未准备好”,用以提示己方用户已经有人进来了,改准备开始游戏了。等对方准备完毕,则立即开始游戏,不再给予等待时间。

    按照五子棋的规则,黑棋先下,即代表头像为黑色的用户一方先落子。用户可以用鼠标点击棋盘的任意一个位置,如果范围超出了棋盘或者已经落子,那么该次点击不会有任何效果,相等于没有进行操作。用户每下一个子,都会发送数据给服务端,由服务端进行保存状态和转发给对面的玩家。对面玩家在收到落子信号前不能进行任何的落子操作。

    对面玩家的客户端收到了都成服务器的<KIND>moves</KIND>文本信号,客户端在数据中提取出落子位置,游戏桌ID、用户座位、棋子横坐标、棋子纵坐标,然后由程序模拟对方用户进行自动操作。落完子后进入下一回合,刚落子的用户便无法操作,需要等待对方落子,继续由服务器进行转发落子信号,在自己的棋盘上落子。这样来回循环直至游戏结束。

    游戏胜利,由胜利的一方的客户端发送数据给服务端,然后服务端根据双方的状态判断用户端是否是真的胜利,若有错则进行纠错处理,发送逻辑出错的error信号。目前五子棋稳定性极高,还没有遇见过出错的情况。

    获胜的一方可以获得大量的积分奖励,游戏胜利后弹出对话框显示结果,并且显示奖励的积分数量。同时原先的头像下方的状态标签变为暗金色的“胜利”二字,对面失败者的状态标签则变成“失败”,并且是惨淡惨淡的灰色。

    失败者也会受到安慰的少量积分,大概是胜利者的三分之一不到。
    游戏结果出来之后,双方各自的操作按钮会继续显示,按钮文字变成“准备下一局”。点击此按钮则重新进入准备状态,红色的“等待开始”,可以进行下一局。
    此时如果有一方离开了游戏桌,那么其状态标签会改成灰色的“对方已离开”,头像也一起隐藏起来。

    除此之外,如果是在游戏途中离开,会询问“当前您正在对战,如果现在退出将会默认对方胜利,并且扣除自己的积分。是否继续?”。点Yes会退出游戏桌,惨淡收场。

    玩家中途退出后,剩下的一方将会立即获得胜利,但不会奖励积分。这是为了避免刷积分引起的操作。放弃掉的一方头像消失,状态变成“对手已放弃”。胜利者恢复到比赛开始的“未准备”状态,等待继续准备。

    6.4 服务端界面服务端主要用于数据存储和数据传输,无需手动干预,故界面仅由两部分组成,一是日志控件,二是调试控件。
    服务端在启动时会读取文件中存储的用户信息:用户ID、昵称、密码、排名,依次添加进一个封装后的UserInfo类,并且使用List构成一个用户数组,包含了所有的用户信息。打印用户数量至日志控件。

    在日志控件下面,是一排水平放置的调试功能的空间布局,分别是游戏桌ID、座位号、发送的数据文本。这片布局仅仅用来开发时进行调试,根据传输的数据和客户端的反应来判断逻辑有没有出错。目前已经完成了其调试的使命,暂时不需要理睬。
    在服务端界面中,可以看到所有传输的数据,例如下图新的客户端进入与登录的XML格式的数据。

    如上图,客户端启动后设置唯一的sessionID给客户端,并且保持连接。同时获取到所有游戏桌的玩家状态,用<T>标签包裹起来,返回给客户端,最后到客户端的游戏大厅中刷新,有人的座位变黑,并且显示相应位置的玩家昵称。
    在注册/登录后获取到账号密码,与用户列表中的信息进行匹配,如果登录成功就返回1,登录失败则返回0。图中的数据是登录成功,于是在<KIND>login</KIND>XML文本中标记了RESULT为1,并且添加上了存储在服务端的用户信息返回给客户端。客户端读取后显示在自己的界面之上展示给用户。

    上图是双方玩家准备完毕后的收发的数据,所有文本皆显示在上面。一个玩家准备,发送结果给游戏桌对面的玩家。如果双方都已经准备好了,则发送<KIND>start</KIND>内容给双方,开始游戏。每一个落子的信号也是封装在一个<KIND>moves</KIND>``文本之中,同时这串文本带有落子的位置,服务端收到落子信号后转发给游戏桌对面的玩家,对面玩家客户端收到信号后游戏界面存放五子棋数据的数据设置相应的位置为对方棋子,然后进入下一轮,即对方落子。接着对方也发送信号过来,继续互相传输落子数据,直至游戏结束。
    七、代码实现此处应该略过,毕竟是 gayhub,自己找源代码吧,注释很多的。
    八、总结总的来说,这次课程设计是做得最顺利的一次了……老师布置了题目之后,就在光棍节的那一天,那一个周末,我闲得无聊,就开始着手做课程设计了。既然都要做,那么就不如直接选个最有趣的吧,于是一眼就看中了棋牌类在线游戏平台。虽然觉得是最难的……但试试又无妨。
    以前已经做了好几次的五子棋,分别是安卓、C、Java,这次恰逢好机会就打算用C++做一个图形化的。而且刚好有空,便开始新建工程。
    虽然有些小意外,比如莫名失效的信号槽机制,我就调试了6个多小时……而且没有任何进展。不过这个应该不是我的锅吧。还有Session,怎么在刚开始连接的时候就知道是哪个用户,连接时好像并不能传送数据,总不能等到传送数据时再进行维护吧,于是想了一会儿,就干脆在新连接进入时增加了一个sessionID,还封装了一个SessionInfo类来进行维护会话列表。这些都很顺利,轻车熟路了。而且QT对Socket的封装真的特别特别友好,多线程什么的完全不需要我考虑,只需要把功能实现就行了。也不会产生阻塞、溢出什么的,实在是太省心了。
    然后一不小心,就差不多完成了。
    多人在线五子棋平台最麻烦的地方就是调试了,服务端只能一直写一直写,写好后再统一运行,出了错误也得重新打开两个客户端慢慢调试。因为debug机制只能调试一个客户端,干脆就直接在服务端输出调试的日志了,显示数据传输的所有内容,顺带还打印log。
    再加上了伪造发送数据的调试控件组,就是手动写数据发送给客户端,这样就能知道客户端的状况,以及跳过了数据发送出现的更加容易出现bug的隐患。这个调试的方法应该算是比较新颖的吧,而且确实非常好用呢。
    时间比较仓促,因为还有好几个项目要赶,就花了匆匆的两天时间大概24小时吧。除去无用的找框架bug的时间,粗略估计约15个小时。没有好好地修改界面,看起来界面会比较丑,但是无伤大雅,能看就好。等以后有空了再好好地修改界面,让它能够发布出去,给其他人尝尝鲜。
    虽然除了QT的socket用法以外,我并没有学到多少其他知识,但是也增加了一些开发经历,算是有不小的收获吧。
    九、服务器服务端主要用于数据存储和数据传输,无需手动干预,故界面仅由两部分组成,一是日志控件,二是调试控件。
    服务端在启动时会读取文件中存储的用户信息:用户ID、昵称、密码、排名,依次添加进一个封装后的UserInfo类,并且使用List构成一个用户数组,包含了所有的用户信息。打印用户数量至日志控件。

    在日志控件下面,是一排水平放置的调试功能的空间布局,分别是游戏桌ID、座位号、发送的数据文本。这片布局仅仅用来开发时进行调试,根据传输的数据和客户端的反应来判断逻辑有没有出错。目前已经完成了其调试的使命,暂时不需要理睬。
    在服务端界面中,可以看到所有传输的数据,例如下图新的客户端进入与登录的XML格式的数据。

    如上图,客户端启动后设置唯一的sessionID给客户端,并且保持连接。同时获取到所有游戏桌的玩家状态,用<T>标签包裹起来,返回给客户端,最后到客户端的游戏大厅中刷新,有人的座位变黑,并且显示相应位置的玩家昵称。
    在注册/登录后获取到账号密码,与用户列表中的信息进行匹配,如果登录成功就返回1,登录失败则返回0。图中的数据是登录成功,于是在<KIND>login</KIND>XML文本中标记了RESULT为1,并且添加上了存储在服务端的用户信息返回给客户端。客户端读取后显示在自己的界面之上展示给用户。

    上图是双方玩家准备完毕后的收发的数据,所有文本皆显示在上面。一个玩家准备,发送结果给游戏桌对面的玩家。如果双方都已经准备好了,则发送<KIND>start</KIND>内容给双方,开始游戏。每一个落子的信号也是封装在一个<KIND>moves</KIND>文本之中,同时这串文本带有落子的位置,服务端收到落子信号后转发给游戏桌对面的玩家,对面玩家客户端收到信号后游戏界面存放五子棋数据的数据设置相应的位置为对方棋子,然后进入下一轮,即对方落子。接着对方也发送信号过来,继续互相传输落子数据,直至游戏结束。
    2 评论 17 下载 2019-08-22 07:14:37 下载需要13点积分
  • 基于winpcap的网络嗅探器设计与实现

    第一章 摘要随着网络的普及和网络技术的发展,网络已经成为了人们日常生活和工作中不可获缺的一部分,越来越多的信息和资源放到了互联网上,网络的安全性和可靠性变得越来越重要,因此,对于能够分析、诊断网络,测试网络性能与安全性的工具软件的需求也越来越迫切。网络嗅探器作为一个使用WinPcap开发包,嗅探流过网卡的数据并智能分析过滤,快速找到所需要的网络信息的工具,成为了人们获取、分析数据包的主要工具,网络嗅探器具有两面性,攻击者可以用它来监听网络中数据,达到非法获得信息的目的,网络管理者可以通过使用嗅探器捕获网络中传输的数据包并对其进行分析,分析结果可供网络安全分析之用。
    本设计的基本任务是设计一个嗅探软件,实现对常用网络数据包抓取、分析。
    软件所要完成对本机在网络中的通信数据,比如协议类型,源、目的地址和端口、数据包的大小等加以分析的功能。
    本设计用到的开发工具为Microsoft Visual Studio 2010 开发环境为Windows 7/Windows XP。
    关键字:网络嗅探器,数据报文,数据包,捕捉,分析
    第二章 开发背景2.1 网络安全现状随着各种新的网络技术的不断出现、应用和发展,计算机网络的应用越来越广泛,其作用也越来越重要。但是由于计算机系统中软硬件的脆弱性和计算机网络的脆弱性以及地理分布的位置、自然环境、自然破坏以及人为因素的影响,不仅增加了信息存储、处理的风险,也给信息传送带来了新的问题。计算机网络安全问题越来越严重,网络破坏所造成的损失越来越大。Internet 的安全已经成为亟待解决的问题。多数黑客入侵成功并植入后门后的第一件事就是选择一个合适当前网络的嗅探器,以获得更多的受侵者的信息。嗅探器是一种常用的收集有用数据的方法,可以作为分析网络数据包的设备。网络嗅探器就是利用计算机的网络接口截获其他计算机的数据报文的一种工具,而且它与一般的键盘捕获程序不同。键盘捕获程序捕获在终端上输入的键值,而嗅探器捕获的则是真实的网络报文.如果把网络嗅探器放置于网络节点处,对网络中的数据帧进行捕获的一种被动监听手段,是一种常用的收集有用数据的方法,可以分析各种信息包并描述出网络的结构和使用的机器,由于它接收任何一个在同一网段上传输的数据包,所以也就存在着捕获密码、各种信息、秘密文档等一些没有加密的信息的可能性。这成为黑客们常用的扩大战果的方法,用来夺取其他主机的控制权。当然嗅探器的正当用处主要是网络管理人员分析网络的流量,以便找出所关心的网络中潜在的问题。
    2.2 开发意义本次设计只是对抓取到的本机在网络中的通信数据,比如说协议类型,源、目的地址和端口、数据包的大小等加以分析,而无法做到像Sniffer 或者影音神探那种成熟的嗅探器所拥有的强大功能。作为从事网络技术方面的人员来说,要想有效地利用它、防范它,就得深入地学习、分析网络嗅探技术。最为重要的是,对于网络嗅探器的设计与实现,使我对网络通信,数据传输和网络信息安全等有了切身的体会与融入,同时也是对网络安全技术这门课的学以致用,不断提高自我的一种有效途径。
    第三章 设计分析3.1 实现目标
    实现网络嗅探器的界面。
    实现抓取数据包的功能。
    实现暂停抓取数据包功能。
    实现清空列表功能。

    3.2 开发技术简介3.2.1 TCP/IP协议分析TCP/IP 是供已连接因特网的计算机进行通信的通信协议。
    TCP/IP 定义了电子设备(比如计算机)如何连入因特网,以及数据如何在它们之间传输的标准。
    TCP/IP是一个四层的分层体系结构。高层为传输控制协议,它负责聚集信息或把文件拆分成更小的包。这些包通过网络传送到接收端的TCP层,接收端的TCP层把包还原为原始文件。低层是网际协议,它处理每个包的地址部分,使这些包正确的到达目的地。网络上的网关计算机根据信息的地址来进行路由选择。即使来自同一文件的分包路由也有可能不同,但最后会在目的地汇合。 TCP/IP使用客户端/服务器模式进行通信。TCP/IP通信是点对点的,意思是通信是网络中的一台主机与另一台主机之间的。TCP/IP与上层应用程序之间可以说是“没有国籍的”,因为每个客户请求都被看做是与上一个请求无关的。正是它们之间的“无国籍的”释放了网络路径,才是每个人都可以连续不断的使用网络。 许多用户熟悉使用TCP/IP协议的高层应用协议。
    众所周知,如今电脑上因特网都要作TCP/IP协议设置,显然该协议成了当今地球村“人与人”之间的“牵手协议”。 通俗而言:TCP负责发现传输的问题,一有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地。而IP是给因特网的每一台电脑规定一个地址。1974年12月,卡恩、瑟夫的第一份TCP协议详细说明正式发表。当时美国国防部与三个科学家小组签定了完成TCP/IP的协议,结果由瑟夫领衔的小组捷足先登,首先制定出了通过详细定义的TCP/IP协议标准。当时作了一个试验,将信息包通过点对点的卫星网络,再通过陆地电缆,再通过卫星网络,再由地面传输,贯串欧洲和美国,经过各种电脑系统,全程9.4万公里竟然没有丢失一个数据位,远距离的可靠数据传输证明了TCP/IP协议的成功。
    1983年1月1日,运行较长时期曾被人们习惯了的NCP被停止使用,TCP/IP协议作为因特网上所有主机间的共同协议,从此以后被作为一种必须遵守的规则被肯定和应用。正是由于TCP/IP协议,才有今天“地球村”因特网的巨大发展。
    以下简单介绍TCP/IP中的协议都具备什么样的功能,都是如何工作的:
    3.2.1.1 IPIP层接收由更低层(网络接口层例如以太网设备驱动程序)发来的数据包,并把该数据包发送到更高层—-TCP或UDP层;相反,IP层也把从TCP或UDP层接收来的数据包传送到更低层。IP数据包是不可靠的,因为IP并没有做任何事情来确认数据包是按顺序发送的或者没有被破坏。IP数据包中含有发送它的主机的地址(源地址)和接收它的主机的地址(目的地址)。高层的TCP和UDP服务在接收数据包时,通常假设包中的源地址是有效的。也可以这样说,IP地址形成了许多服务的认证基础,这些服务相信数据包是从一个有效的主机发送来的。IP确认包含一个选项,叫做IP source routing,可以用来指定一条源地址和目的地址之间的直接路径。对于一些TCP和UDP的服务来说,使用了该选项的IP包好像是从路径上的最后一个系统传递过来的,而不是来自于它的真实地点。这个选项是为了测试而存在的,说明了它可以被用来欺骗系统来进行平常是被禁止的连接。那么,许多依靠IP源地址做确认的服务将产生问题并且会被非法入侵。
    3.2.1.2 TCP如果IP数据包中有已经封好的TCP数据包,那么IP将把它们向‘上’传送到TCP层。TCP将包排序并进行错误检查,同时实现虚电路间的连接。TCP数据包中包括序号和确认,所以未按照顺序收到的包可以被排序,而损坏的包可以被重传。
    TCP将它的信息送到更高层的应用程序,例如Telnet的服务程序和客户程序。应用程序轮流将信息送回TCP层,TCP层便将它们向下传送到IP层,设备驱动程序和物理介质,最后到接收方。
    3.2.1.3 UDPUDP与TCP位于同一层,但它不管数据包的顺序、错误或重发。因此,UDP不被应用于那些使用虚电路的面向连接的服务,UDP主要用于那些面向查询—-应答的服务,例如NFS。相对于FTP或Telnet,这些服务需要交换的信息量较小。使用UDP的服务包括NTP(网络时间协议)和DNS(DNS也使用TCP)。
    3.2.1.4 ICMPICMP与IP位于同一层,它被用来传送IP的控制信息。它主要是用来提供有关通向目的地址的路径信息。ICMP的‘Redirect’信息通知主机通向其他系统的更准确的路径,而‘Unreachable’信息则指出路径有问题。另外,如果路径不可用,ICMP可以使TCP连接‘体面地’终止。PING是最常用的基于ICMP的服务。
    3.2.2 数据包简介包是TCP/IP协议通信中的基本的数据单位之一,一般也叫数据包。
    必须把内装产品的包装盒放到一个邮局指定的专用纸箱里,这样才能够邮寄。这里,产品包装盒相当于数据包,里面放着的产品相当于可用的数据,而专用纸箱就相当于帧,且一个帧中只有一个数据包。 “包”听起来非常抽象,那么是不是不可见的呢?通过一定技术手段,是可以感知到数据包的存在的。
    通过数据包捕获软件,也可以将数据包捕获并加以分析。就是用网络嗅探器捕获数据包,可以查看捕获到的数据包的 MAC 地址、IP 地址、协议类型端口号等细节。通过分析这些数据,网管员就可以知道网络中到底有什么样的数据包在活动了。数据包的结构非常复杂,不是三言两语能够说清的,在这里主要了解一下它的关键构成就可以了,这对于理解TCP/IP 协议的通信原理是非常重要的。数据包主要由“目的IP 地址”、“源IP 地址”、“净载数据” 等部分构成。 数据包的结构与我们平常写信非常类似,目的IP 地址是说明这个数据包是要发给谁的,相当于收信人地址;源IP 地址是说明这个数据包是发自哪里的,相当于发信人地址;而净载数据相当于信件的内容。 正是因为数据包具有这样的结构,安装了 TCP/IP 协议的计算机之间才能相互通信。我们在使用基于TCP/IP 协议的网络时,网络中其实传递的就是数据包。比如说当你上网打开网页,这个简单的动作,就是你先发送数据包给网站,它接收到了之后,根据你发送的数据包的 IP 地址,返回给你网页的数据包,也就是说,网页的浏览,实际上就是数据包的交换。理解数据包,对于网络管理的网络安全具有至关重要的意义。
    3.2.3 C++语言简介C++程序设计语言是由来自AT&T Bell Laboratories的Bjarne Stroustrup(即本文作者)设计和实现的,它兼具Simula语言在组织与设计方面的特性以及适用于系统程序设计的C语言设施。C++最初的版本被称作“带类的C(C with classes)” [Stroustrup,1980],在1980年被第一次投入使用;当时它只支持系统程序设计(§3)和数据抽象技术(§4.1)。支持面向对象程序设计的语言设施在1983年被加入C++;之后,面向对象设计方法和面向对象程序设计技术就逐渐进入了C++领域。在1985年,C++第一次投入商业市场[Stroustrup,1986][Stroustrup,1986b]。在1987至1989年间,支持范型程序设计的语言设施也被加进了C++[Ellis,1990][Stroustrup,1991]。
    C++的一个目标就是提供更易用并具有一定承受能力的设计思想和程序设计技术,进一步提高程序的质量。这些技术中的绝大部分都源自Simula [Dahl,1970][Dahl,1972][Birtwistle,1979],并通常被作为面向对象程序设计和面向对象设计思想来讨论。然而,C++的设计目标总还是在于要支持一定范围内的各种程序设计风格和设计思想。这与一般在语言设计方面的观点形成一定对比。一般在语言设计上总是试图将所有系统内建于单独一个被重点支持的、带有强制性的程序设计风格之中(或称典范paradigm)。
    3.2.4 嗅探技术简介数据在网络上是以很小的称为帧(Frame)的单位传输的,帧由几部分组成,不同的部分执行不同的功能。帧通过特定的称为网络驱动程序的软件进行成型,然后通过网卡发送到网线上,通过网线到达它们的目的机器,在目的机器的一端执行相反的过程。接收端机器的以太网卡捕获到这些帧,并告诉操作系统帧已到达,然后对其进行存储。就是在这个传输和接收的过程中,存在安全方面的问题。
    每一个在局域网(LAN)上的工作站都有其硬件地址,这些地址惟一地表示了网络上的机器(这一点与Internet 地址系统比较相似)。当用户发送一个数据包时,这些数据包就会发送到LAN 上所有可用的机器。
    在一般情况下,网络上所有的机器都可以“听”到通过的流量,但对不属于自己的数据包则不予响应(换句话说,工作站A 不会捕获属于工作站B 的数据,而是简单地忽略这些数据)。
    嗅探器工作在网络的底层,在网络上监听数据包来获取敏感信息。从原理上来说,在一个实际的系统中,数据的收发是由网卡来完成的,网卡接收到传输来的数据,网卡内的单片程序接收数据帧的目的MAC 地址,根据计算机上的网卡驱动程序设置的接收模式判断该不该接收,认为该接收就接收后产生中断信号通知CPU,认为不该接收就丢掉不管,所以不该接收的数据网卡就截断了,计算机根本就不知道。对于网卡来说一般有四种接收模式:

    广播方式:该模式下的网卡能够接收网络中的广播信息。
    组播方式:设置在该模式下的网卡能够接收组播数据。
    直接方式:在这种模式下,只有目的网卡才能接收该数据。
    混杂模式:在这种模式下的网卡能够接收一切通过它的数据,而不管该数据是否是传给它的。

    首先,在以太网中是基于广播方式传送数据的,也就是说,所有的物理信号都要经过我的机器。其次,如果某个工作站的网络接口处于混杂模式,那么它就可以捕获网络上所有的数据包和帧。
    Sniffer 程序是一种利用以太网的特性把网络适配卡(NIC,一般为以太网卡)置为混杂模式状态的工具,一旦网卡设置为这种模式,它就能接收传输在网络上的每一个信息包, 而不管该数据是否传给它的。
    第四章 嗅探器4.1 嗅探器设计原理嗅探器作为一种网络通讯程序,也是通过对网卡的编程来实现网络通讯的,对网卡的编程也是使用通常的套接字(socket)方式来进行。但是,通常的套接字程序只能响应与自己硬件地址相匹配的或是以广播形式发出的数据帧,对于其他形式的数据帧比如已到达网络接口但却不是发给此地址的数据帧,网络接口在验证投递地址并非自身地址之后将不引起响应,也就是说应用程序无法收取到达的数据包。而网络嗅探器的目的恰恰在于从网卡接收所有经过它的数据包,这些数据包即可以是发给它的也可以是发往别处的。显然,要达到此目的就不能再让网卡按通常的正常模式工作,而必须将其设置为混杂模式。
    嗅探器最初由 Network General 推出,由 Network Associates 所有。最近,Network Associates 决定另开辟一个嗅探器产品单元,该单元组成一家私有企业并重新命名为 Network General,如今嗅探器已成为 Network General 公司的一种特征产品商标
    4.2 网络技术与设备简介数据在网络上是以很小的称为帧(Frame)的单位传输的,帧由几部分组成,不同的部分执行不同的功能。帧通过特定的称为网络驱动程序的软件进行成型,然后通过网卡发送到网线上,通过网线到达它们的目的机器,在目的机器的一端执行相反的过程。接收端机器的以太网卡捕获到这些帧,并告诉操作系统帧已到达,然后对其进行存储。就是在这个传输和接收的过程中,存在安全方面的问题。
    每一个在局域网(LAN)上的工作站都有其硬件地址,这些地址惟一地表示了网络上的机器。当用户发送一个数据包时,这些数据包就会发送到LAN上所有可用的机器。
    在一般情况下,网络上所有的机器都可以“听”到通过的流量,但对不属于自己的数据包则不予响应(换句话说,工作站A不会捕获属于工作站B的数据,而是简单地忽略这些数据)。如果某个工作站的网络接口处于混杂模式,那么它就可以捕获网络上所有的数据包和帧。
    网络监听原理
    Sniffor程序是一种利用以太网的特性把网络适配卡(NIC,一般为以太网卡)置为杂乱(promiscuous)模式状态的工具,一旦网卡设置为这种模式,它就能接收传输在网络上的每一个信息包。 普通的情况下,网卡只接收和自己的地址有关的信息包,即传输到本地主机的信息包。要使Sniffer能接收并处理这种方式的信息,系统需要支持 BPF,Linux下需要支持SOCKET-PACKET。但一般情况下,网络硬件和TCP/IP堆栈不支持接收或者发送与本地计算机无关的数据包,所以,为了绕过标准的TCP/IP堆栈,网卡就必须设置为混杂模式。一般情况下,要激活这种方式,内核必须支持这种伪设备BPFilter,而且需要root权限来运行这种程序,所以Sniffer需要root身份安装,如果只是以本地用户的身份进入了系统,那么不可能嗅探到root的密码,因为不能运行Sniffer。
    基于Sniffer这样的模式,可以分析各种信息包并描述出网络的结构和使用的机器,由于它接收任何一个在同一网段上传输的数据包,所以也就存在着捕获密码、各种信息、秘密文档等一些没有加密的信息的可能性。这成为黑客们常用的扩大战果的方法,用来夺取其他主机的控制权。
    4.3 网络监听的目的当一个黑客成功地攻陷了一台主机,并拿到了root权限,而且还想利用这台主机去攻击同一网段上的其他主机时,他就会在这台主机上安装Sniffer软件,对以太网设备上传送的数据包进行侦听,从而发现感兴趣的包。如果发现符合条件的包,就把它存到一个LOG文件中去。通常设置的这些条件是包含字“username”或“password”的包,这样的包里面通常有黑客感兴趣的密码之类的东西。一旦黑客截获得了某台主机的密码,他就会立刻进入这台主机。
    Sniffer除了能得到口令或用户名外,还能得到更多的其他信息,比如一个重要的信息、在网上传送的金融信息等等。Sniffer几乎能得到任何在以太网上传送的数据包。
    Sniffer是一种比较复杂的攻击手段,一般只有黑客老手才有能力使用它,而对于一个网络新手来说,即使在一台主机上成功地编译并运行了 Sniffer,一般也不会得到什么有用的信息,因为通常网络上的信息流量是相当大的,如果不加选择地接收所有的包,然后从中找到所需要的信息非常困难;而且,如果长时间进行监听,还有可能把放置Sniffer的机器的硬盘撑爆。
    这种对网卡混杂模式的设置是通过原始套接字(raw socket)来实现的,这也有别于通常经常使用的数据流套接字和数据报套接字。在创建了原始套接字后,需要通过setsockopt()函数来设置IP头操作选项,然后再通过bind()函数将原始套接字绑定到本地网卡。为了让原始套接字能接受所有的数据,还需要通过ioctlsocket()来进行设置,而且还可以指定是否亲自处理IP头。至此,实际就可以开始对网络数据包进行嗅探了,对数据包的获取仍象流式套接字或数据报套接字那样通过recv()函数来完成。但是与其他两种套接字不同的是,原始套接字此时捕获到的数据包并不仅仅是单纯的数据信息,而是包含有 IP头、 TCP头等信息头的最原始的数据信息,这些信息保留了它在网络传输时的原貌。通过对这些在低层传输的原始信息的分析可以得到有关网络的一些信息。由于这些数据经过了网络层和传输层的打包,因此需要根据其附加的帧头对数据包进行分析。
    4.4 数据包、TCP、IP的结构数据包的总体结构:

    数据在从应用层到达传输层时,将添加TCP数据段头,或是UDP数据段头。其中UDP数据段头比较简单,由一个8字节的头和数据部分组成,具体格式如下:

    而TCP以20个固定字节开始,在固定头后面还可以有一些长度不固定的可选项,下面给出TCP数据段头的格式组成:

    对于此TCP数据段头的分析在编程实现中可通过TCPPacket来定义:
    #if !defined(AFX_TCPPACKET_H__8EC6C630_C16F_446F_9A03_E86E99A89BE4__INCLUDED_)#defineAFX_TCPPACKET_H__8EC6C630_C16F_446F_9A03_E86E99A89BE4__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000class CTCPPacket {public: CTCPPacket(); virtual ~CTCPPacket(); CTCPPacket(unsigned char *buf,int buflen);private: int m_nSrcPort;//源端口 int m_nDestPort;//目的端口 unsigned int m_uSeqNum;//顺序号 unsigned int m_uAckNum;//确认号 int m_nHeadLen;//头部长 bool m_bURG;//为1表示使用紧急指针 bool m_bACK;//为1表示确认号合法 bool m_bPSH;//表示带有PUSH标志的数据 bool m_bRST;//用于主机崩溃或其他原因后的复位 bool m_bSYN;//用于建立连接 bool m_bFIN;//用于释放连接 int m_nWindowSize;//窗口大小 int m_nCheckSum;//校验和 int m_nUrgPos;//紧急指针,从当前顺序号到紧急数据位置偏移量 int m_nOptLen;//选项长度 unsigned char *m_pOptions; int m_nDataLen; unsigned char *m_pData;public: CString GetSrcPort(); CString GetDestPort(); CString GetSeqNum();//顺序号 CString GetAckNum();//确认号 CString GetHeadLen();//头部长 CString GetURG();//为1表示使用紧急指针 CString GetACK();//为1表示确认号合法 CString GetPSH();//表示带有PUSH标志的数据 CString GetRST();//用于主机崩溃或其他原因后的复位 CString GetSYN();//用于建立连接 CString GetFIN();//用于释放连接 CString GetWindowSize();//窗口大小 CString GetCheckSum();//校验和 CString GetUrgPos();//紧急指针,从当前顺序号到紧急数据位置偏移量 CString GetOptLen();//选项长度 CString GetOptions();//选项值 CString GetDataLen();//数据长度 CString GetData();//数据值private: CString GetStr(unsigned int nNum,unsigned char * pData = NULL,bool nFlag = true); CString GetBool(bool nFlag);};#endif // !defined(AFX_TCPPACKET_H__8EC6C630_C16F_446F_9A03_E86E99A89BE4__INCLUDED_)
    在网络层,还要给TCP数据包添加一个IP数据段头以组成IP数据报。IP数据头以大端点机次序传送,从左到右,版本字段的高位字节先传输。
    IP数据段头格式如下:

    同样,在实际编程中也要用一个IPPacket来表示此IP数据段头,下面给出此数据结构的定义:
    #if !defined(AFX_IPPACKET_H__E7869A50_D11B_487D_807D_657E4C3D2A97__INCLUDED_)#define AFX_IPPACKET_H__E7869A50_D11B_487D_807D_657E4C3D2A97__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000class CIPPacket {public: CIPPacket(); CIPPacket(const unsigned char* buf,int buflen); virtual ~CIPPacket();private: int m_nVersion; //版本 int m_nHeaderLength; //头部长度 int m_nServiceType; //服务类型 type of service int m_nPrecedence; //优先级 bool m_bDelay; //延迟 bool m_bThroughtPut; //吞吐量 bool m_bReliability; //可靠性 unsigned int m_uTotalLength; //总长total length int m_nIdentification; //标识 bool m_bDF; //不要分段 bool m_bMF; //还有进一步的分段 int m_nFragOffSet; //分段偏移fragment offset int m_nTTL; //生命期time to live int m_nProtocol; //协议,如TCP,UDP unsigned int m_nCheckSum; //头部校验和 long m_lSrcIP; //源IP地址 long m_lDestIP; //目的IP地址 int m_nOptLength; //选项长度 unsigned char *m_pOptions; //选项内容 int m_nDataLength; //数据长度 unsigned char *m_pData; //数据内容public: CString GetProtocol(); CString GetDestIP(); CString GetSrcIP(); unsigned char* GetTData(); int GetDataLength(); CString GetVersion(); //版本 CString GetHeaderLength(); //头部长度 CString GetServiceType(); //服务类型 type of service CString GetPrecedence(); //优先级 CString GetDelay(); //延迟 CString GetThroughtPut(); //吞吐量 CString GetReliability(); //可靠性 CString GetTotalLength(); //总长total length CString GetIdentification(); //标识 CString GetDF(); //不要分段 CString GetMF(); //还有进一步的分段 CString GetFragOffSet(); //分段偏移fragment offset CString GetTTL(); //生命期time to live CString GetCheckSum(); //头部校验和 CString GetOptLength(); //选项长度 CString GetOptions(); //选项内容 CString GetDLength(); //数据长度private: CString GetInt(int nNum); CString GetBool(bool nBool);};#endif // !defined(AFX_IPPACKET_H__E7869A50_D11B_487D_807D_657E4C3D2A97__INCLUDED_)
    第五章 实验过程截图嗅探器在嗅探之前

    网卡配置

    嗅探以后

    文件导出

    第六章 结束语通过两周的奋斗,终于将我的课程设计终于完成了,我觉得这使得自己的独立应用能力得到了明显的提高。在没有做课程设计以前觉得课程设计只是对这几年来所学知识的单纯总结,但是通过这次做课程设计发现自己的看法有点太片面。课程设计不仅是对前面所学知识的一种检验,而且也是对自己能力的一种提高。通过这次课程设计使我明白了自己原来知识还比较欠缺。自己要学习的东西还太多,以前老是觉得自己什么东西都会,什么东西都懂,有点眼高手低。通过这次课程设计,我才明白学习是一个长期积累的过程,在以后的工作、生活中都应该不断的学习,努力提高自己知识和综合素质。
    课程设计结束后,我发现理论和实践之间还是存在一定的差距,要把理论知识灵活运用于实践才是最好的,因此我也希望学校能多给我们提供一些实践的机会在设计的过程中遇到的问题,可以说得是困难重重,由于自己的实践机会稀少,因此这次在设计的过程中,难免会遇到过各种各样的问题,同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固等等。经过这次的课程设计我会在以后的时间里努力的学习一些课外的知识不能仅仅局限在课堂上。通过这次设计我在学会独立思考的同时,更懂得了要虚心向同学请教,这样可以达到事半功倍的效果。在具体编程实现系统功能的过程中,我遇到了不少的问题,我曾通过不同渠道向老师、同学、上相关网站、到bbs论坛寻求答案,收到了很好的效果,再者,我希望通过这次的课程设计,能够对我以后的理论联系实际等方面起到积极的促进作用,让我以后拒绝眼高手低的坏毛病,让自己学习的理论应用到实际生活中去,以便能够为社会做出自己应有的贡献。
    在此要感谢我们的指导老师对我悉心的指导,感谢老师给我们的帮助和鼓励,正是有了您的帮助,才使得我少走了许多弯路;由于自己在设计的过程中在知识、经验方面都存在着不足,另外,由于学校元旦放假的原因,自己不得不修改了原来的计划,使得时间安排的不是非常合理,致使该课程设计必然会存在一些缺陷和不足。希望可以得到老师和同学们宝贵的建议。
    第七章 参考文献
    《C/C++程序设计学习辅导》中国水利水电出版社 李婷, 李云峰编著
    《C++面向对象程序设计》清华大学出版社 (美) 萨维奇 (Walter Savitch)著
    《TCP/IP协议分析与应用》机械工业出版社 杨延双, 张建标, 王全民编著 百度百科:TCP/IP 协议分析、嗅探技术、数据包、C++
    《网络信息安全》清华大学出版社 安葳鹏, 刘沛骞主编
    《计算机网络安全技术》王群 编著
    3 评论 107 下载 2019-02-08 10:28:08 下载需要13点积分
  • 基于QT和UDP Socket实现的即时通信软件

    摘 要随着计算机应用技术的快速发展和日益普及,网络也遍及到我们生活的每个角落,为我们的学习和工作带来极大的方便。现很多人都使用网络通讯软件来进行聊天、交流,这种软件极大地缩短了人与人之间的沟通距离,使人们能够随时随地的进行交流。因此,一个即时通讯软件的设计是有必要的。
    而本设计是基于Qt的开发平台上开发的一款即时通讯软件,通过网络编程SOCKET函数以实现同局域网内的文字传输。
    关键词:通讯软件;网络编程;文字传输
    第一章 设计内容设计一个类似QQ的聊天软件,实现在同一局域网内不同用户之间的即时通信,程序具体功能有:

    sqlite3数据库插入用户表
    登录界面:数据库验证登录
    用户主界面:数据库匹配用户好友列表
    聊天界面:在同一局域网内采用UDP的方式实现即时通信
    聊天记录以文件“.txt”的形式保存

    第二章 总体设计2.1 模块化设计为实现系统功能,本程序主要分为四个模块。他们分别是:登录界面、用户主界面、好友列表界面、聊天界面。这四个模块是通过主函数实例化一个不显示的空用户主界面,在用户主界面的构造函数里还会实例化一个登录界面,当登录界面用户登录成功后,用户主界面转为显示状态并更新登录的用户信息(显示登录账号,更新用户好友列表),双击对应好友就可弹出聊天窗口,实现即时聊天。
    主函数(main)
    // 实例化用户主界面MainWindowmainwin
    登录界面类(logonscreen)
    // 构造函数LogonScreen(QWidget *parent = 0); // 创建数据库连接createConnection(); // 创建用户表,添加可登陆用户createTable();// 查询用户表,显示所有用户selectTable(); // 验证登录信息verify(const Qstring, const QString); // 登录按键的槽on_pushButton_login_clicked(); // 退出按键的槽on_pushButton_close_clicked(); // 自定义用户登录信号,向用户主界面传输当前登录账号值user_signal(QString value);
    用户主界面类(mainwindow)
    // 构造函数MainWindow(QWidget *parent = 0);// 创建数据库连接createConnection();// 匹配用户好友,更新好友列表matchUserFriend(); // 注销按钮的槽,返回登录界面on_pushButton_quit_clicked();// 获取用户登录信号响应的槽getUserValue(QString value); // 鼠标移动事件,单击移动界面mouseMoveEvent(QMouseEvent *event);
    好友列表界面类(userwidget)
    // 原构造函数userwidget(QWidget *parent = 0);// 构造函数的重载userwidget(int receive_port,QString send_ip ,int send_port,QString send_account,QWidget *parent = 0); // 鼠标双击事件mouseDoubleClickEvent(QMouseEvent *event);
    聊天界面类(chatwindow)
    // 原构造函数ChatWindow(QWidget *parent = 0); // 构造函数的重载ChatWindow(int receive_port,QString send_ip,int send_port,QString send_account,QWidget *parent = 0);// 键盘按下事件(ctrl+Enter)keyPressEvent(QKeyEvent *event); // 键盘释放事件keyReleaseEvent(QKeyEvent *event); // udp数据报接收processPendingDatagram(); // 发送按钮的槽,发送udp数据报on_pushButton_send_clicked(); // 关闭按钮的槽,关闭窗口on_pushButton_close_clicked(); // 聊天记录按钮的槽,显示隐藏的界面on_pushButton_chatdata_toggled(bool checked);
    2.2 程序运行示意图
    第三章 详细设计3.1 登录界面设计3.1.1 登录界面UI设计
    3.1.2 登录界面类设计在登录界面类的构造函数里,会做连接sqlite3数据库,创建用户表和查询用户表并显示查询结果于调试窗口的操作。当用户在登录界面输入账号时,就会触发QT的自动补全功能(QCompleter),补全内容为在查询用户表时记录的用户账号(QStringList),方便用户输入体验。当用户输入密码时,lineEdit_password里的值会以密码的形式显示(setEchoMdoe)。用户键入完成,点击登录按钮,调试窗口显示键入内容,并调用verify(account, password)函数,把键入的账号密码作为数据库查询的where条件。如果查询结果存在,则发送accept()信号允许登录,并且还会发送一个自定义的emit user_signal(account)信号给用户主界面,传入当前登录账号值,作为主界面更新该用户好友列表的判断依据;否则,弹出一个dialog提示账号或密码错误。
    3.2 用户主界面设计3.2.1 用户主界面UI设计
    3.2.2 用户主界面类设计当实例化用户主界面时,主界面是不会show() 出来的,用户主界面类构造函数首先会实例化一个登录界面类的指针对象。然后,关联(connect)这个对象的自定义信号user_signal(account),使用户主界面收到这个信号时,能转到槽getUsrValue(QString),获取信号传进来的当前登录账号值。接着,显示登录界面,等待用户在登录界面的操作。最后,用户主界面会等待登录界面的用户登录成功后的Accepted信号,如果收到Accepted信号,主界面show() 出来,并且调用matchUserFriend()函数,匹配当前登录账号的好友列表。
    更新好友列表的功能实现是通过在用户主界面的toolBox部件的page_friend里添加一个垂直布局(QBoxLayout),然后在matchUserFriend()函数里查询数据库里的用户表,查到一个好友则在垂直布局里实例化一个QT设计师类userwidget的指针对象。
    3.3 好友列表界面设计3.3.1 好友列表UI界面
    3.3.2 好友列表类设计这个类是在用户主界面matchUserFriend()函数里实例化使用的,结果是会在用户主界面的toolBox部件里的好友列表显示出来。因为要实现鼠标双击这个类(好友)就会弹出和这个好友的聊天窗口。所以这时候就需要考虑这个聊天窗口的接收UDP数据报的绑定端口和发送UDP数据报的目标IP、目标端口。为要解决这个问题,我这个类使用了构造函数的重载,在实例化该类的过程中同时传入接收端口、发送目标IP、发送目标端口和发送目标的名字。
    好友列表类重载的构造函数主要做记录传入接收端口、发送目标IP、发送目标端口和发送目标的账号,并根据传进来的发送目标的账号从QT资源文件里查找对应的头像、昵称和签名。最后在鼠标双击事件里再用同样的方法把这些值传进聊天窗口界面。
    3.4 聊天界面设计3.4.1 聊天界面UI设计
    3.4.2 聊天界面类设计聊天界面类重载的构造函数,首先记录从好友列表类传进来的接收端口、发送目标IP、发送目标端口和发送目标的账号。然后隐藏聊天记录的textEdit部件,调整窗口的大小。最后绑定接收UDP数据包的端口和IP,关联QudpSocket::readyRead信号,当收到UDP数据报时,触发槽processPendingDatagram(),使收到的数据显示在listWidget上,并写入名为发送对象的txt文件里作为聊天记录保存起来。
    发送按钮的槽函数,把当前时间(QDateTime::currentDateTime())和发送内容里(textEdit里面的数据)一起以UDP数据报发送出去,同时也写入到对应txt文件里面。
    聊天记录按钮的槽函数,点击聊天记录按钮,检查按钮当前状态,如果按钮checked值为true,则显示隐藏的textEdit,并重新调整聊天界面大小,textEdit里面的值为从对应txt文件里读取的全部内容。
    第四章 调试与测试4.1 调试过程中的主要问题
    用户登录成功后,登录界面类的当前登录值怎么传进用户主界面?
    最后的解决方法是在用户主界面实例化登录界面指针对象,然后使用信号和槽传输登录账号值。
    用户主界面收到登录界面发来的信号后,已经知道当前登录账号了,怎么在该用户好友列表显示出来?
    最后的解决办法是新建QT设计师类(好友列表类),查询数据库,查到一个实例化一个好友列表类指针对象到toolBox部件里的垂直布局里。
    鼠标双击好友列表里的一个好友,弹出聊天窗口,聊天窗口的UDP数据报的接收端口和发送IP、发送端口的值怎么获取?
    最后解决办法是通过构造函数的重载,在实例化的过程中传进对应参数。

    4.2 具体测试过程4.2.1 登录界面
    4.2.2 用户主界面
    4.2.3 聊天界面

    5 心得体会通过这次课程设计,我学会了使用Qt制作一个简易的聊天工具,学到了Qt的UI布局、数据库操作、多界面的切换、信号与槽、socket编程、UDP通讯以及文件操作等,希望以后能进一步的深造学习。
    参考文献[1] 陈维兴 林小茶, C++面向对象程序设计教程(第3版). 北京: 清华大学出版社, 2009年5月
    [2] 闫锋欣 曾泉人 张志强 译, C++ GUI Qt4 编程(第2版). 电子工业出版社, 2013年5月
    [3] 金大颐 翻译:张红艳, Qt5开发实践. 北京: 人民邮电出版社, 2015年9月
    3 评论 107 下载 2018-12-13 09:32:25 下载需要12点积分
  • 基于MFC的飞机大战小游戏

    1 概述飞机大战游戏(Plane Game)是在Microsoft Visual Studio编程软件的MFC环境下制作的一款桌面游戏,界面简洁流畅、游戏方式简单。
    主要功能:

    积分功能:本游戏中,每击落一架敌机加1分,积分每满十分为战机增加一条生命值,同时,通过分数调整游戏进入不同的关卡
    关卡设计:本游戏普通模式中共有10个关卡,每通过一关,为战机增加两条生命值,根据关卡的增加,战机数量会增加,游戏难度加大。在无敌模式中,当10关全部打通之后,可以选择进入特别关卡,这时会有非常多的敌机出现
    敌机:通过屏幕上方随机产生敌机,产生频率受关卡的控制,只有当我机位于敌机正下方时,敌机才会向正下方发射子弹,当敌机被战机导弹命中后即爆炸摧毁
    战机:我方战机初始有六条生命,按空格可以发射导弹,当我方分数每加50会进入下一关
    游戏概况:利用键盘中的上下左右键控制我方战机,空格键发射子弹。游戏开始时有对话框显示游戏说明并且选择是否进入无敌模式,进入游戏后可以按P暂停开始游戏,当战机生命值减为0之后,会有对话框提示是否原地复活,每当战机击毁一架敌机加1分。游戏屏幕右上方有关数显示和得分显示,右下方有生命值显示

    2 相关技术2.1 设置定时器,销毁定时器用SetTimer()函数设置定时器,在游戏暂停时,用KillTimer()函数销毁计时器。
    2.2 获得矩形区域,实现碰撞检测首先,使用CRect定义一个对象,然后使用GetClientRect(&)函数,获取界面的矩形区域。其中,rect.Width()返回矩形区域的宽度,rect.Height()返回矩形区域的高度。
    使用IntersectRect(&,&)函数来判断两个源矩形是否有重合的部分。如果有不为空,则返回非零值;否则,返回0。以此判断子弹与战机,导弹与敌机,导弹与子弹是否相撞。
    2.3 CImageList()处理爆炸效果爆炸效果,是通过连续显示一个爆炸过程不同状态的图片,营造出完整、流畅的爆炸效果。如果把每一张图片单独保存,依次显示出来的话,占用的时间、内存是非常多的,必然会导致程序的可行性下降。MFC中,图像列表控制(CImageList)是相同大小图像的一个集合,每个集合中均以0为图像的索引序号基数,图像列表通常由大图标或位图构成,其中包含透明位图模式。用这种方式,可以将爆炸效果的一系列图片排列为一张图片,使用Draw()函数来绘制在拖拉操作中正被拖动的图像,即可连续绘制出完整、流畅的爆炸效果。
    2.4 CButton类实现消息映射类CButton提供了对Windows按钮控件的操作。按钮控件是一个小的矩形子窗口,可以通过单击选中(按下)或不选中。按钮可以单独使用,也可以成组使用,它还可以具有文本标题。在用户单击它的时候,按钮通常要改变显示外观。
    其过程是先调用构造函数CButton构造一个CButton对象,然后调用成员函数Create创建Windows按钮控件并应用到CButton对象上。如果想处理Windows的通知消息,按钮控就要在父对象中加入消息映射入口以及处理每个消息的成员函数。
    每个消息映射入口的格式如下:
    ON_Notification(id, memberFxn)
    其中id指定了发送通知的控件的子窗口的ID,而memberFxn指定了处理该通知的父对象中的成员函数名。
    父对象的函数原型格式如下:
    afx_msg void memberFxn( );
    2.5 键盘控制利用GetKey函数和键的虚拟键码,控制战机上下左右移动,使战机发射子弹。
    比如:
    GetKey(VK_SPACE)==1;
    2.6 创建对话框AfxMessageBox函数用于在应用程序还没有产生具体窗口时弹出消息框,同时有相应的返回值,通过选择不同的选项,可以通过选择不同选项做出不同的设置。
    2.7 利用CString对象和CDC类的有关函数实现游戏字幕输出通过调用CString的对象和CDC的相关函数来实现游戏字幕的输出,其中:
    int SetBkMode(intnBkMode ):返回背景模式的前一次取值。其中参数是表明背景在绘图之前不改变。
    SetTextAlign(UNITnFlags):如果成功,则返回文本对齐设置的前一次取值,低位字节包含水平设置,高位字节包含垂直水平设置,否则为0。参数TA_CENTER是使点与外接矩形的中点对齐。

    SetTextColor(COLORREF crColor):来设置输出文本的颜色
    TextOut(int x ,inty ,LPCSTR lpszString ,int nCount):输出文本以及控制文本的位置

    2.8 CObList链表MFC类库中提供了丰富的CObList类的成员函数,此程序主要用到的成员函数如下:

    构造函数,为CObject指针构造一个空的列表
    GetHead(),访问链表首部,返回列表中的首元素(列表不能为空)
    AddTail(),在列表尾增加一个元素或另一个列表的所有元素
    GetNext(),返回列表中尾元素的位置
    GetHeadPosition(),返回列表中首元素的位置
    RemoveAt(),从列表中删除指定位置的元素

    在CPlaneGameView.h文件中声明各游戏对象与游戏对象链表:
    创建各游戏对象
    CMyPlane *myplane;CEnemy *enemy; CBomb *bomb; CBall *ball;CExplosion*explosion;
    创建储存游戏对象的对象
    CObList ListEnemy;CObList ListMe; CObList ListBomb; CObList ListBall;CObListListExplosion;
    3 总体设计与详细设计3.1 系统模块划分本游戏由很多的C++类构成。游戏主体的基类为CGameObject类,其派生类有CBall,CBomb,CEnemy, CMyPlane,CExplosion类等;有关对话框的基类为CDialog类,其派生类有CAboutDlg,dlg类等构成了本程序的类体系。这两个主要基类都是由CObject类派生而来(其他类不再赘述)。其派生关系如图所示。

    3.2 主要功能模块游戏规则子系统



    模块名称
    功能简述




    人工智能
    人机对战规则的实现



    游戏子系统



    模块名称
    功能简述




    应用程序对象
    游戏程序的加载、游戏对象的绘制、游戏规则的调用、玩家的键盘事件获取


    游戏对象
    各个游戏对象的抽象父类(CGameObject)


    战机对象
    战机类(MyPlane)


    敌机对象
    敌机类(Enemy)


    导弹对象
    导弹类(Bomb)


    炸弹对象
    炸弹类(Ball)


    爆炸对象
    爆炸类(Explosion)



    4 编码实现由于本程序中编写了多个类来实现该游戏功能,所以程序代码较多,这里只展示核心部分以及特色部分。
    4.1 PlaneGameView.cpp// PlaneGameView.cpp : CPlaneGameView 类的实现//#include "stdafx.h"#include "PlaneGame.h"#include "PlaneGameDoc.h"#include "PlaneGameView.h"#include "MyPlane.h"#include "Enemy.h"#include "Bomb.h"#include "Ball.h"#include "Explosion.h"#include <atlimage.h>#include <windows.h>#include <mmsystem.h>#pragma comment(lib, "WINMM.LIB")#ifdef _DEBUG#define new DEBUG_NEW#endif// CPlaneGameViewIMPLEMENT_DYNCREATE(CPlaneGameView, CView)BEGIN_MESSAGE_MAP(CPlaneGameView, CView) // 标准打印命令 ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview) ON_WM_TIMER()END_MESSAGE_MAP()// CPlaneGameView 构造/析构static int count = 0;CPlaneGameView::CPlaneGameView():m_pMe(NULL){ // TODO: 在此处添加构造代码}CPlaneGameView::~CPlaneGameView(){}BOOL CPlaneGameView::PreCreateWindow(CREATESTRUCT& cs){ // TODO: 在此处通过修改 // CREATESTRUCT cs 来修改窗口类或样式 return CView::PreCreateWindow(cs);}// CPlaneGameView 绘制void CPlaneGameView::OnDraw(CDC* /*pDC*/){ CPlaneGameDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码}// CPlaneGameView 打印BOOL CPlaneGameView::OnPreparePrinting(CPrintInfo* pInfo){ // 默认准备 return DoPreparePrinting(pInfo);}void CPlaneGameView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/){ // TODO: 添加额外的打印前进行的初始化过程}void CPlaneGameView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/){ // TODO: 添加打印后进行的清理过程}// CPlaneGameView 诊断#ifdef _DEBUGvoid CPlaneGameView::AssertValid() const{ CView::AssertValid();}void CPlaneGameView::Dump(CDumpContext& dc) const{ CView::Dump(dc);}CPlaneGameDoc* CPlaneGameView::GetDocument() const // 非调试版本是内联的{ ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPlaneGameDoc))); return (CPlaneGameDoc*)m_pDocument;}#endif //_DEBUG// CPlaneGameView 消息处理程序void CPlaneGameView::OnInitialUpdate(){ CView::OnInitialUpdate(); // TODO: 在此添加专用代码和/或调用基类 //初始化游戏 if (AfxMessageBox(_T("欢迎来到飞机大战\nWelcome To The PlaneGame!\n是否开始游戏?"), MB_YESNO) == IDYES) { //BGM PlaySound(MAKEINTRESOURCE(IDR_WAVE2), AfxGetResourceHandle(), SND_ASYNC | SND_RESOURCE | SND_NODEFAULT | SND_LOOP); if (AfxMessageBox(_T("游戏说明:\n1、本游戏共分为十关;\n(为增加游戏体验,关卡之间没有弹窗)\n2、普通模式中,每通过一关,获得两次被击落的机会;\n3、每击落十架敌机获得一次被击落机会;\n4、按P键可以暂停游戏;\n5、进入无敌模式后,你将不会被击落,并且通关之后可以进入意想不到的特别关卡哦 快来试试吧!\n\n是否进入无敌模式?"), MB_YESNO) == IDYES) { Blood = 1; Flag_Of_WD = 1; } else { Blood = 6; Flag_Of_WD = 0; } gq = 1; score = 0; } else exit(1); InitGame();}void CPlaneGameView::StopGame(){ delete m_pMe; delete m_pMemDC; delete m_pDC; delete m_pMemBitmap;}BOOL CPlaneGameView::InitGame(){ CRect rc; GetClientRect(rc); //产生随机数种子 srand( (unsigned)time( NULL ) ); //建立设备DC m_pDC = new CClientDC(this); //建立内存DC m_pMemDC = new CDC; m_pMemDC->CreateCompatibleDC(m_pDC); //建立内存位图 m_pMemBitmap = new CBitmap; m_pMemBitmap->CreateCompatibleBitmap(m_pDC,GAME_WIDTH,GAME_HEIGHT); //将位图选入内存DC m_pMemDC->SelectObject(m_pMemBitmap); CMyPlane::LoadImage(); CEnemy::LoadImage(); CBomb::LoadImage(); CBall::LoadImage(); CExplosion::LoadImage(); //产生主角(战机) m_pMe = new CMyPlane; //启动游戏 SetTimer(1,30,NULL); return TRUE;}void CPlaneGameView::UpdateFrame(CDC* pMemDC){ //绘制天空 pMemDC->FillSolidRect(0,0,GAME_WIDTH,GAME_HEIGHT,RGB(84, 142, 239)); //背景滚动 CDC m_MemDc; CDC m_cacheDC; CBitmap m_BKBmp, m_cacheCBitmap; BITMAP m_Bmplnfo; CDC*pDc = GetDC(); m_BKBmp.LoadBitmapW(IDB_BITMAP5); m_BKBmp.GetBitmap(&m_Bmplnfo); m_MemDc.CreateCompatibleDC(pDc); m_MemDc.SelectObject(&m_BKBmp); CRect m_CliRect; GetClientRect(&m_CliRect); //创建缓冲区,提前加载缓存背景图片,防止刷新闪屏 m_cacheDC.CreateCompatibleDC(NULL); m_cacheCBitmap.CreateCompatibleBitmap(pDc, m_CliRect.Width(), m_CliRect.Height()); m_cacheDC.SelectObject(&m_cacheCBitmap); count++; pMemDC->BitBlt(0, 0, m_CliRect.Width(), m_CliRect.Height(), &m_MemDc, 0, 0, SRCCOPY); pMemDC->BitBlt(0, 0, m_CliRect.Width(), count, &m_MemDc, 0, m_CliRect.Height() - count, SRCCOPY); pMemDC->BitBlt(0, count, m_CliRect.Width(), m_CliRect.Height() - count, &m_MemDc, 0, 0, SRCCOPY); if (count >= m_CliRect.Height()) count = 0; //在绘制完图后,使得窗口有效 ValidateRect(&m_CliRect); //释放缓冲DC m_cacheDC.DeleteDC(); //释放对象 m_cacheCBitmap.DeleteObject(); //释放窗口DC ReleaseDC(pDc); //显示关卡 CString str3 = _T("当前关卡 :"); CString strgq; strgq.Format(_T("%d"), gq); if (gq == 666) strgq = _T("特别关卡"); str3 += strgq; pMemDC->SetTextColor(RGB(255, 0, 255)); pMemDC->TextOut(GAME_WIDTH / 2 + 130, 40, str3); //显示血量 CString str = _T("剩余生命值 :"); CString strBlood; strBlood.Format(_T("%d"), Blood); str += strBlood; if (Flag_Of_WD == 1) str = _T("无敌模式"); pMemDC->SetTextColor(RGB(255, 0, 255)); pMemDC->TextOut(GAME_WIDTH / 2 + 150, 600, str); //显示得分 CString str2 = _T("当前积分 :"); CString strScore; strScore.Format(_T("%d"), score); str2 += strScore; pMemDC->SetTextColor(RGB(255, 0, 255)); pMemDC->TextOut(GAME_WIDTH / 2 + 130, 20, str2); //显示暂停游戏 CString strp= _T("按P键暂停游戏"); pMemDC->SetTextColor(RGB(255, 0, 255)); pMemDC->TextOut(GAME_WIDTH / 2 + 130, 60, strp); //绘制我方战机 if(m_pMe!=NULL) { m_pMe->Draw(m_pMemDC,FALSE); } else { //Game Over CString str=_T("Game Over!"); pMemDC->SetBkMode(TRANSPARENT); pMemDC->SetTextAlign(TA_CENTER); pMemDC->SetTextColor(RGB(255,0,0)); pMemDC->TextOut(GAME_WIDTH/2,GAME_HEIGHT/2,str); } //绘制 导弹、爆炸、敌机、子弹 for(int i=0;i<4;i++) { POSITION pos1,pos2; for( pos1 = m_ObjList[i].GetHeadPosition(); ( pos2 = pos1 ) != NULL; ) { CGameObject* pObj = (CGameObject*)m_ObjList[i].GetNext( pos1 ); if(!pObj->Draw(pMemDC,FALSE)) { m_ObjList[i].RemoveAt(pos2); delete pObj; } } } //复制内存DC到设备DC m_pDC->BitBlt(0,0,GAME_WIDTH,GAME_HEIGHT,m_pMemDC,0,0,SRCCOPY);}void CPlaneGameView::AI(){ static int nCreator = rand() %5+10; //关卡满级之后咋办呢 if (gq == 11) { KillTimer(1); if (Flag_Of_WD == 1) { if (AfxMessageBox(_T("恭喜你,已经打通关了,是否进入特别关卡?\n(进入特别关卡之后,你依然是无敌的哦~~)"), MB_YESNO) == IDYES) { gq = 666; SetTimer(1, 30, NULL); } else exit(1); } else { if (AfxMessageBox(_T("恭喜你,已经打通关了,是否重新开始游戏?)"), MB_YESNO) == IDYES) { //开始游戏 SetTimer(1, 30, NULL); Blood = 6; score = 0; gq = 1; m_pMe = new CMyPlane; } else exit(1); } } //不同关卡的战机产生频率 if (nCreator <= 0) { nCreator = rand() % 5 + 15 - gq; m_ObjList[enEnemy].AddTail(new CEnemy); } nCreator--; //无敌模式下的特别关卡 if (gq == 666) { nCreator = rand() % 5; m_ObjList[enEnemy].AddTail(new CEnemy); } if(m_pMe==NULL) return; //检测四个方向键,移动战机 for(int i=0;i<4;i++) { int nMeMotion=0; m_pMe->SetVerMotion(0); m_pMe->SetHorMotion(0); nMeMotion = GetKey(VK_UP); if(nMeMotion==1) m_pMe->SetVerMotion(1); nMeMotion = GetKey(VK_DOWN); if(nMeMotion==1) m_pMe->SetVerMotion(-1); nMeMotion = GetKey(VK_RIGHT); if(nMeMotion==1) m_pMe->SetHorMotion(1); nMeMotion = GetKey(VK_LEFT); if(nMeMotion==1) m_pMe->SetHorMotion(-1); } //产生战机导弹 if(GetKey(VK_SPACE)==1)//按下了空格键 { if(m_pMe!=NULL && m_pMe->Fired()) { CPoint pt = m_pMe->GetPoint(); m_ObjList[enBomb].AddTail(new CBomb(pt.x+10,pt.y+10)); m_ObjList[enBomb].AddTail(new CBomb(pt.x+30,pt.y+10)); } } //敌机发射子弹 CPoint PlanePt = m_pMe->GetPoint(); for(POSITION ePos=m_ObjList[enEnemy].GetHeadPosition();ePos!=NULL;) { CEnemy* pEnemy = (CEnemy*)m_ObjList[enEnemy].GetNext(ePos); if(!pEnemy->Fired()) continue; CPoint ePt = pEnemy->GetPoint(); BOOL by=FALSE; //敌机在战机前面 if(pEnemy->GetMontion()==1 && ePt.y<PlanePt.y) by= TRUE; //敌机在战机后面 if(pEnemy->GetMontion()==-1 && ePt.y>PlanePt.y) by= TRUE; if(by && ePt.x >= PlanePt.x && ePt.x<PlanePt.x+CMyPlane::PLANE_WIDTH) { m_ObjList[enBall].AddTail(new CBall(ePt.x+10,ePt.y+10,pEnemy->GetMontion())); } } //敌机子弹炸掉战机 POSITION bPos1=NULL,bPos2=NULL; CRect mRect = m_pMe->GetRect(); for(bPos1=m_ObjList[enBall].GetHeadPosition();( bPos2 = bPos1 ) != NULL;) { CBall* pBall = (CBall*)m_ObjList[enBall].GetNext(bPos1); CRect bRect = pBall->GetRect(); CRect tmpRect; if(tmpRect.IntersectRect(&bRect,mRect)) { //添加爆炸效果 m_ObjList[enExplosion].AddTail( new CExplosion(mRect.left,mRect.top) ); //非无敌模式下,减少一次生命值 if(Flag_Of_WD == 0) Blood--; //删除子弹 m_ObjList[enBall].RemoveAt(bPos2); delete pBall; } if (Blood == 0) { KillTimer(1); if (AfxMessageBox(_T("游戏结束!\n是否原地复活?(还能获得6次生命值哦)"), MB_YESNO) == IDYES) { //开始游戏 SetTimer(1, 30, NULL); Blood = 6; } else { exit(1); } } } //战机导弹炸掉敌机 POSITION mPos1=NULL,mPos2=NULL; for (mPos1 = m_ObjList[enBomb].GetHeadPosition(); (mPos2 = mPos1) != NULL;) { CBomb* pBomb = (CBomb*)m_ObjList[enBomb].GetNext(mPos1); CRect bRect = pBomb->GetRect(); POSITION ePos1 = NULL, ePos2 = NULL; for (ePos1 = m_ObjList[enEnemy].GetHeadPosition(); (ePos2 = ePos1) != NULL;) { CEnemy* pEnemy = (CEnemy*)m_ObjList[enEnemy].GetNext(ePos1); CRect mRect = pEnemy->GetRect(); CRect tmpRect; if (tmpRect.IntersectRect(&bRect, mRect)) { //添加爆炸效果 m_ObjList[enExplosion].AddTail( new CExplosion(mRect.left, mRect.top) ); //删除导弹 m_ObjList[enBomb].RemoveAt(mPos2); delete pBomb; //删除敌机 m_ObjList[enEnemy].RemoveAt(ePos2); delete pEnemy; //加分 score++; //关卡自动生成 if (score % 50 == 0 && score != 0) { gq++; Blood += 2; } //为战机补充生命值 if (score % 10 == 0 && score != 0) { Blood++; } break; } } } //暂停 if (GetKey('P') == 1) { KillTimer(1); if (AfxMessageBox(_T("是否继续游戏?"), MB_YESNO) == 6) SetTimer(1, 30, NULL); else exit(1); }}void CPlaneGameView::OnTimer(UINT_PTR nIDEvent){ //刷新游戏帧画面: 在内存DC上绘图 UpdateFrame(m_pMemDC); AI(); CView::OnTimer(nIDEvent);}
    5 测试



    2 评论 51 下载 2019-03-19 18:27:47 下载需要12点积分
  • 基于JSP实现的学生成绩管理系统

    1 引言1.1 任务简介
    多用户管理:用户分管理员,学生
    网页界面设计:利用HTML和CSS实现客户端前台设计
    类间关系的设计、数据库表格设计
    数据库数据的增(录入)、删、改、查等基本功能
    JSP中Requests Response内置对象的使用;
    数据库表格结构的生成(SQL脚本)
    前台JS校验设计
    DOM技术实现
    其他扩展功能
    开发环境与技术:IDEA、Java 语言、JDK 1.7、MySQL 6.0

    1.2 需求分析本学生成绩管理系统分为管理员登录,学生登录,其中管理员可以实现增加学生成绩信息,删除学生成绩信息,修改学生成绩信息,查找学生成绩信息,按照学生GPA进行排名,其中学生可以实现登录查询成绩功能,能否成功登录取决于数据库中是否有该学生。
    2可行性分析2.1 社会可行性分析成绩是每一个大学生都会接触到的东西,不仅学生为之心动,为了管理学生的成绩,如果不用计算机来实现,老师们也会感觉很头疼麻烦,开发学生成绩管理系统后,让学生的成绩管理变的更加方便,学生也可以实现自助查询成绩功能,老师们也可以对学生成绩进行排名等。
    2.2 经济可行性分析该系统的开发调查主要是需要软件,这些软件都是免费的。主要的花销在于服务器的维护,除此之外没有其他的花销。
    2.3 法律可行性分析系统开发及维护所使用工具和技术及数据信息不违反法律。
    3系统设计3.1 系统功能设计学生成绩管理系统具备以下功能:管理员学生分权限登录,增加学生成绩信息,删除学生成绩信息,修改学生成绩信息,查询学生成绩,按照学生GPA进行排名。

    分权限登录:系统分为管理员和学生用户两个权限,因为管理员就一个,所以账号秘密固定,但是学生有很多,所以在学生登录的过程中要对数据库中的学生进行查询,如果存在,而且密码正确,才能成功登录
    增加学生成绩:该功能可以将学生的姓名,学号,一系列成绩,登录密码等信息录入系统
    删除学生成绩:该功能可以将学生的信息全部列举出来,然后选择想要删除的学生的信息
    修改学生成绩:该功能可以将学生的所有信息全部列举出来,然后再选择想要修改的学生的信息,然后弹出一个修改框,再做仔细的修改
    查询学生成绩信息:该功能可以在输入学号后显示出学生的各项成绩信息
    按照学生GPA进行排名:该功能可以将所有学生按照GPA进行排名,并显示出来

    3.2 算法流程设计根据需求分析,将本系统分为以下模块,模块图如下:

    4 关键技术及代码实现4.1 基本功能4.1.1 Web前端设计与实现4.1.1.1 HTML关键技术及应用include file技术
    <html> <head> <title> 学生成绩管理系统 </title> </head> <body bgcolor="#FFFFFF"> <%@ include file="include_head_JSP2.jsp"%> </body></html>
    Bootstrap 框架技术
    <%@page contentType= "text/html; charset=UTF-8" language= "java" errorPage=""%> <!DOCTYPE html><html> <head> <style> body{ background-image: url("1281116171866201.jpg"); } </style> <title>学生管理系统</title> <meta name= "viewport" content = "width=device-width, initial-scale= 1.0"> <!-引入Bootstrap-> <link href="bootstrap.css" rel="stylesheet"> </head> <body> <center> <hi>学生成绩管理系统</hi></center> <br> <center> <div class ="container"> <a href= "selectLogin .j sp" class= "btn btn-info" role= "button">管理员</a> <a href= "studentLogin.jsp" class= "btn btn-info" role= "button">学生</a> </div></center> <!– jQuery (Bootstrap 的 JavaScript 插件需要引⼊ jQuery) –> <script src=”jquery-3.2.1.min.js”></script> <!– 包括所有已编译的插件 –> <script src=”bootstrap.min.js”></script> </body> </html>
    4.1.1.2 CSS关键技术及应用Bootstrap.css技术
    大量运用Boostrap前段框架中的CSS样式,美化登录界面,表格,按钮。
    响应式表格:
    <table class=”table table-condensed table-hover” >
    美化按钮:
    <a href=”Findinfo2.jsp” class=”btn btn-info” role=”button”> 返回 </a>
    4.1.1.3 JS校验设计及应用登录界面的校验
    <script language=”javascript” type=””> function checkform() { //验证输⼊数据的合法性 if (form1.teacherName.value==””) { alert(” ⽤户名不能为空。”); return false; } if (form1.teacherPassword.value==””) { alert(” 密码不能为空。”); return false; }}</script>
    往数据库写⼊数据的检验
    function checkform(){ //验证输⼊数据的合法性 if (form1.id.value==””) { alert(” 学号不能为空。”); return false; } if (isNaN(form1.id.value)) { alert(” 学号只能为数字”); return false; } if (form1.name.value==””) { alert(” 姓名不能为空。”); return false; } if (form1.cppstring.value==””) { alert(”C++ 成绩不能为空。”); return false; } if (isNaN(form1.cppstring.value)) { alert(”C++ 成绩只能为数字”); return false; } else { var num=parseFloat(form1.cppstring.value); if (num<0||num>100) { alert(”C++ 成绩必须在 0-100 之间!”); return false; } } if (form1.cirstring.value==””) { alert(” 电路成绩不能为空。”); return false; } if (isNaN(form1.cirstring.value)) { alert(” 电路成绩只能为数字”); return false; } else { var num=parseFloat(form1.cirstring.value); if (num<0||num>100) { alert(” 电路成绩必须在 0-100 之间!”); return false; } } if (form1.Ewritestring.value==””) { alert(” 英语读写成绩不能为空。”); return false; } if (isNaN(form1.Ewritestring.value)) { alert(” 英语读写成绩只能为数字”); return false; } else { var num=parseFloat(form1.Ewritestring.value); if (num<0||num>100) { alert(” 英语读写成绩必须在 0-100 之间!”); return false; } } if (form1.Elistenstring.value==””) { alert(” 英语听说成绩不能为空。”); return false; } if (isNaN(form1.Elistenstring.value)) { alert(” 英语听说成绩只能为数字”); return false; } else { var num=parseFloat(form1.Elistenstring.value); if (num<0||num>100) { alert(” 英语听说成绩必须在 0-100 之间!”); return false; } } if (form1.physicsstring.value==””) { alert(” ⼤学物理成绩不能为空。”); return false; } if (isNaN(form1.physicsstring.value)) { alert(” ⼤学物理成绩只能为数字”); return false; } else { var num=parseFloat(form1.physicstring.value); if (num<0||num>100) { alert(” ⼤学物理成绩必须在 0-100 之间!”); return false; } } if (form1.prostring.value==””) { alert(” 概率论成绩不能为空。”); return false; } if (isNaN(form1.prostring.value)) { alert(” 概率论成绩只能为数字”); return false; } else { var num=parseFloat(form1.prostring.value); if (num<0||num>100) { alert(” 概率论成绩必须在 0-100 之间!”); return false; } } if (form1.hisstring.value==””) { alert(” 近代史成绩不能为空。”); return false; } if (isNaN(form1.hisstring.value)) { alert(” 近代史成绩只能为数字”); return false; } else { var num=parseFloat(form1.hisstring.value); if (num<0||num>100) { alert(” 近代史成绩必须在 0-100 之间!”); return false; } } if (form1.xingzhengstring.value==””) { alert(” 形势与政策成绩不能为空。”); return false; } if(isNaN(form1.xingzhengstring.value)) { alert(” 形势与政策成绩只能为数字”); return false; } else { var num=parseFloat(form1.xingzhengstring.value); if (num<0||num>100) { alert(” 形势与政策成绩必须在 0-100 之间!”); return false; } } if (form1.pestring.value==””) { alert(” 体育成绩不能为空。”); return false; } if (isNaN(form1.pestring.value)) { alert(” 体育成绩只能为数字”); return false; } else { var num=parseFloat(form1.pestring.value); if (num<0||num>100) { alert(” 体育成绩必须在 0-100 之间!”); return false; } } if (form1.discretestring.value==””) { alert(” 离散数学成绩不能为空。”); return false; } if (isNaN(form1.discretestring.value)) { alert(” 离散数学成绩只能为数字”); return false; } else { var num=parseFloat(form1.discretestring.value); if (num<0||num>100) { alert(” 离散数学成绩必须在 0-100 之间!”); return false; } } if (form1.rank.value==””) { alert(” 查询密码成绩不能为空。”); return false; } if (form1.rank.value.length<1||form1.rank.value.length>20) { alert(” 密码超出了范围(1 ~ 20)”); return false; }}</script>
    4.1.1.4 DOM 关键技术及应用DOM 实际上是以面向对象方式描述的文档模型。DOM 定义了表⽰和修改⽂档所需的对象、这些对象的⾏为和属性以及这些对象之间的关系。可以把 DOM 认为是页面上数据和结构的一个树形表示,不过页面当然可能并不是以这种树的方式具体实现。 通过 JavaScript,您可以重构整个 HTML 文档。您可以添加、移除、改变或重排页面上的项目。 例如使用 Dom 技术来进⾏ Js 校验:
    <script language=”javascript” type=””> function checkform() { //验证输⼊数据的合法性 if (form1.teacherName.value==””) { alert(” ⽤户名不能为空。”); return false; } if (form1.teacherPassword.value==””) { alert(” 密码不能为空。”); return false; }} </script>
    4.1.2 Web 后台设计及实现本学生管理系统后台设计使用了 Java 脚本,Java servlet 过滤器,以及 Java 数据库技术等。
    4.1.2.1 数据库设计及 SQL 脚本生成数据库脚本
    CREATE TABLE ‘grade‘ ( ‘id‘ varchar(30) NOT NULL, ‘name‘ varchar(30) NOT NULL, ‘cpp‘ varchar(30) NOT NULL, ‘circuit‘ varchar(30) NOT NULL, ‘Ewrite‘ varchar(30) NOT NULL, ‘Elisten‘ varchar(30) NOT NULL, ‘physics‘ varchar(30) NOT NULL, ‘probability‘ varchar(30) NOT NULL, ‘history‘ varchar(30) NOT NULL, ‘xingzheng‘ varchar(30) NOT NULL, ‘pe‘ varchar(30) NOT NULL, ‘discrete‘ varchar(30) NOT NULL, ‘overall‘ varchar(30) DEFAULT ’0’, ‘gpa‘ varchar(30) DEFAULT ’0’, ‘rank‘ varchar(30) DEFAULT ’0’ )
    4.1.2.2 增删改查功能实现增加学生成绩信息
    String idstring=ChangeEncoding(request.getParameter(”id”).trim()); String namestring=ChangeEncoding(request.getParameter(”name”).trim());String cppstring=request.getParameter(”cppstring”); String cirstring=request.getParameter(”cirstring”); String Ewritestring=request.getParameter(”Ewritestring”);String Elistenstring=request.getParameter(”Elistenstring”); String physicsstring=request.getParameter(”physicsstring”);String prostring=request.getParameter(”prostring”);String hisstring=request.getParameter(”hisstring”); String xingzhengstring=request.getParameter(”xingzhengstring”);String pestring=request.getParameter(”pestring”);String discretestring=request.getParameter(”discretestring”); String overallstring=getOvarall(cppstring,cirstring,Ewritestring,Elistenstring, physicsstring,prostring,hisstring,xingzhengstring,pestring,discretestring); String gpastring=getGPA(cppstring,cirstring,Ewritestring,Elistenstring, physicsstring,prostring,hisstring,xingzhengstring,pestring,discretestring); String rankstring=request.getParameter(”rank”); //构造 SQL 语句 Stringsql=”insertintograde(id,name,cpp,circuit,Ewrite,Elisten,physics,probability,history,xingzheng”+”,pe,discrete,overall,gpa,rank)”+”VALUES(’”+idstring+”’,’”+namestring+”’,’”+cppstring+”’,’”+cirstring+”’,’”+Ewritestring+”’,’”+Elistenstring+”’,’”+physicsstring+”’,’”+prostring+”’,’”+hisstring+”’,’”+xingzhengstring+”’,’”+pestring+”’,’”+discretestring+”’,’”+overallstring+”’,’”+gpastring+”’,’”+rankstring+”’)”; String DBDRIVER = ”org.gjt.mm.mysql.Driver” ; // 定义 MySQL 数据库的连接地址 String DBURL = ”jdbc:mysql://localhost:3306/student”; // MySQL 数据库的连接⽤户名 String DBUSER = ”root” ;// MySQL 数据库的连接密码String DBPASS = ”xzk520521”;try { Class.forName(DBDRIVER).newInstance();} catch (ClassNotFoundException e) { out.print(” 错误”); e.printStackTrace();}try { Connection conn=DriverManager.getConnection(DBURL, DBUSER, DBPASS); Statement stmt=conn.createStatement(); stmt.executeUpdate(sql); out.print(”<center>”); out.println(”<P><font size=2’>”+” 向数据库增加学⽣信息”+”</font>”); out.println(”<P><font size=2’>”+” 该学⽣信息数据已经成功添加到数据库。”+”</font>”); out.print(”</center>”); stmt.close(); conn.close(); } catch(SQLException e) { out.print(” 错误”); e.printStackTrace(); }
    删除学生成绩
    String DBDRIVER = ”org.gjt.mm.mysql.Driver” ;// 定义 MySQL 数据库的连接地址String DBURL = ”jdbc:mysql://localhost:3306/student”; // MySQL 数据库的连接⽤户名 String DBUSER = ”root” ; // MySQL 数据库的连接密码 String DBPASS = ”xzk520521”; String id=codeToString(request.getParameter(”id”).trim());//构造 SQL 语句 String sql=”delete from grade where id=’”+id+”’”; try { Class.forName(DBDRIVER).newInstance(); } catch (ClassNotFoundException e) { out.print(” 错误”); e.printStackTrace();} try{ Connection conn=DriverManager.getConnection(DBURL, DBUSER, DBPASS); Statement stmt=conn.createStatement(); stmt.executeUpdate(sql); out.print(”<center>”); out.println(”<P><font size=2 color=’blue’>”+” 向数据库删除学⽣信息数据”+”</font>”); out.println(”<P><fontsize=2’>”+”学号为:”+id+”的学⽣数据信息已经被成功删除。”+”</font>”); out.print(”</center>”); stmt.close(); conn.close(); }catch(SQLException e) { out.print(” 错误”); e.printStackTrace(); }
    查找学生成绩信息
    String DBDRIVER = ”org.gjt.mm.mysql.Driver” ; // 定义 MySQL 数据库的连接地址 String DBURL = ”jdbc:mysql://localhost:3306/student” ; // MySQL 数据库的连接⽤户名 String DBUSER = ”root” ; // MySQL 数据库的连接密码 String DBPASS = ”xzk520521”; String id=request.getParameter(”id”); String sql=”select * from grade where id=’”+id+”’”;//设置查询 SQL 语句try { Class.forName(DBDRIVER).newInstance(); } catch (ClassNotFoundException e) { out.print(” 错误”); e.printStackTrace(); } try { Connection conn=DriverManager.getConnection(DBURL, DBUSER, DBPASS); Statement stmt=conn.createStatement(); ResultSet rs=stmt.executeQuery(sql); if(!rs.next()) { out.print(”<center>”); out.println(”<P><fontsize=2color=’blue’>”+”该学⽣尚未录⼊系统,请前去录⼊!”+”</font>”); } else{ dec.idField.setText(rs.getString(”id”)); dec.nameField.setText(rs.getString(”name”)); dec.cppField.setText(rs.getString(”cpp”)); dec.cirField.setText(rs.getString(”circuit”)); dec.EwriteField.setText(rs.getString(”Ewrite”)); dec.ElistenField.setText(rs.getString(”Elisten”)); dec.phyField.setText(rs.getString(”physics”)); dec.proField.setText(rs.getString(”probability”)); dec.historyField.setText(rs.getString(”history”)); dec.xingzhengField.setText(rs.getString(”xingzheng”)); dec.peField.setText(rs.getString(”pe”)); dec.discreteField.setText(rs.getString(”discrete”)); dec.overallField.setText(rs.getString(”overall”)); dec.gpaField.setText(rs.getString(”gpa”)); } rs.close(); stmt.close(); conn.close();}catch (SQLException e) { e.printStackTrace(); }
    修改学生成绩信息
    String idstring=ChangeEncoding(request.getParameter(”id”).trim()); String namestring=ChangeEncoding(request.getParameter(”name”).trim()); String cppstring=request.getParameter(”cpp”); String cirstring=request.getParameter(”circuit”); String Ewritestring=request.getParameter(”Ewrite”); String Elistenstring=request.getParameter(”Elisten”); String physicsstring=request.getParameter(”physics”); String prostring=request.getParameter(”probability”);String hisstring=request.getParameter(”history”);String xingzhengstring=request.getParameter(”xingzheng”);String pestring=request.getParameter(”pe”);String discretestring=request.getParameter(”discrete”); Stringoverallstring=getOvarall(cppstring,cirstring,Ewritestring,Elistenstring,physicsstring,prostring,hisstring,xingzhengstring,pestring,discretestring); Stringgpastring=getGPA(cppstring,cirstring,Ewritestring,Elistenstring,physicsstring,prostring,hisstring,xingzhengstring,pestring,discretestring); String rankstring=request.getParameter(”rank”); String DBDRIVER = ”org.gjt.mm.mysql.Driver” ; // 定义 MySQL 数据库的连接地址 String DBURL = ”jdbc:mysql://localhost:3306/student” ; // MySQL 数据库的连接⽤户名 String DBUSER = ”root” ; // MySQL 数据库的连接密码 String DBPASS = ”xzk520521”; String id=ChangeEncoding(request.getParameter(”id”).trim());//构造 SQL 语句 Stringsql=”updategradesetid=’”+idstring+”’,name=’”+namestring+”’,cpp=’”+cppstring+”’,circuit=’”+cirstring+”’,Ewrite=’”+Ewritestring+”’,Elisten=’”+Elistenstring+”’,physics=’”+physicsstring+”’,probability=’”+prostring+”’,history=’”+hisstring+ ”’,xingzheng=’”+xingzhengstring+”’,pe=’”+pestring+”’,discrete=’”+discretestring+”’,overall=’”+overallstring+”’,gpa=’”+ gpastring+”’,rank=’”+ rankstring+”’where id=’”+id+”’”; try { Class.forName(DBDRIVER).newInstance();} catch (ClassNotFoundException e) { out.print(” 错误”); e.printStackTrace();}try { Connection conn=DriverManager.getConnection(DBURL, DBUSER, DBPASS); Statement stmt=conn.createStatement(); stmt.executeUpdate(sql); out.print(”<center>”); out.println(”<P><font size=2 color=’blue’>”+” 向数据库修改学⽣信息数据”+”</font>”); out.println(”<P><fontsize=2’>”+”学号为:”+id+”的学⽣数据信息已经被成功修改。”+”</font>”); out.print(”</center>”); stmt.close(); conn.close();} catch(SQLException e) { out.print(” 错误”); e.printStackTrace(); }
    显⽰——按照学⽣的 GPA 进⾏排名并打印
    <% String DBDRIVER = ”org.gjt.mm.mysql.Driver” ; // 定义 MySQL 数据库的连接地址String DBURL = ”jdbc:mysql://localhost:3306/student” ; // MySQL 数据库的连接⽤户名 String DBUSER = ”root” ; // MySQL 数据库的连接密码 String DBPASS = ”xzk520521”; int realrank=1; String sql=”select * from grade ORDER BY gpa DESC”;//设置查询 SQL 语句 try { Class.forName(DBDRIVER).newInstance();}catch (ClassNotFoundException e) { out.print(” 错误”); e.printStackTrace(); } try { Connection conn=DriverManager.getConnection(DBURL, DBUSER, DBPASS); Statement stmt=conn.createStatement(); ResultSet rs=stmt.executeQuery(sql); %> <center><h1> 学⽣成绩 GPA 排名表 </h1></center> <hr> <table class=”table table-condensed table-hover” > <thead> <tr > <th> 学号 </th> <th> 姓名 </th> <th>C++ 成绩 </th> <th> 电路成绩 </th> <th> 英语读写 </th> <th> 英语听说 </th> <th> ⼤学物理 </th> <th> 概率论 </th> <th> 近代史 </th> <th> 形势与政策 </th> <th> 体育 </th> <th> 离散数学 </th> <th> 总分 </th> <th>GPA</th> <th> 排名 </th> </tr> </thead> <% while (rs.next()){ //获取学⽣数据表中的记录 %> <tr > <td><%=rs.getString(”id”)%></td> <td><%=rs.getString(”name”)%></td> <td><%=rs.getString(”cpp”)%></td> <td><%=rs.getString(”circuit”)%></td> <td><%=rs.getString(”Ewrite”)%></td> <td><%=rs.getString(”Elisten”)%></td> <td><%=rs.getString(”physics”)%></td> <td><%=rs.getString(”probability”)%></td> <td><%=rs.getString(”history”)%></td> <td><%=rs.getString(”xingzheng”)%></td> <td><%=rs.getString(”pe”)%></td> <td><%=rs.getString(”discrete”)%></td> <td><%=rs.getString(”overall”)%></td> <td><%=rs.getString(”gpa”)%></td> <td><%=realrank++%></td> </tr> <% } rs.close(); stmt.close(); conn.close(); } catch (SQLException e){ e.printStackTrace(); } %> </table>
    4.1.3 Java-Serviet设计与实现Java-Serviet技术主要用于过滤器的实现,过滤器就是不能再未登录的情况下直接用URL 地址访问操作界面,用Java-Serviet技术实现如下:
    userLoginCheckFilter.java
    package mywebapp; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.servlet.FilterConfig;import javax.servlet.ServletException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession; public class userLoginCheckFilter implements Filter { public static final Stringloginpage = ”index.jsp”; public void destroy(){ } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)throws ServletException, IOException { HttpServletRequest request = (HttpServletRequest)servletRequest; HttpServletResponse response = (HttpServletResponse)servletResponse; String currentURL = request.getRequestURI(); String ctxPath = request.getContextPath(); //除掉项⽬名称时访问页⾯当前路径 String targetURL = currentURL.substring(ctxPath.length()); System.out.println(targetURL); List<String>info = new ArrayList<String>(); HttpSession session = request.getSession(false); //对当前页⾯进⾏判断,如果当前页⾯不为登录页⾯ if(!((”/index.jsp”.equals(targetURL)) || (”/selectLogin.jsp”.equals(targetURL)) || (”/studentLogin.jsp”.equals(targetURL)))){ //在不为登陆页⾯时,再进⾏判断,如果不是登陆页⾯也没有 session 则跳转到登录页⾯ if(session == null || session.getAttribute(”admin”) == null){ info.add(”You are not logged in!”); request.setAttribute(”info”,info); request.getRequestDispatcher(loginpage).forward(request,response); return; } else{ //这⾥表⽰正确,会去寻找下⼀个链,如果不存在,则进⾏正常的页⾯跳转 filterChain.doFilter(request, response); return; } } else{ //这⾥表⽰如果当前页⾯是登陆页⾯,跳转到登陆页⾯ try{ filterChain.doFilter(request, response); } catch (Exception e){ throw e; } return; } } public void init(FilterConfig filterConfig)throws ServletException{ }}
    web.xml ⽂件
    <?xml version=”1.0” encoding=”UTF-8”?> <web-app xmlns=”http://xmlns.jcp.org/xml/ns/javaee” version=”3.1”><filter> <filter-name>userLoginCheckFilter</filter-name> <filter-class>mywebapp.userLoginCheckFilter</filter-class></filter> <filter-mapping> <filter-name>userLoginCheckFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping> </web-app>
    4.1.4 JSP内置对象的使用本成绩管理系统用了4种JSP内置对象,分别是Request、Response、Out、Session。下面分别列出:
    4.1.4.1 RequestString idstring=ChangeEncoding(request.getParameter(”id”).trim()); String namestring=ChangeEncoding(request.getParameter(”name”).trim()); String cppstring=request.getParameter(”cpp”); String cirstring=request.getParameter(”circuit”);String Ewritestring=request.getParameter(”Ewrite”); String Elistenstring=request.getParameter(”Elisten”); String physicsstring=request.getParameter(”physics”);String prostring=request.getParameter(”probability”); String hisstring=request.getParameter(”history”);String xingzhengstring=request.getParameter(”xingzheng”); String pestring=request.getParameter(”pe”); String discretestring=request.getParameter(”discrete”);
    4.1.4.2 Responseresponse.sendRedirect(”teacharMenu.jsp”);
    4.1.4.3 Outout.print(”<center>”); out.println(”<P><font size=2 color=’blue’>”+” 管理员⽤户或密码错误”+”</font>”);
    4.1.4.4 Sessionsession.setAttribute(”teacherName”,name); session.setAttribute(”teacherPassword”,password); String user=(String)session.getAttribute(”teacherName”); String pwd=(String)session.getAttribute(”teacherPassword”);
    4.1.5 多用户管理设计与实现首先进入系统时出现选择用户,如果选择管理员需要知道管理员账号密码,如果选择学生, 需要该学生的学号在数据库中而且密码正确。
    5 系统演示登录

    增加


    删除


    查找


    修改

    排名

    6 总结6.1 系统缺陷与不足
    系统运用的查找算法都是暴力算法,如果面对很多数据的话,系统运行会缓慢,可以运用二分查找算法或者改变存储的数据结构进行优化
    系统编码不够灵活,编码转换方面容易产生乱码

    6.2 系统可扩展功能
    增加选课功能
    增加多个管理员功能
    增加学生自助修改密码功能
    增加一系列功能做成教务系统
    3 评论 408 下载 2018-11-05 12:31:35 下载需要14点积分
  • 基于汇编语言的学生成绩管理系统

    一 需求分析用汇编语言编写一个学生成绩管理系统,实现基本的学生成绩管理,功能包括成绩的录入,总分和平均分的计算,数据存档,从文件中读入数据等。要求程序界面友好,有输入界输出提示,有菜单等。
    二 程序设计2.1 程序总流程设计
    2.2 添加记录流程设计
    2.3 打印记录流程设计
    三 程序实现3.1 开发工具该程序使用基于DOS操作系统的16位实模式汇编语言编写,使用的编译器为微软的MASM 5.0,调试工具为DOS下的debug.exe程序。
    3.2 基本原理本程序使用了DOS系统功能调用(INT 21H),程序中用到的系统功能调用如下:



    AH
    功能
    调用参数
    返回参数




    02
    显示输出
    DL=输出字符



    09
    显示字符串
    DS:DX=串地址 字符串以‘$’符结束



    3C
    建立文件
    DS:DX=ASCIZ串地址 CX=文件属性
    成功:AX=文件代号 失败:AX=错误代码


    3D
    打开文件
    DS:DX=ASCIZ串地址 AL=访问文件和共享方式 0=读,1=写,2=读/写
    成功:AX=文件代号 失败:AX=错误代码


    3E
    关闭文件
    BX=文件代号
    失败:AX=错误代码


    3F
    读文件或设备
    DS:DX=缓冲区首地址 BX=文件代号 CX=读取的字节数
    成功:AX=实际读取的字节数 AX=0已到文件尾 失败:AX=错误代码


    40
    写文件或设备
    DS:DX=缓冲区首地址 BX=文件代号 CX=写入的字节数
    成功:AX=实际写入的字节数 失败:AX=错误代码



    3.3 数据结构程序采用静态链表的方式来存储学生成绩信息,链表结点描述如下:
    struct Node{ byte name[20]; // 学生姓名 word maths; // 数学成绩 word english; // 英语成绩 word computer; // 计算机成绩 word total; // 总成绩 word avg; // 平均成绩 word next; // 指向下一个结点的指针}
    说明:结点大小为32字节,其中name占20字节,剩下的六个字段,每一个都是一个字,占两个字节。
    3.4 模块说明该程序一共分为三大模块:分别完成数据的录入,存档以及从文件读取数据。各模块分别介绍如下:
    3.4.1 数据录入数据的录入项目包括学生的姓名,各科成绩。数据录入后,程序自动计算出每位学生的平均成绩和总成绩。
    姓名的输入方式
    首先利用09号系统调用,将字符串输入到内存缓冲区,然后用字符串传送指令将缓冲区中的字符串传送到记录结点。程序自动在输入的字符串后加上美元符号“$”,目的是方便使用系统调用将其输出。
    成绩的输入方式
    为了方便输入,首先利用09号系统调用,让用户以10进制的形式输入成绩到内存缓冲区,然后调用子程序将字符串转换成二进制数值,并保存到记录中相应的字段里。
    3.4.2 数据存档文件格式采用二进制格式,即直接将内存中的数据复制到文件中而不经过任何转换。文件开头的两个字节表示文件中记录的总数,之后的每32个字节存储一条记录。文件的结构如下表所示:



    记录总数:2个字节




    记录1:20个字节


    记录2:20个字节


    ……


    记录n:20个字节



    3.4.3 从文件中读取数据由于该程序生成的文件为二进制格式,因此读取过程十分简单,是写入过程的逆过程:首先读取文件开头的两个字节,便知道了文件中记录的总数,然后循环读取之后的每一条记录。
    四 运行测试程序共一个可执行文件,可以在DOS系统或者直接在Windows下运行,程序运行后在屏幕上显示主菜单,如下图所示:

    选择相应的菜单项可使用对应的功能,以下为各个功能模块的详细说明。
    4.1 数据的录入在主菜单下选择“1”,进入记录输入模块,按照提示输入各字段的值,如下图所示:

    4.2 数据和显示在主菜单下选择“2”,进入记录输出模块。下图为添加了5条记录后打印的效果:

    4.3 数据存档在主菜单下选择“3”,将当前在内中的全部记录保存到文件中(c:\student.txt),如下图所示:

    4.4 从文件中读取在主菜单下选择“4”,将当前在内中的全部记录保存到文件中(c:\student.txt),如下图所示:
    2 评论 125 下载 2018-11-04 19:18:48 下载需要10点积分
  • 基于JAVA的图书管理系统

    1 数据库设计1.1 需求分析1.1.1系统简要分析本系统的用户为图书馆工作人员,系统用户分为管理员和普通用户两种。管理员为系统的高级用户,普通用户为图书馆工作人员。管理员账号和密码预先写入数据库中,账号是每位同学的学号,密码是学号后三位。
    系统为不同用户提供不同的功能:
    1.1.2基本需求功能点分析系统为不同用户提供不同的功能:

    管理员功能:

    登陆:输入管理员帐号和密码,验证通过后可登陆系统。
    用户管理:

    添加系统普通用户为普通用户重置登陆密码。
    图书类别管理:

    添加图书类别,如:政治,经济,军事,医药等。修改图书类别名称。类别查询。
    图书管理:

    添加一本图书。图书信息包括:书名,第一作者,第一出版社,出版年份,状态(正常,报废),类别等。修改图书信息。图书查询。
    读者类别管理:

    添加读者类别,类别信息包括:类别名称,最长借阅天数,最大借阅本数等。修改读者类别名称。读者类别查询。
    读者管理:

    添加读者。读者信息包括:姓名,读者类别,身份证号,联系电话等等。修改读者信息。读者查询。
    普通用户功能:

    系统登陆和密码修改图书馆工作人员凭用户号和密码登陆系统。图书借阅为读者借书。如果该读者的借书量未达到最大借阅本书,且无超期欠费情况,则可以为其登记借书信息;如有欠费,则需先缴费还书。为读者还书。如果该读者所还图书未超期欠费,则可以为其还书;如欠费,则先计算欠费金额,付费后再还书。

    1.1.3 系统运行条件分析此软件系统需要至少一台计算机为服务器Windows操作系统SQL Server 2008 或更高版本数据库服务器
    1.1.4 数据字典


    表名
    字段序号
    字段名
    主键
    类型
    占用字节
    长度
    允许空




    t_borrowing
    1
    readerId

    int
    4
    10




    2
    bookId

    int
    4
    10




    3
    borrowingTime

    date
    3
    10



    t_return
    1
    readerId

    int
    4
    10




    2
    bookId

    int
    4
    10




    3
    returnTime

    date
    3
    10



    t_reader_bookRelation
    1
    readerId

    int
    4
    10




    2
    bookId

    int
    4
    10



    t_user
    1
    id

    int
    4
    10




    2
    password

    varchar
    50
    50




    3
    username

    varchar
    50
    50




    4
    usertype

    varchar
    20
    20



    t_bookType
    1
    id

    int
    4
    10




    2
    bookTypeName

    varchar
    10
    10




    3
    bookTypeDesc

    varchar
    1000
    1000



    t_book
    1
    id

    int
    4
    10




    2
    bookName

    varchar
    20
    20




    3
    author

    varchar
    20
    20




    4
    bookTypeid

    int
    4
    10




    5
    publisher

    varchar
    20
    20




    6
    publishtime

    varchar
    10
    10




    7
    state

    varchar
    10
    10




    8
    bookDesc

    varchar
    100
    100



    t_readerType
    1
    id

    int
    4
    10




    2
    readerTypeName

    varchar
    20
    20




    3
    theLongestBorrowingDay

    int
    4
    10




    4
    maximumBorrowingNumber

    int
    4
    10



    t_reader
    1
    id

    int
    4
    10




    2
    IDNumber

    varchar
    20
    20




    3
    name

    varchar
    20
    20




    4
    readerTypeid

    int
    4
    10




    5
    tel

    varchar
    11
    11




    1.2 概念结构设计系统E-R图如图

    1.3 逻辑结构设计此部分需要列出由E-R图转化得到的数据表。

    用户表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    id
    int
    4
    主码
    用户id


    password
    varchar
    50
    非空
    用户登录密码


    username
    varchar
    50
    非空
    用户名


    usertype
    varchar
    20
    非空,管理员或普通用户
    用户类型




    图书类别表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    id
    int
    4
    主码
    图书类别id


    bookTypeName
    varchar
    10
    非空
    图书类别名


    bookTypeDesc
    varchar
    1000

    图书类别描述




    图书表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    id
    int
    4
    主码
    图书id


    bookName
    varchar
    20
    非空
    图书名


    author
    varchar
    20
    非空
    作者


    bookTypeid
    int
    4
    非空,外键
    图书类别id


    publisher
    varchar
    20
    非空
    出版社


    publishtime
    varchar
    10
    非空
    出版时间


    state
    varchar
    10
    正常或报废
    图书状态


    bookDesc
    varchar
    100

    图书描述




    读者类别表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    id
    int
    4
    主码
    图书id


    readerTypeName
    varchar
    20
    非空
    读者类型名


    theLongestBorrowingDays
    int
    4
    非空
    最长借阅时间


    maximumBorrowingNumber
    int
    4
    非空
    最大借阅数量




    读者表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    id
    int
    4
    主码
    读者id


    IDNumber
    varchar
    20
    非空
    身份证号


    name
    varchar
    20
    非空
    姓名


    readerTypeid
    int
    4
    非空,外键
    读者类别号


    tel
    varchar
    11

    联系方式




    借书表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    readerId
    int
    4
    主码
    读者id


    bookId
    int
    4
    主码
    图书id


    borrowingTime
    date
    8
    主码
    借阅时间




    还书表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    readerId
    int
    4
    主码
    读者id


    bookId
    int
    4
    主码
    图书id


    returnTime
    date
    8
    主码
    归还时间




    读者-图书关系表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    readerId
    int
    4
    主码
    读者id


    bookId
    int
    4
    主码
    图书id



    1.4 物理结构设计数据库管理系统:SQLServer 2014
    1.5 数据库实施1.5.1 数据库表和视图清单如图所示:

    1.5.2 数据库基本表
    用户表


    图书类别表


    图书表


    读者类别表


    读者表


    借书表


    还书表


    读者-图书关系表

    1.5.3 视图1.5.3.1 view_bookType创建视图代码:
    create view view_bookTypeasselect* from t_bookType
    作用:对图书类别全部属性的查询语句,通过java代码实现可显示在图书类别维护界面的表格中。
    1.5.3.2 view_borrowing创建视图代码:
    create view view_borrowingasselect readerId,IDNumber,name,bookId,borrowingTimefrom t_reader,t_borrowingwhere t_reader.id=t_borrowing.readerId;
    作用:对借书表和读者表部分属性的查询语句,通过java代码实现可显示在图书借阅记录界面的表格中。
    1.5.3.3 view_userlist创建试图代码:
    create view view_userlistasselect * from t_user where usertype='普通用户'
    作用:查询用户类别为普通用户的用户的全部属性,通过java代码显示在重置用户密码界面的表格中。
    1.5.4 存储过程1.5.4.1 existBookByBookTypeId存储过程创建存储过程代码:
    create procedure existBookByBookTypeId(@ID int)as (select*from t_bookwhere bookTypeId=@ID)
    作用:判断指定图书类别下是否有图书
    1.5.4.2 existReaderByReaderTypeId存储过程create procedure existReaderByReaderTypeId(@ID int)as(select*from t_readerwhere readerTypeId=@ID)
    作用:判断指定读者类别下是否有读者
    1.5.5 触发器删除读者触发器
    create trigger triger_deletereaderon t_reader instead of deleteasbeginEXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'--禁用约束delete from t_borrowing where readerId=(select id from deleted)delete from t_return where readerId=(select id from deleted)delete from t_reader where id=(select id from deleted)EXEC sp_msforeachtable 'ALTER TABLE ? CHECK CONSTRAINT ALL' --启用约束end
    作用:删除读者时有外键约束,触发器取消外键约束,删除借书还书记录中该读者的记录,再删除该读者,再启用约束。
    2 系统设计2.1 系统功能模块设计此部分主要描述各个模块具体实现的各项功能点以及模块之间的关系,模块结构划分如图所示:

    2.1.1 管理员用户模块该模块具体功能是管理员对图书系统进行管理,主要包括图书类别管理模块,图书管理模块,读者类别管理模块,读者管理模块,用户管理模块。

    图书类别管理模块:此模块下可进行图书类别的添加和维护,维护包括查询、删除和修改,可以对图书类别名和图书类别描述等属性进行操作。
    图书管理模块:此模块下可进行图书的添加和维护操作,维护包括查询删除和修改,可对图书名称、图书作者、图书类别、出版社、出版时间、图书状态、图书描述等属性进行操作。
    读者类别管理模块:此模块下可进行读者类别的添加和维护,维护包括查询、删除和修改,可对读者类别名称、最长借阅天数和最大借阅本数等属性进行操作。
    读者管理模块:此模块下可进行读者的添加和维护,维护包括查询、修改和删除,可对读者身份证号、姓名、联系方式、读者类别等属性进行操作。
    用户管理模块:此模块下可进行对普通用户的添加和修改普通用户密码操作。

    2.1.2 普通用户具体功能模块该模块具体功能是普通用户登录系统后进行借书和还书操作,主要包括图书借阅和图书归还模块。

    图书借阅模块:此模块下可进行图书借阅操作和对借阅记录的查询操作。图书借阅可添加图书借阅记录。
    图书归还模块:此模块下可进行图书归还操作和对归还记录的查询操作。图书归还可添加图书归还记录。

    2.2 系统功能设计本部分按系统主要功能绘制流程图,说明系统功能将如何现。如图所示:

    3 系统实现3.1系统项目清单系统项目具体所含如图所示:
    model包包含各种实体类,dao包包含各种数据库操作的类,util包包含数据库工具类和字符串工具类,model包包含各种界面类。


    3.2 登录界面登录界面由LogOnFrm.java实现,输入用户名和密码,选择用户类型为管理员或普通用户,验证成功即可进入主界面。用户名或密码错误或未输入则弹出窗体提示。如图所示。

    3.3 管理员主界面管理员主界面由MainFrm.java实现,选中菜单栏中选项选择要显示的功能窗体。如图所示:

    3.3.1 图书类别维护界面

    3.3.2 图书添加图书的添加是管理员向数据库中加入一条图书信息,若图书名称、图书作者等非空数据为空,则弹出提示图书不能为空等。图书类别为一个下拉框,其中显示图书类别表中的图书类别名称。图书状态只有正常和报废两种,用单选按钮实现。图书添加界面如图所示。

    3.3.3 图书维护图书维护界面可实现图书的查询、修改删除。没有操作时中间表格bookTable显示所有图书。进行查询操作时表格中显示查询到的结果。添加了表格行点击事件,点击指定行时,下面的表单操作中的文本框被选中内容填充,修改文本框的内容后点击修改按钮,对数据库执行update操作,修改了数据库中数据,然后界面中bookTable表刷新,显示更新后的数据。点击删除按钮时执行sql的delete操作。图书维护界面如图所示。

    3.3.4 添加普通用户在管理员主界面选择用户管理-添加普通用户弹出菜单如图3-8,输入要添加的用户名和密码,点击添加按钮,提示用户添加成功。如用户名和密码为空则弹出错误提示。重置按钮可清空两个文本框。

    3.3.5 重置用户密码菜单在管理员主界面选择用户管理-重置用户密码菜单如图,可进行查询和修改密码操作。在查询框中输入要查询的用户名,中间的userTable中将显示查询出的信息,运用视图view_userlist。点击要修改的用户所在行,该用户密码将出现在密码修改框的密码文本框中,修改内容,点击修改按钮,弹出用户密码修改成功则完成用户密码修改。选中表中用户点击删除按钮,弹出删除成功提示框,则完成了删除该普通用户操作。

    3.3.6 读者维护界面在管理员主界面选择读者管理-读者维护显示读者维护界面如图。可对读者进行查询、修改、删除操作。查询结果显示在表格中。选择表格中数据可进行修改、删除操作。修改、删除完成后提示修改成功或删除成功。删除操作运用触发器triger_deletereader同时删除被删除读者的借书记录和还书记录。

    3.3.7 读者类别维护界面在管理员主界面选择读者类别管理-读者类别维护显示读者类别维护界面如图。读者类别管理界面可实现对读者类别的查询、修改、删除操作,其中删除操作调用存储过程existReaderByReaderTypeId判断该读者类别下是否有读者。有读者时的错误提示如图。


    3.4 普通用户主界面普通用户主界面由MainFrm2.java实现,选中菜单栏中选项选择要显示的功能窗体。如图所示。

    3.4.1 图书借阅界面在普通用户主界面点击借书-图书借阅显示图书借阅界面如图。输入读者编号和图书编号点击确定,若读者编号和图书编号在t_reader和t_book表中不存在则弹出错误提示框。点击重置两文本框重新为空。借书本数超限提示如图,借书时间超限提示如图。



    3.4.2 图书借阅记录查询在普通用户主界面选择借书-借阅记录查询显示界面如图。在查询框中输入读者身份证号和图书编号,点击查询按钮,可进行查询操作。中间表格运用视图view_borrowing显示查询出来的记录,查询之前显示所有的借书记录。

    4 总结图书管理系统运用java语言,连接数据库,主要用eclipse的windowsbuilder插件完成图形化界面,数据存储在SQL server数据库中,通过SQL语句完成对数据库的操作。
    运用了视图、存储过程、触发器来完善系统。系统完成了对图书、读者、用户等对象的增删改查操作。实现了大部分图书管理系统要求的功能。
    不足:系统虽然完成了图书借阅超过期限的提示,但没有写有关的缴费界面和操作。
    8 评论 376 下载 2019-03-02 17:57:58 下载需要12点积分
  • 基于JAVA和MYSQL实现的清朝名人数据库系统

    摘 要清朝是中国历史最后一个大一统封建王朝,共传十帝,享国二百七十六年。为了能够将古代名人及各个朝代的皇帝的信息统一起来,使用数据库信息管理系统是很常见的 方法。数据库与 JAVA Swing 结合起来,既可以做出一个直观、简约的界面,也可以很容易实现添加、删除、查询和修改操作。同时也可以存储相当可观的资料。首先,利用 java 做出必要的界面,其中包括登录以及增删查改五个界面,其次,使用 JDBC 将已经存入名人、皇帝资料库的数据库连接起来,最后再加入指令代码,即可实现名人数据库 管理系统。在名人数据库管理系统设计完成之后,它必须具备界面中所对应的功能,即可以完成登录、注册、添加、删除、查询和修改操作,并且在数据库中会得到相应的反映。名人数据库管理系统相对于之前的管理方法及途径更方便管理,易于更新,最大化 的简化了管理员的管理工作,同时也让使用者更容易接受该系统。
    关键词:古代名人;管理系统;javaswing 开发;mysql 储存
    AbstractThe Qing Dynasty was the last unified feudal dynasty in Chinese history. It was handed down to ten emperors for 276 years. In order to unify the information of ancient celebrities and emperors of different dynasties, the use of database information management system is a common method. The combination of database and JAVA Swing can not only make an intuitive and concise interface, but also make it easy to add, delete, query and modify operations. At the same time, considerable data can be stored. Firstly, we use java to make the necessary interfaces, including login, add, delete and modify five interfaces. Secondly, we use JDBC to connect the databases already stored in celebrities and emperors’databases. Finally, we add instruction codes to realize the celebrity database management system. After the design of celebrity database management system is completed, it must have corresponding functions in the interface, that is, it can complete login, registration, addition, deletion, query and modification operations, and it will be reflected in the database accordingly. Celebrity database management system is easier to manage and update than the previous management methods and ways, which simplifies the management of administrators and makes users more receptive to the system.
    Keywords:Ancient celebrities; Management system; JavaSwing development; Mysql storage
    第一章 课题背景以前对古代名人管理的主要方式是基于文本、表格等纸介质的手工处理,对于数据信息处理工作量大,容易出错;随着网络的发展很多资料由纸质迁移到了网络上,但是 由于数据繁多,杂乱且良莠不齐,不易查找[1]。采用数据库技术生成的名人管理系统 将会极大地方便古代名人管理和使用人员,使得需要查找整理此类资料的人员从繁忙、复杂的工作进入到一个简单、高效的工作中。
    1.1 课题介绍进入 21 世纪,随着计算机和网络技术的飞速发展,数字资源越来越显现其重要作 用,依托计算机中的资源,建立具有文化特色的专题资源数据库,已成为许多机构的重要任务之一[1]。名人数据库就是其中的一种以收集、整理、开发、利用具有公众效应的 名人资料,并对名人资源进行重组、整合和分层次加工,实现多途径的管理和深层次地揭示名人资料的一种专题数据库[2]。
    名人数据库是一种以收集、整理、开发、利用具有公众效应的名人资料,并对名人 资源进行重组、整合和分层次加工,利用多个软件实现检索和增删查改的功能。建设名人数据库应具备资源、数据、技术和网络等方面的基础[2]。名人专题数据库的组织结构应以人为主线,并充分发挥 JAVA 的性能,集多功能为一体,具体结构框架可由 MYSQL 中建立的数据库、JAVA 的功能和 JDBC 连接构成。
    网络中虽然存贮大量古代名人资料,但是其中的内容也是鱼龙混杂。所以让当用户 们在网上查询名人资料时,虽然网页上囊括的知识比较多,但是事实上见效甚微[3]。为 了能够使得用户们可以更高效的查询到自己想要的知识内容,名人数据库管理系统应运而生。现代计算机可以帮助人们实现这些看似并不复杂的而实际操作起来非常不顺心的工作。试想一下,当用户想要查询某个人的资料时,只需要输入人物名字,就可以看到 该人的详细资料。设计名人数据库的目的便在于在计算机软件支持下,实现对名人资料信息采集、输入、输出,便于管理,便于检索的技术系统[4]。
    1.2 工具介绍1.2.1 java 语言Java 是一门面向对象编程语言,不仅吸收了 C++语言的各种优点,还摒弃了 C++ 里难以理解的多继承、指针等概念,因此 Java 语言具有功能强大和简单易用两个特征。Java 语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程[5]。
    Java 具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点。Java 可以编写桌面应用程序、Web 应用程序、分布式系统和嵌入 式系统应用程序等。
    1.2.2 Eclipse 介绍Eclipse 是著名的跨平台的自由集成开发环境(IDE)。最初主要用来 Java 语言开发, 通过安装不同的插件 Eclipse 可以支持不同的计算机语言,比如 C++和 Python 等开发工具。Eclipse 的本身只是一个框架平台,但是众多插件的支持使得 Eclipse 拥有其他功能相对固定的 IDE 软件很难具有的灵活性。许多软件开发商以 Eclipse 为框架开发自己的 IDE[6]。
    Eclipse 最初由OTI和IBM两家公司的IDE产品开发组创建,起始于1999年4月。IBM 提供了最初的 Eclipse 代码基础,包括 Platform、JDT 和 PDE。Eclipse 项目 IBM 发起,围绕着 Eclipse 项目已经发展成为了一个庞大的 Eclipse 联盟,有 150 多家软件公司参与到Eclipse项目中,其中包括Borland、Rational Software、Red Hat及Sybase 等。Eclipse 是一个开放源码项目,它其实是Visual Age for Java的替代品,其界面跟先前的Visual Age for Java 差不多,但由于其开放源码,任何人都可以免费得到,并可以在此基础上开发各自的插件,因此越来越受人们关注[7]。随后还有包括 Oracle 在内的许多大公司也纷纷加入了该项目,Eclipse 的目标是成为可进行任何语言开发的 IDE 集成者,使用者只需下载各种语言的插件即可。
    1.2.3 SQL Server 简介SQL Server 是由 Microsoft 开发和推广的关系数据库管理系统(DBMS),目前最新版本是2012年3月份推出的SQL SERVER 2012。SQL是英文(Structured Query Language) 的缩写,意思为结构化查询语言。SQL语言的主要功能就是同各种数据库建立联系,进行沟通。SQL被作为关系型数据库管理系统的标准语言[8]。SQL语句可以用来执行各种 各样的操作,例如更新数据库中的数据,从数据库中提取数据等。
    1.3 章节安排本报告总共分为四个章节:

    第一章:主要写的是名人管理系统的背景、设计目的、使用的工具介绍等
    第二章:主要介绍该系统的实现的主要功能以及相应的模块
    第三章:主要介绍 MySQL 中主要的数据格式,以及实现各个功能的伪码
    第四章:主要写的是该系统的测试以及结果分析

    第二章 设计简介及设计方案论述整个应用系统的设计严格按照数据库设计的方法来进行,包括数据库的设计和应用程序的设计,两部分相辅相成[9]。数据库设计过程包含以下步骤:需求分析:系统的目 的、用户需求、功能流程图;概念结构设计:用 E-R 图来描述实体及实体间的联系;逻辑结构设计:确定关系模式,各种约束的声明,同时给出系统的功能模块组成图,系统 各模块功能;物理结构设计。数据库的实施阶段:数据库用 SQL SERVER 等创建,前端开发使用 JAVA 实现。
    2.1 需求分析所谓”需求分析”,是指对要解决的问题进行详细的分析,弄清楚问题的要求,包括需要输入什么数据,要得到什么结果,最后应输出什么。可以说需求分析是做系统之前必做的。需求分析是软件工程中的一个关键过程[10]。在这个过程中,系统分析员和软件工程师确定顾客的需要。只有在确定了这些需要后,设计者才能够分析和寻求新系统的 解决方法。需求分析阶段的任务是确定软件系统功能。
    2.1.1 用户需求在构造系统时,首先从需求出发构造数据库表,然后再由数据库表结合需求划分系统功能模块。这样,就把一个大的系统分解成了几个小系统。这里把系统划分为了三个模块:登录模块,管理员模块,用户模块。模块分别能够实现以下功能:

    登录模块,实现登录功能,注册功能
    管理员模块,实现管理员对名人的增删改减功能
    读者模块,实现用户查询功能

    2.1.2 系统目标根据需求分析及用户的沟通,该系统应达到以下目标:

    界面设计友好,美观
    数据存储安全,可靠
    信息分类清晰,准确
    强大的查询功能,保证数据查询的灵活性
    操作简单易用,界面清晰大方
    系统安全稳定
    开发技术先进,功能完备,扩展性强
    占用资源少,对硬件要求低
    提供灵活,方便的权限设置功能,使整个系统的管理分工明确

    2.2 概要设计数据库系统主要使用面向对象的分析方法,采用 JAVA、SQL语句来详尽地描述清朝历代皇帝和名人的详细资料,名人数据库管理系统可以分为两个大型模块:用户登录和 管理员登录[11]。
    用户登录是名人数据库系统中的一个重要部分,它虽然不能像管理员一样对数据库进行更新操作,但是管理员的存在也正是服务于用户,管理员的操作能够让用户查询到 相对准确的信息,同时也提高了用户查询的效率。同时给予用户查询功能可以防止一些不良用户对系统的恶意使用,进而保证了系统的安全性[12]。
    Swing 程序表示 JAVA 的客户端窗体程序,除了通过手动编写代码的方式设计 Swing 程序之外,Eclipse中还提供了一种Window Builder工具,该工具是一种非常好用的 Swing 可视化开发工具,有了它,开发人员就可以通过拖放组件的方式编写 Swing 程序了。
    当名人、皇帝的资料表导入 MYSQL之后,需要在 Eclipse 中做出几个必要的界面: 登录界面和增加、删除、查询、修改界面,同时也需要必须的管理员选择界面。在界面中设计采用 Window Builder 插件,进而在后台自动生成代码。
    数据库管理系统是在管理员对系统进行更新操作之后,数据库内的数据随之发生改 变。登录操作已经完成,其中包括用户登录与管理员登录。两种身份登陆之后出现的界面是不同的,用户登录成功之后只能进入查询界面,而管理员登录之后进入一个选择界面,可以自主选择增加、删除、查询、修改操作。
    登录操作已经完成,其中包括用户登录与管理员登录。两种身份登陆之后出现的界面是不同的,用户登录成功之后只能进入查询界面,而管理员登录之后进入一个选择界面,可以自主选择增加、删除、查询、修改操作。
    在管理员登录成功之后,进入一个选择界面,在这个界面中包含增删查改四个功能。在添加界面中,必须先输入人物的名字,并在文字提示框后输入相应的内容,进而通过系统将输入的信息录入数据库。
    增加、删除、修改三个操作中,无论其中哪一种进行操作,数据库中的数据也需要发生相应改变,这一点可以在基本实现系统中进行操作,操作完成之后打开 MYSQL的 表进行验证。
    管理员登录的数据需求分析用户的需求具体体现在各种信息的提供、保存、更新和查询上,这就要求数据库结构能充分满足各种信息的输出和输入。其主要模块示意图如 图 2.1 所示。


    增加信息(管理员身份):在界面上输入相应的名人信息后,经过系统确认即可以在数据库中存储名人的信息,并且在查询界面可以查询到相应的信息
    查询信息(管理员身份):输入人物名字,选择该人物的身份(皇帝或者名人),经过系统查询之后即可在界面上显示相应内容
    删除名人(管理员身份):在相应界面中输入需要删除的名人姓名,确认之后系统将删除该名人信息,并在数据库中清除该名人信息
    修改信息(管理员身份):在修改界面中输入名人姓名及相应的信息,系统确认之后即可修改信息,并且在数据库中得以修改,在查询界面亦可查询到更新后的信息
    查询信息(用户身份):输入人物名字,选择该人物的身份(皇帝或者名人),经过系统查询之后即可在界面上显示相应内容
    登录验证(用户身份):输入用户名字和密码,点击登录,通过验证即可登录跳转用户查询界面,假如密码错误,则显示“该用户不存在”
    登录验证(管理员身份):输入管理员名字和密码,点击登录,通过验证即可登录跳转用户查询界面,假如密码错误,则显示“该管理员不存在”
    用户注册(用户身份):在用户登录界面点击用户注册,输入用户名和密码以及 Id,点击确定,即可注册成功

    第三章 详细设计概念设计是由分析用户需求到生成概念产品的一系列有序的、可组织的、有目标的设计活动,它表现为一个由粗到精、由模糊到清晰、由抽象到具体的不断进化的过程。概念设计即是利用设计概念并以其为主线贯穿全部设计过程的设计方法。概念设计是完整而全面的设计过程,它通过设计概念将设计者繁复的感性和瞬间思维上升到统一的理性思维从而完成整个设计。
    3.1 逻辑设计逻辑设计就是把一种计划、规划、设想通过视觉的形式通过概念、判断、推理、论证来理解和区分客观世界的思维传达出来的活动过程。逻辑设计比物理设计更理论化和抽象化,关注对象之间的逻辑关系,提供了更多系统和子系统的详细描述。
    3.1.1 关系模型概念结构设计所得的 E-R 模型是对用户需求的一种抽象的表达形式,它独立于任何一种具体的数据模型,因而也不能为任何一个具体的 DBMS 所支持。为了能够建立起最终的物理系统,还需要将概念结构进一步转化为某一 DBMS 所支持的数据模型,然后根据逻辑设计的准则、数据的语义约束、规范化理论等对数据模型进行适当的调整和优化,形成合理的全局逻辑结构,并设计出用户子模式。这就是数据库逻辑设计所要完成的任务。
    数据库逻辑结构的设计分为两个步骤:首先将概念设计所得的 E-R 图转换为关系模 型;然后对关系模型进行优化,如图 3.1 所示。

    关系模型是由一组关系(二维表)的结合,而 E-R 模型则是由实体、实体的属性、实体间的关系三个要素组成。所以要将 E-R 模型转换为关系模型,就是将实体、属性和联 系都要转换为相应的关系模型。
    本系统的关系模型转换如下:
    user (id,username,password)people(id,name,national,place,time,work,message)emperor(id,name,national,yearname,place,miaohao,overtime,message,shihao)3.1.2 系统功能总框图书馆管理系统功能总框图,如图 3.2 所示。

    3.2 物理设计数据库在物理上的存储结构与存储方法称为数据库的物理结构,它依赖于选定的数据库管理系统。为一个给定的逻辑数据模型选取一个最适合应用要求的物理结构的过程, 就是物理设计。
    3.2.1 基本表设计由于名人数量过于繁多,需要先从网络中收集名人信息,并按照一定的属性存放在 Excel 工作表中。清朝名人分为皇帝、名人两个表,并在收集工作完成之后导入 MYSQL 中,在 MYSQL 同样需要两个表进行存储[10]。
    皇帝表需要的属性有 Id、姓名、在位时间、民族、年号、庙号、成就,在 MYSQL 存储方式如表 3-1 所示。



    属性
    存储类型
    是否可为空




    Id
    Var char(10)



    姓名
    Var char(10)



    在位时间
    Var char(10)



    民族
    Var char(10)



    年号
    Var char(10)



    庙号
    Var char(10)



    成就
    Long text




    名人表需要的属性有 Id、姓名、时期、民族、官职、出生地、成就,在 MYSQL 存 储方式如表 3-2 所示。



    属性
    存储类型
    是否可为空




    民族
    Var char(10)



    Id
    Var char(10)



    时期
    Var char(10)



    姓名
    Var char(10)



    官职
    Var char(10)



    成就
    Long text



    出生地
    Var char(10)




    对于数据库中的皇帝表和名人表存在一定联系,其中的实体与属性的联系如图 3.1 所示。

    3.2.2 系统功能设计当名人、皇帝的资料表导入 MYSQL之后,需要在 Eclipse 中做出几个必要的界面: 用户和管理员登录界面、用户注册界面、增加、删除、查询、修改界面,同时也需要必须的管理员选择界面。在界面中设计采用 Window Builder 插件,进而在后台自动生成代码[10]。
    在用户和管理员登录界面中,在键盘上输入用户名和密码,如果为空或者用户名与 密码不匹配都会给出错误提示并无法登录,且在登陆之前需要选择登录身份,即选择“管理员”或者“用户”。如果登陆错误次数超过一定数目,同样会导致无法登陆。如果登 录成功则进入相应的界面。故可以写出登录伪码:
    If 用户名=空 Then 输出 "登录用户名不能为空,请重新填写!" ExitEnd IfIf 密码= 空 Then 输出"登录用户密码不能为空,请重新填写!"End If If 选择身份=空 Then 输出 "你没有选择用户身份,请选择!" Exit End If连接数据库之后,核对过账号密码; 输出"祝贺你!你已经成功登录!" "如果账号密码不匹配,输出"对不起!你输入的用户密码不正确,请重新输入!" 次数 + 1;重新输入; 如果连续三次不正确,则输出“对不起,你已经连续三次输入错误,不能继续登录 程序就退出!" End ELSE If 身份 = "管理员" Then 出现选择界面 Else If 身份= "用户" Then 出现查询界面 End If此时,登录操作已经完成,其中包括用户登录与管理员登录。两种身份登陆之后出 现的界面是不同的,用户登录成功之后只能进入查询界面,而管理员登录之后进入一个选择界面,可以自主选择增加、删除、查询、修改操作。
    在管理员登录成功之后,进入一个选择界面,在这个界面中包含增删查改四个功能。在添加界面中,必须先输入人物的名字,并在文字提示框后输入相应的内容,进而通过系统将输入的信息录入数据库。
    If 身份= "皇帝" Then 查找皇帝名字; 更新信息; End If If 身份 = "名人" Then 更新信息 If 信息错误 输出"添加失败",Else 输出"添加成功" End If对于增加操作,实际上是在系统中键入皇帝或者名人的资料,在 UTF-8 格式中的信 息会被系统识别,所以在文本框内添加信息会被系统录入。在选择了身份之后,系统会根据代码将信息录入对应的表中,进而将存入的信息放入数据库中,在添加之后,就可以在查询界面中查到相应结果。
    同样的,在实现删除功能之前,首先要通过 SQL 语句连接上数据库,在管理员输入了人物姓名之后,系统查找出相应的人物,进而删除掉该任务的所有信息,有删除界 面伪代码如下:
    连接数据库; If 身份= "皇帝" Then 查找皇帝名字; 删除; End If If 身份 = "名人" Then 删除; If 信息错误 输出"添加失败" Else 输出"添加成功" End If删除功能实际为系统在识别查询出管理员键入的人物名字之后,在数据库中将相应的信息更新为空,同时将姓名置空,所以在删除之后,数据库中该人物的资料已经被清除,无法再被查询出来。
    在修改功能中,管理员首先通过输入人物名字并选择相对应的身份(皇帝或者名人),在相对应的文本框内输入更改后的信息,在输入完成之后,点击修改,系统则会自动修改数据库内的人物信息。修改界面伪代码如下:
    连接数据库; If 身份= "皇帝" Then 查找皇帝名字; 修改信息; End If If 身份 = "名人" Then 修改信息; If 信息错误 输出"修改失败" Else 输出"修改成功" End If修改功能中同样是经过识别之后,找到相应的人物,将其中的信息更新为管理员键入的新内容,伪代码中的“修改信息”实际上是将管理员键入的内容代替原来的资料,从而做到信息更改。
    用户或者管理员都可以使用查询界面,在此界面中,需要在文本框内输入人物名字,再选择人物的身份(皇帝或者名人),点击查询,系统则会输出对应的人物信息,如果信息错误则无法输出。查询界面伪代码如下:
    连接数据库; If 身份= "皇帝" Then 查找皇帝名字; 输出信息; End If If 身份 = "名人" Then 输出信息; If 姓名错误 输出"查询失败"Else 输出"查询成功" End If查询信息的运作方式与其他操作类似,在用户或者管理员选择人物身份之后,系统在数据库的表中查询对应的人物名字,查询成功之后在界面上显示出内容。伪代码中的“输出信息”实为将表中的某一项内容特定输出,在不同的文本框内输出不同的内容。
    增加、删除、修改三个操作中,无论其中哪一种进行操作,数据库中的数据也需要发生相应改变,这一点可以在基本实现系统中进行操作,操作完成之后打开 MYSQL的表进行验证。
    四种操作已经基本完成,也就是 MYSQL 和 Eclipse 两个软件的工作已经完成,此时需要使用 JDBC 将二者进行连接,才能在 Eclipse 中的界面实现对应的功能。打开 NAVICAT FOR MYSQL 后,建立连接,新建数据库,在 JDBC 的连接 MYSQL。即完成了 Eclipse 与 MYSQL 的连接。
    第四章 设计结果及分析系统有 3 个模块:登录模块,管理员模块和用户模块。登录模块实现登录功能, 注册功能;管理员模块实现名人的增删改查;用户模块实现名人查找功能。
    4.1 功能测试在 Eclipse 打开工程,即可进入用户登录界面,登录界面显示如图 4.1 所示。

    选择用户身份进行登录操作时,点击注册用户,注册用户账号密码,即可完成注册,显示如图 4.2 所示。

    注册用户账号密码及序号填写完毕后,即可完成注册,具体结果显示如图 4.3 所示。

    使用数据库中已经存储的用户账号密码,进行登录,登录成功界面如图 4.4 所示。

    查询界面选项界面,在此界面中,需要选择人物的身份(皇帝或者名人),在文本框内输入人物名字,再点击查询,显示如图 4.5、4.6 所示。


    选择人物的身份(皇帝或者名人)之后,在文本框内输入人物名字,再点击查询,系统则会输出对应的人物信息。显示如图 4.7、4.8 所示。


    选择以管理员身份进入系统,显示管理员登录验证界面,输入管理员帐号和密码,点击登录按键,如图 4.9 所示。

    管理员帐号、密码和数据库管理员信息表比对后,验证成功,即可出现管理员主界面如图 4.10 所示。

    选择皇帝中的查询,即可看到添加窗口,名人和此界面一样,如图 4.11,图 4.12 所 示。

    点击添加皇帝,即可成功添加皇帝 选择皇帝中的查询,即可看到查询窗口,名人和此界面一样,如图 4.13 所示。

    搜索刚才的添加皇帝,即可进入皇帝的删,改界面,如图 4.14 所示。

    加入新的文字,或者修改旧信息,即可做到修改皇帝的功能,如图 4.15所示。

    直接点击删除按钮,即可做到删除当前页面皇帝的功能。
    4.2 结果分析一款好的名人数据库管理系统是在管理员对系统进行更新操作之后,数据库内的数据随之发生改变。在这一款清朝名人管理系统中,经过增加、删除、更改之后,再次查询人物信息都能得到正确的结果,说明在各种操作之后,数据库中的数据同样改变,可以评价为这一款名人管理系统是相对比较成功的。
    管理员增加、删除、修改三个操作中,无论其中哪一种进行操作,数据库中的数据也需要发生相应改变,这一点可以在基本实现系统中进行操作,操作完成之后打开 MYSQL 的表进行验证。四种操作已经基本完成,也就是 MYSQL和 Eclipse 两个软件的 工作已经完成,此时需要使用 JDBC 将二者进行连接,才能在 Eclipse 中的界面实现对应的功能[11]。
    总 结经过两周的努力,清朝名人管理系统终于完成,经过这次综合设计,自己总结了这个名人数据库管理系统的一些问题,不过收获还是颇为丰富的,再有理论知识上结合实践,使我学到了更多知识。
    首先,更进一步的了解了系统分析与设计、JAVA、JDBC 的基本操作,在这之前,系统分析与设计的学习仅仅刚开了个头,我们只是在了解一些概念性的东西。在做这个系统之前,我连基本的系统分析与设计,界面设计等这些东西都不熟练。现在对于系统中的增删改查操作比较熟练了。
    对于初学者来说,比较头疼的就是对于数据库连接的处理。我的建议是如果不理解先把按照课本上正确的语句敲,然后在多次进行数据库的链接,增删改查操作中不断总结规律。
    这次设计的名人数据库管理系统,全在自己所掌握的知识下,进行系统分析与设计,完全体现了自己在系统分析与设计中设计课程学习状况,充分地为自己以后更深入了数据库语言奠下深厚的基础。 纵观此名人数据库管理系统的整体概况,目前,自我认为设计良好,相关功能都能够实现,功能强大,条理清晰,界面可观性比较好。并且特色在于,所设计的表单都在一个表单系统桌面中运行,比较符合系统的观念。 在系统设计的过程中,我从中发现,学习系统分析与设计要细心和有耐性,并且要不断地从外界学习更多的技术才能设计出一套完美的系统。
    参考文献[1] 余丽君.关于建立沈阳名人数据库的设想[J].图书馆学刊,1999,21 (6):19-20.
    [2] 赵志刚,王伟.使用 SQL Server 管理应用程序服务数据[J].沈阳师范大学学报(自然 科学版),2010,28(2):233-235.
    [3] 黄欣欣.浅谈权限管理系统的需求分析[J].科技信息,2010(16):69-70.
    [4] 杨华.基于 B/S 模式的高校仓库管理系统的需求分析[J].无线互联科技,2014(8): 71-71.
    [5] 周龙.分布式数据库管理系统实现技术[M].科学出版社,1998.15-16.
    [6] 张慎明,卜凡强,姚建国.遵循 IEC61970 标准的实时数据库管理系统[J].电力系 统自动化,2002,26(24):26-30.
    [7] 廖卫东.陈梅. JAVA 程序设计[M].机械工业出版社,2008.268-346.
    [8] 李素若.JAVA 面向对象程序设计[M].北京化学工业出版社,2008.126-136.
    [9] 傅仕星.JAVA Swing 设计基础[M].清华大学出版社,2003.68-89.
    [10] 刘彦明.数据库基础设计与开发[M].西安电子科技大学出版社,2009.56-67.
    [11] 华轩逸.JAVA 面向对象程序设计(第二版)[M].北京:中国铁道出版社,2012.21-29.
    [12] 郑国果.JAVA 语言程序设计(第 4 版)[M].北京:清华大学出版社,2010.33-38.
    3 评论 39 下载 2019-02-25 17:44:01 下载需要14点积分
  • 基于JAVA的停车场管理系统

    第一章 概述1.1 项目背景车辆越来越多的今天,停车场只靠人工管理显然难度已经是提高很多,所以应该开发出便于管理记录的停车场管理系统来帮助对停车场进行管理。
    1.2 软件定义一款帮助停车场管理员对车辆进出进行管理的软件。
    1.3 开发环境
    Window10系统
    Eclipse java开发工具
    Oracle数据库

    第二章 需求分析2.1 题目要求2.1.1 问题陈述要求能够进行如下工作:

    车位基本信息维护(车位增加修改、收费标准变动等)
    交班报表功能(当班收费员收款总额)
    当前车位状况查询(车位状况分为:停用,占用和空闲)
    用户分级管理,人机界面良好

    2.1.2 功能描述该软件能对车辆进出进行管理,能计算停车时间并给管理员报出停车费用;能将流水显示给管理员;管理员能增加停车场会员、增减停车场车位;有一个客户面板给客户显示当前停车场的信息,如停车空位数。管理员分普通管理员和超级管理员,超级管理员能对普通管理员进行增删或者是修改管理员的权限将其改为超级管理员或者普通管理员。
    2.2 总体设计2.2.1 系统数据流图
    2.2.2 数据库E-R图
    第三章 数据库设计3.1 数据库表3.1.1 车位信息表t_parking


    字段名
    数据类型
    含义说明
    空值情况




    id
    varchar2(5)
    车位编号
    主键


    state
    varchar2(10)
    车位状态
    不为空


    type
    varchar2(10)
    车位类型
    不为空


    t_price
    number(6,2)
    临时单价(¥/h)
    不为空


    m_price
    number(6,2)
    会员单价(¥/m)
    不为空



    3.1.2 管理员表t_manager


    字段名
    数据类型
    含义说明
    空值情况




    id
    varchar2(10)
    工号
    主键


    pwd
    varchar2(20)
    密码
    不为空


    name
    varchar2(20)
    姓名
    不为空


    power
    number(1)
    权限
    不为空



    3.1.3 会员表t_Member


    字段名
    数据类型
    含义说明
    空值情况




    id
    varchar2(5)
    车位编号
    外键


    p_num
    varchar2(15)
    车牌号
    不为空


    name
    varchar2(20)
    姓名
    不为空


    tel
    varchar2(15)
    电话
    不为空



    3.1.4 会员收费表t_MemberFee


    字段名
    数据类型
    含义说明
    空值情况




    s_num
    varchar2(20)
    流水号
    主键


    id
    varchar2(5)
    车位编号
    外键


    p_num
    varchar2(15)
    车牌号
    不为空


    eff_date
    date
    生效期
    不为空


    ex_date
    date
    有效期
    不为空


    fee
    number(6,2)
    收费
    不为空


    m_id
    varchar2(10)
    收费员工工号
    外键



    3.1.5 临时用户收费表t_TempFee


    字段名
    数据类型
    含义说明
    空值情况




    s_num
    varchar2(20)
    流水号
    主键


    id
    varchar2(5)
    车位编号
    外键


    p_num
    varchar2(15)
    车牌号
    不为空


    en_time
    date
    进入时间
    不为空


    ex_time
    date
    退出时间
    可为空


    fee
    number(6,2)
    收费
    可为空


    m_id
    varchar2(10)
    收费员工工号
    外键



    3.1.6 停车场日常信息表t_infor_parking


    字段名
    数据类型
    含义说明
    空值情况




    today
    date
    日期
    主键


    en_num
    number(5)
    进入数
    不为空


    ex_num
    number(5)
    离开数
    不为空


    fee
    number(8,2)
    收费总额
    不为空


    m_id
    varchar2(10)
    收费员工工号
    外键



    其中t_Member的id是依赖于t_parking的id,t_MemberFee的m_id是依赖于t_manager的id,t_MemberFee的id是依赖于t_parking的id,t_TempFee的id依赖于t_parking的id,TempFee的m_id是依赖于t_manager的id,t_infor_parking的m_id是依赖于t_manager的id。
    第四章 软件功能设计4.1 程序设计4.1.1 程序工程文件结构
    4.2 详细设计4.2.1 dao文件dao文件定义了各个功能函数的接口,子目录imp文件中的类是对各个接口的实现,各个类定义了各个实体的相应操作,比如ManagerDao.Java就定义了对管理员的增减,权限修改,权限查询,信息查询等函数。
    /** * @Description:校验登录信息并返回登录人员是否能登录以及其权限 * @param tf * @param pf * @return HashMap<String,Object> */ public HashMap<String, Object> check(String tf, String pf); /** * @Description 判断权限 * @param tf * @return int */ public int judgeP(String tf); /** * @Description 增加员工 * @param manager * @return boolean */ public boolean add(Manager manager); /** * @Description 删除员工 * @param id * @return boolean */ public boolean delManager(String id); /** * @Description 查询员工 * @param id * @return String */ public String findManager(String id); /** * @Description 改变权限 * @param id * @return boolean */ public boolean upMP(String id,int power);}
    4.2.2 data文件data文件包含一个ConnOra.java,该类用于连接数据库,java连接Oracle数据库的基本模式为:
    public static Connection connOracle() { Connection con = null;// 创建一个数据库连接 try { Class.forName("oracle.jdbc.driver.OracleDriver");// 加载Oracle驱动程序 System.out.println("开始尝试连接数据库!"); String url = "jdbc:oracle:" + "thin:@127.0.0.1:1521:orcl";// 127.0.0.1是本机地址,XE是精简版Oracle的默认数据库名 String user = "C##U_32";// 用户名 String password = "zww0902150232";// 设置的密码 con = DriverManager.getConnection(url, user, password);// 获取连接 System.out.println("连接成功!"); } catch (Exception e) { System.out.println("未连接"); e.printStackTrace(); } return con; }
    4.2.3 table文件该文件包含了各个实体类。停车场日常信息InforParking.Java、管理员Manager.java、会员Membe.java、会员收费MemberFee.java、车位Parking.java、临时收费TemporaryFee.java。
    4.2.4 ui文件此文件包含了对各个ui界面的设计以及事件的监听和触发,DataChooser.java是时间选择界面,InforPanel.java是客户面板,Login.java是登录界面,ManagerUI.java是系统主界面。
    4.3 程序功能图
    第五章 界面设计5.1 登录界面
    输入输出时

    5.2 程序主界面
    普通管理员和超级管理员界面略有不同,超级管理员多了对管理员管理的菜单选项。



    车辆进入成功后弹出提示窗口,车辆离开时,弹出收费窗口



    增加会员,填写会员信息,点击时间会弹出时间选择界面


    车位增减


    查看流水


    用户面板


    管理员工


    更改员工权限
    6 评论 387 下载 2019-01-28 16:38:21 下载需要13点积分
  • 基于J2EE的新闻管理系统的设计与实现

    摘 要为了实现网上新闻的发布与管理,方便后台人员操作,提高工作效率,构建了基于Java Web技术的新闻管理系统。文中论述了新闻管理系统的开发工具,系统分析、设计、实现和测试过程。分析了系统的可行性和用户需求,给出了系统的总体设计,包括功能模块划分和数据库设计,进一步阐述了系统的详细设计与实现。经过测试,系统实现了用户身份验证,管理员可以对新闻进行添加、修改、删除、查询等操作,普通用户可以浏览和评论新闻。系统比较完善,达到了预期目标。
    关键词:新闻管理,系统分析,系统设计,系统测试
    ABSTRACTIn order to implement the release and management of news on-line, be convenient to operate for administrators and improve the efficiency, the news management system based on Java Web technology is constructed. In the paper, it elaborates the development tools of the system, the procedure of system analysis, design, implementation and test. First, the feasibility and requirement are anglicized. Next, the general design, including function module dividing and database design is given. Furthermore, the detail design and implementation are expounded. After testing, the system has realized the functions of user authentication. Administrator can add news, update news, delete news, and search news, beside the ordinary people can browse news and review news. The system is nearly perfect, and the expected goal has achieved.
    KEY WORDS: News Management, System Analysis, System Design, System Testing
    1 绪论1.1 选题的背景现在是一个科学技术飞速发展的世纪。随着计算机及网络技术的飞速发展,Internet应用在全球范围内日益普及,当前社会正快速向信息化社会前进,各个领域都向系统化、规范化、自动化的方向发展,信息自动化的作用也越来越大,使得人们的工作效率、工作成绩和生活水平都日益提高。为了满足人们各自兴趣,如阅读新闻或对时事新闻的评论,社会上有不少的各类新闻网站等为人们提供获取新闻及新闻评论的平台。新闻管理系统在信息技术的强有力的推动下,已经叩响了人类的大门。当今社会,人们深深领略到了网络新闻的迅猛发展,在已经迈入21世纪的今天,认识、了解新闻管理系统,是每个人都要认真对待的一项新任务。
    1.2 选题的意义随着Internet的兴起,网络已经成为现代人生活的一部分,人们越来越想在最短的时间内知道所发生的各种新闻。于是新闻自动化便成了人们向往的事情,本系统就是一个基于B/S模式的新闻管理系统,采用的是J2EE技术,实现了网站新闻的动态管理,使得对信息的管理更加及时、高效,提高了工作效率。一方面,它提供了一个新闻发布和管理的功能;另一方面,现在的新闻发布要求与普通的用户实现交互,这一点也是其他一些媒体(电视、电台等)现在无法做到的,以后新闻管理系统会成为人们生活中不可缺少的一部分。
    1.3 系统及开发工具简介本系统是基于Java Web技术的新闻管理系统,其主要功能是信息的发布和管理,涉及到前台用户对新闻的浏览及评论和后台管理员对用户和新闻的管理。在前台新闻浏览模块,对新闻进行分类别展示,并通过栏目导航进入特定的新闻信息分类模块。前台浏览新闻不需要用户登录注册,对所有用户均开放,但是只有注册登录的用户才能发表评论。后台管理一般只有使用了正确的管理员账号和密码才能进入后台管理新闻和用户信息。
    本系统是采用Myeclipse8.6作为开发工具,MySQL作为后台数据库的基于B/S模式的新闻管理系统。MyEclipse是功能丰富的J2EE集成开发环境,包括了完备的编码、调试、测试和发布功能。MyEclipse可以简化Web应用开发,利用它可以在数据库和J2EE的开发、发布,以及应用程序服务器的整合方面极大地提高工作效率。MySQL是一套功能强大的关系型数据库管理系统,适用于Windows平台,采用它作为新闻管理系统的数据来源,可以让用户很简便地实现所要进行的数据存取操作。
    2 系统分析2.1 系统设计原则新闻是直接与广大用户进行会面的,新闻管理系统是用户对外发布消息的门户,对用户也有非常重要的影响。在进行系统设计时要充分考虑新闻管理工作的特点,需要遵循以下几个原则[1]:
    目的要明确
    首先,要有明确的设计目标和意图,需要设计开发什么类型的系统,系统应该有哪些功能,只有这样才会构建一个良好的新闻管理系统。
    可扩展性较强
    新闻管理系统完成并投入使用以后,主、客观条件难免会发生变化,同时在使用过程中也许会发现软件系统不够完善,此外为了加强系统功能,都需要对该系统进行维护和优化,因此在系统开发过程中要预先考虑到系统可扩展性,采取一定方法,增强系统的可扩展性。
    实用性和经济性
    在新闻管理系统设计开发过程中,要在尽量降低成本的同时,满足系统实用的需要,使的系统操作更加简便,使用效率更高,灵活性更强。
    2.2 系统需求分析作为软件的开发人员,无论开发任何一种软件,设计任何一个软件系统,首先要做的第一步骤就是需求分析[2]。软件需求分析是软件生存期中重要的一步,也是决定性的一步。需求分析的基本任务是准确地回答“系统必须做什么”这个问题,深入描述软件的功能和性能需求,确定软件设计的约束和软件同其他系统元素的接口细节,定义软件的其他有效性需求[3]。
    系统的需求分析在整个系统的开发过程中有着举足轻重的作用,只有在做好系统需求分析的基础上,才能开发出好的应用系统。
    2.2.1 系统的功能需求分析在对文献研究以及对相关用户充分调研的基础上,总结出了新闻管理系统的功能需求:

    新闻管理系统首先要具有新闻管理的功能,即发布新闻、修改新闻和删除新闻
    级别不同的用户要有不同的权限:管理员不仅可以对新闻进行分类、添加、修改和删除,还可以管理普通用户;普通用户登录系统后可对新闻进行浏览和评论
    要优化新闻管理流程,提高效率,保证新闻时效性

    综上所述,可将新闻管理系统分为前台页面模块和后台管理模块两大部分进行设计与实现。
    前台页面模块主要提供浏览功能,是用户访问新闻的界面。具体功能如下:

    首页是整个新闻管理系统的第一个页面,负责从总体上对系统信息进行显示。在首页的顶部要有用户注册和登录的模块
    用户注册和登录模块的下方要有新闻分类的主题。可以将新闻分为国内、国际、军事、财经、体育、娱乐、科技、房产、汽车、社会、游戏、教育等几类。点击某个主题后,仅对应该分类的所有新闻要以列表的形式分页显示出来
    首页的左侧,要将新闻标题以列表的形式显示出来,图片新闻显示在首页的右侧
    由于新闻管理系统的数据量极大,新闻标题也会很多,所以系统对新闻标题的显示要有分页功能,每一页显示一定数量的新闻标题
    首页的底部要显示网站的服务链接,网站地图,留言反馈,常见问题解答,热线电话,举报邮箱,以及版权等相关信息
    点击新闻标题,打开一个新闻后,要在新闻内容的下方显示出评论列表。评论包括评论人、评论内容和评论时间。如果一条新闻还没有用户评论,则在新闻内容的下方显示“暂无评论”
    新闻阅读页面顶部要有返回新闻首页的链接,页面底部要有合作伙伴的友情链接
    普通用户登录新闻管理系统后,在首页的顶部要有“返回用户主页”的链接。管理员登录系统后,在首页的顶部要有“返回后台主页”的链接,方便管理员进入系统后台对新闻管理系统进行管理
    新闻管理系统要有一定的出错提示。例如用户登录时没有输密码或者密码输入错误,要有“请输入密码”或“密码错误,请重新输入”的提示;用户注册时输入的密码和确认密码不一致时也要有提示,同时,为了方便数据库的管理,对用户注册输入的用户名和密码要有长度限制,如果用户输入的信息不在此限制范围内,也要有出错提示
    系统还要用一定的确认操作提示,以防止用户在不小心的情况下对系统做出错误的操作,造成损失。例如管理员在删除用户、删除新闻和删除分类主题时,要有确认是否删除的对话框提示

    后台管理模块 主要实现新闻管理系统的管理与维护,又分为管理员管理维护系统的界面和普通用户的个人主页。具体功能如下:

    管理员登录系统后进入后台管理界面。用户管理模块实现用户信息的查看和删除。新闻管理模块实现新闻的添加、分类、编辑、删除及相关属性的设置。分类管理模块实现新闻类别的添加、修改、删除
    普通用户登录系统后进入个人主页,在个人主页可以查看个人信息,可以修改密码
    注册并登录过用户可以对新闻发表评论,未注册的用户则不能对新闻发表评论

    2.2.2 系统的性能需求分析在功能需求基础上,要提出系统的性能目标,新闻管理系统需要达到以下性能要求[4]:

    界面友好。系统各个模块的界面布局和背景要美观,不能给用户很乱的感觉
    操作简单。新闻管理系统所面向的用户众多,用户角色也各不相同,他们中有系统管理人员,有注册过的普通用户,也有以游客身份访问系统、无需登录系统的匿名用户。其文化程度各异,掌握的计算机水平也不同。因此,设计的新闻管理系统在操作上要简单易用,人机界面友好,使用户无需培训就能在较短时间内熟练使用系统,完成新闻的管理、浏览和评论等业务
    安全性高。新闻管理系统是用户对外宣传的门户,系统设计的安全性十分重要。一旦系统遭到非法入侵,破坏系统或发布不良信息,将对用户产生严重的不良影响。为此,新闻管理系统将采取用户信息加密、用户权限设计、数据库备份等措施来保证系统的安全性
    稳定性高,易维护。一般来讲,新闻管理系统运行在中心服务器上,因此新闻管理系统必须有较强的稳定性和易维护性,一旦系统出现问题,可以快速修复,恢复正常运行

    2.3 用例图用例图描述的是参与者(actor)所理解的系统功能。用例图的建立是系统开发者和用户反复讨论的结果,描述了开发者和用户对需求规格达成的共识[5]。首先,它描述了待开发系统的功能需求;其次,它把系统看做黑盒子,从参与者的角度来理解系统;第三,它驱动了需求分析之后各阶段的开发工作,不仅在开发过程中保证了系统所有功能的实现,而且被用于验证和检测所开发的系统,从而影响到开发工作的各个阶段和UML的各个模型[6]。
    用例图的主要元素是用例和参与者。该新闻管理系统的参与者主要有:管理员,注册过的用户和没有注册过的匿名用户。
    注册过的用户可以浏览新闻、评论新闻,可以查看个人信息,也可以修改自己的登录密码。
    注册过的用户在新闻首页任意点击一个新闻标题,系统就会跳转到新闻阅读界面,用户就可以查看新闻的具体内容。
    新闻内容的下方是评论列表,注册过的用户登录系统后,还可以在评论列表下方的评论框里发表对该新闻的评论。
    注册过的用户登录系统后会跳转到个人主页。
    在个人主页里,用户点击查看个人信息,就会在个人主页看到自己的用户名和密码。用户点击修改密码,在出现的文本框里输入自己的新密码,点击修改,提示修改成功,则用户的密码被成功修改。
    注册用户的用例图如图2-1所示:

    没有注册过的匿名用户只可以浏览新闻,在新闻首页点击任意一个新闻的标题,就能在阅读页面看到该新闻的具体内容和其他用户对该新闻的评论。
    匿名用户的用例图如图2-2所示:

    管理员对新闻管理系统的管理主要分为用户管理、新闻管理和主题管理。其中在用户管理模块中,管理员可以查看其他用户的信息,可以删除其他用户。在新闻管理模块中,管理员可以添加新闻、修改新闻、删除新闻和查找新闻,当然管理员也可以浏览和评论新闻。在主题管理模块中,管理员可以添加主题、修改主题和删除主题。
    管理员登录系统后会跳转到后台管理页面。
    管理员点击“用户管理”,用户的详细信息就会以表格的形式出现在用户管理页面。点击任意一条用户信息后面的“删除”,会弹出确认删除对话框,点击“确认”,就可以删除一条用户信息。
    管理员点击“添加新闻”,在添加新闻页面,从新闻分类的下拉菜单选择新闻分类的主题,输入新闻的标题、作者以及正文内容,点击“提交”,就能成功发布一条新闻。
    管理员点击“编辑新闻”,会出现新闻的标题列表,在新闻标题的后面有“修改”和“删除”两个按钮。
    点击新闻标题后的“修改”,会跳转到新闻编辑页面,管理员在新闻编辑页面可以对新闻的分类主题、标题、作者以及正文内容进行修改,修改完后点击“提交”,就能成功修改一条新闻。
    点击新闻标题后的“删除”,会弹出确认删除对话框,点击“确定”,就能成功删除一条新闻。
    管理员点击“查找新闻”,在查找框里输入要查找的新闻标题,点击“提交”,想要查找的新闻的标题就会以列表的形式出现在查找结果页面。点击新闻标题或者标题后的“修改”和“删除”,就可以对查找到的新闻进行进一步的操作。
    管理员点击“添加主题”,输入要添加的新闻分类的名称,点击“提交”,就能成功添加一个新闻分类。
    管理员点击“编辑主题”,新闻的分类主题就会以列表的形式分页显示出来,在每个主题的后面都有“修改”和“删除”两个按钮。
    点击主题名称后的“修改”,管理员在修改框里输入新的标题,点击“提交”,就能成功修改一个新闻分类。
    点击主题名称后的“删除”按钮,会弹出一个确认删除对话框,点击“确定”,就能成功删除一个新闻分类。
    管理员的用例图如图2-3所示:

    2.4 系统的可行性分析系统的可行性分析是对开发系统的可行性程度进行评价,以便对系统开发、应用进行评测,主要包括技术可行性、经济可行性、操作可行性等[7]。
    技术可行性分析
    新闻管理系统使用计算机对新闻信息进行全面管理。为了提高工作效率和工作质量,系统通过运用计算机网络技术和数据库技术,对新闻管理系统的各个阶段实现计算机管理和控制。
    考虑到系统的扩展性,本系统以Java为开发语言、MySQL作为后台数据库,进行新闻管理系统的研究与开发。Java语言是一种跨平台、适合分布式计算机环境的面向对象编程语言。它具有的特点很多,如简单易学、面向对象性、分布式、可靠性、安全性、平台无关性、高性能、多线程、动态性等。
    系统开发步骤依据软件工程的项目开发模型,结合通用的应用开发平台进行系统配置,且有很多相关的成熟系统可以参考,因此,课题开发在技术上完全可行的。
    操作可行性分析
    该系统基于B/S模式,客户端只需安装Web浏览器即可访问系统,通用简单的操作界面,具有一般计算机知识的人员都可以轻松掌握其使用方法。用户交互界面友好,简洁明了,能切实提高新闻管理系统的可操作性,几乎无需人员培训。
    经济可行性分析
    根据新闻系统的实际需求,开发本系统,不但可以提高用户的新闻管理水平,同时还可以大大提高新闻采编的效率,优化新闻流程,保证新闻的时效性。就目前这个系统,需求方并不需要花太大的代价就能保证系统的运行。服务器可以用原有的Tomcat6,至于数据库,需求方只需在服务器上安装MySQL5.5.15就可以了,运行维护过程中也不要花费很多人力和物力,只要有管理员和一般维护性人员即可,所以在经济方面也是可行的。
    3 系统总体设计3.1 系统体系结构设计新闻管理系统是典型的管理信息系统。管理信息系统的结构设计是系统设计中的一项重要工作,系统结构设计的好坏,直接影响着系统的效率、安全性、可维护性。管理信息系统常用的体系结构有:文件服务器模式(File/Server)、C/S模式(Client/Server,客户机/服务器)和B/S模式(Browser/Server,Web浏览器/服务器)[8]。
    新闻管理系统需要向外发布信息,用户众多,并且数据库信息的更新和维护涉及到地域和即时性的制约,系统的实现一般采用B/S结构,操作方便快捷,而且对服务器端数据库的访问量较小[9]。 B/S结构用通用浏览器就实现了原来需要复杂专用软件才能实现的强大功能,简单易用,节约了开发成本,减轻了系统维护和升级的成本。可以说B/S结构,是当今Web应用软件的首选体系结构[10]。
    采用B/S结构的新闻管理系统可以轻松地发布新闻信息,而用户也无须安装专门的客户端软件,直接使用浏览器就可以查看新闻。
    未注册的普通用户可浏览新闻信息;注册用户可浏览新闻、发表评论等;系统管理员完成新闻管理、用户管理、系统维护等。
    3.2 系统功能模块新闻管理系统具有多个模块。该系统的用户分为三种:未注册的匿名用户,注册过的普通用户和管理员。
    所有用户都能浏览新闻。
    注册过的普通用户登录系统后可以查看自己的个人信息,可以对新闻进行评论,修改自己的密码。管理员登录后可以管理新闻、主题和用户,实现信息的添加、修改和删除。其中用户管理分为查看用户信息、删除用户;新闻管理分为添加新闻、查找新闻、编辑新闻和删除新闻;主题管理分为添加主题、修改主题和删除主题。
    系统功能模块如图3-1所示。

    3.3 数据库设计新闻管理系统的大量新闻信息保存在数据库中,同时新闻管理系统的用户相关信息也保存在数据库中。由于新闻管理系统处理的新闻信息数据更新较快,随着新闻管理系统使用时间的增长,数据日积月累,必将产生海量数据。同时在功能上考虑到数据处理速度、数据处理能力、性能稳定性、安全可靠性等,需要合理设计数据库系统。由于大量的信息被组织在数据库中,数据库的设计将影响整个管理系统的性能,数据库设计是系统设计中的一个重点。
    数据库作为新闻管理系统的基础,首先要保证其设计的合理性。在使用应用系统时,拥有设计合理的数据库往往可以起到事半功倍的效果。数据库设计是针对给定的应用环境,构造最优的数据库模式,建立数据库及其应用系统,使之能够高效地存储数据,满足系统用户的应用需求[11]。目前通用的数据库设计开发流程,主要分以下几个阶段:需求分析、概念结构设计、逻辑结构设计、物理结构设计、数据库实施、数据库运行和维护[12]。设计一个完善的数据库应用系统是不可能一蹴而就的,它往往是上述六个阶段的不断重复。
    本新闻管理系统一共用到四个表:评论信息表(comments),新闻信息表(news),用户信息表(news_users),分类信息表(topic)。这四个表的设计分别如下:
    评论信息表(comments)



    字段名称
    字段类型
    字段长度
    字段说明




    CID
    int
    11
    评论编号


    CNID
    int
    11
    评论所对应的新闻编号


    CCONTENT
    varchar
    3000
    评论内容


    CDATE
    datetime
    0
    评论日期


    CAUTHOR
    varchar
    100
    发表评论的用户



    新闻信息表(news)



    字段名称
    字段类型
    字段长度
    字段说明




    NID
    int
    11
    新闻编号


    NTID
    int
    11
    所属分类号


    NTITLE
    varchar
    200
    新闻标题


    NAUTHOR
    varchar
    50
    作者


    NCREATEDATE
    datetime
    0
    发布时间


    NCONTENT
    mediumtext
    0
    新闻内容



    用户信息表(news_users)



    字段名称
    字段类型
    字段长度
    字段说明




    USID
    int
    11
    用户编号


    UNAME
    varchar
    20
    用户名


    UPWD
    varchar
    20
    用户密码



    分类信息表(topic)



    字段名称
    字段类型
    字段长度
    字段说明




    TID
    int
    11
    主题编号


    TNAME
    varchar
    50
    主题名



    3.4 实体关系图实体关系图,简记E-R图,是指以实体、关系、属性三个基本概念概括数据的基本结构,从而描述静态数据结构的概念模式[13]。
    本新闻管理系统有四个实体,分别为用户、主题、新闻和评论。

    用户的属性:登录名,密码
    新闻的属性:主题,标题,作者,发布时间,内容。
    评论的属性:用户,内容,发表时间
    **主题只有主题名一个属性

    其中用户分为管理员和普通用户。管理员可以管理主题、新闻以及普通用户。所有用户都可以发表新闻评论。
    各实体之间的关系如图3-2和图3-3所示:


    3.5 过程设计概要设计的任务完成后,就进入详细设计阶段,也就是过程设计阶段。在这个阶段要解决新闻管理系统各个模块的实现算法,并使用过程描述工具(程序流程图、N-S图、PAD图、决策树等)精确地描述这些算法。对于比较简单的算法,可以采用自然语言来描述。但是对于此新闻管理系统,有一些算法比较复杂,使用自然语言描述就不太合适。一方面自然语言在语法上和语义上往往具有歧义性,常常要依赖上下文才能把问题描述清楚;另一方面,自然语言本身具有顺序性,不适合描述具有很多分支和循环的算法[14]。
    因此本新闻管理系统使用程序流程图来描述一些比较复杂的算法。
    用户注册的流程为:在新闻首页点击“注册”,输入用户名和密码,如果密码长度少于6位,则会提示“密码长度为6-255”,重新输入符合标准的密码后,输入“确认密码”,确认密码要和密码一致,否则会提示“密码不正确,请重新输入”。最后点击“注册”,跳转到注册成功页面,提示“注册成功”。
    用户注册流程图如图3-4所示:

    用户登录的流程为:用户输入登录名和密码,点击登录,如果是管理员账户,则跳转到后台管理页面;如果是注册过的普通用户,则跳转到普通用户的个人主页;如果输入的登录名和密码不是注册过的,则不能登录到系统,会提示请先注册。
    用户登录流程图如图3-5所示:

    3.6 类图模型的静态结构也称为静态模型,在UML中表示为类图。类图显示了类(及其接口)、类的内部结构以及与其他类的联系。联系是指类元之间的联系,在类的建模中可以使用关联、聚合和泛化(继承)关系[15]。
    在新闻管理系统中,涉及到的主要类有CommentsServlet,ExitServlet,LoginServlet,NewsServlet,ShowInfoServlet,TopicServlet,UserServlrt;CommentsServiceImpl,NewsServiceImpl,TopicServiceImpl,UserServiceImpl;CommentsDaoImpl,NewsDaoImpl,TopicDaoImpl,UserDaoImpl;DButil等。
    新闻管理系统的核心类图如图3-6所示。

    其中,CommentsServlet,CommentsServiceImpl,CommentsDaoImpl,这三个类是控制用户对新闻的评论的,实现的功能有用户新增评论,所有的评论以列表的形式显示出来,管理员删除评论。
    NewsServlet,NewsServiceImpl,NewsDaoImpl,这三个类是控制新闻管理的。实现的功能有浏览新闻、添加新闻、按标题查找新闻、编辑新闻、删除新闻等。
    TopicServlet,TopicServiceImpl,TopicDaoImpl,这三个类是控制主题管理的。所实现的功能有添加主题、编辑主题、删除主题等。
    UserServlrt,UserServiceImpl,UserDaoImpl,这三个类是控制用户管理的。所实现的功能有显示用户的信息,添加用户,修改用户信息,删除用户等。
    4 系统实现4.1 新闻首页用户进入本新闻管理系统后,首先看到的是新闻首页。
    首页的顶部是用户注册和登录模块,用户在本新闻管理系统注册后,输入登录名和密码即可登录本系统。
    在用户注册和登录模块的下方,是新闻管理系统的logo,“新闻中国,有态度的新闻门户”。网站logo里包含有一个超链接,用户在任意页面,只要点击网站的logo,就可以返回到新闻首页。
    网站logo的下方是一个类似于分割线功能的有色框。
    再下方是新闻分类主题的导航模块。有国内新闻、国际新闻、军事新闻、财经新闻、体育新闻、娱乐新闻、科技新闻、房产新闻、汽车新闻、社会新闻、游戏新闻、教育新闻等分类。
    新闻分类导航模块的下方是新闻浏览模块。新闻浏览模块左边是新闻列表,可以看到新闻标题列表和新闻发布时间。
    点击新闻标题,可以超链接到另一个显示新闻具体内容的阅读页面,可以查看新闻的具体内容。
    新闻浏览模块的右边,上部分是滚动的图片新闻,新闻的图片会自动切换,时间间隔是1秒。用户也可以分别点击滚动框里的四个按钮,可以查看相对应的新闻图片。
    下部分是旋转新闻,新闻标题以旋转的方式显示出来,旋转的轨迹是一个球形。把鼠标放在一个标题的上面,该标题的颜色会发生变化,突出显示出来。用户点击新闻标题就可以跳转到新闻阅读界面,查看新闻的详细内容。
    滚动新闻和旋转标题,这两部分都是用的特效。用Javascript控制图片滚动和标题旋转,用CSS控制这两部分的样式,再把Javascript和CSS引用到控制首页显示的JSP页面中,这两个特效就显示在网站的首页了。
    首页底部显示网站的一些服务的链接,包括广告服务、供稿服务、法律声明、招聘信息、网站地图、留言反馈等。还有热线电话,常见问题解答,举报邮箱,以及版权等信息。
    首页如图4-1所示。

    4.2 各类新闻浏览模块在该模块中,显示新闻的分类,新闻的标题列表,以及新闻的发布时间,还有图片新闻。
    新闻浏览模块如图4-2所示。

    4.3 用户注册点击新闻首页上方的“注册”,用户即可进入注册页面,输入用户名、密码和确认密码,点“注册”,即可完成注册。
    如果输入错误,可以点击“重置”,就会清空所有已输入的信息,重新输入用户名、密码和确认密码。
    注册页面如图4-4所示:

    注册成功后,系统会跳转到注册成功的提示页面。点击“现在登录”,返回新闻首页,即可用刚才注册的用户信息登录新闻管理系统。
    注册成功页面如图4-5所示:

    实现注册功能的关键代码如下:
    private void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); String pwd = request.getParameter("pwd"); User n = new User(); n.setUname(name); n.setUpwd(pwd); boolean b = userServiceImpl.save(n); if (b) { request.getRequestDispatcher("WEB-INF/user/doregister.jsp").forward(request, response); } }
    4.4 用户登录在新闻管理系统中有三种用户:未注册的用户,注册过的用户,管理员。
    在新闻首页,管理员和注册过的用户输入登录名和密码,点击“登录”即可进入新闻管理系统。在登录前勾选“七天免登录”,系统会自动记住该用户的登录名和密码,该用户七天内即可免登录进入新闻管理系统。
    用户登录模块如图4-6所示:

    其中,管理员登录到系统后会进入后台管理页面,普通用户登录到系统后会进入个人主页。判定输入的登录名和密码是否是管理员的关键代码如下:
    if ("admin".equals(name)) { request.getSession().setAttribute("sname", name); response.sendRedirect("NewsServlet");}if (!("admin".equals(name))) { request.getSession().setAttribute("sname", name); response.sendRedirect("UserServlet");}
    4.5 管理员后台管理模块用管理员账号登录后,即可进入后台管理页面,对新闻管理系统进行管理。
    在后台管理的欢迎页面,左边是功能模块,包括用户管理、添加新闻、编辑新闻、查找新闻、添加主题、编辑主题。欢迎页面的右边有欢迎语:“欢迎来到后台管理,数据无价,谨慎操作!”
    后台管理的欢迎页面如图4-7所示:

    4.5.1 用户管理页面在后台管理页面,点击“用户管理”进入用户管理界面,可以查看到注册用户的用户信息(包括用户名和密码),点击“删除”,会弹出确认删除对话框,再点击确定,就可删除一条用户信息。
    用户管理页面如图4-8所示。

    实现删除用户信息的关键代码如下:
    private void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String usid = request.getParameter("id"); System.out.println("++++deleteUser_usid++++"+usid); Integer id=Integer.parseInt(usid); System.out.println("++++deleteUser_usid++++"+id); boolean b = userServiceImpl.deleteById(id); if (b) { request.getRequestDispatcher("UserServlet?model=show_users").forward(request, response); }}
    4.5.2 添加新闻页面在该页面中,输入新闻的各项信息:点击下拉菜单选择新闻的分类主题,输入新闻的标题、作者、内容。点击“提交”,即可成功发布一条新闻,在新闻首页可以查看到新添加的新闻。如果新闻的某项信息填写有误,点击“重置”,即可清空所有已输入信息,方便重新输入。
    添加新闻页面如图4-9所示:

    实现添加新闻功能的关键代码如下:
    private void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String ntid = request.getParameter("ntid");// 获取新闻id String ntitle = request.getParameter("ntitle");// 获取新闻title String nauthor = request.getParameter("nauthor");//获取新闻的author System.out.println("---->"+nauthor); String ncontent = request.getParameter("ncontent"); News n = new News(); // request获取到的值是字符串类型,转换成integer类型的。 Integer tid = Integer.valueOf(ntid); n.setNtid(tid); n.setNtitle(ntitle); n.setNauthor(nauthor); n.setNcontent(ncontent); boolean b = newsServiceImpl.save(n); if (b) { response.sendRedirect("NewsServlet"); }}
    4.5.3 编辑新闻页面管理员进入后台管理页面后,点击编辑新闻,会显示出新闻标题列表。
    新闻标题列表如图4-10所示。

    点击新闻标题后的“修改”,就进入新闻修改页面。在修改新闻页面可以对新闻的主题、标题、作者、内容进行修改,修改完后再点击“提交”即可完成修改。或者点击“重置”,就可以清空该新闻的所有信息,再重新输入新闻的主题、标题、作者、内容等。
    点击新闻标题后的“删除”,会弹出确认删除对话框,点击“确定”即可删除一条新闻。
    新闻修改页面如图4-11所示:

    实现修改新闻功能的关键代码如下:
    private void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String nid = request.getParameter("nid"); // 获取新闻id String ntid = request.getParameter("ntid"); // 获取新闻主题id String ntitle = request.getParameter("ntitle"); // 获取新闻title String nauthor = request.getParameter("nauthor"); // 获取新闻author System.out.println("nauthor"+nauthor); String ncontent = request.getParameter("ncontent"); News news = new News(); // request获取到的值是字符串类型,转换成integer类型的。 Integer id = Integer.valueOf(nid); Integer tid = Integer.valueOf(ntid); news.setNid(id); news.setNtid(tid); news.setNtitle(ntitle); news.setNauthor(nauthor); news.setNcontent(ncontent); boolean b = newsServiceImpl.update(news); if (b) { response.sendRedirect("NewsServlet"); } else { response.sendRedirect("NewsServlet?model=update_jsp"); }}
    4.5.4 查找新闻页面新闻管理系统的查找新闻的功能是根据新闻的标题查找的。
    在后台管理页面中点击“查找新闻”,在查找新闻页面中输入要查找的新闻标题,点击“提交”,即可得到想要查找的新闻。
    查找新闻页面如图4-12所示:

    查找结果如图4-13所示:

    实现查找新闻功能的关键代码如下:
    /*** 按新闻标题检索新闻* * @param request* @param response*/private void search(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub String ntitle = request.getParameter("ntitle"); System.out.println("++++++++"+ntitle); List<News> lst = newsServiceImpl.findNews(ntitle); System.out.println("++++++++"+lst); request.setAttribute("lst", lst); request.getRequestDispatcher("WEB-INF/news/newList01.jsp").forward(request, response);}
    4.5.5 添加主题页面在该页面输入要添加的新闻分类名称,点击“提交”,即可添加一个新闻分类。在新闻首页就可以看到新添加的分类。同时,在“添加新闻”页面的新闻主题下拉菜单中也会增加新添加的新闻主题。
    添加主题页面如图4-14所示:

    4.5.6 编辑主题页面点击主题后的“修改”,就进入主题修改页面,在修改主题页面可以对主题进行修改,再点击“提交”即可完成修改。点击主题后的“删除”,会弹出确认删除对话框,点击“确定”即可删除一个新闻分类,否则点击“取消”。
    主题列表如图4-15所示:

    修改主题页面如图4-16所示:

    4.6 普通用户功能模块普通用户登录新闻管理系统后会进入个人主页的欢迎页面。
    欢迎页面的左边是功能模块,包括查看个人信息和修改密码。欢迎页面的右边是欢迎语:欢迎来到个人主页。
    欢迎页面如图4-17所示:

    4.6.1 查看个人信息普通用户登录系统后,点击“查看个人信息”,可查看该用户的登录名和密码。
    查看个人信息的页面如图4-18所示:

    实现查看个人信息功能的关键代码如下:
    private void show_users(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub List<User> lst=userServiceImpl.findAll(); request.setAttribute("lst", lst); request.getRequestDispatcher("WEB-INF/admin/userList.jsp").forward(request, response);}
    4.6.2 修改密码普通用户进入个人主页后点击“修改密码”,输入新密码,点击“修改”,即可修改该用户的密码。如果点击“取消”则会清空已输入的新密码。
    修改密码的页面如图4-19所示:

    实现修改密码功能的关键代码如下:
    private void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String uname=request.getParameter("uname"); String upwd = request.getParameter("password"); User user=new User(); user.setUname(uname); user.setUpwd(upwd); boolean b=userServiceImpl.update(user); if(b){ request.getRequestDispatcher("WEB-INF/user/success.jsp").forward(request, response); }else{ response.sendRedirect("UserServlet?model=update_jsp"); }}
    4.6.3 评论新闻普通用户登录新闻管理系统后,可以点击新闻标题浏览新闻,也可以在新闻内容的下方进行评论。用户在评论框里输入评论后,点击“发表”,即可发表评论。评论列表里会显示出发表评论的用户名、评论日期和评论内容。
    评论列表如图4-20所示:

    没有注册过的用户则只可以浏览新闻,不能对新闻进行评论。匿名用户在评论框里输入评论,点击提交时,会提示“您还没登陆,请先登录”。
    评论失败的提示如图4-21所示:

    实现评论功能的关键代码如下:
    public class CommentsServlet extends HttpServlet { private static final long serialVersionUID = 1L; public CommentsServlet() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); String nid=request.getParameter("cnid"); Integer cnid=Integer.parseInt(nid); String cauthor=request.getParameter("cauthor"); String ccontent=request.getParameter("ccontent"); //添加日期的格式 Timestamp cdate=new Timestamp(System.currentTimeMillis()+8*60*60*1000); String cip=request.getRemoteAddr(); Comments comments =new Comments(cnid,ccontent,cdate,cip,cauthor); CommentsServiceImpl commentsServiceImpl=new CommentsServiceImpl(); boolean b=commentsServiceImpl.save(comments); if(b){ response.sendRedirect("NewsServlet?model=read&nid="+cnid); } }}
    5 系统的测试与评价5.1 系统测试系统测试采用黑盒测试法(Black-box Testing),黑盒测试方法,也称功能测试或数据驱动测试方法,在测试时,把程序看做一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下,测试人员针对软件直接进行测试[16]。
    首先运行整个程序进入到网站首页,在网站首页显示出用户登录、新闻分类、新闻标题、新闻图片等模块,达到了预期效果。
    首页中的各项均是用超链接实现的,依次点击相应的功能按键和超链接,查看功能是否能够按照设计时的构想实现,例如,在点击“注册”,出现用户注册界面,填写用户的登录名、密码和确认密码,再点击“注册”,进入注册成功页面等等。依照此思想逐个点击各项功能和超链接,检查是否实现该功能。



    测试项目
    功能描述
    操作步骤/输入数据
    预期结果
    测试结果




    新闻浏览
    查看新闻的具体内容
    进入主界面,点击新闻标题
    跳转到新闻阅读页面,能看到新闻的详细内容。
    成功


    新闻分类
    将新闻按照分类分页显示
    点击新闻主题
    新闻按照对应的分类分页显示
    成功


    未注册的用户的权限:不能评论新闻
    对新闻进行评论
    进入新闻管理系统后不登录,直接点击一条新闻标题,在新闻内容的下方输入评论,然后点击“发表”
    评论不成功,提示“您还没登陆,请先登陆”。
    成功


    用户注册
    注册一个新用户
    进入主界面,点击注册,输入登录名:aaa,密码:aaaaaa,确认密码:aaaaaa,提交表单后跳转到注册成功页面。
    成功注册一个新用户
    成功


    普通用户登录
    普通用户登录系统
    进入主界面,登录名输入“aaa”,密码输入“aaaaaa”,点击登录。
    登录成功,跳转到个人主页,返回新闻首页后在左上角显示用户名。
    成功


    管理员登录
    管理员登录系统
    进入主界面,登录名输入“admin”,密码输入“admin”,点击登录。
    登录成功,跳转到后台管理页面,返回新闻首页后在左上角显示管理员名称。
    成功


    查看个人信息
    查看已登录用户的个人信息
    进入主界面,登录名输入“aaa”,密码输入“aaaaaa”,点击登录,跳转到个人主页后点击“查看个人信息”。
    能看到个人信息:登录名为aaa,密码为aaaaaa。
    成功


    修改密码
    修改登录密码
    进入主界面,登录名输入“aaa”,密码输入“aaaaaa”,点击登录,跳转到个人主页后点击“修改密码”,输入新密码并点击“修改”。提示密码修改成功后退出当前用户,用新密码重新登录。
    提示密码修改成功,用新密码重新登录后能正常登录。
    成功


    评论新闻
    对新闻进行评论
    用用户aaa登录系统,点击新闻标题,跳转到新闻阅读页面后在新闻内容下方写评论,并点击“发表”。
    评论发表成功,在评论列表里能看到发表的评论。
    成功


    查看用户信息
    查看注册用户的登录名和密码
    用管理员身份登录系统后选择“用户管理”。
    能查看到注册用户的登录名和密码。
    成功


    删除用户
    删除一个注册过的用户
    用管理员身份登录系统后选择用户管理,点击想要删除的用户信息后的“删除”,在弹出的确认删除对话框里点“确定”。然后退出管理员,用刚删除的那个用户的登录名和密码登陆系统。
    成功删除一条用户信息,退出管理员后,用刚删除的用户的信息登录系统,提示请先注册。
    成功


    添加新闻
    向系统里添加一条新闻
    用管理员身份登录系统后选择“添加新闻”,填写新闻的主题、标题、作者、内容,点击“提交”。返回新闻首页,点击新添加的新闻所属的主题,看新闻列表里是否有刚才添加的新闻的标题。
    成功添加一条新闻,在新闻首页的新闻列表里能看到新添加的新闻。
    成功


    编辑新闻
    修改已经发布过的新闻
    用管理员身份登录系统后选择“编辑新闻”,点击新闻标题后面的“修改”,进入到新闻修改页面,修改新闻的主题、标题、作者、内容,点击“提交”。
    成功修改一条新闻。
    成功


    查找新闻
    根据新闻标题查找想要的新闻
    用管理员身份登录系统后选择“查找新闻”,进入新闻查找页面后输入新闻标题,点击“提交”。
    在一个新页面显示出要查找的新闻的标题。
    成功


    删除新闻
    删除过时的新闻
    用管理员身份登录系统,在后台管理页面,点击新闻标题后面的“删除”,再点击弹出的确认删除对话框里的“确定”。返回新闻首页,点击新添加的新闻所属的主题,看新闻列表里是否有刚才添加的新闻的标题。
    成功删除一条新闻,在新闻首页的新闻列表里也看不到删除的那条新闻的标题。
    成功


    添加主题
    添加一个新闻分类
    用管理员身份登录系统后选择“添加主题”,输入主题名称,点击“提交”。
    返回新闻首页后可以看到新添加的新闻分类,添加新闻时主题的下拉菜单里也有新添加的主题。
    成功


    编辑主题
    修改已有的主题
    用管理员身份登录系统后选择“编辑主题”,点击主题后面的“修改”,进入到主题修改页面,输入新的主题名,点击“提交”。
    返回新闻首页后可以看到修改后的新闻分类。
    成功


    删除主题
    删除一个新闻分类
    用管理员身份登录系统后选择“编辑主题”,点击主题后面的“删除”,再点击弹出的确认删除对话框里的“确定”。
    返回新闻首页后可以看到被删除的新闻分类不再显示,添加新闻时主题的下拉菜单里也看不到新添加的主题。
    成功


    分页功能
    让新闻分页显示
    依次点击新闻列表右下角的“下一页”、“上一页”、“末页”、“首页”。
    分页功能正常实现,在不同的页面能看到不同的新闻标题。
    成功



    经过不断的“测试——修改——测试”的往复,该系统已经达到设计要求,各项功能都得到了完美的实现,达到了预期的效果。
    5.2 系统的评价通过以上各步工作,该新闻管理系统基本符合要求,在这里对本系统做一个简单的评价。
    本系统在设计开发时采用后台的方法,整个系统具有以下几个特点:
    安全性和可移植性较好
    可以在任何Windows系统平台上运行。系统根据其权限做相应的处理,保护数据安全,方便管理员维护数据。
    容错性能较好
    在系统测试阶段对系统进行过大量的实例测试,并有许多出错提示,加强了系统的稳定与容错性。
    结束语课题结合新闻管理工作的实际需求,在B/S架构中,以数据库技术和Java语言作为主要工具,最终完成了新闻管理系统。其功能基本符合新闻管理的需求,并提供部分系统维护功能,使用户方便进行新闻浏览和管理员对数据进行添加、修改和删除。
    通过对新闻管理系统的设计和实现,使我对新闻工作有了更全面的理解,同时也将学习到的软件工程的相关知识运用到实践中,学习并运用Java编程语言基本完成了既定设计任务。虽然设计和开发的系统在用户界面人性化设计、操作便捷性、功能完善性和系统运行稳定性等方面还存在一定不足,但已基本达成预期目标。在课题研发和开发工作中所学习到的分析问题和解决问题的方法,对自己以后的学习和工作将大有裨益。
    通过做这个系统,我知道,有些东西细节决定成败,无论怎样都不能忽视细节的东西。这不是毕业设计的结束,更不是人生在学习生涯中的结束,而是新环境、新学习、新挑战的开始。只有这样我们才能学无止境,以求得更大的发展。对于我们年轻人来说,我相信:挑战越多,机会越多。我会打足精神,努力开创新的成绩,勇敢的面对以后发生的一切,更好的提高自己,以便能够更好为社会服务,为人民服务,进而体现自己在社会发展中的价值。
    参考文献[1] 史济民,顾春华,郑红.软件工程:原理、方法与应用[M].3版.北京:高等教育出版社,2009,298.
    [2] Shari Lawrence Pfleeger.Software Engineering Theory and Practice [M].2nd ed.影印版.北京:高等教育出版社,2001,57.
    [3] 郑人杰,马素霞,殷人昆.软件工程概论[M].北京:机械工业出版社,2009,38.
    [4] 吴洁明.软件工程实例教程[M].北京:清华大学出版社,2010,40-42.
    [5] Roger Pressman.Software Engineering:A Practitioner’s Approach [M].6th ed.影印版.北京:清华大学出版社,2005,207.
    [6] Stephen R Schach.面向对象与传统软件工程:统一过程的理论和实践[M].韩松,等译.6版.北京:机械工业出版社,2006,180.
    [7] 张海潘.软件工程导论[M].北京:清华大学出版社,2004.
    [8] 马军.JAVA完全自学手册[M].北京:机械工业出版社,2007,186.
    [9] 明日科技.Java Web从入门到精通[M].北京:清华大学出版社,2012,97.
    [10] Jon Duckett.Web编程入门经典[M].杜静,敖福江译.北京:清华大学出版社,2010,109.
    [11] 姚卿达.数据库设计[M].北京:高等教育出版社,1989,186.
    [12] 王珊,萨师煊.数据库系统概论[M].4版.北京:高等教育出版社,2006,202-203.
    [13] 百度百科—实体关系图:http://baike.baidu.com/link?url=FjXNUBVZNYUiuwf1aTOURJE3QIwcPe7_61Vi5Gnb85NIo2pmORpoIH_lTez6M-Yt#3
    [14] 齐治昌,谭庆平,宁洪.软件工程[M].3版.北京:高等教育出版社,2012,165.
    [15] 郑人杰,殷人昆,陶永磊.实用软件工程[M].3版.北京:清华大学出版社,2010,171.
    [16] 朱少民.软件测试方法和技术[M].2版.北京:清华大学出版社,2010,38.
    6 评论 63 下载 2019-05-20 22:09:24 下载需要15点积分
  • 基于mfc实现的21点小游戏

    1.系统的介绍1.1 设计的目的与意义21点游戏是一款经典的扑克牌游戏,由古至今衍生的各种各样的规则和玩法,游戏的设计旨在为平淡的生活带来乐趣,以及最重要的,通过对游戏的设计来实现练习,实际操作,学习他人程序优点,通过研究,了解需求并设计程序,掌握设计课题的基本步骤和方法。
    1.2 本设计的主要内容程序使用较为简单的游戏规则:玩家与电脑对战,使用一副没有大小王的扑克,游戏开始后,起始发两张手牌,玩家可根据所持牌的点数选择继续要牌或开牌,使得自己牌的点数尽可能接近但不超过21点,玩家最多可要5张牌,开牌后最接近且不超过21点的一方为赢家,双方点数相同或双方点数均超过21点为平局。

    要求实现游戏规则中的功能
    要求基于对话框界面操作
    界面美观,具有用户友好性

    2.需求分析及设计2.1 类的设计根据游戏规则和MFC程序设计要求,程序的主要类为CDialog的派生类CMFC_GameDlg:
    该类中主要的数据成员有以下几种:

    玩家持牌信息user_card
    电脑持牌信息com_card[]
    玩家持牌的点数user_dot[]
    电脑持牌点数com_dot[]
    玩家持牌张数count
    判断是否开牌的变量flag

    该类中的主要成员函数有以下几种:

    初始化函数Init(),用于给变量赋初值
    电脑抽牌函数com_getcard(),利用srand生成随机函数种子,rand()函数根据种子生成随机数并对52取余,若得到余数不为了0且该牌编号未曾出现,则将这张牌的编号赋值给com_card[],表明电脑抽到一张牌
    胜负判断函数Judge(),若双方点数一致或均超过21点,为平局,电脑点数较大且不超过21点,或电脑超过21点玩家超过21点则电脑胜,若非平局或电脑胜,则玩家胜
    显示牌面函数show_card(),通过创建位图兼容设备,将电脑持牌信息com_card[]和玩家持牌信息user_card[]中对应编号与资源中ID一致的位图显示到屏幕上
    显示点数函数show_dot(),通过电脑持牌信息com_card[]和玩家持牌信息user_card[]可确定电脑和玩家的点数,将其输出到对话框对应的文本框中
    显示以往对战记录函数Record(),将一个CString对象与显示记录的文本框关联,该对象值的变化可即时反映到文本框中,实现记录的显示
    记录清除函数OnClear(),将保存记录的CString对象赋值为空字符串,并将保存轮数的变量T归零
    记录保存函数OnSave(),通过CFileDialog类显示文件保存对话框,将保存记录的CString对象保存为文本文档。

    2.2 系统的数据设计为了方便用户查看以往的记录,程序添加了记录显示函数Record()和记录保存函数OnSave(),每轮游戏结束后,双方的牌面和游戏结果会显示在界面右边的文本框中,并且可以通过菜单将记录保存为文本文档。
    为实现界面美观性和用户友好性,程序在中加入了头文件SkinH.h和库文件skinH.lib,以及动态链接库skinH.dll;用来实现载入外部皮肤的功能。
    2.3 系统的实现及调试程序完成的初期由于选择的不恰当的函数,无法载入图片,通过查看网上一些在MFC载入图片的实例后,了解到可以通过CBitmap这个类的中的LoadBitmap接口获取图片信息,并BitBlt实现位图的指定位置投影。
    关于皮肤的设置需要手动添加头文件和代码,前期由于疏忽,漏掉的预编译中的的头文件,导致程序十分不稳定,修改后总是无法通过编译,后来通过不断调试才发现这个bug并修复。
    由于开发环境为windows 8专业版 + Microsoft Visual C++ 6.0,在编译过程中出现很多由于软件本身不兼容出现的问题;例如无法加载资源文件,已经定义的语句编译出错,只好通过每次改动调试成功就备份一次文件方式规避,下次改动出错后重新从之前保存的文件修改。
    3.使用说明游戏主界面,还未点击“开始游戏”之前,“要牌”与“开牌”按钮为灰色(禁用)。

    点击“开始游戏”按钮以后,初始发两张牌,显示玩家当前持牌图片和持牌点数并启用“要牌”和“开牌”按钮。

    玩家根据自己的持牌点数,决定是否继续要牌,但是要牌不能超过5张,超过5张以后弹出“你最多只能抽五张牌!“的警告消息框,并禁用”要牌“按钮。

    点击“开牌“按钮后,会弹出显示胜负情况的消息框,显示双方的持牌,点击确定后右边文本框会显示历史记录,并禁用”开牌“和”要牌“按钮,再次点击开始游戏后启用。

    点击菜单栏中的“记录->保存记录”,默认可将以往游戏记录保存为“.txt”的文本文档,方便用户查看。

    4.总结及心得体会第一次完成MFC程序,有点小激动,过程很多,框架与具体功能代码的编写,包括初始化,电脑和玩家的随机数取余方式抽牌,判定胜负函数,按钮的启用与禁用,菜单栏的编码,部分代码的重构及优化;素材的收集,需求分析,外部皮肤载入,位图资源的显示,文件的保存操作,图标的设计和美化,以及部分代码的优化及后期注释。
    由于自己的能力有限,很多功能不够完善,例如没有加入下注的功能,电脑的要牌策略也十分简单,不能提供按钮点击换肤的功能等等,在编写过程中也发现了自身的许多问题,对于MFC的许多函数接口不熟悉,很多细节没有注意到,缺乏耐心等等,想想实在乏善可陈,但是通过学习MFC编程,初步形成了面向对象和模块化设计的思想,培养了查阅文献资料的习惯和能力,具备了完成编写任务,调试并优化程序的能力,我也明白了学无止境的道理,与那些完成MFC底层代码编写,提供给广大程序远便捷接口的人相比,我们要学的实在还有很多很多。
    0 评论 2 下载 2020-07-06 09:34:20 下载需要11点积分
  • 基于C#实现的操作系统模拟系统

    一、课程设计的性质与目的操作系统是计算机系统配置的基本软件之一,其作用是对计算机系统进行统一的调度和—管理,提供各种强有力的系统服务,为用户创造既灵活又方便的使用环境。本课程是计算机及应用专业的一门专业主干课和必修课。通过课程设计,使学生掌握操作系统的基本概念、设计原理及实施技术,具有分析操作系统和设计、实现、开发实际操作系统的能力。
    二、课程设计任务采用C或C#程序设计语言,模拟实现一个简单功能的操作系统。
    三、设计要求3.1 实现作业管理
    创建作业

    为每个作业定义一个作业控制块(包含作业标识、用户名称、预计运行时间、要求内存大小、作业大小、资源需求的类型和最大数量、以及其他所需信息等)建立后备作业队列(不少于10个作业)
    采用短作业优先调度算法
    每次作业调度时,最多从后备队列选取5个作业调入内存
    显示作业的调度情况

    3.2 实现进程管理
    假设每个作业只创建一个进程,进程控制块PCB包含进程标识、状态、大小、进程页表地址、资源类型和数量以及其他信息等
    创建进程

    申请空白进程控制块PCB内存分配初始化进程控制块将新进程插入就绪队列
    进程调度:采用时间片轮转进程调度算法,将CPU分配给就绪队列队首进程,原进程插入就绪队列队尾。显示各进程信息
    当进程被调度执行时,提出资源请求,采用银行家算法实现资源分配,避免死锁
    唤醒进程:当某类资源被释放时,则对该资源阻塞队列中的进程按顺序判断是否满足资源需要,如果满足资源需求,则把该进程插入就绪队列
    终止进程:当进程完成时,释放内存,释放其他资源,撤销进程控制块PCB,进行作业调度。

    3.3 实现内存管理功能
    采用请求分页虚拟存储器管理方式,页面大小为1K个存储单元
    建立一个存储分块表(MBT),表示内存所有物理页的当前状态
    允许多进程并发执行,为每个进程建立一个页表,表示该进程中各逻辑页是否已经调入内存,如果已经调入,该逻辑页对应的内存物理页号
    当进程发生缺页中断,并且没有空闲物理页时,采用LRU算法页面置换
    当进程被调度执行时,模拟进程的访存过程:输入逻辑地址,转换为逻辑页号和页内地址,判断是否产生缺页中断完成调页,然后实现地址变换,查页表得到对应的物理页号,最后显示物理地址

    四、总体设计模拟实现操作系统的作业管理、进程管理和存储管理等功能。
    4.1 总体设计图
    4.2 各模块功能作业管理



    子功能模块
    功能




    作业创建
    获取text文本框输入的信息,生成作业控制块


    作业删除
    点击Delete按钮,即可删除相关作业


    作业修改
    点击Edit按钮,即可修改相关作业


    作业添加
    点击Add按钮,即可修改相关作业


    作业调度
    采用短作业优先调度算法,从后备队列选取作业调入内存



    进程管理



    子功能模块
    功能




    进程创建
    每个作业只创建一个进程,根据作业信息以及键盘输入的信息生成进程控制块


    进程终止
    当进程完成时,释放内存,释放其他资源,撤销进程控制块PCB,进行作业调度


    进程调度
    采用时间片轮转进程调度算法,将CPU分配给就绪队列队首进程,原进程插入就绪队列队尾。


    进程执行
    提出资源请求,采用银行家算法分配资源,避免死锁。



    存储管理



    子功能模块
    功能




    内存分配
    在进程创建时进行内存分配,生成页表


    内存回收
    在进程终止时,将分配给该进程的存储块回收(状态标为空闲),将页表删除。


    页面置换
    当进程发生缺页中断,并且没有空闲物理页时,采用LRU算法页面置换。


    地址变换
    将输入的逻辑地址分成页号和位移量,若该页在主存中则根据块号和页内偏移量计算出物理地址。



    五、详细设计5.1 作业管理5.1.1 作业创建操作流程和实现方法

    为每个作业定义一个作业控制块(包含作业标识、用户名称、预计运行时间、要求内存大小、作业大小、资源需求的类型和最大数量、以及其他所需信息等)
    插入作业队列末尾

    运行界面

    5.1.2 作业删除操作流程和实现方法
    选择要删除的项目,点击删除,显示作业队列查看作业信息是否被删除。
    运行界面


    5.1.3 作业修改操作流程和实现方法
    选择要修改的项目,获取输入的数据将原数据覆盖,显示作业队列查看作业信息是否被修改。
    运行界面


    5.1.4 作业调度操作流程和实现方法
    点击作业调度即可。
    运行界面




    5.2 进程管理5.2.1 进程创建操作流程和实现方法
    用户输入进程的名称、当前资源占用情况,根据进程所属的作业的信息生成进程控制块(包含进程标识、状态、大小、进程页表地址、资源类型和数量以及其他信息等)。
    运行界面


    5.2.2 进程终止操作流程和实现方法
    当进程已分配资源达到该进程所需的最大资源数量且无剩余运行时间,进程完成。当进程运行时间结束撤销进程。
    运行界面

    5.2.3 进程调度操作流程和实现方法
    采用时间片轮转进程调度算法,将CPU分配给就绪队列队首进程,将其状态从“就绪”改为“运行”,原进程插入就绪队列队尾;
    运行界面



    5.2.4 进程执行操作流程和实现方法
    提出资源请求,若资源请求合法,采用银行家算法分配资源,检查资源预分配后的系统安全性,如不安全,则该进程转为“等待”状态,放入等待队列队尾,如安全,则实现本次资源分配。
    运行界面


    5.3 存储管理5.3.1 内存分配操作流程和实现方法

    初始化存储分块表,在进程创建时进行内存分配,生成页表
    根据进程的大小以及进程申请的内存大小来确定页表中物理页的数量以及分配的存储块的数量

    运行界面

    5.3.2 内存回收操作流程和实现方法
    在进程终止时,将分配给该进程的存储块回收(状态标为空闲),将页表删除。
    运行界面

    5.3.3 页面置换操作流程和实现方法

    当进程发生缺页中断,并且没有空闲物理页时,采用LRU算法页面置换
    当进程发生缺页中断,有空闲物理页时,将该页面调入空闲物理页中

    运行界面

    5.3.4 地址变换操作流程和实现方法

    将输入的逻辑地址分成页号和位移量,若该页在主存中则根据块号和页内偏移量计算出物理地址
    若该页不在主存中则缺页中断,进行页面调度

    运行界面
    0 评论 3 下载 2020-07-06 10:02:45 下载需要11点积分
显示 105 到 120 ,共 15 条
eject