基于socket通信的在线考试系统设计-物流工程毕业论文_第1页
基于socket通信的在线考试系统设计-物流工程毕业论文_第2页
基于socket通信的在线考试系统设计-物流工程毕业论文_第3页
基于socket通信的在线考试系统设计-物流工程毕业论文_第4页
基于socket通信的在线考试系统设计-物流工程毕业论文_第5页
已阅读5页,还剩25页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

安徽农业大学经济技术学院安徽农业大学经济技术学院 毕毕 业业 论论 文(设计)文(设计) 论文题目基于基于 socket 通信的在线考试系统设计通信的在线考试系统设计 姓名宋杰学号09539042 院系经济技术学院专业网络工程 指导教师陈卫职称讲师 中国中国合肥合肥 二二o一三年一三年 六六 月月 课题名称基于 socket 通信的在线考试系统设计课题来源导师指定 学生姓名宋杰专业网络工程学号09539042 指导教师姓名陈卫职称讲师 研 究 内 容 1Swing 界面设计:使用 java 的 Swing 技术实现软件界面。 2I/O 流:通过 I/O 流读取配置文件。 3Socket 通信:使用 Socket 实现客户端和服务器端之间的通信。 4多线程:服务端使用多线程技术为多个客户端提供服务。 5Java 反射机制:使用反射机制实现方法的远程调用。 6Java 异常控制机制:使用自定义异常提高系统的健壮性。 7MVC:使用 MVC 设计模式实现软件的分层设计。 8IOC:使用控制反转的思想实例化类。 研 究 计 划 3 月中3 月底调研、查资料。 4 月初4 月中确定系统架构、分析并划分各功能模块的接口。 4 月底5 月初各功能模块设计与开发。 5 月初5 月中各功能模块及整个系统的调试与运行。 5 月下撰写毕业设计论文。 特 色 与 创 新 1.界面友好:界面 UI 美观,用户体验良好。 2.系统稳定,能实现远程部署,支持多人同时在线考试。 3.具有较强的实际应用价值。 指 导 教 师 意 见 教 研 室 意 见 学 院 意 见主要领导签字: 年月日 目目录录 1 引言引言 1 2 设计思想设计思想 2 3 考试系统软件结构设计考试系统软件结构设计4 3.1 数据模型设计4 3.2 客户端设计4 3.2.1 控制器设计5 3.2.2 服务层设计5 3.3 服务端设计7 3.3.1 无连接协议状态保持 7 3.3.1 服务端网络层工具类封装 9 4 考试系统软件界面设计考试系统软件界面设计 10 5 考试系统通信机制设计考试系统通信机制设计 11 5.1 客户端通信 11 5.2 服务端通信 11 6 系统读取配置文件信息系统读取配置文件信息 13 7 考试系统业务功能点设计考试系统业务功能点设计 13 7.1 系统时间 13 7.2 系统异常控制 14 7.3 系统读题 15 7.4 考试及成绩 18 8 系统模块集成系统模块集成21 9 系统测试系统测试22 10 结束语结束语 24 参考文献参考文献24 致谢致谢24 1 基于基于 socketsocket 通信的在线考试系统设计通信的在线考试系统设计 学生:宋杰,指导教师:陈卫 (安徽农业大学 经济技术学院 合肥 230036) 摘摘 要:要:本文介绍了基于 socket 通信的在线考试系统设计。给出了考试系统的设计方案 和代码实现,讨论了 socket 通信机制、MVC 软件设计模式,客户端服务器通信模式以 及 JAVA 软件编程。本系统建立了两个 JAVA 工程、分别为考试客户端和考试服务器端, 服务器端通过多线程机制和 socket 通信为多个客户端提供在线考试的功能, 客户端为用 户提供了可操作的界面,并使用反射机制远程调用服务端中的方法。本文还介绍如何使 用属性注入的方式解决软件模块与模块之间的依赖关系。 关键词关键词:Swing,Socket,反射机制,I/O 流,多线程,异常处理,MVC,IOC 1 1引言引言 网络技术是计算机领域中发展最为迅速的技术之一,它在政治、经济、生活等各个 方面发挥着十分重要的作用。随着计算机网络的普及和推广,将会有越来越多的人利用 网上资源,享受不断发展和完善的网络服务,以此来提高工作效率和水平。随着我国经 济发展和网络的普及, 网络技术也越来越多地被应用于日常工作之中。 在程序设计领域, 面向对象的编程技术正在逐步代替面向过程的程序设计技术, 成为计算机应用设计开发 的主流,尤其在网络技术开发中,面向对象的 Java 语言编程和相关的 Java 技术正在以 前所未有的速度发展。网上购物、网上银行、远程教学、网络聊天、网络游戏等都开始 使用 Java 技术。而且 Java 使平台无关性的思想成为现实,独立的 Java 程序可以被编 译为与平台无关的字节码,这种字节码可以运行在任何拥有 Java 解释器的机器上。 真 正降低了企业成品和程序员的负担。 Socket(套接字)是一种基于 TCP/IP 的编程接口。它采用客户/服务器通信机制,使 客户端和服务器端通过 Socket 接口在网络上实现连接和数据交换。它提供了一系列系 统调用,使用户可以方便地实现 TCP 和 UDP 等多种网络协议的通信。它使用户可以在网 络协议上工作而不必对该网络协议有非常深入的了解。 这样编写的程序可被迅速移植到 任何支持 Socket 的网络系统中去。 本文利用 Java Socket 来实现双机通信,能够达到在一台服务器上部署服务端,在 多台客户机上部署客户端,最终实现服务端能够同时为多个客户端提供在线考试的目 的。在系统设计的过程,我将逐步探索 Socket 通信的原理和软件设计的奥秘。 2 2 2 设计思想设计思想 在本设计中,系统分为客户端和服务端两个部分,客户端和服务端之间的通信由 socket 通信机制完成。客户端适应 Swing 技术给用户提供操作的界面,并通过 java 中 的监听器来监听用户的操作。当监听器监听到用户的某个点击事件后,他需要实例化相 应的 java 类,调用该实例化对象的相关方法,获取正确的响应数据,并通过界面展示 给用户。在这个触发响应的过程中,将涉及对于软件设计方方面面的考虑。 首先,触发响应过程如何通过标准的软件设计模式来实现。从传统模式来看层次化 的软件设计模式比较适合中小型软件的开发,所以本系统采取了 MVC1的设计思想,将 软件分为视图层,控制层,服务层,网络层和数据层。顾名思义,视图层是给用户提供 操作的接口,当用户在界面上触发一个事件后,会实例化一个控制器(实例化的方式将 在后面讨论) ,然后调用该控制器中的方法,控制器中的方法会调用相应服务层中的方 法来获取数据,再显示相应的界面给用户。可以看出,控制器起到调度者的作用,他是 视图层和服务层之间的桥梁,这样做的好处在于层次之间的分工明确。 那么服务层如何来获取数据呢,在整个系统中,如果按就近原则来说视图层的数据 是由服务层给予的,所以,服务层是软件核心业务的执行者。但是,在客户端/服务器 这样的架构中,服务层需要从远程服务器上获取数据,所以,本系统使用了 socket 通 信机制,于是,系统加入了网络层专门用来建立客户端和服务端之间的连接,用来发送 请求和获取响应数据。那么服务器是如何知道服务层想要调用哪个类中哪个方法呢,这 时,有了 java 中的反射机制就可以迎刃而解了。在发送请求之前,服务层需要实例化 一个类,这个实例化对象中包含了服务层想要调用服务器端目标类的类名,方法名和参 数列表,然后服务层将该对象发送给服务器,这时系统将这个包含目标类类名,方法名 和参数列表的对象叫做 Request 对象,并给他一个属性 sessionID,用来表明这个请求 的身份(借鉴 BS 通信方式) 。在 socket 通信机制中,当客户端和服务端建立连接后, 他们之间的通信可以通过 IO 流机制来实现,所以,系统将服务端实例化的 Request 对 象通过对象输入流 ObjectOutpustStream 写入到网络流中, 在服务器端通过对象输出流 ObjectInputStream 获得该对象,再使用 Request 对象中的类名,方法名和参数列表通 过反射机制来访问数据层。这时,服务端需要将结果返回给客户端了,借鉴 BS 通信模 式,系统定义了一个 Response 对象,该对象中的属性包括返回的数据,sessionId 和相 关异常信息, 客户端在网络输出流中获得该对象, 再从该对象中读取数据返回给控制器, 控制器调用相应的界面显示数据给客户端,这样就完成了一次客户端与服务器端交互。 3 服务端得到客户端发送的 Request 对象后,将通过反射机制访问数据层中的相关方 法。在传统的软件架构中,数据层是和数据库产生交互的组件,但是在本次设计中没有 使用数据库来持久化数据, 而是使用 propertes 配置文件的方法, 通过 FileInputStream 对象和 Properties 对象来加载和读取数据。 最后,在前面提到了实例化方式的问题,在 java 中最简单的实例化方式,是在该对 象被需要时通过 new 关键字来实现,但在整体软件架构中,如果当一个对象被需要时才 实例化,那么会导致对象实例化的泛滥,从而使软件性能降低。这时借鉴在 BS 系统架 构中有名的 Spring 框架能够系统的管理对象实例化的做法, 他是通过 IOC2控制反转的 思想来实现的,简单概述就是实例化对象的主动权不是交给需要该对象的类,而是交给 容器来管理, 容器通过属性注入或者构造器注入的方式将已经实例化的对象注入到需要 该对象的类的中,从而完成一次实例化多次调用的目的,这样做不仅管理了对象,也有 效实现了解耦的目的。所以,在定义一个类时,如果该类依赖其他类,那么就定义该类 的 set 方法,最后在一个公共的 main 方法中完成对象的组装。 具体设计思路如图 2-1 所示: 客户端客户端 服务端服务端 软件界面 JFrame ClientContext ExamServiceAgent Examserver ExamServiceImpl EntityContext 配置文件 Properties 视图层视图层 控制层控制层 服务层服务层 数据层数据层 网络层网络层 服务层服务层 RequestResponseSocket 通信通信 图图 2-1 系统架构系统架构 4 3 3 考试系统软件结构设计考试系统软件结构设计 3.13.1 数据模型设计数据模型设计 根据实际业务需求,我抽象出了如下 4 个实体模型: 表表 3-1 考试系统数据模型考试系统数据模型 Userint id学号 String name名字 String password密码 Questionint id;编号 String title;题目 List options;选项 List answers;答案 int score;分数 int level;难易度 QuestionInfoQuestion question考题 Int questionIndex题号 List userAnswers用户答案 ExaminfoString title考试科目 User user考生 int timeLimit考试时间 int questionCount考题数量 User 类提供用户登陆服务, Question 类表示一道试题, 数据层会将考试配置文件解 析为一个 Question 对象集合,返回给服务层,服务层从这个试题集合中根据难易度比 例随机抽取 20 道试题组合成一套试卷,这保证了每个考生的试题是不一样的。 QuestionInfo 类表示一个试卷试题对象,他将 Question 对象和用户选择的答案做了对 应关系, 这样便于在用户提交试卷后统计分数。 Examinfo 类为考生提供基本的考试信息, 该类中的属性会通过界面显示给考生,起到在线提醒的功能。整个考试系统将围绕该 4 个实体模型展开。 3.2 客户端设计客户端设计 考试系统客户端分为三层:视图层,控制层和服务层。视图层为软件界面,控制层 接受用户请求,访问服务层获得响应数据,向用户返回新界面,服务层发送远程请求并 5 解析服务端的响应数据,其结构图如图 3-2 所示: LoginFrameMenuFrameExamFrameRuleFrame ClientContext ExamService ExamServiceAgent 图图 3-2 服务端设计服务端设计 其中 ExamServiceAgent 依赖 Request,Response 和 Utils 3.2.1 控制器设计控制器设计 控制层包含两个类:ClientContext 控制器类,ClientMain 客户端启动类。控制器的 功能是根据服务层返回的结果控制界面显示和关闭, 以及在界面上显示什么内容。 Swing 技术生成的界面是通过 setVisible()这个方法来控制显示的。比如说,对于视图层的 LoginFrame(登陆界面)类,先将其例化后,通过 loginFrame.setVisible(ture) 显示界面, loginFrame.setVisible(false)关闭界面。那么在 ClinetContext 中就必须先实例化产生该界 面类的对象,再调用该方法,但是在前面讨论过,IOC 思想更适合对象的管理,所以, 设计 ClinetContext 这个控制器时遵守的原则是: 对于 ClinetContext 依赖的类, 将该类设 为控制器的私有属性,并提供 get/set 方法,在 ClientMain 客户端启动类中将控制器依赖 的类全部实例化,通过 set 方法注入到 ClinetContext 中,这样就可以达到控制器无需自 己实例化对象而控制多个界面的效果。 3.2.2 客户端服务层设计客户端服务层设计 服 务 层 包 含 了 所 有 客 户 端 业 务 组 件 , 其 中 ExamService 是 一 个 接 口 , ExamServiceAgent 是该接口的实现类,他具体实现了 ExamService 中定义的户登陆、初 始化考试、获取上一题、下一题,保存答案,提交试卷,获取分数 6 个抽象方法。在服 务层中,ExamServiceAgent 是核心类,他能够向服务端发送请求和获取服务端响应,他 是客户端和服务端的桥梁。 分析来看,ExamSerivceAgent 包括如下功能: (1)读取配置文件,获得服务端的 IP 地址和端口号,通过 Socket(ip,port)与服务器 6 建立连接。 (2)接受控制器的调用,在具体被调用的方法中构造 Request 对象,并将该对象写 入到网络流中发送给服务端。 (3)接受服务端响应,解析响应对象 Response 中的数据,将数据返回给控制器。 我将建立连接,发送请求,获取相应三个处理过程抽象成工具类 Utils,以用户登陆 为例代码片段如图 3-3 和图 3-4 所示: 图图 3-3 用户登陆代码用户登陆代码 图图 3-4 UtilsUtils 工具类代码工具类代码 7 3.3 服务端设计服务端设计 考试系统服务端分为网络层,服务层和数据层,网络层监控客户端的连接请求,当 监控到有客户端发送了连接请求后,服务端通过多线程3机制给该客户端分配一个考试 服 务 对 象 ExamServiceImpl, 并将该客户端 请求对象 Request 中的 SessionId 和该 ExamServiceImpl 对象做键值对,最后通过 HashMap3将该键值对存储在服务器内存中。 当该客户端再次发送请求时,服务端会拿当前请求对象 Request 中的 SessionId 去查找 HashMap 中该 SessionId 所对应的 ExamServiceImpl,这种机制保证了客户端在服务器上 访问的考试服务对象始终是同一个。 服务端结构图 3-5 所示: ExamServer ExamService ExamServiceImpl ExamService ExamServiceImpl 多线程 数据层 ExamService ExamServiceImp 图图 3-5 服务端设计服务端设计 其中ExamServer依赖 Request,Response 和 Utils; 3.3.13.3.1 无连接协议的状态保持无连接协议的状态保持 本系统的客户端和服务端之间的连接状态会经历:建立连接、发送请求、接收响应、 断开连接四个过程,这是一种无持续状态的连接,这种机制充分重用服务器的网络服务 能力, 但其缺点是不能保持持久连接, 那么就需要一种机制来识别客户端是否已经来过。 在传统的 BS 模式的架构中,浏览器访问服务器时,服务器会给本次请求分配一个 SessionId,该 SessionId 就相当于一个令牌,浏览器每次访问都带着这个令牌,而服务 器检查该令牌。在本考试系统中,我模拟了这种令牌访问机制,这种机制能保证客户端 在下一次访问服务器时,能通过该 SessionId 找到服务器为其分配的 ExamServiceImpl 8 对象,其执行流程图 3-6 所示: 获得 Request 是否存在 SessionId 分配 SessionIdHashMap 客户端 构造 Response 分配 ExamServiceImplExamServiceImpl ExamServer ExamServer 图图 3-6 无连接协议状态保持设计无连接协议状态保持设计 服务端返回的 Response 对象中也包含请求对象 Request 中 SessionId, 客户端获取 Response 对象后, 会将该 SessionId 存入内存, 这保证了客户端每次访问都带着同一块 令牌。服务端通过 SessionId 查找服务对象和分配 SessionId 的代码如图 3-7: 图图 3-7 查找查找 ExamServiceImpl 或分配 SessionId 9 该代码的 97 行就是一种 IOC 思想的体现,系统在网络层实例化 EntityContext 数据 访问对象,在第一次创建 ExamServiceImpl 服务对象时,通过 set 方法将该数据访问对 象注入到服务对象中,这样客户端在后继访问服务对象时只使用一个数据对象,这样可 以大大节省服务器端的内存资源,这也是一个简单的单例模式。 对于 SessionId 的生成,我使用了 java 中的 UUID4类, 他能结合机器的网卡、当地 时间、一个随即数来生成一个数字,它保证对在同一时空中的所有机器都是唯一的。用 它来做 SessionId 保证了 ID 号的唯一性。 3.3.23.3.2 服务端网络层工具类封装服务端网络层工具类封装 在服务端,客户端的每一次请求,服务端都会按照如下流程执行: (1) 网络层给该客户端分配一个服务线程; (2) 获得网络流中的 Request 对象; (3) 根据 Request 中的 SessionId 获得其对应的 EaxmServiceImpl 服务对象; (4) 根据 Request 中请求参数通过反射机制5访问服务对象并构建 Response 对象; (5) 将 Response 对象返回给客户端; 在步骤(4)中将使用反射机制访问服务对象,其具体过程包括: (1) 获得被调用对象的类类型; (2) 根据方法名,参数列表获得该类中的方法对象; (3) 传递方法参数,调用方法; 感觉这是一个比较繁琐的过程,我将其封装成工具类如图 3-8 所示: 图图 3-8 反射机制访问对象中的方法反射机制访问对象中的方法 10 4 4 考试系统软件界面设计考试系统软件界面设计 客户端主要为用户提供系统登陆和考试界面,根据业务需求,设计了 5 个界面模块 表表 4-1 界面类界面类 WelcomeWindow系统启动闪屏 LoginFrame登陆界面 MenuFrame菜单界面 RuleFrame考试规则界面 ExamFrame考试界面 软件界面设计本人使用了 Swing5, Swing 中有三个基本构造块:标签、按钮和文本 字段;但是现在需要个地方安放它们,并希望用户知道如何处理它们。JFrame 类就是 解决这个问题的它是一个容器,可以把其他组件添加到它里面,把它们组织起来, 并把它们呈现给用户,所以我将 LoginFrame,MenuFrame,RuleFrame,ExamFrame 这 三个界面类都继承 JFrame 类。Java 中 JWindow 类是一个无装饰的顶层窗口, WelcomeWindow 继承该类,形成一个软件启动窗体,提高用户体验。 软件界面能够监控用户的操作,Swing 给我们提供了监听器,以登陆按钮为例: 图图 4-1 考试按钮考试按钮 代码第 118 行创建 JButton 对象,并设置按钮标题;第 119 行设置按钮大小和在界 面上的坐标,其参数含义为 setBounds(宽,高,横坐标,纵坐标);第 121 行给登陆按 钮绑定键盘回车事件;第 123 行开始为按钮添加监听器,我使用内部类的方式为按钮绑 定控制器中的 start()方法;由于在视图层依赖控制器类,运用 IOC 思想,我将 ClientContext 注入到界面类中便于监听器调用,所以在每个界面类中必须提供 ClientContext 的 set 方法。 对于界面布局的设计方式,Swing 中有两种方式: (1)流式布局; (2)绝对定位。 11 由于流式布局按照东西南北的方式分割界面布局,代码臃肿繁琐,我采取了绝对定位的 方式,通过设置组件在界面上坐标来进行定位。 5 5 考试系统通信机制设计考试系统通信机制设计 考试系统的客户端和服务器端的通信是建立在 Socket 通信的基础上, 但需要形成一 个比较规范的通信流程完成通信过程,在前面也谈到过客户端如何向服务端发送请求, 服务端如何去响应请求的,那么这里我想完整的概述考试系统的通信机制。 通信流程如图 5-1 所示: ServiceSocket 网络流 Socket 图图 5-1 通信机制通信机制 5.15.1 客户端通信客户端通信 客户端通信的流程为: (1) 通过 new Socket(host,port)和服务端建立连接; (2) 通过 getOutputStream()方法从 Socket 对象中获得网络输入流; (3) 通过 writeObject()方法将 Request 对象写入到网络流中,刷新输入流; (4) 通过 getInputStream()方法从 Socket 对象中获得网络输出流; (5) 通过 readObject()方法从流中获得 Response 对象,关闭 Socket; 代码设计请见图 3-4。 5.25.2 服务端通信服务端通信 服务端通信的流程为: (1) 创建 ServiceSocket 对象,通过 accpet()方法监控服务端的 Socket 请求; (2) 如有连接,通过 getInputStream()方法从 Socket 对象中获得网络输出流; (3) 使用 readObject()方法从流中获得 Request 对象; (4) 根据 Request 对象中的请求参数访问数据层 (5) 根据返回的数据构建 Response 对象 (6) 通过 getOutputStream()方法从 Socket 对象中获得网络输入流; (7) 通过 writeObject()方法将 Response 对象写入到网络流中,刷新输入流; 12 设计代码如图 5-2 所示: 图图 5-2 服务端启动方法服务端启动方法 在该 start()方法中使用了无限循环,在该循环中 ss.accept()不断监控客户端的请求, 一旦有客户端请求,将给该客户端分配服务线程,其代码如图 5-3 所示: 图图 5-3-考试服务线程考试服务线程 服务线程的定义系统使用了内部类的方式,其中的 getService()方法请见图 3-7。 13 客户端和服务端创建 Socket 的时机是有所差异的, 客户端是当用户产生某个请求时 间时才发起连接,而服务端需要在考试服务开启之前手动调用 ExamServer 中的 start(),相当于启动服务器的概念。 6 6 系统读取配置文件信息系统读取配置文件信息 本系统为了方便管理 IP 地址,端口号等一些可能发生改变的参数,系统使用了 properties 配置文件。在 properties 文件中,信息是通过键值对的方式来存储的,同 过 load 方法可以将一个 properties 文件输出流对象载入到 Properties 对象中,这样 可以通过 getProperty(String key)方法,根据建值来获取其对应的字符串参数。 为了方便读取配置文件,我定义了 Config 工具类,代码如下: 图图 6-1 配置文件工具类配置文件工具类 7 7 考试系统业务功能点设计考试系统业务功能点设计 本系统涉及到的功能点比较多,从打开软件界面,到交卷,系统在代码实现上结合 了很多 java 编程方面的知识,比如定时器,集合框架,自定义异常,IO 流,时间,字 符串处理等等。 7.1 系统时间系统时间 一场考试是有时间限制的,所以,本系统应该具备时间提醒功能,并在考试开始时 14 计时,时限到后提醒交卷或强制交卷,startTimer 方法代码如下: 图图 7-1 系统时间系统时间 代码 235 行从考试信息对象中获取这场考试的时限,并将其转化为毫秒,236 行通 过获取当前时间和时限计算考试结束的时间,240 行获得考试剩余时间,241243 行是 将剩余时间转化为时分秒,再调用界面类 ExamFrame 中的 updateTime 方法更新 JLabel 标签中内容,updateTime 方法代码如下: 图图 7-2 更新界面更新界面 在 startTimer 方法中,使用了定时器来更新界面和时间到后强制交卷,startTimer 方 法的 246 行和 252 分别定义了任务执行的时间和任务过期的时间。248251 行为任务过 期时执行的方法体,238244 行为定时任务的方法体。 7.2 系统异常控制系统异常控制 系统在运行过程中可能会因为用户误操作产生运行时异常,比如用户输入的用户名 15 和密码不匹配会产生异常,需要将异常信息显示到界面以提醒用户,为此我自定义了 IdOrPwdException 异常,代码如图 7-3: 图图 7-3IdOrPwdException 异常类 其中 message 为自定义异常信息,其他程序捕捉到该异常后会通过 getMessage 方法 获取该异常中的 message 信息, 服务端 ExamServiceImpl 类中的 login 方法会根据用户名 和密码是否匹配判断是否抛出该异常,login 代码方法图 7-4: 图图 7-4ExamServiceImpl 中的 login 方法 最后在客户端控制器中通过 try catch 块捕获该异常,通过 getMessage 方法获取异常 信息,并将异常通过 JLable 标签显示到界面。 7.3 系统读题系统读题 系统读题是考试系统的核心业务, 服务端会在调用 ExamServer 中的 start()方法时 将试题配置文件中的所有试题读入内存作为一个试题库,当客户端调用 startExam()方法 16 后,会从内存的题库中随机抽取 20 道题组成一张试卷,那么题库的存储格式至关重要, 因为会影响下面选题的执行。 本人将题库设计为一个 HashMap, 其 key 为 level (难以水平) ,value 是一个 Question 集合,这样就可以在每个 level 下随机抽取若干题目了。为了方便通过 IO 流6的方式将 配置文件中的试题读出,本人将试题配置文件设计为如图 7-5 格式: 图图 7-5 考试配置文件考试配置文件 corejava.txt 通过如下代码读取配置文件: 图图 7-6 EntityContext 中的中的 loadQuestion 方法方法 代码7982行是打开字符流, 通过readLine()连续读出五行字符串交给paresQuestion() 方法将其解析成一个 Question 对象,其代码如图 7-7: 17 图图 7-7EntityContext 中的中的 paresQuestion 方法方法 从试题配置文件中可以看出有些题目是多选项的,答案通过“/”连接,因此需要切 割成一个集合,所以在 paresQuestion()方法代码的第 117 行使用了 parseAnswers()方法, 代码如图 7-8: 图图 7-8 EntityContext 中的中的 paresAnswers 方法方法 通过 paresQuestion 和 paresAnsers 两个方法解析出 Question 对象后,将其存入到 HashMap 中,该 HashMap 的结构如下: HashMap questionMap = new HashMap(); questionMap 对象的第一个参数为该 Question 对象的 level,第二个参数为该 level 所 对应的 Question 对象集合。那么将一个 Question 对象放入其 level 对应 List 中的流程如 下: 18 (1) 查询 questionMap 中是否有该 Question 的 level; (2) 有,则取出 questionMap 中该 level 对应的 List,将 Question 加入 到集合中; (3) 无, 则创建List,将Question加入, 在将level作为key,List 作为 value 存入 questionMap 中; loadQuestion 方法代码实现如图 7-9: 图图 7-9 EntityContext 中的中的 addQuestion 方法方法 试题库形成后,存入内存,客户端发出开始考试请求后,将调用服务端 ExamServiceImpl 对象的 startExam()方法, 该方法会调用 createPaper()方法, 创建一套 20 题的试卷,这时 ExamServiceImpl 中 peper 属性将指向该试卷(QusetionInfo 集合) ,这 保证了用户下一次访问服务器时使用的是同一套试卷。随机生成试卷代码如图 7-10: 图图 7-10 ExamServiceImpl 中的中的 createPaper 方法方法 7.4 考试及成绩考试及成绩 用户在考试过程中需要选择答案,点击下一题、上一题和交卷,这是一系列和服务 端产生交互的过程。在服务器的内存中已经保存着和该客户端对应的 ExamServiceImpl 19 对象, 该对象的 paper 属性指向了一套试卷, paper 是一个 QuestionInfo 集合, QuestionInfo 用来保存试题 Question,题号 QuestionIndex 和用户答案 UserAnswer。所以,我们可以 使用 QuestionIndex 属性来控制上一题或下一题的获取, 使用 UserAnswer 保存用户答案, 使用 JLable 标签将 Question 中试题信息显示到界面。 在界面中,使用监听器给上一题,下一题和提交按钮绑定控制器中的 prev(),next() 和 send()方法,通过这个三个方法,界面可以和服务端产生交互。获取界面上用户选择 的答案至关重要,通过 Swing 中的 Option 类可以获取用户选择的答案,代码如图 7-11: 图图 7-11 ExamFrame 中的中的 getUserAnswers 方法方法 那么用户点击下一题按钮时其执行流程如下: (1)获取当前界面试题的题号和用户选择的答案; (3)将答案保存到服务端的 ExamServiceImpl 的对象中 paper 属性中; (4)获取下一题,显示到界面; 具体代码如图 7-12: 图图 7-12 ClinetContext 中的中的 next 方法方法 代码第 160 行使用 Swing 中的对话框,提醒用户已是最后一题。 20 用户点击上一题按钮执行流程如下: (1)获取当前界面试题的题号和用户选择的答案; (2)将答案保存到服务端的 ExamServiceImpl 对象的 paper 属性中; (3) 获取上一题 QuestionInfo 对象, 将 QuestionInfo 中的 Question 信息显示到界面; (4)根据 QuestionInfo 中的 userAnswers 将 options 设置选中; 具体代码如图 7-13 下: 图图 7-13ClinetContext 中的中的 prev 方法方法 next()和 prev()需要依赖 saveUserAnswers()、getQuestion()、updataView()、updateOption() 等方法,其代码见附录附录 1。 用户点击 send()交卷按钮系统执行流程如下: (1)系统弹出提示,提醒用户是否确认交卷并保存最后一题的答案和统计分数; (2)将分数保存到内存和将分数通过弹框返回给用户; (3)关闭考试界面,返回到系统菜单界面; 具体代码如图 7-14: 21 图图 7-14 ClinetContext 中的中的 send 方法方法 Send 方法依赖 overExam()、saveUserAnswers()、getQuestion()、putInPapar()等方法;其中 overExam()和 putInPaper()方法代码见附件附件 2。 8 8 系统模块集成系统模块集成 系统客户端和服务端都需要一个启动的 main 方法,在客户端的 main 方法中完成客 户端模块的集成,其主要任务是将客户端需要使用的所有对象完成实例化,并通过 set 方法将对象注入需要他的对象中,完成对象与对象之间的依赖关系。客户端主方法代码 如图 8-1: 22 图图 8

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论