分类

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

资源列表

  • 基于JAVA和MYSQL的医院简易挂号管理系统

    一、需求分析1.1 题目要求采用桌面应用程序模式,开发一个医院挂号系统,管理包括人员、号种及其挂号费用,挂号退号等信息,完成登录、挂号、查询和统计打印功能。数据库表如下所示,建立索引的目的是加速访问,请自行确定每个索引要涉及哪些字段。
    T_KSXX (科室信息表)



    字段名称
    字段类型
    主键
    索引
    可空
    备注




    KSBH
    CHAR(6)



    科室编号,数字


    KSMC
    CHAR(10)



    科室名称


    PYZS
    CHAR(8)



    科室名称的拼音字首



    T_BRXX (病人信息表)



    字段名称
    字段类型
    主键
    索引
    可空
    备注




    BRBH
    CHAR(6)



    病人编号,数字


    BRMC
    CHAR(10)



    病人名称


    DLKL
    CHAR(8)



    登录口令


    YCJE
    DECIMAL(10,2)



    病人预存金额


    DLRQ
    DateTime



    最后一次登录日期及时间



    T_KSYS (科室医生表)



    字段名称
    字段类型
    主键
    索引
    可空
    备注




    YSBH
    CHAR(6)



    医生编号,数字,第1索引


    KSBH
    CHAR(6)



    所属科室编号,第2索引


    YSMC
    CHAR(10)



    医生名称


    PYZS
    CHAR(4)



    医生名称的拼音字首


    DLKL
    CHAR(8)



    登录口令


    SFZJ
    BOOL



    是否专家


    DLRQ
    DATETIME



    最后一次登录日期及时间



    T_HZXX (号种信息表)



    字段名称
    字段类型
    主键
    索引
    可空
    备注




    HZBH
    CHAR(6)



    号种编号,数字,第1索引


    HZMC
    CHAR(12)



    号种名称


    PYZS
    CHAR(4)



    号种名称的拼音字首


    KSBH
    CHAR(6)



    号种所属科室,第2索引


    SFZJ
    BOOL



    是否专家号


    GHRS
    INT



    每日限定的挂号人数


    GHFY
    DECIMAL(8,2)



    挂号费



    T_GHXX (挂号信息表)



    字段名称
    字段类型
    主键
    索引
    可空
    备注




    GHBH
    CHAR(6)



    挂号的顺序编号,数字


    HZBH
    CHAR(6)



    号种编号


    YSBH
    CHAR(6)



    医生编号


    BRBH
    CHAR(6)



    病人编号


    GHRC
    INT



    该号种的挂号人次


    THBZ
    BOOL



    退号标志=true为已退号码


    GHFY
    DECIMAL(8,2)



    病人的实际挂号费用


    RQSJ
    DATETIME



    挂号日期时间



    为了减少编程工作量,T_KSXX、T_BRXX、T_KSYS、T_HZXX的信息手工录入数据库,每个表至少录入6条记录,所有类型为CHAR(6)的字段数据从“000001”开始,连续编码且中间不得空缺。为病人开发的桌面应用程序要实现的主要功能具体如下:

    病人登录:输入自己的病人编号和密码,经验证无误后登录
    病人挂号:病人处于登录状态,选择科室、号种和医生(非专家医生不得挂专家号,专家医生可以挂普通号);输入缴费金额,计算并显示找零金额后完成挂号。所得挂号的编号从系统竞争获得生成,挂号的顺序编号连续编码不得空缺

    功能2的界面如下所示,在光标停在“科室名称”输入栏时,可在输入栏下方弹出下拉列表框,显示所有科室的“科室编号”、“科室名称”和“拼音字首”,此时可通过鼠标点击或输入科室名称的拼音字首两种输入方式获得“科室编号”,用于插入T_GHXX表。注意,采用拼音字首输入时可同时完成下拉列表框的科室过滤,使得下拉列表框中符合条件的科室越来越少,例如,初始为“内一科”和“内二课”。其它输入栏,如“医生姓名”、“号种类别”、“号种名称”也可同时支持两种方式混合输入。

    每种号种挂号限定当日人次,挂号人数超过规定数量不得挂号。一个数据一致的程序要保证:挂号总人数等于当日各号种的挂号人次之和,病人的账务应保证开支平衡。已退号码不得用于重新挂号,每个号重的GHRC数据应连续不间断,GHRC从1开始。若病人有预存金额则直接扣除挂号费,此时“交款金额”和“找零金额”处于灰色不可操作状态。
    为医生开发的桌面应用程序要实现的主要功能具体如下:

    医生登录:输入自己的医生编号和密码,经验证无误后登录
    病人列表:医生处于登录状态,显示自己的挂号病人列表,按照挂号编号升序排列。显示结果如下表所示。




    挂号编号
    病人名称
    挂号日期时间
    号种类别




    000001
    章紫衣
    2018-12-30 11:52:26
    专家号


    000003
    范冰冰
    2018-12-30 11:53:26
    普通号


    000004
    刘德华
    2018-12-30 11:54:28
    普通号




    收入列表:医生处于登录状态,显示所有科室不同医生不同号种起止日期内的收入合计,起始日期不输入时默认为当天零时开始,截止日期至当前时间为止。时间输入和显示结果如下表所示。
    起始时间:2018-12-30 00:00:00 截止时间:2018-12-30 12:20:00



    科室名称
    医生编号
    医生名称
    号种类别
    挂号人次
    收入合计




    感染科
    000001
    李时珍
    专家号
    24
    48


    感染科
    000001
    李时珍
    普通号
    10
    10


    内一科
    000002
    扁鹊
    普通号
    23
    23


    保健科
    000003
    华佗
    专家号
    10
    20



    病人应用程序和医生应用程序可采用主窗口加菜单的方式实现。例如,医生应用程序有三个菜单项,分别为“病人列表”、“收入列表”和“退出系统”等。
    考虑到客户端应用程序要在多台计算机上运行,而这些机器的时间各不相同,客户端程序每次在启动时需要同数据库服务器校准时间,可以建立一个时间服务程序或者直接取数据库时间校准。建议大家使用MS SQL数据库开发。
    挂号时锁定票号可能导致死锁,为了防止死锁或系统响应变慢,建议大家不要锁死数据库表或者字段。程序编写完成后,同时启动两个挂号程序进行单步调试,以便测试两个病人是否会抢到同一个号、或者有号码不连续或丢号的现象。
    系统考核目标:

    挂号后数据库数据包括挂号时间不会出现不一致或时序颠倒现象,以及挂号人次超过该号种当日限定数量的问题
    挂号号码和挂号人次不会出现不连续或丢号问题
    病人的开支应平衡,并应和医院的收入平衡
    系统界面友好、操作简洁,能支持全键盘操作、全鼠标操作或者混合操作
    能支持下拉列表框过滤输入
    系统响应迅速,不会出现死锁
    统计报表应尽可能不采用多重或者多个循环实现
    若采用时间服务器程序校准时间,最好能采用心跳检测机制,显示客户端的上线和下线情况

    思考题:当病人晚上11:59:59秒取得某号种的挂号价格10元,当他确定保存时价格在第2天00:00:00已被调整为20元,在编程时如何保证挂号费用与当天价格相符?
    1.2 需求分析对于病人的操作界面而言,需要有题目要求的挂号功能,包括人性化的过滤功能,需要足够的提示信息用于提示当前的操作状态,此外,还需要题目要求中没有提到的对于余额的操作功能;对于医生的操作界面而言,除了需要题目要求的两种统计功能外,还需要额外的过滤功能以供更于便捷的查询。此外,还需要一个统一的登录界面以供医生和病人登录。
    对于程序的功能而言,不仅需要程序具有健壮性,在发生错误的时候不能崩溃,而且要求界面友好,支持多种操作方式,相应迅速。
    二、系统设计2.1 概要设计整个系统分为2个部分:程序部分以及数据库部分。数据库部分用于存储数据并同时服务多个客户端,而程序部分则负责相应用户的输入,与数据库沟通、处理数据并返回处理的结果。而程序部分总体上又分为4个模块:登录界面、医生操作模块,病人操作模块以及数据库连接器。总体的模块图如图 1所示。其中,登录界面用于负责检查用户的登录信息是否正确,并负责唤醒医生操作界面或病人操作界面,而医生操作界面或病人操作界面则调用数据库模块与数据库进行沟通,处理数据并返回结果。
    此外,程序入口也被封装为一个较小的main模块,用于执行包括加载数据库驱动、连接数据库、启动化图形界面引擎在内的初始化操作,以及实现唤醒登录界面的功能。如果不能成功连接数据库则此模块进行相应的处理并退出程序。由于此模块较小,且功能较为简单,因此不列入主要模块中。

    程序的总体状态转移图如图 2所示,首先进入登录界面并等待用户输入登录信息,然后通过查询数据库判断登录信息是否匹配,如果匹配则登录,否则提示错误并等待用户重新输入登录信息。登录成功后通过判断用户点击的是医生登录按钮还是病人登录按钮来判断加载医生登录界面还是病人登录界面。此后进入图形界面引擎控制的事件循环。当有事件到来时(如用户输入、点击等)处理事件、显示返回结果并继续等待下一个事件。所有的状态都是可逆的,也就是说用户可以通过退出按钮来回到上一个界面,以此来增加界面的可操作性。

    2.2 详细设计2.2.1 登录界面设计登录界面的设计较为简单,其功能为检测用户输入的登录信息是否与数据库中的登录信息相同。其应该包含一个用户名框,一个密码框,一个医生登录按钮、一个病人登录按钮以及一个退出按钮。由于图形化界面一般采用事件驱动,因此在按下按钮时进行对于用户输入的处理。按下医生登录按钮以及病人登录按钮的流程图如图 3所示。如果点击的是医生登录按钮或病人登录按钮,则首先判断用户名和密码是否为空。由于设计不允许出现空的用户名和密码,因此提前进行这一步判断有助于减少用户的等待时间以及无效的数据库访问,如果不为空则通过事先建立好的连接在数据库中查询,并通过查询结果进行比对:如果不存在此用户(查询结果为空)或密码比对错误,则做出相应的提示并禁止用户登录,如果用户名和密码均正确则加载对应的登录界面。如果点击的是退出按钮,则执行清理工作并退出界面。值得注意的是,由于医生登录界面与病人登录界面为同一个界面,因此第一步的输入信息不为空的检查可以提取到一个函数中进行,在本程序中validateUserNameAndPassword函数执行这一操作。

    此外,为了提高用户体验,在提示错误重新输入时需要清理掉上次提示的错误,而这些函数绑定在两个输入框的输入触发器上,这一绑定由此类的initialize方法完成。按照JavaFX的规范,initialize方法会在界面初始化时被调用。由于这些函数主要对于FXML的StyleSheet进行修改,与主要逻辑相比重要性较低,因此不做赘述,详见源代码部分。
    2.2.2 数据库连接器设计数据库连接器是整个程序的基础,它位于层次结构的最底层并被医生操作模块或病人操作模块所调用。这一模块在整个界面被初始化之前初始化,又由于没有它整个程序将无法运作,因此如数据库连接器不能正确被初始化,则程序将拒绝运行并退出。
    数据库连接器作为一个单例,为医生操作模块和病人操作模块提供必要的服务。这样可以简化上层的逻辑,将部分逻辑移动到底层,从而降低了整个系统的耦合度,同时便于代码的修改。虽然数据库连接器在全局作为一个单例对象存在,但由于需要考虑到多个客户端同时连接同一个数据库的情况,依然要考虑数据库层面的并发安全性问题。
    考虑到一个数据库仅供给一个人使用,为了简便起见,此类中仅维持一个连接实例,所有的statement均通过这一个连接进行。数据库对上层提供的服务(即公有方法)以及对应的执行语句如表 1所示(以略去参数类型)。此外,还提供了connectDataBase方法供初始化使用以及getInstance方法供获得实例使用。



    方法 (参数)
    说明
    执行的Sql语句




    getWholeTable (table)
    获得表table中的全部内容
    SELECT * FROM \<table>


    getPatientPassword (number)
    获得编号为number的病人的密码
    SELECT password FROM patient WHERE pid=\<number>


    getPatientInfo (number)
    获得编号为number的病人的全部信息
    SELECT * FROM patient WHERE pid=\<number>


    getDoctorInfo (number)
    获得编号为number的医生的全部信息
    SELECT * FROM doctor WHERE docid=\<number>


    getRegisterForDoctor (number, start, end)
    获得起止时间分别为start和end的有关医生编号number的全部挂号信息
    SELECT reg.reg_id,pat.name, reg.reg_datetime,cat.speciallist FROM ( SELECT reg_id,pid,reg_datetime,catid FROM register WHERE docid=\<number> AND reg_datetime>=\<start> AND reg_datetime<=\<end> ) as reg inner join ( SELECT pid,name FROM patient ) as pat on reg.pid=pat.pid inner join ( SELECT reg_id, specialist FROM register_category ) as cat on reg.catid=cat.catid


    getIncomeInfo (start, end)
    获得起止时间分别为start和end的所有医生的收入信息
    SELECT dep.name as depname, reg.docid, doc.name as docname, cat.specialist, reg.current_reg_fount, SUM(reg.fee) as sum FROM ( SELECT * FROM register WHERE reg_datetime>=<start> AND reg_datetime<=<end> ) as reg inner join ( SELECT docid,name,depid FROM doctor ) as doc on reg.docid=doc.docid inner join( SELECT depid,name FROM department ) as dep on doc.depid=dep.depid inner join( SELECT reg_id,specialist FROM register_category ) as cat on reg.catid=cat.catid GROUP BY reg.docid, cat.specialist


    updatePatientLoginTime (number, time)
    更新编号为number病人的最近登录时间为time
    UPDATE patient SET last_login_datetime=\<time> WHERE pid=\<number>


    updateDoctorLoginTime (number, time)
    更新编号为number医生的最近登录时间为time
    UPDATE doctor SET last_login_datetime=\<time> WHERE docid=\<number>


    tryRegister
    根据所给参数尝试挂号(较为复杂,见下)



    tryRegister方法由于不仅仅是执行一个简单的任务并返回结果而显得较为复杂:这个函数是为了将上层的部分逻辑转移到下层以降低系统耦合度而产生的。其流程图如图 4所示。由于这一方法需要分为多步执行,并且需要考虑并发安全性,因此需要启动一个transaction,在图中流程中任意一个地方发生错误则直接报错并回滚,回滚后不会对数据库造成任何影响。由于需要挂号编号是单调递增且连续的,因此transaction的隔离级别设置为repeatable read(可重复读)。执行挂号的sql语句前执行的判断为当前挂号数是否超过最大挂号数,而执行之后的判断为两次对于是否更新余额的判断:一次是判断是否需要从余额扣款,一次判断是否将找零存入余额。在所有语句得以正确执行后提交transaction以持久化更改。

    由于tryRegister返回的是成功挂号时的号码,占用了错误信息的返回渠道,因此为这一方法定义了一个异常RegisterException类来返回错误信息,其中包含错误代码可以指示出错的原因。
    2.2.3 病人操作界面设计病人操作界面的设计是整个程序中最为复杂的部分,其大部分代码均为界面更改代码。界面包含4个输入/下拉框、一个滑块以及2个复选框,输入框分别用于选择科室名称、医生姓名、号种类别以及号种名称,滑动条用于选择交款金额,两个复选框用于选择是否使用余额付款以及是否将找零存入余额。此外,界面上还包含需要显示的信息,包括应缴金额、找零金额以及挂号号码、还包含挂号按钮和退出按钮用于开始执行挂号逻辑以及退出当前界面。用于搭建界面的逻辑此处不再赘述,下面主要描述核心部分较为重要的复选框过滤方法以及当挂号按钮按下后所执行的逻辑。
    由于程序需要良好的用户体验,下拉框需要同时支持鼠标输入以及键盘输入,而当一个下拉框选择了一项内容后,其余的下拉框也应该更新其可选内容以匹配当前内容,这就涉及到过滤策略的问题:如何进行过滤以及在何时进行过滤。经过一番考虑与实践后决定采用如下的过滤策略:为每一个下拉框定义一个原始列表与一个当前列表,原始列表用于存放此下拉框在没有其它限制的情况下所有的可选值,而当前列表用于存放经过过滤后下拉框的候选值。再为每一个下拉框定义2种操作:更改与提交。鼠标在候选值上滑动、键盘正在进行输入的时候下拉框为更改状态,而鼠标点击后、键盘换行键按下后下拉框显示当前列表中的某一个值的状态为提交状态。
    于是过滤策略为:进行更改操作时仅过滤当前列表并将过滤后的内容加入下拉框的候选值中,而提交操作后对于所有的当前列表重新从原始列表进行按序更新,扩展到一般情况,假设共有N个列表,在提交任意一个下拉框m后对于当前列表1~m-1, m+1~N依次进行更新,而对于列表k的更新过程为:依次使用1 ~ k-1、k+1 ~ N的下拉框的已选择值以及此下拉框选择的内容类型对于第k个列表的语义限制对第k个列表进行更新。这一操作看似是具有时间复杂度O(M^2)的,而实际上进行了一定的优化后可以仅仅在O(M)的时间内完成,其中M为平均原始列表长度(由于过程较为庞杂,此处不便于使用图形进行展示)。
    这样设计的好处在于:能够在较短的时间内对于所有的列表进行动态的过滤而不会带来自定义的更新规则或带优先级的更新规则所带来的混乱,当用户选择下拉框m时m自动成为最高优先级(这也是合理的,因为用户当前的焦点在m处),并结合之前已选的内容对于所有下拉框进行过滤,在删除复选框内容时也不会造成其它更新策略可能带来的列表内容丢失。
    在挂号按钮按下后首先进行挂号前检查:判断必要的下拉框是否已经有选择的值以及余额是否充足,然后调用数据库连接器中的tryRegister函数尝试挂号,并根据返回的结果显示相应的挂号号码或者错误信息。
    2.2.4 医生操作界面设计医生操作界面则较为简单,其以查询、统计功能为主,并且统计功能可以集成在sql语句中完成,因此代码逻辑简短。值得注意的是需要使用TreeTableColumn来存储各列的值, 并使用DateTimeFormatter对于时间格式进行转换,否则列表可能不能正常更新,时间也不能正常被数据库连接器读取。
    医生操作界面界面包含一个挂号列表、一个收入列表,均可以按照任意一栏进行排序,包含2个时间选择器以及2个日期选择器,用于过滤起止日期,在2个表中均能过滤,并有2个复选框能够快捷的选定今天或全部时间,此处的界面更新逻辑为:但两个复选框中的任意一个被按下另一个都会取消选择,并且时间选择器与日期选择器会被禁用。最后,界面上包含2个按钮,分别用于发送数据库请求并更新界面以及退出当前界面。
    三、软件开发本程序以及测试程序的编写均在Arch Linux x64系统下完成,并分别在Linux和Windows下进行了测试,具体开发以及测试环境见表 2。



    项目
    版本




    开发操作系统
    Arch Linux 2018年4月更新


    JDK (Linux)
    OpenJDK 1.8.0_172, Java 8


    集成开发环境
    IntelliJ IDEA 2018.1.3


    测试操作系统1
    Arch Linux 2018年5月更新


    JRE (Linux)
    OpenJDK Runtime Environment 1.8.0_172-b11


    数据库 (Linux)
    MariaDB 10.3.7.r77.gee5124d714e


    测试操作系统2
    Windows 10 Pro x64 Version1803


    JRE (Windows)
    Oracle Java SE Runtime 1.8.0_161-b2


    数据库 (Windows)
    MariaDB 10.3.7 x64



    四、软件测试本软件测试在Arch Linux下进行。经测试,程序在Windows下的行为和运行结果与在Arch Linux下完全相同。
    4.1 登录测试首先不启动数据库,在无数据库连接的情况下启动程序,程序直接报错退出,如图 5所示,这是预期行为,因为不能要求用户手动连接数据库,因此只能报错退出。

    在数据库运作正常的情况下,启动后的界面如图 6所示。

    然后尝试不使用用户名、密码输入错误的用户名、密码登录,程序应该提示对应的错误,知己的程序输出如图 7和图 8所示。可以看出,与预期的结果相同。下方的显示区域分别显示“请输入用户名”、“请输入密码”、“用户不存在”以及“密码错误”。














    在使用用户名003、密码003003并点击病人登录后,成功登录,登录后的界面如 所示。此处登录测试完成,进入病人操作界面测试阶段。
    4.2 病人操作界面测试进入病人操作界面后如图 9所示。其中所有的可交互控件均可同时使用鼠标和键盘进行操作。当号种类别以及号种名称被选择时,应缴金额以及找零金额会自动显示,并且找零金额会随着付款方式以及交款金额的变化而变化。当未满足挂号条件时,挂号按钮为未激活状态。

    接下来尝试进行挂号操作当余额低于应缴金额时,使用余额付款按钮为未激活状态,不可使用余额付款,否则可以选择使用余额付款或使用现金付款,当选择使用余额付款时,交款金额滑块为未激活状态以减少无效操作的可能性。正在使用现金挂号的界面以及挂号成功的界面分别如图 10以及图 11所示,在挂号成功后,底部状态栏显示了挂号成功的信息以及挂号号码。


    为了测试程序的并发安全性,使用IntelliJ IDEA同时打开两个程序进行单步调试,调试结果显示无论两个程序以何种方式穿插挂号的操作都不会发生编号冲突或缺失的情况,但有可能造成某一个客户端不能挂号成功而发生数据库回滚。在这种情况下用户需要重新挂号。而当挂号数量达到限额时也会提示挂号失败,如图 12所示,当多次点击挂号后,此号码达到了人数上限,因此在访问数据库的时候会抛出异常并禁止用户进行进一步的挂号操作。
    此外,本程序还支持将找零存入余额以供下次使用。使用另一个号码进行挂号,并勾选将找零存入余额,挂号成功后余额有所增加,如图 13所示。


    在界面的友好性方面,所有的交互控件均能够同时支持鼠标和键盘操作,一个使用键盘通过输入拼音进行下拉框过滤的例子如图 14所示。

    4.3 医生操作界面测试退出病人操作界面后进入医生操作界面,图 15展示了上面用于演示的008医生登录并查询所有挂号列表的操作界面。界面的下方为过滤器,可以自定义时间过滤,也可以使用“全部时间”和“今天”复选框进行快捷的过滤。使用这两个复选框的效果与手动设置时间的效果相同,但是免去了较为费时的选择操作。

    图 16展示了手动输入时间进行过滤的效果,显示的值为上方病人测试中最后一次挂号的信息。可以看出与病人挂号时选择与返回的信息相同。

    标签栏的另一个标签为收入列表,这一列表的过滤方式与挂号列表的过滤方式相同,只是显示的内容有所差异。

    值得注意的是,无论是挂号列表还是收入列表,各栏的相对位置都可以移动,并且可以按照任意一栏排序。图 17即为将挂号人次移动到第三栏并以之为基准进行排序的结果。

    五、特点与不足5.1 技术特点
    病人操作界面使用了效率较高的过滤算法,以多个维度进行过滤,提高了程序的可用性和便捷性
    采用了移动端的控件风格构造了一个更为人性化的操作界面
    程序考虑到了多种异常以及并发的安全问题,健壮性强,并且程序效率较高
    将程序分解为多个模块,耦合度低、可扩展性强,易于修改
    编译时将所有的依赖打入一个jar包中,不存在依赖问题,全平台通用, 图 19为本程序在Window10下的运行效果。可以看出,除了字体有些微的差别外其余并无不同


    5.2 不足和改进的建议
    由于数据库定义密码长度限制,所有的密码为明文存储,安全性较低。可以考虑将密码改为hash加密后的密码存储
    下拉框过滤算法以及医生界面的更新算法可以改为增量更新,并多加上一级cache,这样可以减少数据库操作,并提升性能
    可以添加更多的统计功能供不同角度的查询使用
    可将sql用户名密码等全局变量提取到配置文件中,避免硬编码

    六、过程和体会6.1 遇到的主要问题和解决方法在医生见面设计中发生了统计表格不能自动更新的问题,通过阅读文档发现TreeTable类需要设置CellValueFactory才能实现自动更新,遂修改程序使之得以正常运行。在病人界面的设计时遇到了下拉框过滤输入时过滤算法失效的问题,经过仔细的检查后、发现原因在于应用过滤的优先级混乱造成了下拉框备选项丢失的错误,经过一番思考后想出了上面详细设计所述的过滤算法,从而从根本上解决了这一问题。此外,IntelliJ IDEA的FXML编辑工具缺失部分功能,使得FXML文件不能指定控制类,并且容易导致IDE崩溃退出,这一问题可以使用独立的SceneBuilder解决。
    6.2 课程设计的体会通过此次课程设计,我最大的收获是学习了如何使用JavaFX搭建一个现代化的、友好的界面,以及如何让Java程序与数据库协作来完成复杂的功能。对于第一次接触JavaFX库的我而言,这是一个挑战,但是经过近一个星期的不懈努力,我深入的了解了JavaFX的运作方式,并使用其构造了一个较大的项目,在这个过程中我学到了不少有用的知识。不仅如此,在这一综合性较强的实验中我还顺带复习了有关Java的语言特性、有关数据库的知识以及许多软件工程的经验与知识,这对于今后的学习生活奠定了不小的基础。
    七、源码和说明7.1 文件清单及其功能说明文件(夹)结构及其说明如下:
    src 项目根目录├── 说明文件.txt 说明文件├── lib 第三方库文件夹│ ├── jfoenix-8.0.1.jar JFoenix第三方库│ └── mysql-connector-java-5.1.46-bin.jar MySQL第三方库├── out 编译输出文件夹│ └── hims.jar 编译输出Jar包├── src 源文件夹│ └── hims 源文件夹(包级)│ ├── Login.fxml 登录界面FXML文件│ ├── Doctor.fxml 医生界面FXML文件│ ├── Patient.fxml 病人界面FXML文件│ ├── LoginController.java 登录界面控制类源码│ ├── PatientController.java 病人界面控制类源码│ ├── DoctorController.java 医生界面控制类源码│ ├── DBConnector.java 数据库连接器源码│ ├── Config.java 配置文件│ ├── Main.java 主函数所在类源码│ └── Main.css 界面使用的层叠样式表文件└── sample_data.sql 数据库样例数据文件7.2 用户使用说明书要使用本程序,须按照下列步骤进行环境搭建:

    前提条件

    操作系统:Windows/Linux/OS XJava 运行环境:Jre 1.8.0_161 或其兼容版本数据库:MariaDB 10.3.7或其兼容版本或MySQL对应的兼容版本
    样例数据导入

    启动数据库服务使用root登录进入数据库,创建名为java_lab2的数据库CREATE DATABASE java_lab2;
    创建名为java的用户,设置其密码为javajava,并授予其在java_lab2上的所有权限GRANT ALL ON java_lab2.* TO 'java'@'localhost' IDENTIFIED BY 'javajava';FLUSH PREVILEGES;
    使用java用户登录java_lab2数据库,并运行source sample_data.sql来初始化数据由于数据库名称、用户名以及密码均硬编码在程序中,因此上述信息不可更改
    使启动数据库服务维持启动状态
    运行out文件夹下的hims.jar,可以在命令行中运行java -jar hims.jar,也可直接在文件管理器中点击(需要java在PATH环境变量中并正确的设置MIME TYPE)
    7 评论 259 下载 2019-03-10 13:55:02 下载需要14点积分
  • 基于汇编语言的井字棋游戏程序开发设计

    一、游戏背景介绍1.1 背景介绍井字棋,英文名叫Tic-Tac-Toe,是一种在3*3格子上进行的连珠游戏,和五子棋比较类似,由于棋盘一般不画边框,格线排成井字故得名。井字棋的具体玩法为在一个3x3的棋盘上,一个玩家用X做棋子,另一个玩家用O做棋子,谁先在棋盘上的一行、一列或对角线上画满三个棋子,即可获胜,如果棋盘下满无人胜出,即为平局。
    由于井字棋玩法简单,界面比较简洁,能够快速完成游戏,因此具有较强的娱乐性,基本上每个人都会玩。所以我们将其作为我们设计的项目。
    在这个项目中,我们设计为双人对战游戏,并且能够对玩家的落棋进行判断,是否符合井字棋的游戏规则。还有输赢检测机制,能立即检测出来是否有玩家获胜。
    1.2 基本功能由于井字棋只有9个棋子位,所以在我们用一种更简单的表示方法,即直接用1-9个9个数字来表示位置,其索引顺序与键盘上的数字键排列一致,下棋时玩家看着数字键下,较为简便。

    当有玩家先在棋盘上的一行、一列或对角线上画满三个棋子时,该玩家获得胜利。

    判断胜利的方法就是检测所有的横行和竖列以及对角线是否画满三个棋子。具体实现方法为先检查斜方向是否有三个一样的棋子,有的话对应棋子的玩家胜出,结束游戏。如果没有就继续检查横方向,如果有三个一样的棋子,对应棋子的玩家胜出,结束游戏。没有的话继续检查竖方向,如果有三个一样的棋子,对应棋子的玩家胜出,结束游戏,如果还没有,就代表没有玩家胜出。继续游戏。
    当棋盘的格子都被落棋了,但是没有玩家在一行、一列或对角线上画满三个棋子,此时双方打成平手。

    在玩家游戏过程中,如果玩家落棋不符合井字棋游戏规则的话,程序会提醒落棋错误,并且要求玩家重新落棋,直到玩家落棋成功。

    二、核心算法思想2.1 设计棋盘的算法棋盘是整个游戏中的框架,玩家在落子后都会显示一个棋盘目前状态。
    先绘制棋盘的上边界,然后调用绘制行的方法来绘制棋盘的内容。每个格子都由多个竖线和空格组成,这就需要不断地打印这些字符来实现,具体方法是绘制一个竖线,在绘制格子里的数字或者棋子,然后再绘制一个竖线,这样一个一个格子就绘制好了。
    棋盘一共有九个格子,每行有三个格子,每画完一个格子后,就会跳转到下一个字符,画这个字符所在的格子,并且每绘制三个格子就进行换行,这样9个格子就会组成一个3x3的棋盘。
    同时给棋盘里的格子和每个格子的符号以及玩家的两个棋子分配了不同的颜色,这样使得界面比较美观。
    2.2 设计棋子并定义玩法的算法该程序是一个双人游戏,这里我们的玩家有两名,所以我们可以定义棋子为X和O,通过比较指令可以规定他们依次落棋,落棋次数最多为9次,玩家落棋后即可把相应格子的数字改为玩家的棋子并涂上颜色,在游戏界面中还会提示玩家选择的格子。
    2.3 检测有效数字的算法在游戏过程中,玩家要落的必须是数字1-9,而不能是其他的字符,并且已经落棋的格子不能再落棋。首先玩家选择要从键盘上敲的字符,我们把玩家输入的字符放到寄存器中,同时进行检查数字是否有效。
    通过比较指令完成对有效数字的判断。如果大于等于1并且小于等于9,则玩家输入的字符有效,如果小于1或大于9或者是其他的字符,则提醒玩家这不是一个有效数字,需要重新选择落子的位置,直到所下的棋子为有效数字。
    最后一步是检查所下的是有效数字是否重复占用,玩家不能在自己以及对手之前落棋的位置进行重复落棋,必须保证不会下重复的棋子。当玩家进行重复落棋时,程序会提醒玩家该位置已经有棋子,需重新选择落棋位置,直到所选位置是新的。
    2.4 检测有玩家胜利的算法在游戏过程中,由于某个玩家在棋盘一个方向连成三个棋子便可以判定其胜利,所以需要有算法去检测三子连线。我们需要从不同方向去考虑,横方向,纵方向,斜方向,这就涉及三种检测算法。
    首先进行斜方向检测。先获取斜方向上第一个和第二个棋子,进行比较,如果不一样,就进行反斜方向的检测,如果一样,继续获取该方向上第三个棋子,继续进行比较,如果还是一样的话,说明再该方向上有玩家胜出。反斜方向的检测机制与斜方向的相同。
    如果斜方向没有三个一样的,则进行横方向的检测,首先是第一行的检测,获取该行的第一个棋子和第二个棋子进行比较,如果不一样进行下一行检测,一样的话就获取该行第三个棋子,进行比较,如果一样,说明在该方向上有玩家胜出,不一样的话进行下一行检测。第二行的检测方法与第一行相同。第三行检测如果不一样,就说明没有玩家胜出。
    如果横方向没有三个一样的,就进行竖方向检测。首先是第一列的检测,获取该列的第一个棋子和第二个棋子进行比较,如果不一样进行下一列检测,一样的话就获取该列第三个棋子,进行比较,如果一样,说明在该方向上有玩家胜出,不一样的话进行下一列检测。第二列的检测方法与第一列相同。第三列检测如果不一样,就说明没有玩家胜出。
    如果棋子已经下满,并且通过三个方向的检测,并没有玩家胜出,此时游戏平局。
    2.5 界面设计玩家每落一次棋,就更新一次棋盘。并且在游戏过程中有语句提示,一开始会有欢迎语句和规则介绍语句,之后随着玩家每落一次棋,程序都会显示当前玩家是谁,落棋的位置,当游戏结束时,会有胜利提示语句,平局会有双方打平提示语句。
    三、核心算法流程图核心算法主要分为判断落棋是否有效,判断输赢。

    本程序是通过玩家输入棋盘上相应的位置数字来进行落棋,当玩家输入一个字符,判断是否是在1-9的数字,并且对应位置没有落过棋,最后根据玩家所代表的符号(X或O)来进行落棋。

    当玩家落好一次棋后,程序就会从三个方向进行输赢判断。先进行斜方向判断,然乎进行横方向判断,最后进行竖方向判断,只要满足其中一种就代表有玩家获胜,还需判断出当前玩家是哪个,哪个玩家就获胜,另一个玩家就输了。

    主方法的基本思路就是:首先判断玩家输入的字符是否有效,若不是则重新选择落子位置直到是有效位置,若是,则该玩家落子,程序进行输赢判断,如果有一方胜出,则游戏结束,如果没有,则临一玩家进行落棋。双方最多总共落九次,九次之后还没有玩家胜出的话,打成平局,游戏结束。如图所示。
    四、开发中遇到的问题4.1 汇编语言定义变量问题在学习c语言和c++语言时,习惯了首先声明变量,而汇编语言中无需变量的声明,因为汇编语言是直接对具体的内存单元操作,而每个单元有16进制的地址码,因此所有变量都可人为地由该地址码表示。但是汇编语言提供了EQU伪指令,可以将特定的内存空间标记为特定的名称,这就为变量定义提供了可能。而使用EQU伪指令的好处就是将抽象的物理内存分化为具体的变量名,避免了内存冲突,同时又增加了程序可读性。
    4.2 系统功能调用中遇到的问题系统功能调用——由DOS提供的一组实现特殊功能的子程序供程序员在编写自己的程序时调用,以减轻编程的工作量。分两种,DOS系统功能调用和BIOS终端调用。汇编语言中DOS系统功能调用有很多,涉及屏幕显示、文件管理、I/O管理等等,每个子程序都有一个功能号,所有的功能调用的格式都是一致的。调用的步骤大致如下:

    系统功能号送到寄存器AH中;
    入口参数送到指定的寄存器中;
    用INT 21H指令执行功能调用;
    根据出口参数分析功能调用执行情况。

    4.3 给字符上色问题既然是游戏,那么我们就要考虑其美观性,给棋盘上色能使游戏更加美观,给棋子涂上颜色更加提高了分辨感,那么问题就在于如何给棋盘和棋子上色。这里用INT 10H 指令执行功能调用,把11送到bl寄存器中,而11所对应的二进制数1011为淡青色,这样棋盘的边框就涂上了淡青色;把14送到bl寄存器中,而14所对应的二进制数1110为黄色,这样数字就涂上了黄色;同理玩家1的棋子x涂成淡绿色,玩家2的棋子o涂成淡红色。优化游戏界面如图所示。

    4.4 寄存器问题代码中大量充斥着各种寄存器,通过查阅资料了解一些寄存器的功能,以数据寄存器为例:数据寄存器可分为8位的寄存器,作为通用寄存器,可存储算术逻辑运算的操作数和运算结果。

    AX,Accumulator,通累加器,用累加器进行的操作可能需要更少时间。可用于乘、 除、输入/输出等操作,使用频率很高;BX,Base,基址寄存器,虽然属于数据寄存器,但它经常用作地址寄存器。CX,Count,计数寄存器,经常用作一个循环的计数,在循环语句中,默认CX的内容为循环次数。在位操作中,当移多位时,要用CX的低8位CL来指明移位的位数。DX,Data,数据寄存器,在进行乘、除运算时,它可作为默认的操作数参与运算,但在I/O指令中,DX用于表示I/O的端口地址。
    5.5 对简化主方法编写的问题这里设计了一些子方法,子方法对程序结构化的作用是其可简化主方法的编写,使得程序主干的编写思路清晰化,而一些复杂的算法与功能则放在一层层的子方法中实现。在井字棋代码中我们设计了打印字符串,画棋盘,玩家落棋顺序,判断胜利等子方法,这些方法通常比较复杂,在执行主方法的时候可直接调用这些子方法。
    五、心得体会首先,在汇编语言这方面是零基础,刚入手的前两天简直是寸步难行。参考一些教材书又很难看懂,什么ax,bx,cx啊,看着就心烦。但是,借鉴之前学习c语言的方法,又对比了两者之间的相同思想,最后在脑海中形成了一些思维框架。我和我搭档的同学互相研究这门语言并且交换心得,感觉有了很大进步。在编写过程中用到了很多基础知识,但是在程序运行时总会出现一些问题,由于汇编基础比较薄弱,所以有时会打错了程序代码,误解了知识点,不了解程序结构等,但是通过查阅资料,请教老师并和同学讨论,最终解决了所有问题,也成功的运行出了结果。通过本次课程设计,不仅加深了我对汇编程序设计的认识,也提高了改写程序代码和动手操作的能力,还有编程的基本习惯和开发系统时应注意的流程,同时也对各种指令有了进一步的理解。并且我发现一个好的汇编程序不仅要正确可行,还要有健壮性,当用户输入非法的数据,使运行环境改变时,程序能恰当地作出反应或进行处理,不会产生莫名奇怪的输出结果。因为完成设计的时间较短,并且对汇编语言知识比较生疏,设计之中难免有一些错误和不妥之处,同时也需要改进,所以真诚的希望尊敬的老师批评指正。
    在接触这门课程后,感到汇编语言并不是很容易就可以弄懂的。相比较以前学过的高级语言如C、C++等,电脑等于在迁就人的思维方式,但学汇编,人却必须要去迁就电脑的思维方式,要设身处地地用电脑的角度去思考问题,这就是我们学习汇编语言时遇到的最大的障碍。 另外,在C语言中不到10个语句构成的程序,用汇编语言却要好几十行甚至上百行。这不得不让我们对汇编产生一种恐惧感。事实上,这是完全不必要的。一旦对它的原理掌握后,编写程序就容易多了。另外,学习汇编语言能让我们更加了解计算机内部的组织结构,对我们计算机专业的学生来说,学习汇编也是提升综合能力的关键环节。
    汇编的学习不仅仅是学习其语法,而更多的是学习计算机基本的体系结构。其中遇到很多新的概念,名字。如寄存器、中断、寻址方式等。这些概念在刚接触汇编这门课的时候难以理解,但在之后的学习中通过老师的讲解,自己亲手编程的方式也就渐渐清晰明了。在学习汇编语言时,指令的功能是学习和掌握的重点,要准确有效并合理的使用这些指令,必须了解一些使用的规则。现对汇编语言编程时的规则进行总结,归纳起来有三点:1、要求指令操作数的寻址方式;2、指令对标志位的影响和标志位对指令的影响;3、指令的执行时间,对可完成同样功能的指令,要选用执行时间短的指令。
    1 评论 35 下载 2019-06-21 22:19:37 下载需要8点积分
  • 基于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 评论 212 下载 2018-10-31 11:28:48 下载需要12点积分
  • 基于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 评论 2 下载 2020-07-06 10:02:24 下载需要15点积分
  • 基于JAVA实现的简易聊天室

    一、设计目的信息技术的高速发展给人类生产,生活带来了广泛而深远的影响。“上网冲浪”、“数码相机”“PDA”、“彩屏手机”、“蓝牙技术”等新产品,新概念层出不穷,不断冲击着人们的视听。这些高科技成果为人们带来便捷、快乐的同时,也促进了人机交互技术的发展。人机交互是关于设计、评价和实现供人们使用的交互式计算机系统,并围绕相关的主要现象进行研究的科学。它主要研究人与计算机之间的信息交换,涉及计算机科学,心理学,认知科学等诸多学科,是信息技术的一个重要组成部分,并将继续对信息技术的发展产生巨大影响。
    聊天室是一项应用广泛,并且实用性强的一个非常典型的人机交互系统。在信息世界里,聊天工具的使用是非常频繁的,如MSN、QQ、校内通,之类的聊天工具许多人都正在使用。此次设计的聊天室系统虽然其功能简单,但是在开发技术和过程中,能够充分学习和使用JAVA的技术,进一步培养学生面向对象程序设计的思想,加深对面向对象程序设计四大特性的理解。
    二、需求分析人们日常生活中越来越多地使用聊天室这项应用来为自己的工作和学习服务。一个操作简单,界面友好、运行稳定的聊天室对于小型局域网的用户可以起到很好的交流作用。所谓聊天室就是一个可以让许多用户同时互相通信的网上园地,个人用户可以通过聊天室将自己融入整个主流社会中。
    根据目前使用聊天室的用户需求显示,用户对于聊天室主要有以下几点要求:

    聊天功能:可以实时接收和发送信息,并能支持公聊和私聊的的方式,能够查看聊天记录,聊天过程中能对字体、表情等进行设定等
    用户功能:可以随时注册和登录及注销,并能选择性加好友和删除好友以及查看对方的开放信息,还能看到对方的登录状态
    文件传输功能:用户可以共享资源,能发送及接收文件
    保密功能:用户可以设定自己的保密状态,使某些信息对于其他用户是不可见的
    系统稳定:客户端与服务端的连接稳定,不出现或者少出现连接不上的情况

    该简易聊天室是为许多喜爱聊天的用户开发设计的,和许多大型的网络聊天室相比该小聊天室功能比较简单,但能实现基本的聊天功能,点对多、点对点聊天和基本的用户功能,登录、注销、查看在线用户等。
    三、软件功能描述3.1 用户设置功能描述:用户自定义自己的登录名,成功设置后,服务端能接收到新设置的用户名;
    3.2 登录功能功能描述:在服务端开启的情况下,用户可以以自己自定义或者默认的登录名和登录地址端口登录到客户端,并能在服务器端显示登录状态;
    3.3 公聊功能描述:用户在聊天室中可以选择与“所有人”聊天,聊天室中的其他在线用户可以正常接收并正确显示公聊消息。
    3.4 私聊功能描述:用户可以选择与聊天室的在线用户列表中的其他用户聊天。双方的聊天记录对于聊天室的其他用户是不可见的。
    3.5 聊天心情功能描述:用户在聊天的过程中可以选择相应的心情来表达自己的情感。
    3.6 系统消息功能描述:服务端正常运行的过程中,在聊天室的每一个用户都能接收服务器端发送的信息提示信息。
    3.7 用户的状态功能描述:每一个客户端用户都可以实时看到目前其他在线用户的状态。
    3.8 用户注销功能描述:用户可以注销自己的账号,并重新登记登录名和地址。
    3.9 用户退出功能描述:用户可以在正常情况下退出聊天室。
    3.10 服务端控制功能描述:只有在服务端开启的情况下,用户才能登陆成功和聊天;用户设置的地址端口也必须与服务端的侦听端口一致,否则不能登录。
    四、主要模块描述及流程图4.1 模块描述本聊天室分为聊天室服务端和聊天室客户端,服务端与客户端之间通过套接口Socket(TCP)连接。在java中使用套接口相当简单,Java API为处理套接口的通信提供了一个类java.net.Socket.,使得编写网络应用程序相对容易.服务器采用多线程以满足多用户的请求,通过JDBC与后台数据库连接,并通过创建一个ServerSocket对象来监听来自客户的连接请求,默认IP地址为:127.0.0.1默认端口为8888。
    聊天室服务端模块图


    端口服务:输入要侦听的端口,默认为 8888
    启动服务:启动服务器,并开始在设置的端口中侦听,客户端用户可以登录并开始聊天
    停止服务:关闭服务器,侦听结束。客户端用户不能再聊天
    发送系统消息:服务器端给所有人或者个别用户发送消息
    消息显示:可以显示所有用户的聊天记录,和上线、下线信息
    退出服务器:退出程序,并停止服务

    聊天室客户端模块图


    用户设置:用户可以设置自己的用户名进行聊天
    连接设置:用户可以设置自己的服务器的IP地址和端口号,默认的连接地址为:127.0.0.1:8888
    用户登录:只能在聊天室服务端已开启的情况下,用户才能登录,用户登录之后才能开始聊天,登录后不能再修改用户设置和连接设置
    用户注销:退出聊天,可以继续修改用户设置和连接设置
    发送和接收聊天信息:用户可以给所有人或者个别用户发送信息,并能看到其他用户发送给自己或所有人的消息
    退出:关闭所有聊天并退出客户端

    4.2 流程图
    五、主要类UML关系图5.1 聊天室服务器端设计
    聊天室服务端主要包括 7 个文件,它们的功能如下:

    ChatServer.java:包含名为ChatServer的public类,其主要功能为定义服务器端的界面,添加事件侦听与事件处理。调用ServerListen类来实现服务端用户上线与下线的侦听,调用ServerReceive类来实现服务器端的消息的收发
    ServerListen.java:该类实现服务端用户上线与下线的侦听。该类对用户上线下线的侦听是通过调用用户链表类(UserLinkList)来实现的,当用户上线与下线情况发生变化时,该类会对主类的界面进行相应的修改
    ServerReceive.java:该类是实现服务器端的消息的收发的类。该类分别定义了向某用户及所有人发送消息的方法,发送的消息会显示在主界面类的界面上
    PortConf.java:该类继承自JDialog,是用户对服务器端侦听端口进行修改配置的类
    Node.java:用户链表的节点类,定义了链表中的用户。该类与前面所讲的链表节点Node类的功能相当
    UserLinkList.java:用户链表节点的具体实现类。该类通过构造函数构造用户链表,定义了添加用户,删除用户、返回用户数、根据用户名查找用户、根据索引查找用户这5个方法
    Help.java:服务端程序的帮助类

    5.2 聊天室客户端设计
    聊天室客户端主要包括5个文件,它们的功能如下:

    ChatClient.java:包含名为ChatClient的public类,其主要功能为定义客户端的界面,添加事件侦听与事件处理。该类定义了Connect()与DisConnect()方法实现与服务器的连接与断开连接。当登录到指定的服务器时,调用ClientReceive类实现消息收发,同时该类还定义了SendMessage()方法来向其他用户发送带有表情的消息或者悄悄话
    ClientReceive.java:该类是实现服务器端与客户端消息收发的类
    ConnectConf.java:该类继承自JDialog,是用户对所要连接的服务器IP及侦听端口进行修改配置的类
    UserConf.java:该类继承自JDialog,是用户对连接到服务器所显示的用户名进行修改配置的类
    Help.java:客户端程序的帮助类

    六、软件使用方法和操作步骤首先运行ChatServer工程文件,会出现如下画面

    选择端口设置,可以设置您要侦听的端口号,不设置将默认端口号为8888

    选择启动服务,服务器开始在您刚才设置的端口中侦听

    运行ChatClient工程文件,打开如下画面

    选择用户设置可以设置自己的登录名

    选择连接设置可以设置您的IP地址和端口号

    选择登录进入聊天室并可以开始跟所有人或者个别其他用户聊天,其中可以选择心情等

    在服务端也可以选择给所有人或者个别用户发送消息

    注意:客户端只有在服务端开启的情况下才能正常聊天
    4 评论 75 下载 2019-03-27 22:25:01 下载需要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 下载需要8点积分
  • 基于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 评论 103 下载 2019-02-08 10:28:08 下载需要11点积分
  • 基于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 评论 106 下载 2018-12-13 09:32:25 下载需要5点积分
  • 基于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 评论 48 下载 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 评论 403 下载 2018-11-05 12:31:35 下载需要6点积分
  • 基于汇编语言的学生成绩管理系统

    一 需求分析用汇编语言编写一个学生成绩管理系统,实现基本的学生成绩管理,功能包括成绩的录入,总分和平均分的计算,数据存档,从文件中读入数据等。要求程序界面友好,有输入界输出提示,有菜单等。
    二 程序设计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 评论 124 下载 2018-11-04 19:18:48 下载需要3点积分
  • 基于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 评论 371 下载 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 下载需要16点积分
  • 基于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 评论 384 下载 2019-01-28 16:38:21 下载需要8点积分
显示 0 到 15 ,共 15 条
eject