分类

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

资源列表

  • 基于C#的模仿windows记事本程序

    一、实验目的和要求
    掌握C#的基本语法
    掌握菜单、工具栏和状态栏控件的使用
    掌握计时器控件和通用对话框的使用方法
    掌握自定义控件的编写和使用方法
    掌握窗体交互的方法

    二、实验内容和原理
    完成C#windows窗体的模拟电脑记事本做一个相关应用
    实现记事本的基本功能包括文件打开、保存、另存为、新建、新建窗口、文本的编辑包括撤销、剪切、复制、粘贴、删除等基本功能;格式中的字体设置;查看中的状态栏
    在以上的功能上添加了编辑的使用baidu搜索、查找(未完善)、格式的自动换行功能;在窗体方面完全模仿电脑记事本,但存在部分功能为实现,包括文件中页面设置、打印未实现
    编辑中查找下(上)一个、替换、转到为实现;编辑中查找功能未完善

    三、实验环境
    硬件:PC机
    软件:windows10、VS2017

    四、算法描述及实验步骤4.1 界面步骤
    打开vs2017,创建新项目(windows窗体),项目名称为Form1为主窗体
    模仿windows系统下的记事本搭建界面
    创建新项目(windows窗体),项目名称为Form2为主窗体
    模仿windows系统下的记事本的查询搭建界面
    创建新项目(windows窗体),项目名称为Form3为主窗体
    加入自己设计的字体设计器界面

    4.2 功能实现4.2.1 保存利用SaveFileDialog类打开系统文件目录界面;Filter方法的保存类型
    saveFileDialog1.Filter = "ext files (*.txt)|*.txt|All files(*.*)|*>**";
    当条件
    dr == DialogResult.OK && saveFileDialog1.FileName.Length > 0
    成立时保存文件。
    4.2.2 新建文件新建一个From1界面。
    4.2.3 打开文件利用组建OpenFileDialog 设置打开格式限制
    Filter = "文本文件(*.txt)|*.txt";
    利用IO接口的
    StreamReader sr = new StreamReader(this.OpenFileDialog1.FileName, System.Text.Encoding.Default);
    将文件写入界面中。
    4.2.4 保存文件SaveFileDialog方法打开文件目录;设置保存文件格式限制
    saveFileDialog1.Filter = "ext files (*.txt)|*.txt|All files(*.*)|*>**";
    4.2.5 另存为文件通保存文件类似。
    4.2.6 字体点击格式字体是跳出设计的字体设计界面利用委托传值设置字体。
    4.2.7 查找获取textBox1的值,当文件中内容相同时利用richTextBox.Select()方法选中文字。
    4.2.8 复制、粘贴、剪切设置其他复制、粘贴、剪切功能设置相应的函数即可
    五、实验结果新建

    首页

    打开

    保存

    未查找到

    查找

    字体设计

    帮助

    六、总结6.1 错误总结
    当点击下划线或者删除线的时候,之前设置的字形格式会丢失
    在进行委托传参的时候不能按要求修改样式

    6.2 解决方案定义变量fontstr和fontunder分别来判断checkbox是否被选中,新建一个函数为setFont(string s),用来设置FontStyle的格式,在listbox2获取到值后调用函数setFont参数为listbox2.text,在checkbox点击的事件中判断是否被选中,然后修改相应的值,调用setFont函数,参数还是listbox2.text,在setFont中通过判断listbox2.text和fontstr和fontunder的值来确定FontStyle的格式,从而解决了不同操作引起的覆盖。
    为givevalue函数设置四个参数,String fontName, float fontSize, FontStyle fontstyle, Color myColor,然后对textbox的Font和ForeColor属性进行修改。
    6.3 总结感悟通过这次的实验,使我对c#的功能有了更深的理解,对一些常用组件有了更好的掌握如单选按钮控件、复选框、列表控件、组合框控件等。通过使用常规组件构造出一个复杂的功能。此外通过本次的实验,我还学习到了一些之前所不懂的内容,窗体之间使用委托来进行数据传输以及对自定义控件的使用方法有了更深的了解。
    通过本次的实验,不仅是对现有基础控件有了更深的掌握,也是对接下来学习高级控件的一种很好的铺垫。
    1 评论 2 下载 2020-06-20 14:47:35 下载需要14点积分
  • 基于python的新闻检索系统

    1 系统介绍1.1 系统需求新闻检索系统:定向采集不少于 4 个中文社会新闻网站或频道,实现这些网站新闻信息及评论信息的自动爬取、抽取、索引和检索。本项目未使用 lucene,Goose 等成熟开源框架。
    1.2 系统思路与框架本系统总体的实现思路如图 1 所示:

    一个完整的搜索系统主要的步骤是:

    对新闻网页进行爬虫得到语料库
    抽取新闻的主体内容,得到结构化的 xml 数据
    内存式单遍扫描索引构建方法构建倒排索引,供检索模块使用
    用户输入查询,得到相关文档返回给用户

    2 设计方案2.1 新闻爬取2.1.1 算法简述该模块针对搜狐,网易,腾讯三大主流新闻网站及官方的参考消息网站进行了新闻获取。并基于其网站结构,设计了不同的爬取模式。由于网站架构两两相似,以下选取两种类型的典型代表进行介绍:
    (1)搜狐新闻搜狐新闻除正常主页外,存在隐藏的列表式新闻页 , 如 http://news.sohu.com/1/0903/62/subject212846206.shtml ,其新闻组织方式如下图所示:

    源代码中以:
    <a test=a href='http://www.sohu.com/a/201108961_115479' target='_black'>美CIA秘密文件宣称:希特勒二战后最少活了十年</a><span> (10/30 11:33) </span>
    <a> 作为各条新闻的分割,且含有新闻标题,发表时间,通过 Beautiful soup 该款开源格式解析工具,我们获取到列表中所有新闻的 URL,并记录其相应的标题,发表时间。注意 URL 的最后数字串对应于该条评论的 newsID。
    新闻内容页中,正文部分以:
    <div class="text"> <div class="text-title"> <h1>美CIA秘密文件宣称:希特勒二战后最少活了十年<span class="article-tag">
    <div class=‛text‛>包含正文部分,而评论消息正文部分记录于 http://quan.sohu.com/pinglun/cyqemw6s1/+newsID 所在网页,且通过 js 动态进行加载。针对这一问题,我们采用了 Selenium + PhantomJS 伪浏览器获取网页动态内容的方式,冒充真实用户请求,获取动态加载的评论。其评论以<span class=‛ wrap-word-gw‛>的方式包裹,逐条进行呈现。而评论的数量,需要通过访问:
    http://changyan.sohu.com/api/3/topic/liteload?callback=jQuery1709683075909326675_1500009616671&client_id=cyqemw6s1&topic_url=+newsID进行获取,返回结构体:
    {"cmt_sum":0, "comments":[], "mode":6, "outer_cmt_sum":0, "participation_sum":0, "topic_id":4285033212});其中 cmt_sum 即为所求。
    (2)网易新闻可以将网易新闻及腾讯新闻归结为一般类型的新闻主页,我们采用了自新闻主页开始的广度优先的递归爬取策略。注意到新闻的正文页往往是静态网页.html,因此,我们将网页中出现的所有以.html 结尾的网页的 URL 均记录下来,在爬取到一定量时,进行一次去重。
    对于一些不是新闻的错分网页,容错处理即通过检查新闻正文标签 <div post_content_main> 时会被剔除。
    新闻正文页中我们重点关注内容,时间,评论获取。
    正文起始
    <div class="post_content_main" id="epContentLeft"> <h1>外交部:法国总统马克龙将于1月8日至10日访问中国</h1>
    新闻时间
    <div class="post_time_source"> 2018-01-02 10:38:01 来源:
    评论相关
    网易新闻为直接通过新闻的 URL 的末尾编号(NewsID)与关联评论的网址的组合:http://comment.news.163.com/api/v1/products/a2869674571f77b5a0867c3d71db5856/threads/+NewsID 获取评论数量及内容:

    这里的 cmt 相关的数字,我们认为是其评论的大致数量。
    加上 /comments/newList?offset 即返回含有评论的结构体:

    腾讯新闻通过新闻正文主页中的 comment_id 实现对评论的检索:
    document.domain = 'qq.com';cmt_site = 'news';cmt_id = 2331528973;cmt_is_group = 0;cmt_count_id = 'comment_count|comment_count2';
    之后仍然是跳转与评论相关的网址:http://coral.qq.com/article/+cmt_id

    返回结构体中的 commentnum 即为数量,加上/comment?reqnum=num,即得到 json 形式的评论

    我们对其转码进行解析即可,其中 content 即为所求:

    2.1.2 创新点
    实现了对新闻网页动态加载的评论进行爬取,如搜狐新闻评论爬取
    未借助开源新闻爬取工具,自己实现了对新闻标题,正文,时间,评论内容,评论数目的高效爬取

    2.2 索引构建
    分词,我们借助开源的 jieba 中文分词组件来完成,jieba 分词能够将一个中文句子切成一个个词项,这样就可以统计 tf, df 了
    去停用词,去停词的步骤在 jieba 分词之后完成
    倒排记录表存储,词典用 B-树或 hash 存储,倒排记录表用邻接链表存储方式,这样能大大减少存储空间

    倒排索引构建算法使用内存式单遍扫描索引构建方法(SPIMI),就是依次对每篇新闻进行分词,如果出现新的词项则插入到词典中,否则将该文档的信息追加到词项对应的倒排记录表中。SPIMI 的伪代码如下:
    SPIMI-INVERT(Token_stream) Output_file=NEWFILE() dictionary = NEWHASH() while (free memory available) do token <-next(token_stream) //逐一处理每个词项-文档ID对 if term(token) dictionary /*如果词项是第一次出现,那么加入hash词典,同时,建立一个新的倒排索引表*/ then postings_list = ADDTODICTIONARY(dictionary,term(token)) /*如果不是第一次出现,那么直接返回其倒排记录表,在下面添加其后*/ else postings_list = GETPOSTINGLIST(dictionary,term(token)) if full(postings_list) then postings_list =DOUBLEPOSTINGLIST(dictionary,term(token)) /*SPIMI与BSBI的区别就在于此,前者直接在倒排记录表中增加此项新纪录*/ ADDTOPOSTINGSLIST (postings_list,docID(token)) sorted_terms <- SORTTERMS(dictionary) WRITEBLOCKTODISK(sorted_terms,dictionary,output_file) return output_file
    运行代码之后会在./data/下生成一个 ir.db 数据库文件,这就是构建好的索引数据库。
    2.3 检索模块2.3.1 检索模式(1)关键词检索查询即根据用户输入的关键字,返回其相应的新闻。首先根据用户的查询进行 jieba 分词,记录分词后词项的数量以字典形式进行存储。
    def clean_list(self, seg_list): cleaned_dict = {} n = 0 for i in seg_list: i = i.strip().lower() if i != '' and not self.is_number(i) and i not in self.stop_words: n = n + 1 if i in cleaned_dict: cleaned_dict[i] = cleaned_dict[i] + 1 else: cleaned_dict[i] = 1 return n, cleaned_dict
    根据每个词项返回的结果,利用 BM25 计算公式得到每个文档的分数,得到最终的文档排名。
    (2)布尔检索对于布尔检索,这里只简单实现支持 OR、AND 操作,首先根据用户的查询,得到 OR 还是 AND,分别得到相应的文档序号,然后进行返回文档的 OR 和 AND 得到最终的文档结果。
    def process_bool(self, seg_list): if 'OR' in seg_list: return 'OR' elif 'AND' in seg_list: return 'AND' else: return False def intersection(self, doc1, doc2): doc = [val for val in doc1 if val in doc2] return doc def unionset(self, doc1, doc2): return list(doc1.union(doc2))
    2.3.2 检索排序(1)按相关度按新闻的相关度排序,相关度越高的新闻排名越高。检索模型中检索效果最好的是基于概率的 BM25 模型。
    (2)按时间类似的,我们还可以对所有文档按时间先后顺序排序,越新鲜新闻排名越高。
    (3)按热度按新闻的热度排序,越热门的新闻排名越高。关于热度公式,我们认为主要和三个因素有关:相关度,这个不需要过多解释,列出的新闻一定要和查询相关;用户评论数,评论数和点击数是呈正相关的,若一篇新闻下的评论越多,则表明该新闻更受用户关注;同时也要考虑时间因素,时间越久远,新闻的热度就会越低。所以热度公式是 BM25 打分、评论数打分和时间打分的一个综合。
    比较有名的热度公式有两个,一个是 Hacker News,另一个是 Reddit。他们均为将新闻/评论的一个原始得分和时间组合起来,只是一个用除法,一个用加法。我们借鉴 reddit 的热度公式,将其稍作简化,并添加评论数打分,开创如下的热度公式:

    将 BM25 得分、评论数、新闻时间和当前时间的差值的倒数线性加权,k1、k2、 k3 均是可调参数。
    创新点:与典型的热度公式相比,添加了评论数的指标,更精准的刻画“热度”的含 义。
    2.4 用户接口2.4.1 查询自动补全(1)功能介绍
    用户在输入框输入搜索内容时,根据用户的输入内容,自动完成数据匹配和前端展示,最多展示十条
    用户可以通过键盘方向键浏览
    用户可以通过鼠标的点击和键盘的回车选中需要的数据项并更新显示在输入框中,同时实现搜索


    (2)算法简述
    使用 html 和 js 实现前端展示和用户行为监听。其中,ajax 实现前端和后端的数据传输
    匹配数据部分,我们使用 SQL 语句
    SELECT term FROM postings WHERE term like ‘term%’ ORDER BY df DESC LIMIT 10
    来对数据进行匹配。其中,我们以用户输入的内容为前缀在倒排索引表内进行数据匹配,同时根据文档频率进行降序排序,也就是说,出现在文档中次数多的词条会被提示。同时使用’?’ 赋值的方式,防止 SQL 注入,保证了数据库的安全
    键盘方向键浏览补全,鼠标点击提示内容或者键盘回车,实现自动查询

    2.4.2 实时 snippet 生成该模块给用户提供了一个更加方便快速的视角查看检索结果中检索词出现的语境和上下文,从而快速排查是否为所需信息。其核心思想是对检索词所在句子进行整合和凸显。具体做法如下:

    利用 jieba 对检索词进行切分,并去除停用词,过滤,最终得到检索切分词表
    在新闻正文中用 “。|?|!|#|,|……|~|;|:|~|,” 对中文句子进行简单切分,对每个分句进行判断,若存在任一检索切分词则将其突出,其他分句均用省略号表示

    2.4.3 相关搜索推荐(1)算法简述该模块针对用户的搜索给用户提供相关联的搜索词或者用户可能想了解的相关信息。其核心思想是提取用户检索结果中除检索词之外的关键词。具体做法如下:

    提取出前二十个检索结果的标题,若检索结果没有 20 条则取全部检索结果的标题
    用 TextRank 算法对所取标题组成的整个文本进行关键词的抽取
    按照重要值取前 10 个关键词作为推荐搜索词

    (2)创新点
    在没有大量用户日志数据的情况下,也能够较准确地推荐相关检索词,且耗费成本较少,根据排序依据不同,推荐检索词也会随之变化,较为灵活
    在无法直接得知用户所需信息时,转换思路,利用用户初次搜索的结果中的重要信息作为相关推荐,并经过了经验和实践的认证
    使用 TextRank 算法进行关键词抽取。TextRank 算法是一种用于文本的基于图的排序算法。其基本思想来源于谷歌的 PageRank 算法, 通过把文本分割成若干组成单元(单词、句子)并建立图模型,利用投票机制对文本中的重要成分进行排序, 仅利用单篇文档本身的信息即可实现关键词提取、文摘。和 LDA、HMM 等模型不同, TextRank 不需要事先对多篇文档进行学习训练, 因其简洁有效而得到广泛应用。

    2.4.4 热点新闻推荐该算法与按热度排序的算法相似,只是去掉与查询相关度的信息,表示为评论数、新闻时间和当前时间的差值的倒数线性加权。
    另外与按热度排序的算法不同的是,按热度排序的算法应用于检索出的相关文档,而该算法应用于全部的文档,选出评分最高的前 K 个新闻放在主页上显示。公式如下:

    其中,k1、k2 均是可调参数。
    创新点:将最热新闻置于网站首页,更大限度的让用户捕捉到热点信息。
    2.4.5 相似新闻推荐当用户浏览某条具体新闻时,我们在页面底端给出 5 条和该新闻相关的新闻。推荐模块的思路是度量两两新闻之间的相似度,取相似度最高的前 5 篇新闻作为推荐阅读的新闻。
    一篇文档可以用一个向量表示,向量中的每个值是不同词项 t 在该文档 d 中的词频 tf。但是一篇较短的文档(如新闻)的关键词并不多,所以我们可以提取每篇新闻的关键词,用这些关键词的 tf*idf 值构成文档的向量表示,这样能够大大减少相似度计算量,同时保持较好的推荐效果。
    jieba 分词组件自带关键词提取功能,并能返回关键词的 tf*idf 值。所以对每篇新闻,我们先提取 tf*idf 得分最高的前 25 个关键词,用这 25 个关键词的 tf*idf 值作为文档的向量表示。由此能够得到一个 1000*m 的文档词项矩阵 M, 矩阵每行表示一个文档,每列表示一个词项,m 为 1000 个文档的所有互异的关键词(大概 10000 个)。M 是稀疏矩阵。
    得到文档词项矩阵 M 之后,我们利用 sklearn 的 pairwise_distances 函数 计算 M 中行向量之间的 cosine 相似度,对每个文档,得到与其最相似的前 5 篇 新闻 id,并把结果写入数据库。
    2.4.6 情感分析(1)算法简述该模块给用户提供了对每条新闻评论的情感极性分析,并且对每篇新闻所有新闻的总体评价极性趋势以及情绪波动情况进行了统计分析。其核心思想是利用情感词典给评论进行情感分析。具体做法如下:


    切分句子,利用标点符号(,.!?;~,。!?;~…)对句子进行切分
    切词并清理,对每个句子进行 jieba 分词,并去除停用词,过滤
    判断句子中是否出现情感词典中的词,以及多个情感词之间的位置;若出现,判断前后一定范围内是否出现程度词表中的词,判断句子是否是感叹句反问句等情感强烈的句式以及是否存在表情符号。根据以上判断,分别赋予相应的分值加权。累计每个分句得到每条评论的极性分析
    统计所有评论的情感分析数据,统计正向评论占比和负向评论占比,以及情感分析值的均值和方差,对应总体极性偏向和评论之间的情感波动情况

    (2)创新点
    利用情感词典,无需进行监督学习即可快速进行极性判断,且正确率还可以。该方法快速便捷,适应网络用户的需要
    情感词典涵盖较丰富,综合现有开放的资源,包括褒贬词及其近义词、 汉语情感词极值表、清华大学李军中文褒贬义词典、台湾大学 NTUSD 简体中文情感词典以及知网 Hownet 情感词典
    不仅对每条句子进行了极性分析,也对总体评论进行了分析统计,能给用户一个较为直观的分析结果

    2.5 前端模块前端部分采用 flask 框架搭建,用 bootstrap 框架进行美化,模板匹配采用 jinja2 模板引擎搜索界面风格及配色模仿谷歌。
    3 测试报告3.1 新闻爬取达到了 24h 内爬取 10W 条新闻及其评论的要求。实际测试中,该速度在很大程度上取决于带宽及对方服务器的响应速度。如不考虑评论更新问题,除腾讯新闻外,其他三类网站的 30W 条新闻可以在 5h 以内完成爬取。(笔者机器:Intel Xeon(R) E3-1220v5 @3.00GHz x 4; 32GB Memory; 1000Mbit/s 网卡)
    3.2 索引测试查询时间达到了平均不超过 2 秒。界面简洁大方,将热点新闻置于首页,用户查询后将排序方式置于检索框下方便用户选择,点击 view 可以预览,新闻正文界面清晰明了,用户体验良好。
    3.3 测试截图搜索自动补全

    按相关度-搜索结果

    按时间-搜索结果

    按热度-搜索结果

    内容页面

    4 总结4.1 经验总结4.1.1 新闻爬取出于礼貌爬取的考虑,我们并没有采用多线程爬取的策略。在实际中即使是单线程爬取,腾讯新闻也对爬取的速度进行了限制。
    4.1.2 自动补全前缀补全可以满足基本需求。但是可以有更加智能的补全方式,例如加入句子的补全,不只限于词条。
    4.1.3 相关搜索推荐有关用户推荐,在数据量并不足够的情况下可以寻求别的思路来代替无法直接获得的信息。
    4.1.4 评论情感分析对网络搜索引擎而言,快速地提供信息是最主要的目的,因此在正确率尚可的情况下应采用快速而便捷的方法。
    4.2 不足之处4.2.1 热度排序为提高运算效率,热度排序公式只是简单地线性加权,没有更复杂的考虑。
    4.2.2 相关搜索推荐缺少足够的用户数据,无法对用户做个性化推荐。大部分功能依赖于分词效果,尤其在网络环境中,用户检索词多样化且新词快速出现,要适应不断增大的网络词库,分词模块应该不断优化改良。
    4.2.3 热点新闻推荐热点新闻推荐需要对全部新闻计算分值,当新闻数据量过大时效率会比较低。
    5 系统功能实现5.1 基本功能检索系统功能中没有实现通配符检索并用布尔检索代替,其他功能全部实现。
    5.2 创新点5.2.1 新闻爬取实现了对新闻网页动态加载的评论进行爬取,如搜狐新闻评论爬取。未借助开源新闻爬取工具,自己实现了对新闻标题,正文,时间,评论内容,评论数目的高效爬取。
    5.2.2 检索排序与典型的热度公式相比,添加了评论数的指标,更精准的刻画“热度”的含义。
    5.2.3 相关搜索推荐在没有大量用户日志数据的情况下,也能够较准确地推荐相关检索词,根据排序依据不同,推荐检索词也会随之变化;在无法直接得知用户所需信息时,利用用户初次搜索的结果中的重要信息作为相关推荐;使用 TextRank 算法进行关键词抽取。
    5.2.4 评论情感分析利用情感词典,无需进行监督学习即可快速进行极性判断;情感词典涵盖较丰富,综合现有开放的资源;不仅对每条句子进行了极性分析,也对总体评论进行了分析统计。
    6 参考文献
    [1]开源代码使用

    BeautifulSoup:开源 XML 或 HTML 解析库,参考解析爬取网页内容 Jieba:开源中文分词,参考分词模块及 tf-idf 计算textrank4zh:开源中文语句关键词解析,参考新闻关键词提取news-search-engine: 开源中文搜索引擎,参考架构设计及相关新闻推荐
    [2]王斌.信息检索导论[M].北京:人民邮电出版社,2010.
    [3]朱广文. 信息检索系统的设计与实现[D].哈尔滨工业大学,2007.

    PS:新闻数据文件太多,而且压缩过后有将近 330 M,所以放到百度云上了。运行的时候,需要下载这些数据文件和数据库文件!
    1 评论 5 下载 2020-06-22 10:48:27 下载需要16点积分
  • 基于JAVA实现的操作系统文件系统

    一、程序使用说明打开程序的初始界面


    我的Q盘下提供右键格式化选项
    关于地址栏

    如果是“我的Q盘/新建文件”会自动跳转到相应的文件夹下打开文件如果是“我的Q盘/新建文件/”则打开文件夹
    双击我的Q盘可以进入到里面(下面的文件与文件夹双击均可打开)
    右键空白地方会显示出相应的属性,图为建立了2个文件夹和一个文件的界面


    右击文件可显示与文件相关的操作,下图为文件和文件夹的不同操作。

    点击属性显示出一个文件夹或者文件的属性。

    打开文件夹进入下一层目录,和我的Q盘下的目录相同;打开文件,是自己编写的一个简易的记事本。

    在设置菜单下可以更改字体大小,编辑菜单中有包括撤消、重做、和替换的功能。
    如果一个记事本已经被打开,然后又在外面点击删除时,会弹出警告框。

    同样,删除该文件所在的文件夹也会有相应警告。
    如果一个记事本被打开,然后又在外面打开时,不会出现2个记事本,正在打开的记事本会重新获取用户焦点,也就是跳到第一个窗口。
    如果修改了文件,关闭时会提示你是否保存,当然也可以通过菜单栏文件下面的文件设置直接保存。
    二、程序设计图程序共有Disk(我的Q盘)、Folder(文件夹)、MyFile(记事本)三个主要的类。

    2.1 MyDocument(FCB)抽象类该类中提供一些函数的接口,以及文件属性,主要的成员变量有
    class MyDocument{ ContentPanel contentPanel; //文件夹下的内容(file不会被实例化) ContentPanel fatherContentPanel; //所在的文件夹 String whoAmI; //文件or文件夹 String fatherAddress; //所在文件夹的地址 String name; //名字(fatherAddress+name=绝对地址) String createTime; //创建时间 String visitTime; //访问时间 String modifiTime; //修改时间 Block block; //用的块(只是一个指针,不会在这里new) boolean isHide=false; //是否为隐藏文件}
    2.2 Folder类(文件夹)继承自MyDocument;contentPanel是运行哪个文件下的面板,比如在新建文件夹目录下,则界面显示的是新建文件夹.contentPanel。
    class ContentPanel{ Vector<Folder> folderList; //该文件夹下的文件夹 以这个构成目录 Vector<MyFile> fileList; //该文件夹下的文件 ContentPanel fatherContentPanel; //所在的文件夹 static boolean isShowAll=false; //是否显示所有文件 static ContentPanel runningPanel=null;//正在显示哪个文件夹}
    FolderPanel是在上一层中显示的面板,比如需要进入到新建文件夹中,就需要双击这个面板,这个面板是被加入到fatherContentPanel中。
    Class FolderPanel extends JPanel{ …… }
    该类在内部处理后,以“打包”的形式在fatherContentPanel出现,返回的类的样子就是这样的,其中该panel提供一些双击 以及右击查看属性的接口。
    2.3 MyFile类(文件)继承自MyDocument
    { JFrame frame //记事本 FilePanel fileView; //和FolderPanel一样,打包出来是 }
    2.4 Disk类(磁盘)想的是我的Q盘只能有一个,所以该类所有的东西都是static。
    { static JFrame mainFrame; //主要Frame static JPanel mainPanel; //主要的Panel static DiskPanel diskPanel; // static ContentPanel contentPanel; //我的Q盘下的那个面板 static Fat fat=new Fat(); //fat static Block []block=new Block[1000]; //所有的块都放入到我的Q盘中}
    设计失败之处就是因为把disk独立出来了。。。导致程序有许多地方都在特殊判断。
    fatherContentPanel是不是Disk.ContentPanel。因此,加入了太多的补丁和重复代码。
    2.5 Block类(块){ String property; //文件(夹)的一些属性 String data; //文件(夹)数据 int index; //在Disk中是第几个block}
    2.6 Fat类{ final static int totBlock=10;//由于这里采用位运算,所以实际的Block总数totBlock*10 int[] useBlock=new int[totBlock]; //hash判断每个块是否被使用,采用位运算}
    2.7 FolerTooBar工具栏。。提供搜索、后退、根据绝对地址打开文件或者文件夹的功能。
    三、实现思想3.1 创建文件(夹)首先向Disk申请block,如果block申请成功,则分配相应的block给文件夹,并进行初始化处理。如果block申请失败,告知用户内存被用光了。。。
    3.2 删除文件和文件夹先说删除文件吧: 首先要判断文件是否正在被使用,如果正在被使用,需要警告用户,删除失败。否则返回删除成功信息,并从block中移除该文件。回收利用block。
    然后是文件夹:文件夹的删除比较麻烦,需要一层一层利用递归删除下面文件夹的各个文件,扫面一遍该folder下的vector<fileList>,利用删除文件的方法,将每一个文件删除,只有在所有文件都删除成功的情况下(删除文件中,如果文件正在被使用,删除失败),返回删除文件成功的信息。 在删除完文件以后,扫面所有的vector<folderList>再次删除文件夹,利用递归的方法,只有在所有的文件夹都被删除成功的情况下,返回一个删除成功的信息。
    如果folder下面所有的文件和文件夹都被删除成功,则删除floder,释放其资源。否则,告知用户删除失败(文件正在被使用)。
    3.3 重命名重命名本身并不复杂,如果重命名文件,只需要将block中的property修改即可,如果修改的文件夹,需要将该文件夹下所有的MyDocument的fatherAddress都修改一遍。
    另外需要注意的是同名的处理。
    3.4 读写入磁盘将block信息写入磁盘,由于Disk的block被固定为0,因此复原的时候只需要从block[0]入手,即可把所有的数据都恢复。
    3.5 搜索地址搜索地址,实际上就是根据contentPanel中的树形目录去查找所在的地址,然后返回即可。
    四、实现思想这次项目是操作系统的最后一个项目了,由于是期末,所以要写的项目也比较多。为此,这个项目也出现了一些设计上的失误,在类的设计中也都说明了这些失误。。。为此,程序没有少打补丁。
    本学期操作系统的三个项目设计也都结束了,其实,虽然是以操作系统为目的的,但是,总的来说,锻炼价值还是蛮大的,比方说,这次项目就特意加强了对UI的设计(实在不想说。。我UI实在烂的。。),但其实还是没有达到自己预想的效果(也可能是时间太匆忙的原因把)。
    由于时间有限,像复制粘贴的功能都没有做,其实,只要有了block的概念,复制粘贴并不难,只要记录下复制的是哪一个block,粘贴的时候根据那个block的信息新建一个文件就可以了,不过需要进行同名的判断。
    1 评论 57 下载 2019-03-11 19:55:02 下载需要13点积分
  • 基于java和Sql Server数据库的停车场管理系统

    一、实验内容:实现停车场管理系统,应用于车辆的出、入管理。
    二、功能要求:包括车辆进出管理与系统管理等功能模块,可根据车辆停放时间及收费标准自动收费。用户需要事先办理停车卡并充值,停车卡分优惠卡和普通卡两类。

    车场管理:车辆入场、车辆出场
    信息查询:某时间段的出入场信息,当前在场信息,车辆历史停车记录及收费信息
    信息维护:用户及停车卡信息维护、充值等
    系统管理:车位信息,计费标准等

    系统包含两类用户:管理员用户和普通用户。
    管理员可以使用系统所有功能,普通用户只能查询车辆历史记录、用户信息、停车卡充值,查询计费标准。
    三、实验环境:
    Windows XP
    JDK 1.6
    Eclipse
    SQL Server
    备注:

    在XP平台开发DK(JavaDevelopment Kit)是Sun Microsystems针对Java开发员的产品Eclipse进行前台和程序设计,开发图形用户界面和停车收费功能实施
    SQL建立数据库

    四、需求分析与设计:4.1 需求分析:本软件具有如下主要功能:

    本系统包括两类用户:管理员用户和普通用户。管理员可以使用系统所有功能,普通用户只能查询车辆历史记录、用户信息(只限于个人信息)、查询计费标准、查询当前在场信息、查询出入场信息、当前可用车位信息、口令修改。具体模块划分为如下模块:车场管理模块、信息查询模块、信息维护模块、系统管理模块。
    车场管理模块:(应该分为车辆入场和车辆出场两部分)

    车辆入场功能描述:车辆进入停车场时进行登记,记录入场时间并指定车位。只有具有停车卡的车辆才可进场,没有办理停车卡的车辆,应先办理车卡。如果没有相应车位,不能入场;如果卡中余额低于100元,应先充值后再入场。满足条件的车辆,为其指定车位并记录入场时间。车卡分两种类型普通型和优惠型。车辆出场功能描述:车辆开出停车场时进行登记,记录出场的时间并进行自动收费(从卡上扣除)。根据车辆进场时间,出场时间及收费标准自动计算车主应该缴纳的费用。如果停车时间包含不足一小时的时间,超过30分钟按一小时计算,不足三十分钟不计算。如果卡上余额足够则直接扣除;如果卡上余额不足,则应先充值后再扣除相应费用。
    信息查询模块功能描述:在这个模块里用户可以查询出入场信息、当前在场信息、用户个人信息、用户历史记录、收费标准以及当前可用车位信息
    查询出入场信息功能描述: 查询当前在场信息户可以在这里查询到两种车位的总量及当前可有的车位数量。
    查询用户个人信息功能描述:登录的管理员可以根据卡号和名字查询用户信息。登陆的普通用户只可以查到自己的信息。
    查询用户历史记录功能描述:用户可以输入卡号查询相应卡号的历史记录,包括车位号、开始停车时间、结束停车时间、停车总时间、相应收取的费用。
    收费标准功能描述:用户可以在这里查询不同种类的车位和不同卡的计费标准。
    当前在场信息功能描述:用户可以在这里查询到当前在场的车辆信息,包括卡号,车位号,开始停车时间。
    当前可用车位信息功能描述:在这里用户可以查询当前可用的车位的信息,包括车位号、车位类型。
    信息维护模块在这个模块里用户可以实现用户注册、用户修改及用户充值
    用户注册功能描述:在这里管理员可添加新的用户(普通用户)。
    用户修改管理员在这里可以修改用户。这里会以表的形式显示所有的用户信息,包括用户的停车卡信息维护,充值信息等。管理员点击相应的一行用户信息,这行信息会自动填充到表下的面板里,用户可以在面板里修改用户信息,面板下面有两个按钮,修改、删除,点击相应的按钮可以实现相应的功能。
    用户充值功能描述:用户可以再这里查到自己的余额,并且可以在这里完成充值。
    系统管理模块功能描述:在这个模块里可以修改相应的车位信息计费标准、注册管理员、更改用户口令以及查看系统声明信息。
    管理员注册功能描述:管理员可以在这里添加新的管理员。
    更改口令功能描述:用户可以在这里更该自己的密码。注:操作员只可以修改自己的密码。
    计费标准管理功能描述:管理员可以在这里不同车位类型、不同车卡类型的收费标准。
    关于功能描述:用户可以在这里看到系统声明。

    4.2 界面设计登陆界面

    管理员主界面

    普通用户主界面

    车辆入场界面

    车辆出场界面

    计费标准界面

    当场在场信息界面

    用户历史信息界面

    用户个人信息界面

    普通用户个人信息界面

    出入场信息界面

    当前可用车位信息界面

    用户注册界面

    用户修改界面

    用户充值界面

    管理员注册界面

    更改口令界面

    计费标准管理界面

    关于界面

    五、数据库设计5.1 数据库关系图
    5.2 数据表的结构设计


    用户表:users








    字段名称
    数据类型
    可空
    默认值
    说明


    cardid
    int
    不可

    主键,用户的停车卡号


    name
    Nvarchar(20)
    不可

    用户姓名


    password
    Nvarchar(20)


    用户密码


    cardtype
    Nvarchar(20)


    停车卡类型


    userstype
    Nvarchar(20)


    用户类型


    carid
    int


    用户车牌号


    tel
    int


    用户电话号码


    overage
    int


    用户余额






    车位信息表:sit_infor








    字段名称
    数据类型
    可空
    默认值
    说明


    stationid
    int
    不可

    主键,车位号


    stationtype
    Nvarchar(20)
    不可

    车位类型






    停车收费卡收费表:charger








    字段名称
    数据类型
    可空
    默认值
    说明


    cardtype
    Nvarchar(6)


    车卡类型


    stationtype
    Nvarchar(20)


    车位类型(车卡类型与车位类型一起作为主键)


    charge
    int


    价格






    停车表:park








    字段名称
    数据类型
    可空
    默认值
    说明


    cardid
    int


    车卡号(外键)


    stationid
    int


    车位号(外键)


    parkid
    int

    1,每次增加一
    停车号,主键


    startpark
    datetime


    停车开始时间


    endpark
    datetime


    停车结束时间


    fee
    int


    停车的收费


    sumpark
    int


    停车总时间



    六、关键技术介绍6.1 在其他类中得到当前登录用户对象 实现方法:在LoginFrame类中设置两个静态方法,在其他类中只需要引入LoginFrame类,然后调用他的静态方法即可。方法体如下:
    public static users getUser() { return user; } public static void setUser(users user) { LoginFrame.user = user; }
    6.2 实现用户类型不同,主界面不同的功能 可以定义静态方法disMenu().当用户是普通用户时,调用disMenu()方法即可。具体实现如下
    public void disMenu() { mnuPark.setEnabled(false); mnuSever.setEnabled(false); mnuManZhuCe.setEnabled(false); mnuManCharge.setEnabled(false); } if(user.getUserstype().equals("管理员")) { MdiFrame frame1 = new MdiFrame();//创建一个主窗体 frame1.setVisible(true);//设置其可见 LoginFrame.this.setVisible(false);//设置登录窗体为不显示 } else {//判断用户名是否为null MdiFrame frame = new MdiFrame();//创建一个主窗体 frame.disMenu(); frame.setVisible(true);//设置其可见 LoginFrame.this.setVisible(false);//设置登录窗体为不显示 }
    6.3 怎么得到系统时间 SimpleDateFormat myfmt=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String a4 = myfmt.format(new java.util.Date()).toString();
    6.4 怎么计算时间差值 try { java.util.Date now = myfmt.parse(a3);//a3是系统当前时间(即出场时间) java.util.Date date=myfmt.parse(a7);//a7是入场时间 int l=(int) (now.getTime()-date.getTime());//计算毫秒差值 day=l/(24*60*60*1000);//获取天数 hour=(l/(60*60*1000)-day*24);//获得小时 min=((l/(60*1000))-day*24*60-hour*60);//获得分钟 } catch (Exception e1) { JOptionPane.showMessageDialog(null,"消费计算错误"); } if(min < 30)//如果分钟小于30分钟 a8 = day*24+hour; else //如果分钟大于30分钟 a8 = day*24+hour+1;
    6.5 怎么让布局更优美 使用布局管理器; GridBagLayout,以更改密码界面为例:
    getContentPane().setLayout(new GridBagLayout()); setBounds(234, 129, 285, 223); final JLabel label_5 = new JLabel(); label_5.setText("登 录 名:"); final GridBagConstraints gridBagConstraints_11 = new GridBagConstraints(); gridBagConstraints_11.gridy = 2; gridBagConstraints_11.gridx = 0; getContentPane().add(label_5, gridBagConstraints_11);
    七、系统实现功能结构图
    24 评论 993 下载 2018-11-19 09:32:08 下载需要15点积分
  • 基于C语言链表和文件的企业员工管理系统

    一 需求分析企业员工管理系统主要是针对企业员工的基本信息进行增、删、改、查的相关操作,以便用户使用本管理系统时可以快速对企业员工的信息进行管理。
    主要实现以下功能:

    用户首次使用本系统时进行密码设置和初始化操作
    实现添加功能,即添加员工的相关信息
    实现查看功能,即显示系统中所有员工的相关信息
    实现查找功能,即可以通过多种条件对员工进行查询,如姓名、工号等
    实现修改功能,即输入员工的姓名修改其相关信息
    实现删除功能,即输入员工的姓名删除其相关信息
    实现统计员工人数的功能
    实现重新设置密码登录密码的功能
    退出系统

    二 概要设计系统功能模块架构图如下所示:


    首次登陆用户信息初始化功能模块:当用户时首次使用本系统时,则需要根据提示进行设置密码和初始化的操作
    输入员工信息功能模块:实现将用户从键盘输入的数据存储到对应字段或数据成员中,并检查输入的合法性
    显示员工信息功能模块:用户根据提示操作显示系统中已有的员工的相关信息,如果系统中海没有存储员工信息则给出无法显示信息的提示
    查询员工信息功能模块:根据用户输入的待查询记录的关键字,在数据结构中查找该记录,如找到则输出该员工的信息,否则给出无法找到的提示信息
    修改员工信息功能模块:根据用户要求,根据提示操作,找到要修改信息的员工然后修改员工的相关信息,如年龄。工资等
    删除员工信息功能模块:由用户输入选择删除相关的员工的信息
    统计员工信息功能模块:统计本系统中员工的信息,如男、女员工的人数等
    重置系统密码功能模块:根据用户的要求,将旧密码更换设置新密码
    退出系统功能模块:在用户执行完相关系统操作之后,退出使用本系统

    三 详细设计3.1 功能函数的调用关系如下图所示:

    3.2 各功能函数的数据流程如下图所示:

    四 程序实现4.1 初始化模块本系统中对是否是第一次使用本系统进行了处理,如果是第一次使用,则需要根据提示信息进行设置密码和初始化操作。其思路是:首先打开密码文件,判断是否为空,进而判断系统是否是第一次使用,如果是,系统会提示输入初始密码,如果不是,系统会进入登陆页面,提示输入登陆密码。
    void checkfirst(){ FILE *fp,*fp1; //声明文件型指针 char pwd[9],pwd1[9],pwd2[9]; int i; char strt='8'; if((fp=fopen("employee.txt","rb"))==NULL) { printf("\n\t新系统,请进行相应的初始化操作!\n"); //判断系统密码文件是否为空 bound('_',50); getch(); do { printf("\n设置密码,请不要超过8位: "); for(i=0;i<8&&((pwd[i]=getch())!=13);i++) putch('*'); printf("\n请再确认一次密码: "); for(i=0;i<8&&(pwd1[i]=getch())!=13;i++) putch('*'); pwd[i]='\0'; pwd1[i]='\0'; if(strcmp(pwd,pwd1)!=0) printf("\n\n两次密码输入不一致,请重新输入: \n"); else break; }while(1); if((fp1=fopen("employee.txt","wb"))==NULL) { printf("\n系统创建失败,请按任意键退出!\n"); getch(); exit(1); } i=0; while(pwd[i]) { pwd2[i]=(pwd[i]^strt); putw(pwd2[i],fp1);//将数组元素送入文件流中 i++; } fclose(fp1);//关闭文件流 printf("\n系统初始化成功,请按任意键退出后,再重新进入!\n"); getch(); exit(1); } else { i=0; while(!feof(fp)&&i<8)//判断是否读完密码文件 pwd[i++]=getw(fp)^strt;//从文件流中读出字符赋给数组 pwd[i]='\0'; if(i>=8) i--; while(pwd[i]!=-1&&i>=0) i--; pwd[i]='\0'; strcpy(password,pwd); }}
    4.2 管理员登录模块自定义函数login()在初始化检测后调用,用于管理员的登录,用户根据提示密码,函数调用strcmp()函数对输入密码和密码文件中的读取数据进行比较,如果一致则进入系统,不一致会提示重新输入,如果3次不一致会强制退出。
    void login()//检测登陆密码{ int i,n=3; char pwd[9]; do { printf("\n请输入登陆密码: "); for(i=0;i<8&&((pwd[i]=getch())!=13);i++) putch('*'); pwd[i]='\0'; if(strcmp(pwd,password)) { printf("\n密码错误,请重新输入!\n"); system("cls");//调用清屏命令 n--; } else break; }while(n>0); if(!n) { printf("密码输入3次错误,请退出!\n"); getch(); exit(1); }}
    4.3 添加员工信息模块自定义函数addemp()用于添加员工的信息,首先打开存储员工信息的数据文件,系统会提示用户输入相应的员工基本信息,当用户输入完成一个员工的信息后,系统会提示用户是否继续输入员工信息。
    void addemp(){ FILE *fp; EMP *emp1; int i=0; char choice='y'; if((fp=fopen("employee.txt","ab"))==NULL)// 追加打开一个二进制文件,并在文件末尾写数据 { printf("打开文件出错!\n"); getch(); exit(1); } do { i++; emp1=(EMP*)malloc(sizeof(EMP)); if(emp1==NULL) { printf("内存分配失败,请按任意键退出!\n"); getch(); return; } printf("\n\t请输入第%d各员工的信息\n",i); bound('_',40); printf("工号: "); scanf("%d",&emp1->num); printf("职务: "); scanf("%s",&emp1->duty); printf("姓名: "); scanf("%s",&emp1->name); printf("性别: "); scanf("%s",&emp1->sex); printf("年龄: "); scanf("%d",&emp1->age); printf("文化程度: "); scanf("%s",&emp1->edu); printf("工资: "); scanf("%d",&emp1->salary); printf("办公电话: "); scanf("%s",&emp1->tel_office); printf("家庭电话: "); scanf("%s",&emp1->tel_home); printf("手机号码: "); scanf("%s",&emp1->mobile); printf("QQ号码: "); scanf("%s",&emp1->qq); printf("家庭地址: "); scanf("%s",&emp1->address); emp1->next=NULL; if(emp_first==NULL)//判断表头指针是否为空 { emp_first=emp1; emp_end=emp1; } else { emp_end->next=emp1; emp_end=emp1; } fwrite(emp_end,sizeof(EMP),1,fp);//对数据流添加数据项 gfirst=0; printf("\n"); bound('_',40); printf("\n是否继续输入?(y/n)"); fflush(stdin);//清除缓存区 choice=getchar(); if(toupper(choice)!='Y') { fclose(fp);//关闭文件流 printf("\n输入完毕,请按任意键返回!\n"); getchar(); return; } system("cls"); }while(1);}
    4.4 删除员工信息模块自定义函数delemp()实现删除员工的功能。在系统的功能菜单中选择删除信息的操作后,系统就会提示要删除的员工的姓名,输入要删除的员工的姓名后,如果系统从信息链表中找到相关信息后就会将信息显示出来,再次要求用户确定是否要删除,谨防误操作,提高信息的安全性。
    void delemp(){ int findok=0; EMP *emp1,*emp2; char name[10],choice; system("cls"); printf("\n请输入要删除的员工的姓名: "); scanf("%s",name); emp1=emp_first; emp2=emp1; while(emp1) { if(strcmp(emp1->name,name)==0) { findok=1; system("cls"); printf("\n员工 %s 的信息如下: \n ",emp1->name); bound('_',40); printf("工号: %d \n",emp1->num); printf("职务: %s \n",emp1->duty); printf("姓名: %s \n",emp1->name); printf("性别: %s \n",emp1->sex); printf("年龄: %d \n",emp1->age); printf("文化程度: %s \n",emp1->edu); printf("工资: %d\n",emp1->salary); printf("办公电话: %s \n",emp1->tel_office); printf("家庭电话: %s \n",emp1->tel_home); printf("手机号码: %s \n",emp1->mobile); printf("QQ号码: %s \n",emp1->qq); printf("家庭地址: %s \n",emp1->address); bound('_',40); printf("\n确定要删除该员工信息?(y/n) "); fflush(stdin); choice=getchar(); if(choice!='y'&&choice!='Y') return; if(emp1==emp_first) emp_first=emp1->next; else emp2->next=emp1->next; free(emp1); gsave=1; savedata();//保存数据 return; } else { emp2=emp1; emp1=emp1->next; } if(!findok) { bound('_',40); printf("\n没有找到姓名是: %s 的信息!\n",name); getch(); } return; }}
    4.5 员工信息显示模块自定义函数displayemp()在找到员工的信息后,则需进行显示。
    void displayemp(EMP *emp ,char *filed , char *name) { if(emp) { bound('_',40); printf("\n %s : %s 信息如下: \n",filed,name); bound('_',40); printf("工号: %d \n",emp->num); printf("职务: %s \n",emp->duty); printf("姓名: %s \n",emp->name); printf("性别: %s \n",emp->sex); printf("年龄: %d \n",emp->age); printf("文化程度: %s \n",emp->edu); printf("工资: %d \n",emp->salary); printf("办公电话: %s \n",emp->tel_office); printf("家庭电话: %s \n",emp->tel_home); printf("手机号码: %s \n",emp->mobile); printf("QQ号码: %s \n",emp->qq); printf("家庭地址: %s \n",emp->address); bound('_',40); } else { bound('_',40); printf("\n资料库中没有%s为: %s的员工,请重新确认!\n",filed,name); } return;}
    4.6 查询员工信息模块自定义函数findemp()函数用于查询员工信息,在系统的功能菜单中选择查询员工信息的操作后,系统进入一个查询选项列表,用户根据自己的需要选择要使用的查询条件,根据用户输入的条件的不同,系统会调用不同的查询函数,如果系统从信息链表中找到相关的信息就会显示出来。
    void findemp(){ int choice,ret=0,num; char str[13]; EMP *emp1; system("cls"); do{ printf("\n\t查询员工信息:\n"); bound('_',30); printf("\t1.按姓名查询\n"); printf("\t2.按工号查询\n"); printf("\t3.按电话查询\n"); printf("\t4.按QQ号查询\n"); printf("\t0.返回主菜单\n"); bound('_',30); printf("\n请选择(0-4): "); do { fflush(stdin); choice=getchar(); system("cls"); switch(choice) { case '1': printf("\n请输入要查询员工的姓名: "); scanf("%s",str); emp1=findname(str);//调用子函数 displayemp(emp1,"姓名",str); getchar(); getchar(); break; case '2': printf("\n请输入要查询员工的工号: "); scanf("%d",&num); emp1=findnum(num);//调用子函数 itoa(num,str,10); displayemp(emp1,"工号",str); getchar(); getchar(); break; case '3': printf("\n请输入要查询员工的电话: "); scanf("%s",str); emp1=findtelephone(str);//调用子函数 displayemp(emp1,"电话",str); getchar(); getchar(); break; case '4': printf("\n请输入要查询员工的QQ号: "); scanf("%s",str); emp1=findqq(str);//调用子函数 displayemp(emp1,"QQ号码",str); getchar(); getchar(); break; case '0': ret=1; break; } }while(choice<'0'||choice>'4'); system("cls"); if(ret) break; }while(1);}EMP *findname(char *name)//按姓名查找员工信息{ EMP *emp1; emp1=emp_first; while(emp1) { if(strcmp(name,emp1->name)==0)//比较输入的名字和链表中记载的名字是否相同 return emp1; emp1=emp1->next; } return NULL;}EMP *findnum(int num)//按工号查询{ EMP *emp1; emp1=emp_first; while(emp1) { if(num==emp1->num) return emp1; emp1=emp1->next; } return NULL;}EMP *findtelephone(char *name)//按电话号码查询员工信息{ EMP *emp1; emp1=emp_first; while(emp1) { if(strcmp(name,emp1->tel_office)==0||strcmp(name,emp1->tel_home)==0||strcmp(name,emp1->mobile)==0) return emp1; emp1=emp1->next; } return NULL;}EMP *findqq(char *name)//按QQ号码查询员工信息{ EMP *emp1; emp1=emp_first; while(emp1) { if(strcmp(name,emp1->qq)==0) return emp1; emp1=emp1->next; } return NULL;}
    4.7 修改密码模块自定义函数resetpwd()用于修改密码。在系统的功能菜单中选择修改的操作选项后,系统会提示输入旧密码,用户咋正确的输入旧密码后,根据提示即可实现密码的修改。
    void resetpwd(){ char pwd[9],pwd1[9]; int i; FILE *fp1; system("cls"); printf("\n请输入旧密码: \n"); for(i=0;i<8&&((pwd[i]=getchar())!=13);i++) putchar('*'); pwd[i]='\0'; if(strcmp(password,pwd)!=0) { printf("\n密码错误,请按任意键退出!\n"); getchar(); return; } do { printf("\n设置密码,请不要超过8位: "); for(i=0;i<8&&((pwd[i]=getchar())!=13);i++) putchar('*'); printf("\n请再确认一次密码: "); for(i=0;i<8&&((pwd[i]=getchar())!=13);i++) putchar('*'); pwd[i]='\0'; pwd1[i]='\0'; if(strcmp(pwd,pwd1)!=0)//比较两次输入的密码 printf("\n两次密码输入不一致,请重新输入! \n\n"); else break; }while(1); if((fp1=fopen("employee.tex","wb"))==NULL) { printf("\n系统创建失败,请按任意键退出!\n"); getchar(); exit(1); } i=0; while(pwd[i]) { putw(pwd[i],fp1);//将数组元素送入文件流中 i++; } fclose(fp1);//关闭文件流 printf("\n密码修改成功,请按任意键退出后,再重新进入!\n"); getch(); return;}
    4.8 主函数模块int main(){ emp_first=emp_end=NULL;//链表指针初始化 gsave=gfirst=0; checkfirst(); login(); readdata(); menu(); system("PAUSE"); return 0;}
    五 运行测试实现添加员工信息并显示添加后员工的信息的功能,操作如下图:





    实现查询员工信息的功能,操作如下:






    实现修改员工信息的功能,并显示修改后员工的信息,操作如下:




    六 参考文献
    《C语言程序设计教程》,人民邮电出版社
    《C语言程序开发范例宝典》,人民邮电出版社
    2 评论 49 下载 2018-10-26 13:45:48 下载需要12点积分
  • 基于Vue + Node + MongoDB的响应式药品商城系统的分析与设计

    摘要随着科学技术的不断发展,中国的传统行业已经受到了互联网浪潮的不断冲击,在将来很大一部分会被互联网所取代。在传统的医药行业,传统的药品销售方式都是实体药店销售,不仅成本高,还会受到时间、空间的限制,加上药店自身经营管理手段的落后,该销售模式在将来可能退出如今的市场经济。想要有所突破,提高销售利润,将实体药店线下销售模式与互联网线上销售模式相结合是一个不错的选择。
    本文以构建一套在线药品商城销售系统为最终目标,系统采用B/S 架构,开发过程遵循前后端分离开发原则,前端开发使用的是HTML+CSS+JS 三大前端技术和 VUE 框架,后端开发使用了Node.js的Express框架加MongoDB数据库组合,前后端数据交互采用的是 VUE 官方推荐的 Axios 库,主要实现的功能有:前台药品列表的展示;药品列表多条件查询;购物车中药品增删改;用户登录;后台管理员登录、后台药品信息管理、后台用户信息管理等多个功能。在用户体验方面,页面开发采取响应式布局设计,完美兼容PC端和iPad、手机等移动设备。
    通过本次系统开发发现,Vue+ Node 组合开发的药品商城帮助实体药店开拓了一条新的销售渠道,能够高效提高实体药店的日常工作效率,节省了大量的人力、物力成本。
    关键词:药品商城;Node; 响应式布局
    ABSTRACTWith the continuousdevelopment of science and technology, China’s traditional industries have beenconstantly impacted by the wave of the Internet. In the future, a large partwill be replaced by the Internet. In the traditional pharmaceutical industry,traditional drug sales are sold in physical pharmacies, which are not onlycostly, but also subject to time and space constraints, as well as thepharmacy’s own management and management methods. The sales model cannot adaptto the current market economy. To make a breakthrough and increase salesprofits, it is a good choice to combine the offline sales model of physicalpharmacies with the online sales model of the Internet..
    This paper aims tobuild an online drugstore sales system. The system adopts the B/S architecture.The development process follows the separation development principle of thefront and back ends. The front-end development uses the HTML+CSS+JS front-endtechnology and VUE framework. Development and use of a combination of Node +MongoDB, front and back end data exchange is used by the VXI officialrecommended Axios library, the main functions are: front drug list display;drug list multi-condition query; shopping cart drugs add or delete changes;user login ; Background administrator login, background drug information management,back-end user information management and other functions. In terms of userexperience, the drug display module adopts a responsive layout design and isperfectly compatible with mobile devices such as PCs and iPads and mobilephones.
    Through thedevelopment of this system, it was discovered that the drug store developed byVue + Node has helped the physical pharmacy open up a new sales channel, whichcan effectively improve the daily work efficiency of the physical pharmacy, andsave a lot of manpower and material costs
    Keyword:Drug Mall, Node, Responsive layout
    1 绪论1.1 选题背景和意义当下的中国,各个行业都受到了互联网的抨击与挑战,都已经掀起了向互联网发展的浪潮。在这样的发展趋势下, 优胜劣汰,竞争将日趋激烈。药品行业作为传统行业,关系着中国百姓的基本生活,也在寻求突破与发展。在国家不断推进医疗改革的影响之下,大部分药品企业将网络销售作为他们产品的第一销售渠道,同时结合信息化的管理系统对日常的销售工作进行合理的统计与安排。
    在中国市场经济体制确定后,实体药房如雨后春笋,纷纷出现在大众视野,紧随其后的是管理制度的不规范,销售方式不合理。很多中小型药店或者社区门诊药房并没有突破传统,还是手工管理药品信息和单一的实体店销售。在中国现有的条件和大环境下,实体药店要充分与互联网相结合,借助互联网进行日常管理,销售。相比于大的医院、药厂,在实体药店这片市场领域,还存在着较大的空缺与市场,实体药店药品管理销售系统正好可以添补空缺、占领市场,实现日常药品管理的智能化,减少工作人员的成本与劳动量,提高日常的工作效率和药品的销售利润。
    1.2 药品销售的现状在进入21世纪后,国家逐渐重视起老百姓的民生问题,在药品行业,国家始终在不断尝试与创新,为人们提供最基本的医疗保障证,不再让老百姓看不起病,买不起药,为药品市场增添了活力。
    古代药铺门前都会挂上一副对联: 但愿世间人无病,何愁架上药生尘,然而在如今的信息社会,各大药商为了提高药品销售利润,打着铺天盖地的宣传广告。往往在广告中药品疗效被夸大其词,肆意炒作,及其误导消费者,更进一步,有些药房的销售人员,为了提高业务销量,更是做起了“购药满88送鸡蛋10个”等促销活动,而有些医生,一个很常见的感冒发烧,能开出几百块钱的药给病人,一味地想赚钱,而未树立正常的医生形象、医德品质,会让顾客慢慢去而远之,最后形成生病就去大医院的局面,小诊所无人问津,严重导致社会资源使用不均匀。
    2 关键技术的分析与抉择2.1 技术路线使用的技术路线是 Vue + Node + MongoDB ,采用前后端分离的方式开发基于MVVM 模式的药品在线销售系统。
    MVVM(Model, View, ViewModel)架构是在MVC框架的基础上衍生出来的一种新的架构,Model用于逻辑处理,View负责页面展示,ViewModel用可比二者之间的桥梁、纽带,View与Model的变化,都会通过ViewModel 传递到对方身上,这就是MVVM架构所实现的双向数据绑定,其通信方式如图 2-1 MVVM 通信。

    2.1.1 技术可行性分析所使用的技术都是最几年比较流行,用户使用量大的编程语言,在各大公司的真正开发业务中也广泛使用,在全球最大的代码开源网站Github 上已经有十几万的点赞数,各大语言的交流社区活跃,在实际开发过程中,遇到的技术难题,也会有很多教程和朋友提供帮助。
    2.1.2 操作可行性分析该系统在操作使用上,用户无需进行任何程序的安装,只需要使用手机、平板、电脑等设备上安装的浏览器,即可访问和使用该系统,简单而不单一的页面设计更加方便用户的使用。
    2.2 Node技术及其Vue框架介绍2.2.1 Node.js的介绍Node.js相比于其他后端语言,算是非常年轻了,诞生于2009年,它是一个能在Service端运行 JavaScript 的平台[3],同时Node.js 基于全球最大的包管理器 NPM, 使得Node得到广泛的传播和使用。在实际开发Node.js过程中,更有不同集成好的框架可供选择。
    2.2.2 Vue.js的介绍Vue.js 前端框架作为MVVM架构的一个代表,是中国技术牛人尤雨溪在2014年首次发布的个人开源项目,相比于无所不能的 JQuery库和同MVVM架构的React、Angular框架,Vue.js 提供简单的API,上手简单,学习曲线平缓使得发展迅猛,其主要特点体现在响应式编程、组件化、模块化、前端路由、稳定性等方面。
    本系统由于前后端逻辑分离,所以页面的跳转需要在前台进行路由设定,用到了 Vue-Router 路由框架, 只需将组件与路由一一映射,在路由变化的同时,组件也会发生变化,从而实现了页面之间的跳转。
    Vue 组件是组成页面的重要元素,不同页面页面的相同部分可以提取成一个组件,组件是以 .vue 结尾的文件,一个 Vue 组件的基本格式和内容组成如下。
    <template> <div class="test-container"> </div></template><script>export default { name: 'test', data () { return { } }}</script><style scoped>.test-container{ width: 100%; height: 100%; background-color: #f5f5f5;}</style>
    如上代码,一个名为text的Vue组件会将整个组件的样式、行为代码写进一个文件,更加方便了代码的维护。
    如何使用这个text 组件,只需要在页面,或路由配置文件中引入即可,页面引入方式如下代码展示:
    <template> <div id="app"> <test></test> </div></template><script>import Text from './test'export default { name: 'test', components: {Text}, data () { return { } }}</script><style>#app{ width: 100%; height: 100%; background-color: #f5f5f5;}</style>
    2.3 MongoDB 数据库的介绍本次系统开发过程及其存储数据所使用的是MongoDB 数据库,MongoDB数据库也被称之为 NoSQL 数据库,相比于MySQL数据库,不需要编写复杂的SQL查询语句,其最大亮点是使用JSON风格语法。同时前后端的数据交互也都使用的JSON形式来传输,大大方便了数据的存储与查询。
    3 系统分析3.1 需求分析需求分析作为软件工程中的一个关键的部分,主要任务是确定系统所要完成的功能,对整个系统提出完整、准确、规范、清晰、具体的要求。需求分析师和软件工程师需要从用户提出的需求出发,分析提炼,挖掘用户内心真实想要的,并将其转换为产品需求。必要的需求分析有利于提早发现错误,避免在系统开发过程中需求不断变化,提高技术人员的开发效率,降低开发成本,保证软件质量。
    3.1.1 功能需求本系统在功能设计上遵循模块化开发实现,将整体系统分为六大的功能模块,如图所示。
    根据需求分析,系统在大体上分为前、后台两大部分,具体 功能可分为药品展示、药品信息管理、用户操作、用户信息管理、购物车管理和订单信息管理六个模块。具体如图3-1所示:

    3.1.2 性能需求本系统作为实体药店的管理销售系统,在用户、访问量将不断增加等情况下,高并发、系统安全、加载速度慢等一系列性能问题随之而来,确保系统运行在一个安全、平稳、可靠的环境下,需要做到如下几点:

    信息安全:在大数据环境下,个人信息的安全行无比重要,系统做到最基本的安全保障是让用户使用系统的前提。对于药品商城系统而言,更是尤为重要
    及时稳定性:在多用户同时访问、使用系统时,对服务器带来巨大的压力,往往会导致页面无法加载、数据不刷新、出错等一系列高并发问题
    健壮性:人们访问系统所使用的终端设备各不相同,想要做到完美的用户体验,系统代码必须具有健壮性,使其能在不同分辨率的设备上、不同厂商的高低版本上都有很好的页面展示及其功能的实现。在开发过程中。应尽量采用模块化开发,提供数据、程序模块的独立性

    3.2 数据流程图数据流程图以图形化方式反映出系统所要完成的功能。利用数据流程图能方便用户更加清晰地阐述系统需求、有利于开发人员更好的开发等。具体如图3-2所示:

    4 系统设计系统设计也称物理设计,起着承上启下的重要作用,在系统分析的基础上,将分析阶段反应用户需求的逻辑模型装换为可以具体实施的物理模型[6],在经过系统分析后,将得到系统新的逻辑模型。
    4.1 系统结构设计在技术日益更新的网络时代,用户需求不断变化,相应的信息系统的规模和复杂性也在随之改变。不同需求、功能的信息系统对系统所使用的体系结构有着不一样的要求,对于开发人员而言,在开发使用了不同的体系结构的系统时,所需要使用到的技术、开发周期以及系统在实际应用等方面都存在区别。选择合理正确的系统体系结构对整个系统起着关键作用。
    本次系统开发所采用的体系结构是B/S架构,即浏览器/服务器架构,它是在WEB 不断发展的背景下,在C/S 架构(客户机/服务器架构)的基础上变化和改进后的一种新型架构模式。同C/S 架构相比,客户端无需安装制定的软件,只需要通过使用浏览器与WEB服务器通信实现数据交互。可以在不同的操作系统和终端设备下工作,而且具有统一的UI设计和逻辑交互。B/S 架构大大方便了客户端的工作,所有的数据的处理、存储、更新等都在服务器端,这样保证了用户无需升级更新,始终访问的是最新的数据。
    系统的结构设计如图4-1所示:

    用户使用本系统时,页面首次加载、页面跳转、登录退出等等操作都会触发浏览器发送请求给服务器,服务器中的WEB服务器将处理解析这些请求,服务器中的应用层部分调用业务逻辑与数据库进行交互,将请求到的数据处理后传回WEB层进行数据渲染后反馈给客户。
    4.2 系统功能设计功能设计是在最初的需求分析基础上,对系统因具备的功能进行概念性构建的创造活动。为了让整个开发流程更加清晰、高效,系统的功能设计应该分不同的模块进行,各个模块功能应采用一致的设计思路,简化设计的难度,提高代码的可读性与可维护性。
    本系统的功能设计分成商品展示、用户操作、后台管理三大模块。如图4-2所示:

    4.3 数据库设计4.3.1 数据库设计概述数据库相当于系统的仓库,存储着重要数据。用户所有的操作最终都是在同数据库进行数据交互,想要高效处理数据,好的用户体验,规范化的数据库设计是前提条件。
    规范化数据库设计通常会有以下两个基本原则:
    规范性:数据库规范设计是指使用正确的数据结构、字段类型来存储数据,确保在操作、维护数据库时,能对数据进行正常的处理;
    数据冗余:在数据库设计中,应避免数据的冗余,过多的数据冗余不仅会占用更多的存储空间,对后期数据库的维护和检查带来不必要的麻烦。
    4.3.2 数据库的选择数据库的读写速度直接影响系统的用户体验,所以从一开始选择合适本系统的数据库尤为重要。从目前主流的数据库来看,莫过于MySQL和MongoDB,MySQL属于关系型数据库,而MongoDB被称为NoSQL 的数据库,二者在数据存储的方式上有很大差别,代表着不同的设计思路。
    本系统选择的是MongoDB 数据库,主要考虑到以下几点:

    MongoDB 使用了以JSON(JS对象表示法)为基础的文档存储模式,前后端数据交互通常也采用JSON数据格式,所以在数据存储、读取方面,MongoDB无需进行数据格式的转换等,更加直观
    MongoDB相比于MySQL数据库而言,对于那些不懂后端开发的前端开发人员来说更加友好,在短时间内能快速学习、掌握并应用的实际的开发中

    4.3.3 数据库集合设计本系统数据库包含两个数据集合:Drugs 药品数据集和User 用户数据集,数据集字段表如表4-1所示:



    Drugs 药品数据集







    序号
    字段名
    类型
    备注


    1
    drugId
    String
    药品ID


    2
    drugName
    String
    药品名称


    3
    salePrice
    Number
    药品售价


    4
    drugImage
    String
    药品图片


    5
    drugType
    Number
    药品类别


    6
    drugCount
    Number
    药品数量


    7
    checked
    String
    是否选中


    8
    isHot
    Boolean
    是否热销


    9
    isSee
    Boolean
    是否可见


    序号
    字段名
    类型
    备注


    User 用户数据集





    1
    userId
    String
    用户ID


    2
    userName
    String
    用户名


    3
    userPwd
    String
    用户密码


    4
    orderList
    Array
    订单信息


    5
    cartList
    Array
    购物车信息


    6
    addressList
    Array
    地址信息



    5 系统实现5.1 前台页面的原型设计系统的前台是与用户进行交互的平台,前台页面效果相当于系统的外衣,决定着用户对系统的第一印象,好的前台体验效果才能吸引用户使用,在存在竞争对手时,用户往往会选择体验更好的产品。
    “一图胜千言”,在系统正式开发之前,需要讨论需求和技术实现,设计好页面原型,避免在后面开发中的大规模修改,减少不必要的工作。
    本系统前台主要用于商品的展示和用户选购商品,在编程实现上没有采用传统的Table页面布局方式,而是引入一种功能更强的、灵活性更好的 DIV+CSS 页面布局。前台一共包括首页、药品列表页、购物车页、生成订单页等四个页面。首页原型图和药品列表页原型图分别如图5-1和5-2所示:


    5.2 组件化的开发思想上面展示出系统首页和药品列表页的简单原型设计图,不难发现两个页面有相同的部分,头部 Header 导航和底部 Footer 信息,对于这些每个页面都相同的部分,为了减少重复工作和后期代码维护,需要将其从页面代码中抽离出来,形成单独的组件,只需在页面中引入即可,后期维护时,也只需修改单独组件。正因如此,本系统完全采用组件化的开发思想,页面是由大小组件组合而成,最小的按钮都可提取成组件。
    正因为每个页面由组件组成,所以说页面之间的切换其实就是组件之间的切换。本系统开发所使用的前端技术Vue正好符合开发需求,Vue 常用于开发SPA单页面应用,单页面应用就是基于组件和路由,Vue-Router设定好路由与组件之间的映射,从何实现页面的切换。
    5.3 响应式布局的实现响应式布局是一种网络页面设计布局,能将PC桌面设备上的网页内容在移动设备上进行优化排版,使用户能够在移动设备上更方便使用和操作。
    何时选择响应式布局开发?正如上面所提到,响应式布局开发是将PC 端的项目更好的展示在移动端,PC、移动端二者共用一个项目,因此,当系统的PC端页面和移动端页面十分相似,可以选择响应式布局开发。但对于那些内容复杂、使用量多的系统网站来说,为了追求更好的用户体验,PC端和移动端完全分开,分成两个不同项目开发,独立开发管理,更加科学高效。
    如何实现响应式开发?首先介绍系统开发所使用到的一套响应式栅格布局,它预设5个响应尺寸:xs、sm、md、lg和xl , 代表着设备的不同屏幕尺寸,其底层实现思想借用的是媒体查询( @media )来创建不同屏幕尺寸的关键分界点阀值。
    5.4 购物车操作实现从日常网上购物体验流程:打开网站 > 搜索、浏览商品 > 加入购物车 > 生成、确定订单并支付来看,购物车算是本次系统的最为关键之处,跟用户、药品、订单、库存、促销等其它模块都挂钩。
    购物车功能的用户体验好坏直接会影响用户是否直接消费,在设计购物车功能时我们需要考虑到以下几点:

    购物车的入口在哪?本系统在头部导航头提供了直接进入购物车入口,同时在用户浏览商品时,可直接添加商品到购物车
    购物车有哪些基本的展示和操作? 由于移动端、电脑端的屏幕尺寸不同,在移动端展示时会隐藏不常用的信息,但基本的信息都不可缺少,同时需要提供的基本操作包括药品数量的增,减、单件药品移除、多选框的选中取消、动态计算单件商品的总价和所有勾选商品的总价等
    有哪些细节应该考虑?在进入购物车之前我们应该判断用户是否登录,登录后方可进入购物车页面,并将展示用户之前加入到购物车的商品,在进行商品数量改变时,需要设定一个阀值,就是在商品数量仅剩一时,应该禁用减少按钮的操作,只能通过删除来移除商品

    6 结论与展望本系统在技术实现上使用了当下流行的技术和框架,功能方面能够满足小型的实体药店正常的工作使用,能够极大提高工作人员的开发效率和药店的营业额,能够帮助药店在实现全自动管理的道路上更进一步。
    同时,本系统也有不少的遗憾与不足,由于个人独自开发,开发周期短,所考虑的肯定无法很全面,可能很多用户需求没考虑到,同时页面现实效果太过普通,同时整个开发流程缺少了代码编程规范和代码测试。
    对于系统的展望,希望能以本系统为基础,向微信公众号、小程序靠拢,让用户能直接通过微信访问本系统。
    参考文献[1]祥保玉. 响应式内容管理系统的设计与实现[D].哈尔滨工业大学,2017.
    [2]曾德强.中国之痛:医疗行业内幕大揭秘[M],2016(1)
    [3] 李兴华. 基于WebSocket的移动即时通信系统[D]. 重庆大学, 2013.
    [4] 沈姝. NoSQL数据库技术及其应用研究[D]. 南京信息工程大学, 2012.
    [5] 魏桂梅. 面向医学院的医疗低值易耗品管理系统设计与实现[D]. 中国海洋大学, 2010.
    [6] 慎东峰. 邮政储蓄中间业务管理信息系统及实施策略研究[D]. 吉林大学, 2006.
    [7] 冯永祥,杨寒,李雷孝. 基于云计算平台的药品经营监督管理系统的研究与设计[J]. 内蒙古工业大学学报(自然科学版),2015,14(03):10-15
    [8] 康文靖.医院药库管理信息系统分析[J]. 基层医学论坛, 2015,24(12):34
    [9] 赵清华,林学华.基于DIV+CSS的网页布局技术应用研究[J].现代计算机(专业版),2010(05):140-142.
    [10] 邢希,田兴彦,王世运.响应式Web设计方法的研究[J].琼州学院学报,2013,20(02):36-38.
    [11] 王世明,李丹丹. 药品销售管理系统的设计与实现[J].产业与科技论坛,2015,05(05):23-25
    网站界面截图
    3 评论 59 下载 2018-11-17 17:26:53 下载需要13点积分
  • 基于Android Studio实现的在线学习课堂APP

    1 项目介绍1.1 背景本软件的开发意图是想让更多想学习外语,却没有好的方法,不知道如何学习,怎么学习,本软件可以为那些想学习的外语的用户,提供各种资源文件,因为现在是互联网的时代普通的纸质书籍不仅厚重不方便携带,而且版本更新不方便,而我们通过网络这个便捷的平台,使原本厚重的书籍统统的存放在云端,用户可以随时随地的利用自己的空闲时间来学习,真正的做到利用碎片化的时间,真正地做到随时随地想学就学的目的,用户可以使用本软件背单词,练习听力,写作,阅读理解,模拟考试等等功能,为了增加用户学习的动力我们通过设置打卡来督促用户学习的动力,通过设置小组来一起学习创造学习的动力,保证用户能长期的活跃在我们的平台,达到留住用户的目的,我们的软件的服务人群主要是针对在校大学生这个庞大的群体,以白领等想学习外语的人作为我们的次要服务人群来扩展我们的用户群体。
    1.2 开发环境
    操作系统:Windows
    数据库管理系统:MySQL
    其他支撑软件:Android Studio、tomcat、MySQL、sublime Text、eclipse

    2 软件概述2.1 软件范围定义本软件是希望为那些想学习外语的用户提供一套完善的学习理念,包括学习计划,学习周期,学习小组,模拟考试等等,来做到随时随地,想学就学的目的,服务目标人群主要是在校大学生为主,以白领等为辅,在盈利方面,通过广告的投放,以及在线课程的售卖,来获取利益,本软件同时具备web端和PC端两部分,用户可以采取对自己知识点通过分门别类的方式进行具体内容的记录;可以分享自己积累的知识;可以搜集其他人分享的知识充实自己的知识库,用这种新颖的方式来引起大家对知识的渴望,从而在很快的时间内就会积累很多的用户量,保证平台的运营正常,能够长期的存活下去。
    2.2 系统特性概述


    系统特性名称
    系统特性描述
    优先级




    首页展示
    展示软件的主题功能



    知识点管理
    能满足用户学习的使用基本需求



    数据备份
    保证用户数据不丢失



    资源缓存
    保证用户使用体验,能做到边下载边播放



    登录注册
    用户登陆注册



    学习讨论组
    多个用户同时在线一起讨论学习




    2.3 假定和依赖列举出在对本文档中确定的需求进行描述的时候的假设条件。包括预计使用的商业组件、行业法规、开发或运行环境的问题。
    描述软件系统对外部因素存在的依赖。例如,若打算把其他项目开发的组件集成到系统中,那么就要依赖另一个项目按时提供正确的组件。
    3 外部接口需求简要说明该软件同其他软件之间的公共接口、数据通信协议等,如果外部接口仅与某子功能有关,该接口说明需单独陈述。可以使用关联图描述高层抽象的接口信息,也可根据需要将对接口数据和控制组件的详细描述写入数据字典中。
    3.1 用户界面
    主页:包括轮播图(广告推广),听力训练,阅读理解
    学习:包括打卡,每日目标,专项练习
    我的:头像,用户名,设置,关于我的一些设置
    模拟考试:提供模拟试题进行测试
    教师:补充题库 创建试卷

    3.2 软件接口描述软件系统与其他外部组件(须注明名称和版本)的连接,包括数据库、操作系统、工具软件、库和集成的商业组件。
    明确在软件组件之间交换数据的目的,描述所需要的服务以及内部组件通信的性质。确定将在组件间共享的数据。
    4 需求规格列出待开发软件系统中所有系统特性及每个特性中所包含的功能集。如果系统特性的功能集和细化的子功能比较繁多,可以将每个系统特性分别编写“软件需求规格说明”,在本处列出文档编号和分册名称。
    在本文档中,功能需求的描述是根据系统特性即软件所提供的服务来组织的。根据项目的实际需要,也可以通过使用实例、运行模式、用户类、对象类或需求优先级的描述方法对这部分内容加以辅助说明。
    在描述时尽量使用简短明了的语句定义系统特性和功能的名称。例如:“拼写检查和拼写字典管理”。
    为满足确定的软件需求的可跟踪性和可维护性,需唯一确定每个系统特性及相应的功能,尤其对于需求复杂度较高、项目规模较大的项目,唯一性标识尤为必要。对需求的标识可以采用序列号(UR-2;SRS-31B)、层次编码(4.1.3.2)或自定义其他的方法。在下面的系统特性和相应功能集的描述中贯彻并在项目组内达成一致。
    4.1 系统特性1(编号/名称)这部分要求对每个系统特性以及包含的功能集分别进行描述。
    4.1.1 系统特性说明总体用例图

    4.2 系统特性2(编号/名称)4.2.1登陆注册子系统:用于用户的登陆以及注册基本功能


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




    Ud001
    登陆
    用户和教师登陆


    Ud002
    注册
    用户和教师注册



    4.2.2 学生考试子系统


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




    Ud003
    List exam
    学生选择显示试卷列表


    Ud004
    Delete a exam
    删除一个自己的试卷


    Ud005
    get results
    查看试卷成绩



    4.2.3 教师管理子系统


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




    Ud006
    Create a exam
    创建一套试卷


    Ud007
    Delete a exam
    教师可以删除试卷


    Ud008
    Add a score to a volume
    往指定试卷添加一个普通选择题目


    Ud009
    Add a score to a volume
    往指定试卷添加一个听力题


    Ud010
    Show all choose
    显示所有普通选择题


    Ud011
    Show all question
    显示所有听力题



    5 其他非功能需求5.1 一般性性能需求详细描述不同应用领域对软件性能的需求,解释它们的原理以帮助设计人员做出合理的设计选择。确定相互合作的用户数或者所支持的操作、响应时间以及与实时系统的时间关系。定义容量需求,例如存储器和磁盘空间的需求或者存储在数据库中表的最大行数等。
    本软件需要具有强大的健壮性,因为健壮性是一款软件能正常运行的基本,在软件的最开始的设计阶段要保证边开发边测试的原则进行开发,在整体的设计阶段不允许出现业务错误,在软件发生意外的故障时,需要保证软件能及时的处理,保证用户数据不能丢失,要需要定时备份用户的数据并保存在另一台服务器上做数据备份,以免发生未知的意外错误导致系统奔溃。在最终开发完成后,要保证在移动端APK文件的大小要控制适当,尽量控制在60M左右,方便用户的安装,保证用户使用方便简单名了,在web端要能够运行在windows系统上。
    5.2 一般性安全性需求用户信息的安全性:通过MD5信息加密技术,使用户上传的信息做到不泄露不被盗取。
    5.3 用户文档需求系统开发文档,使用视频等。
    6 附件6.1 墨刀界面原型










    6.2 WEB原型





    5 评论 119 下载 2018-11-06 15:59:45 下载需要14点积分
  • 基于C语言实现的旅馆信息管理系统

    1.程序实践概述1.1 题目名称
    旅馆信息管理
    1.2 开发环境
    基于Windows 10操作系统的Microsoft Visual Studio 2017
    2.问题分析2.1 功能说明
    查看旅店各房间信息:列举每个房间的房间号、房间类型、入住人数和房间价格
    查看某一房间信息:显示指定房间的旅客的信息,包括姓名、身份证号、性别和入住时间
    查看旅客信息:显示在旅馆的旅客总数;列举在旅馆的所有旅客的信息,包括姓名、性别、身份证号、房间号、入住时间
    查看某一旅客信息:查看指定旅客的信息,包括姓名、性别、身份证号、房间号、入住时间
    旅客入住:录入旅客的身份证号、姓名、性别等信息,程序将获取当前时间作为入住时间。将旅客的信息保存到链表和文件
    旅客换房:通过身份证号识别旅客,结算旅客已产生的房费,修改有关的旅客和房间信息
    旅客退房:程序获取当前时间作为退房时间,并结合入住时间结算房费。将旅客信息从程序的链表中删除,更改相关房间的信息,将旅客信息添加到旅客历史信息的文档中
    保存信息并退出程序:将旅客信息、房间信息、旅客与房间关系的信息从链表覆盖保存到文件,然后退出程序
    更换主题:更改命令行的颜色主题,程序会将主题信息自动保存到文档

    2.2 解决方案
    从文件读取相关信息,将相关信息储存到文件,从而实现旅馆信息管理的基本功能
    三个链表,分别存储旅客和房间的相关信息,以及这二者关系的信息。用一个枚举类型定义房间的类型
    用操作链表的方式实现旅客的入住,换房和退房三种行为
    程序开始时将文件中的信息读到链表中,修改信息后将链表中的信息保存到文件中。

    3.方案设计3.1 模块结构
    头文件Structs.h: 用于列举整个程序的头文件、结构体定义和函数声明等信息
    mainbody.c:显示主菜单,初始化链表,加载命令行的颜色主题等操作
    Guest.c:从文件中读取旅客信息到链表;将存储旅客信息的链表中的信息保存到文件;查看旅客信息等
    Hotel.c:从文件中读取房间信息到链表;将存储房间信息的链表中的信息保存到文件;查看房间信息等
    Guests.c:用于实现旅客入住、旅客换房、旅客退房等功能
    Guest.txt:用于存储旅客信息,包括姓名、性别、身份证号
    Hotel.txt:用于存储房间信息,包括房间号、房间类型和房间价格
    GuestAndRoom.txt:用于存储旅客与房间关系的信息,包括房间号、身份证号、入住时间
    GuestHistoryInfo.txt:用于存储旅客的历史信息,在旅客退房时可显示旅客曾经入住的次数
    Theme.txt:用于存储命令行的颜色主题信息

    3.2 数据结构旅馆信息管理程序中,主要的数据结构是三个链表:

    Rooms链表存储房间信息,包括房间号、房间类型、入住人数和房间价格
    Guests链表存储旅客信息,包括姓名、性别、身份证号
    GuestAndRoom链表存储旅客与房间关系的信息,包括身份证号、旅客入住的房间号、入住时间和退房时间

    3.3 总体流程总体流程大致如图所示,更多细节未在图中展示。

    3.4 关键算法核心功能是实现旅客的入住、换房和退房,涉及到新增、修改和删除链表中的节点。
    文件输入输出信息是本程序的重要功能,程序开始和结束时,程序中的链表会和文件交换信息。
    计算入住时间和退房时间的时间差属于创新功能,但实现相对较为复杂。旅客入住时会使用time()函数获取时间,将时间存储为字符串。旅客退房时,通过字符串处理,将入住时间放入tm结构体中,使用mktime()函数和difftime()函数计算退房时间与入住时间的差。
    3.5 界面设计整体界面在Windows控制台上。打开程序后的菜单如图:

    查看旅店信息

    查看某一房间信息

    查看旅客信息

    4.调试记录在IDE进行代码分析,没有错误和警告后,开始编译。由于程序开始运行时就会读取文件中的数据,当项目的文件夹内没有相应文件时,出现如下报错。
    按项目要求,添加样例文本文档后程序成功显示菜单。

    程序在读取文件中的字符串时遇到如下调试信息:

    在读取存放数据表格的文件时需要先跳过表头的中文。查询variable was corrupted 的原因是内存越界,后将读取这段中文的临时字符数组设置得更大一些,问题解决。

    cur是0xCDCDCDCD的原因是前面的代码将cur设置为了垃圾指针。此处的cur指针原本用于遍历链表,检查前面代码发现错将cur分配到了一个新的内存地址。将cur指向链表首个节点后问题解决。

    在文件中已有数据的情况下,程序未能读取到旅客信息。检查代码时发现,在读取文件时,弄错了feof函数的返回值真假。feof(fp)在fp指向文件末尾时返回真,在fp指向文件中间时返回假。

    进行旅客入住操作时,弹出调试信息“引发了异常,读取访问权限错误。”多次检查代码后发现,在将数据输出到文件的过程中使用了遍历链表后的地址不明确的链表指针,将指针换为记录数据的普通变量以输出,问题解决。
    存储旅客入住时间时,使用了ctime()函数,调试时发现程序显示的入住时间不正常。查询资料后发现ctime()函数的返回值末尾有换行符,使用strncpy()去除换行符后,屏幕不会输出换行,但字符串末尾出现“屯屯屯……”,表明有未赋值的字符被输出。查询资料后确认,strncpy并不会给目标字符串的末尾添加’\0’,手动为字符串末尾添加’\0’后,问题解决。
    在使用difftime()函数时,返回的时间差是0,查询MSDN后发现difftime()函数执行错误将导致返回值为0。difftime()函数执行错误的具体原因是,程序记录的年份是从1900年开始的,因此存入tm结构体的年份要在真实年份的基础上减去1900。
    5.创新说明结构体定义时没有使用typedef,尽量减少结构体名称数量。每次使用链表时写struct关键字,也能使得代码可读性更强。
    全局定义了printline()函数用于命令行换行,便于调用。
    精细地调整格式化输入输出,使得程序能以整齐的列表形式清晰地显示各项数据。
    查看某一旅客或某一房间信息时,如果旅馆中没有该房间或旅客,会显示提示信息,给予使用者反馈。
    旅客入住时,会显示可用房间的信息,并标注可用房间中是否已有人入住。针对即将入住旅客的身份进行识别,判断该旅客是否已经入住。针对旅客即将入住的房间,判断该房间是否能够容纳该旅客。
    旅客退房时,使用difftime()、mktime()等函数自动计算旅客从入住到退房的天数,而不用手动输入。旅馆管理人员若想给予旅客折扣,可输入折扣率,使程序直接计算出最终的房费。
    旅客换房时,考虑到房间号是否输入错误,新换的房间是否已满等细节,确保程序不会因为使用者的误操作出现异常。在换房前,展示旅客的信息以及房间是否可用的详细信息。
    6.体会与建议与以往学习C语言时写单个文件的小程序不同,此次程序设计需要完成一个项目。完成项目需要编写多个头文件和源文件,谨慎地对项目和解决方案进行配置,甚至要注意版本控制,及时保存现有的代码。
    整个项目的代码量比较大,共1300余行,也涵盖了C语言程序设计课程的许多知识,重要的知识点包括指针、结构体、链表、内存动态分配、枚举类型、文件操作等。
    平常编程时难以纠正的惯性思维也在项目开发的过程中暴露出来。比如局部数组初始化时应当赋空值,字符串之间不能直接用“==”比较而必须用strcmp()函数,数组申请的空间需要足够大,空指针需要及时用free()处理等。也复习到了strncpy()用完后需要手动添加‘\0’等印象不深刻的知识点。
    开发此次项目也自学了更多C语言的知识,比如用于记录时间的结构体tm以及<time.h>中的其他函数,学会了在MSDN文档中查询资料等技能;收获颇丰,相当程度上提升了编程能力,了解了项目开发的基本流程。
    1 评论 61 下载 2019-05-08 17:15:14 下载需要12点积分
  • 基于JSP和MYSQL实现的图书馆管理系统

    一、概述基于Spring + Spring MVC + MyBatis的图书馆管理系统,使用Maven进行包管理。主要功能包括:图书查询、图书管理、图书编辑、读者管理、图书的借阅与归还以及借还日志记录等。
    二、环境配置2.1 开发环境
    Windows 10
    IntelliJ IDEA 2018.3

    2.2 运行配置
    首先安装Mysql5.7,设置用户名为root,密码为123456,并保证其在运行状态,并执行library.sql文件导入数据
    然后再配置Maven到环境变量中,在源代码目录下运行
    # mvn jetty:run
    使用浏览器访问 http://localhost:8080 即可进入系统

    三、概念设计用户分为两类:读者、图书馆管理员。图书馆管理员可以修改读者信息,修改书目信息,查看所有借还日志等;读者仅可以修改个人信息、借阅或归还书籍和查看自己的借还日志。


    四、数据库E-R图
    五、逻辑设计共有6个表:
    5.1 图书书目表book_info


    字段
    类型
    长度
    小数点
    NULL
    用途





    book_id
    bigint
    20
    0

    图书号



    name
    varchar
    20
    0

    书名



    author
    varchar
    15
    0

    作者



    publish
    varchar
    20
    0

    出版社



    ISBN
    varchar
    15
    0

    标准书号



    introduction
    text
    0
    0

    简介



    language
    varchar
    4
    0

    语言



    price
    decimal
    10
    2

    价格



    pub_date
    date
    0
    0

    出版时间



    class_id
    int
    11
    0

    分类号



    number
    int
    11
    0

    剩余数量



    5.2 数据库管理员表admin


    字段
    类型
    长度
    小数点
    NULL
    用途





    admin_id
    bigint
    20
    0

    账号



    password
    varchar
    15
    0

    密码



    username
    varchar
    15
    0

    用户名



    5.3 图书分类表class_info


    字段
    类型
    长度
    小数点
    NULL
    用途





    class_id
    int
    11
    0

    类别号



    class_name
    varchar
    15
    0

    类别名



    5.4 借阅信息表lend_list


    字段
    类型
    长度
    小数点
    NULL
    用途





    ser_num
    bigint
    20
    0

    流水号



    book_id
    bigint
    20
    0

    图书号



    reader_id
    bigint
    20
    0

    读者证号



    lend_date
    date
    0
    0

    借出日期



    back_date
    date
    0
    0

    归还日期



    5.5 借阅卡信息表reader_card


    字段
    类型
    长度
    小数点
    NULL
    用途





    reader_id
    bigint
    20
    0

    读者证号



    password
    varchar
    15
    0

    密码



    username
    varchar
    15
    0

    用户名



    5.6 读者信息表reader_info


    字段
    类型
    长度
    小数点
    NULL
    用途





    reader_id
    bigint
    20
    0

    读者证号



    name
    varchar
    10
    0

    姓名



    sex
    varchar
    2
    0

    性别



    birth
    date
    0
    0

    生日



    address
    varchar
    50
    0

    地址



    phone
    varchar
    15
    0

    电话



    六、功能展示6.1 首页登陆
    管理者账号:123456/123456
    读者账号:10000/123456


    6.2 管理员系统6.2.1 图书管理
    6.2.2 图书详情
    6.2.3 读者管理
    6.2.4 借还管理
    6.3 读者系统6.3.1 查看全部图书
    6.3.2 个人信息查看,可以修个个人信息
    6.3.3 个人借阅情况查看
    5 评论 176 下载 2019-05-09 11:01:25 下载需要13点积分
  • 基于Java的网上书城

    主要技术关键字:JSP、servlet、Ajax、jstl、JavaScript、注册登录、分页、购物车、增删改查
    开发环境:Eclipse、MySQL 5.7、Tomcat 8.0
    数据库表结构设计
    books表结构:

    items表结构:

    orders表结构:

    userinfo表结构:

    项目包结构
    MVC设计模式M(model层)
    biz包:业务处理
    dao包:数据访问,对数据库的一些封装操作
    entity包:实体类,javabean构建,View层和数据库之间的桥梁作用

    V(view层)1. Jsp页面:与用户进行交互的界面。

    C(controller 层)1.servlet包:控制层,处理View层Jsp页面发来的请求。
    注册登录模块Register
    注册页面中form表单
    验证用户名、验证密码、验证邮箱
    <form method="post" action="RegisterServlet" onsubmit="return checkRegister()"> <dl> <dt>用 户 名:</dt> <dd><input class="input-text" type="text" id="username" name="username" onblur="isUsernameLegal()"/><span id="usernull"></span><span id="alreadyExsits"></span></dd> <dt>密  码:</dt> <dd><input class="input-text" type="password" id="password" name="password" onblur="isPasswordLegal()" /><span id="nullpassword"><font color=\"green\">密码至少8位</font></span><span id="simplepassword"></span></dd> <dt>确认密码:</dt> <dd><input class="input-text" type="password" id="rePassword" name="rePassword" onblur="isRepasswordLegal()" /><span id="nullrePassword"></span><span id="uneq"></span></dd> <dt>Email地址:</dt> <dd><input class="input-text" type="text" id="email" name="email" onblur="isEmailLegal()" /><span id="nullemail"><font color=\"green\">请输入正确格式的邮箱</font></span><span id="errorInput"></span></dd> <dt></dt> <dd class="button"><input class="input-reg" type="submit" name="register" value="" /></dd> </dl> </form>
    Ajax(异步 JavaScript 和 XML ):验证用户名是否已被注册,页面部分数据刷新,而无需加载整个网页,提高网站的访问效率。
    /** * Ajax检查用户是否已经被注册 * 异步:发送请求时不等返回结果,由回调函数处理结果 * @returns {Boolean} */function isExists() { var xmlHttp; //定义 xmlHttp XmlHttpRequest对象从服务器异步获取数据后通过javascript修改页面局部信息 try { //根据不同浏览器初始化不同的xmlHttp浏览器对象 //IE6以上浏览器 xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { //FireFox xmlHttp = new XMLHttpRequest(); } catch (e) { try { //IE5.5+ xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { alert("您的浏览器不支持Ajax"); return false; } } } var username = document.getElementById("username").value; //获取用户名 /** * open(提交方式[get|post],url(servlet路径),同步或异步[false|true]) * RegisterServlet: servlet路径 * 打开和后台服务器的链接 */ xmlHttp.open("POST", "RegisterServlet?action=check&username="+username, true); //路径中不能有空格 xmlHttp.send(null); //传送数据 /** * onreadystatechange:调用回调函数 * readyState:请求状态,代码是未初始化,1:初始化,2:发送请求,3:开始接受数据,4:接受结果完毕 * status: http状态码 200成功,404路径错误,500后台代码错误, */ xmlHttp.onreadystatechange = function() { if(xmlHttp.readyState==4 && xmlHttp.status==200) { var usernull = document.getElementById("usernull"); var result = xmlHttp.responseText; //接受服务器端传过来的数据,写出来的数据都是String类型 if(result == "true") { usernull.innerHTML = "<font color='red'>当前用户名已被注册</font>"; return false; } else if(result == "false") { usernull.innerHTML = "<font color='green'>当前用户名可用</font>"; return true; } } }}
    Login
    LoginServlet中doGet方法:
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username");//获取页面传过来的参数 String password = request.getParameter("password"); //登录操作 boolean flag = userBiz.checkLogin(username, password); if(flag) { request.getSession().setAttribute("loginuser", username);// response.sendRedirect("main.jsp"); response.sendRedirect("SearchServlet"); //首页直接显示 } else {//登录失败 response.setContentType("text/html;charset=utf-8");// response.setCharacterEncoding("utf-8"); PrintWriter out = response.getWriter(); out.println("<script type='text/javascript'>"); out.println("alert(\"登录失败!请重新登录\")");//反斜杠转义 out.println("open(\"login.jsp\", \"_self\");");//重新打开新的页面, _self在原窗口打开 out.println("</script>"); out.close(); } }
    网站首页及搜索图书模块
    分页展示Jstl标签库 c:forEach,循环遍历展示图书信息。
    <c:forEach var="book" items="${books }"> <tr> <td><input type="checkbox" name="bookId" value="${book.bid }" /></td> <td class="title">${book.bookname }</td> <input type="hidden" name="title" value = "${book.bid }:${book.bookname}"/> <td>¥${book.b_price }</td> <input type="hidden" name="price" value = "${book.bid }:${book.b_price}"/> <!-- b_price跟数据库字段名相对应 --> <td>${book.stock }</td> <input type="hidden" name="stock" value = "${book.bid }:${book.stock}"/> <td class="thumb"><img src="${book.image }" /></td> <input type="hidden" name="image" value = "${book.bid }:${book.image}"/> </tr></c:forEach>
    <!--分页开始--> <%if(request.getAttribute("current") != null) { %> <div class="page-spliter"> <a href="SearchServlet">首页</a> <%for(int i = 1; i <= totalPage; i++) { %> <%if(i==no) { %> <!-- 如果不是当前页显示为链接 --> <span class="current"><%=i %></span> <%continue;} %> <a href="SearchServlet?currentPage=<%=i %>"><%=i %></a> <%} %> <a href="SearchServlet?currentPage=<%=totalPage %>">尾页</a> </div> <%} %><!--分页结束-->
    servlet处理
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); String currentPage = request.getParameter("currentPage");//获取当前页 int no = currentPage == null?1:Integer.parseInt(currentPage);//如果当前页为空,则默认为1,否则转化为相应的int// String currentSearchPage = request.getParameter("currentSearchPage"); String bookname = request.getParameter("keywords");//获取你输入的书名 List<Book> books = null; if(bookname==null || bookname.equals("")){ books=bookbiz.findAll(3, no);//查询所有。3:代表每页显示的条数,no:当前显示页面 request.setAttribute("totalPage", (bookbiz.count()/3 + 1));//将总页面数存入request } else { books = bookbiz.findBookByName(bookname,3, no);//根据书名模糊查询出数据 System.out.println(books.size()); request.setAttribute("totalPage", (books.size()/3 + 1));//将总页面数存入request } request.setAttribute("books", books);//将查询出的数据存入request request.setAttribute("current", no);//将当前页存入request request.getRequestDispatcher("main.jsp").forward(request, response);//页面转发 }
    关键字匹配查询输入“Java”关键字,展示搜索结果

    购物车模块增
    注意:
    当库存不足时,防止库存数被减到负值。
    if(oneStock > 0) {//如果库存大于0 //查看当前图书是否已经存在于购物车中 //查看购物车列表是否已经存在该图书,对比两个图书id for (int j = 0; j < bookcart.size(); j++) { Book existBook = (Book) bookcart.get(j); if(existBook.getBid() == bid) {//如果购物车中的id==被选中的图书id,则购物车中的数量+1 bookcart.remove(j); existBook.setCount(existBook.getCount()+1);//购物车中商品数量+1 double totalPrice = existBook.getPrice(); bookcart.add(existBook);//商品总价 System.out.println("总价"+totalPrice); isNotExists = false; //修改库存 isOrNotChangeStock = bookbiz.changeStock(bid, "-1"); break; } } if(!isNotExists) { continue; } book.setBid(bid); //判断当前获取的图书信息是否为指定bid下的信息 for (int j = 0; j < title.length; j++) {// request.setCharacterEncoding("utf-8"); //解决页面图书标题中文显示乱码 String title_temp =new String(title[j].getBytes("ISO-8859-1"),"utf-8");//取标题 if(title_temp.indexOf(bids[i]+":")<0) {//indexOf匹配bids是否包含在title_temp中,如果没有返回-1 continue; } if(image[j].indexOf(bids[i]+":")<0) { continue; } if(price[j].indexOf(bids[i]+":")<0) { continue; } if(stock[j].indexOf(bids[i]+":")<0) { continue; } //添加指定bid下的图书信息 book.setBookname(filter(title_temp, bids[i])); book.setImage(filter(image[j], bids[i])); book.setPrice(Double.parseDouble(filter(price[j], bids[i])));// book.setPrice(Double.valueOf(filter(price[j], bids[i]))); book.setStock(filter(stock[j], bids[i])); book.setCount(1); //修改库存 bookbiz.changeStock(bid, "-1"); bookcart.add(book); } }
    删移除操作
    protected void remove(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.获取图书id String bid = request.getParameter("bid"); //2.获取购物车 List<Book> bookcart = (List<Book>) request.getSession().getAttribute("bookcart"); //3.循环查找购物车中相同的图书id for(int i = 0; i< bookcart.size(); i++) { Book book = bookcart.get(i); if(Integer.valueOf(bid) == book.getBid()) { //4.移除图书 bookcart.remove(i); //5.修改库存 bookbiz.changeStock(Integer.parseInt(bid), book.getCount()+""); break; } } //6.将购物车保存到session中// request.getSession().setAttribute("bookcart", bookcart); request.getSession().setAttribute("bookcart_count", bookcart.size()); System.out.println(request.getSession().getAttribute("bookcart_count")); }
    改1.前端shopping.jsp页面,添加onblur失去焦点事件,当鼠标离开输入框时执行JavaScript代码,调用update方法。
    <c:set value="1" var="count"></c:set> <c:forEach var="book" items="${bookcart }"> <tr> <input type="hidden" id="hidden_bid_${count }" name="hidden_bid_${count }" value="${book.bid }"/> <td class="thumb"><img src="${book.image }" /></td> <td class="title">${book.bookname }</td> <td><input class="input-text" type="text" id="nums_${count }" name="nums_${count }" value="${book.count }" onblur="update(${bookcart_count}, ${count }, ${book.bid })"/></td> <!-- onblur事件 --> <input type="hidden" id="hidden_${count }" name="hidden_${count }" value="${book.price }"/> <td>¥<span id="price_${count }"></span></td> <input type="hidden" id="hidden_book_total_price_${count }" name="hidden_book_total_price_${count }" /> <td><span id="remove_${count }"><a href="#" onclick="del(${book.bid})">移除</a></span></td> <!-- href链接, --> </tr> <c:set value="${count+1 }" var="count"></c:set></c:forEach>
    2.异步更新图书购买量数据,并向控制层Servlet中返回一个“update”
    /** * Ajax修改购物车中的数量 */function update(size_str, i, bid_str) { //初始化XMLHttpRequest对象 var xmlHttp; try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlHttp = new XMLHttpRequest(); } catch (e) { try { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { e.message(); alert("你的浏览器不支持Ajax"); } } } //2.获取修改后的数量 var num_str = document.getElementById("nums_"+i); //3.打开服务器链接 xmlHttp.open("POST", "ModifyCartServlet?action=update&bid="+bid_str+"&count="+num_str.value, true); //4.传值 ,无参传null值 xmlHttp.send(null); //5.设置回调函数 xmlHttp.onreadystatechange = function() { if(xmlHttp.readyState == 4 && xmlHttp.status == 200) { count(size_str);//调用Servlet中的方法 } }}
    3.servlet中通过前端返回的请求调用相应的方法。
    String action = request.getParameter("action");if(action.equals("update")) { updateCart(request, response);}else if(action.equals("remove")) { remove(request, response);}
    4.控制层Servlet更新购物车数据,并修改库存。
    protected void updateCart(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.获取图书id和修改后的数量 String bid = request.getParameter("bid"); String count = request.getParameter("count"); //2.获取购物车 List<Book> bookcart = (List<Book>) request.getSession().getAttribute("bookcart"); //3.查找购物车中修改过的图书,并修改相应的信息 for (Book book : bookcart) { if(Integer.valueOf(bid) == book.getBid()) { //4.获取修改前的图书数量 int old_count = book.getCount(); //5.设置当前图书的新数量 book.setCount(Integer.valueOf(count)); System.out.println("当前图书新数量"+count); int nowStock = 0; try { nowStock = basedao.queryStock(Integer.parseInt(bid)); } catch (Exception e) { e.printStackTrace(); } //6.修改库存 bookbiz.changeStock(Integer.parseInt(bid), (old_count-Integer.parseInt(count))+""); break; } } }
    查与搜索图书模块类似
    我的订单模块
    1.获取订单信息,存入List中
    <% List orders = (List) request.getAttribute("orders"); %>
    2.订单展示
    <c:forEach var="order" items="${orders }"> <tr> <td id="id_${td_id}">${order.oid }</td> <td id="user_${td_id}">${order.username }</td> <td id="crdt_${td_id}">${order.createdate }</td> <td id="total_${td_id}">${order.total_price }</td> <td class="thumb"><img src="${order.image }" /></td> <td>${order.bookname }</td> <td>${order.b_price }</td> <td>${order.total_price/order.b_price }</td> </tr></c:forEach>
    用户退出当用户退出登录,清空session。
    <%--用户退出登录 --%><% request.getSession().removeAttribute("loginuser"); request.getSession().removeAttribute("bookcart"); request.getSession().removeAttribute("bookcart_count"); response.sendRedirect("login.jsp");%>
    一些注意细节1.为防止游客非法访问页面,在每一个前端页面body之后加上登录检测代码。
    <% String username = (String)session.getAttribute("loginuser"); if(username == null) { response.sendRedirect("login.jsp"); }%>
    2.当库存不足时,防止库存数被减到负值。
    if(oneStock > 0) {//如果库存大于0 //...}
    3.href中加上空链接,否则该页面中的session不会刷新,必须手动刷新。
    <span id="remove_${count }"><a href="#" onclick="del(${book.bid})">移除</a></span>
    网站云部署一个经过部署的网站才是一个完整的网站
    阿里云平台
    租用ecs云主机,搭建Java运行环境,jdk、mysql、Tomcat
    域名解析
    项目打包成.war文件上传至云服务器。
    启动服务器
    通过域名访问并测试网站:http://ycuer.xin:8080/books/
    7 评论 284 下载 2019-02-12 08:16:01 下载需要16点积分
  • 基于C#实现的文件管理系统

    一、项目背景
    在内存中开辟一个空间作为文件存储器(虚拟磁盘),在其上实现一个简单的文件管理系统
    退出这个文件系统时,应将文件系统的内容保存在磁盘上,下次将其恢复到内存中
    文件目录采用多级目录结构

    二、开发/运行环境
    开发环境:Windows10 Pro 1803
    开发语言:C# 6.0/ .net Framework 4.7.03056
    开发工具:Microsoft Visual Studio Community 2017

    三、数据结构:块组由于模拟的磁盘较为简单,所以这里采用单块组,取消了逻辑扇区的数据结构。事实上,这一个块组对象就等价于一个虚拟磁盘。我使用了ext2的设计思想,并做了必要的简化,在细节上与真实的ext2文件系统有所不同。
    3.1 卷大小由于简化了操作,将单个块组等价于磁盘,所以将磁盘的容量记录在块组里面。同时这是一个不太严格的说法,这里的卷大小实际上是所有数据块的尺寸之和。
    3.2 超级块用于描述文件系统的整体信息

    inode数量
    空闲inode数量

    3.3 组描述符表记录所有的组描述符。
    组描述符
    记录块组中各个描述性质的数据结构的位置,这里用来记录数据块和inode的使用情况。
    块位图
    描述本块组中数据块的使用情况,是一个位向量,1表示数据块已被占用,0表示数据块未被占用。
    inode位图
    描述inode表中inode的使用情况,1表示已被使用,0表示未被使用。
    3.4 数据块表记录块组中所有的数据块。
    数据块data
    一个字符型数组,用于存储各种数据,数组大小为2048,实际占用4096字节,因为C#中字符为Unicode编码,每个字符占据2个字节。
    3.5 inode表记录块组中所有的inode,数量由超级块给出。
    inode
    表示文件系统树型结构节点:

    文件类型
    文件大小
    文件名
    文件创建时间
    文件修改时间
    文件占用数据块数量
    占用的数据块索引
    包含的子文件的inode索引
    包含的子文件的数量
    父目录的inode索引

    注意,这里的子文件均指第一级子文件,即树型结构中的儿子。
    3.6 当前目录索引用于记录用户当前所处的目录的inode索引。由于这是一个单用户系统,所以将这个信息保存在了块组对象中,便于编程实现。
    磁盘映像也是按照这个顺序写入的,保存在与可执行文件同一目录下,名为disk.img,请务必不要随意修改这个文件,否则会导致文件系统读取错误
    四、GUI设计及使用说明整个文件管理系统包含四个窗口:

    主窗口:展示当前目录下的文件和子目录列表,以及各种操作对应的按钮
    输入窗口:用于输入文件或子目录的名称
    文件查看和编辑窗口:用于进行文件查看和编辑
    文件详情窗口:用于查看文件各项详细信息

    其中,主窗体负责调用其它三个窗体,窗体之间通过委托和事件进行信息传递。
    4.1 GUI说明4.1.1 主窗口
    其中,蓝色标识的文件是目录文件,黑色标识的是普通文件,红色标识的是未知文件。未知文件一般不会出现,除非磁盘映像损坏造成错误。我们可以尝试一下:

    重新运行文件管理系统,可以看到:

    目录文件斗破苍穹已被损坏,成为了未知文件。保存此时的磁盘映像,可以看到:

    文件类型已经发生了改变。
    4.1.2 输入窗口这个窗口主要用于进行命名操作,以及在格式化时输入磁盘大小。
    重命名

    点击确定或按下回车键,文件名变为:
    新建文件
    也可以尝试新建目录和文件,并为它们命名:

    格式化
    在进行格式化时,务必注意输入的数字符合要求,否则无法进行格式化:

    磁盘空间大小必须为大于0小于等于100的整数。
    4.1.3 文件查看和编辑窗口首先,只有普通类型的文件可以被“打开”,目录文件和未知文件无法执行“打开”操作。
    “打开”文件分为两种类型:只读和读写模式。只读模式下,用户将无法对文件内容进行编辑,而读写模式下则可以。
    双击文件或按下回车键采用的是只读模式打开,编辑文件需要点击写文件按钮或按下W键。
    只读模式

    用户无法编辑文件内容,确认按钮也没有被激活。
    读写模式

    用户可以对文件进行编辑,编辑之后可以点击确认按钮或同时按下Control+S键保存修改的内容,也可以点击取消按钮或者右上角的叉号或者按下Esc键放弃更改。
    4.1.4 文件详情窗口当用户选中一个文件时,按下空格键可以查看其详细信息。操作时应当注意,当窗口焦点位于某一按钮时,即使文件看起来被选中了,此时按下空格键也无法看到文件详情。
    普通文件详情

    目录文件详情

    当然,目录文件详情中的文件大小是指目录文件本身的大小,不包含目录文件的子文件。
    在详情界面,再次按下空格键即可关闭详情页。
    4.2 使用说明


    主界面操作
    效果




    双击普通文件
    以只读模式打开文件


    双击目录
    进入该目录


    按F键
    格式化磁盘


    按N键
    新建普通文件


    选中普通文件,按回车键
    以只读模式打开文件


    选中普通文件,按W键
    以读写模式打开文件


    按退格键(Backspace)
    返回上一级目录


    选中目录,按回车键
    进入该目录


    按D键
    创建目录


    选中文件,按删除键(Delete)
    删除文件


    选中文件,按R键
    重命名


    按Control+W键
    退出系统,保存映像


    选中文件,按空格键
    查看文件详情






    文件编辑页面操作
    效果




    按退出键(Esc)
    关闭窗口,不保存修改


    按Control+S键
    关闭窗口,保存修改



    注:只读模式打开的文件无法使用Control+S按键关闭窗口



    文件详情页面操作
    效果




    按空格键
    关闭详情页面






    输入窗口页面操作
    效果




    按退出键(Esc)
    关闭窗口,输入不生效


    按回车键(Enter)
    关闭窗口,输入生效



    五、设计细节5.1 系统架构在我的理解中,文件管理系统的作用是:向下管理磁盘和文件,向上提供服务。基于此,我设计了如下架构:

    其中,蓝色部分为用户界面,是用户直接看到的图形化界面;绿色部分为文件管理系统向上对用户提供的功能,它们在用户界面中表现为一个个的按钮和鼠标键盘事件;黄色部分是文件管理系统向下对文件和磁盘进行管理的函数;灰色部分是虚拟磁盘,即管理的对象,文件也储存在这里面;红色部分处于真实的磁盘中,用于保存虚拟磁盘和文件管理系统的映像。
    在这个结构中,用户一般是无法直接对虚拟磁盘进行操作的,除了格式化操作和退出系统操作(需要覆写原有磁盘映像)。这一方面简化了用户的操作,一方面提供了安全性保障,防止用户直接操作黄色部分函数,而损坏管理系统。
    5.2 读取磁盘映像当运行文件管理系统时,系统会进行初始化,尝试读取disk.img文件。如果文件不存在,会进入如下界面:

    若此时不进行格式化,那么主界面上除了关闭系统按钮可以操作,其它功能都无法使用。
    如果磁盘映像读取成功,文件管理系统便会根据映像中的内容恢复磁盘结构和文件内容。磁盘映像并不是将磁盘中所有的内容都包含在内,它只包含了被占用的部分。
    5.3 删除文件对于文件的删除分为2种:删除目录文件和非目录文件。
    删除目录文件时,必须递归地删除目录文件中所有的子文件,这里的子文件指目录文件下所有文件,即树型结构中的所有子孙。删除时,系统会根据inode中子文件的inode索引执行深度优先遍历,自底向上删除目录文件的所有子孙,最终删除目录文件本身。即:对于目录文件A,它包含两个文件B和C,那么当用户删除A时,系统首先删除B和C,再删除A;在删除B和C的过程中,如果B或C也是目录文件,那么就要以相同的方式删除B或C。
    删除普通文件的过程比较简单,直接删除即可。
    具体的删除过程会将inode位图的数据块位图中的相应信息置为true,即未占用;同时为了数据安全,这些inode和数据块中的信息都会被抹去,用0元素覆盖。
    我在代码中留下了测试删除顺序的方法,具体位置位于deleteFile(String fileName)函数中:
    foreach (var index in deleteInode.dataBlockList) groupDescriptorList[0].blockBitmap[index] = true; // 释放占用的数据块groupDescriptorList[0].inodeBitmap[deleteFileIndex] = true; // 释放占用的inode块 //MessageBox.Show(inodeList[deleteFileIndex].fileName, "", MessageBoxButtons.OK, MessageBoxIcon.Error); // 检查删除顺序inodeList[currentInodeIndex].childInodeIndex.Remove(deleteFileIndex);// 抹去inode信息和数据块内容deleteInode.blockSize = 0;
    将注释为检查删除顺序一行开头的注释符去掉,重新编译运行,执行删除操作即可观察到删除顺序。
    5.4 Inode块和数据块分配5.4.1 Inode块分配当新建文件时,文件系统会从空闲的Inode块中选出一个分配给这个新文件,挑选过程使用Inode位图顺序检查每个Inode块是否已被分配,找到第一个空闲的Inode块后停止检查。如果所有的Inode块都已被占用,那么会返回错误。
    int indexOfInode = -1; foreach(KeyValuePair<int, bool> kvp in groupDescriptorList[0].inodeBitmap) { if(kvp.Value == true) { indexOfInode = kvp.Key; break; } } if (indexOfInode == -1) return false; groupDescriptorList[0].inodeBitmap[indexOfInode] = false; Inode inode = inodeList[indexOfInode];
    最后一行代码中取出的inode将被写入各种信息,最终写回到Inode列表中。Inode位图中的信息也应得到更新,这个inode对应的位图标志被置为false。
    5.4.2 数据块分配文件创建之初是不会被分配数据块的,直到文件被写入了信息,才会被分配数据块。在这其中,对目录文件和普通文件的写入还有所不同。由于我规定文件名称不得超过100个字符,所以对于目录文件的一次写入最多会额外申请一个数据块;而普通文件的写入没有限制(C#本身的文本框字符上限为32768个,这是一个上限),所以可能会申请多个数据块。
    当然,对数据块的申请过程都是一致的:
    int indexOfBlock = -1; foreach (KeyValuePair<int, bool> kvp in groupDescriptorList[0].blockBitmap) // 找到一个空闲数据块 { if (kvp.Value == true) { indexOfBlock = kvp.Key; break; } } if (indexOfBlock == -1) // 没有足够的数据块 { updateInodeInfo(ref inode); inodeList[commonIndex] = inode; return false; } groupDescriptorList[0].blockBitmap[indexOfBlock] = false; DataBlock dataBlock = dataBlockList[indexOfBlock];
    文件系统通过检查数据块位图取出相应的数据块,将位图中对应的信息置为false,在数据块被更新完毕后将其写回。
    5.4.3 Inode块和数据块回收当文件被删除或内容被删减时,它占用的inode块和数据块可能会变得“空闲”,这时文件管理系统就必须将空闲的块进行回收,抹掉块中的内容,更新块位图中的信息。
    删除文件时,会触发释放inode事件和数据块事件:
    foreach (var index in deleteInode.dataBlockList) groupDescriptorList[0].blockBitmap[index] = true; // 释放占用的数据块 groupDescriptorList[0].inodeBitmap[deleteFileIndex] = true; // 释放占用的inode块 //MessageBox.Show(inodeList[deleteFileIndex].fileName, "", MessageBoxButtons.OK, MessageBoxIcon.Error); // 检查删除顺序 inodeList[currentInodeIndex].childInodeIndex.Remove(deleteFileIndex); // 抹去inode信息和数据块内容 deleteInode.blockSize = 0; foreach(var index in deleteInode.dataBlockList) { DataBlock dataBlock = dataBlockList[index]; for (int i = 0; i < BLOCKSIZE / 2; i++) dataBlock.data[i] = '\0'; dataBlockList[index] = dataBlock; } deleteInode.dataBlockList.Clear(); deleteInode.fatherIndex = -1; deleteInode.fileSize = 0; superBlock.freeInodeNum++; inodeList[deleteFileIndex] = deleteInode; // 写回 Inode fatherInode = inodeList[tempCurrentInodeIndex]; fatherInode.childrenNum--; inodeList[tempCurrentInodeIndex] = fatherInode; // 写回 writeDirectoryFileToDisk(tempCurrentInodeIndex);
    改写文件时,只可能会触发释放数据块事件:
    int freeIndex = inode.dataBlockList[blockNum]; // 要释放的数据块的index groupDescriptorList[0].blockBitmap[freeIndex] = true; for (int i = 0; i < BLOCKSIZE / 2; i++) dataBlockList[freeIndex].data[i] = '\0'; inode.dataBlockList.Remove(freeIndex); // 从子列表中移除
    5.5 其它信息所有的代码都有必要的注释,读者可以参考注释阅读代码。
    4 评论 57 下载 2019-04-08 15:13:27 下载需要12点积分
  • 基于JAVA实现的网络五子棋游戏

    一、实验目的
    熟练掌握基本网络编程技术
    掌握Swing图形用户界面编程
    掌握多线程编程的基本原理,能使用多线程设计服务器端程序
    培养独立查找资料,并解决问题的能力

    二、实验任务网络五子棋游戏

    服务器端为多线程,当判断有偶数个用户连接时,方可开始游戏
    先连接的客户执黑棋,先下。另一客户执白棋
    双方交替下棋,由服务器端程序判断客户本次下棋步骤是否有效,仅将有效的下棋步骤传递给双方
    客户端程序负责本地下棋界面的显示工作,与服务器通信,并处理相应的鼠标事件
    下棋胜负由客户端自行判定。提供客户退出按钮,点击按钮,将退出游戏
    选作部分

    由服务器端程序判定游戏胜利方,并终止游戏,向双方显示游戏胜利者信息提供玩家注册功能,并保存该玩家胜负局数信息、等级、中途逃逸次数等信息游戏开始时,向双方显示玩家等级、逃逸次数等基本信息,玩家可选择是否继续和对手的游戏

    三、开发工具与平台
    Jdk
    Eclipse

    四、设计思路4.1 界面设计登陆框输入用户名和密码,判断正确方可进入游戏。

    总体布局为BorderLayout,其中西边为用户信息面板,由JLabel加载图片和JTextArea显示信息。中部的棋盘背景为图片,网格线由Graphics2D实现,棋盘的paintComponent( )方法先画图再画线。东边为主机信息和游戏信息,都是JTextArea实现。东边下方的按钮先添加在面板上,在加入东部的面板里。
    4.2 逻辑设计由ServerThread探测是否有客服连接,若有,则为客户创建一个ServerToClientThread,并将其加入Clients的ArrayList集合中,接着验证用户名和密码,验证的信息存在HashMap中,键值为用户名,映射的值为Values的类,类中包含了密码,输,赢,逃跑次数等信息。如果验证成功则将用户信息传给客户端,显示在Info的JTextArea中,客户可以创建游戏或加入游戏,如果创建主机,则别的客户可以加入游戏,由host的ArrayList维护,在登陆成功的同时也会将host和Clients的集合传给客户。
    客户通过JList的选择获得要传送信息的客户,此表与服务器维护的信息相同,所以只需传送选择的Index就可以了。Index通过Clients可以查找到要发送的对象。
    当创建游戏时,ServerThread会将客户对应的ServerToClientThread加入host集合中,并将更新信息传送给Clients中的所有客户。当客户加入游戏时,将对映的信息加入map中,即建立游戏中信息传送对象的信息。
    游戏中的信息通过map查找对手的ServerToClientThread发送。
    4.3 程序测试登陆验证的测试

    下棋及游戏双方的连接测试

    消息的发送测试

    五、实验总结通过这次实验:

    掌握了基本网络编程技术
    掌握Swing图形用户界面编程
    掌握多线程编程的基本原理,能使用多线程设计服务器端程序
    培养独立查找资料,并解决问题的能力

    最大的不足:界面不够美观!
    1 评论 119 下载 2019-05-03 11:28:59 下载需要13点积分
  • 基于Java的局域网聊天工具

    一 需求分析掌握Java语言的程序设计方法,理论结合实际操作巩固我们所学的现有知识,使用图形用户界面和socket通信实现一个聊天程序,充分利用线程知识,实现用一个局域网聊天室,同时学会处理各种异常和io输入输出流的应用,学习运用多线程操作。
    聊天要以图形化界面的形式展现。可以实现聊天窗口的显示和关闭,同时可以载入客户输入的信息和读取输出的信息。在对话区域的右侧有滚动条,当该页面的面版满了,可以通过滚动条进行上拉和下拉。该对话区域可以实现多人同时进行聊天,也可以进行单人私聊。聊天内容前有显示是谁发送的消息,发送给谁等。
    先启动一个服务器,设置服务器端口,然后启动客户端,通过连接IP地址和连接客户端成功之后即可以登入客户。只要连接共同的IP地址和共同的端口即可以通过线程和服务器、客户端之间的联系实现单人与单人私聊,单人与多人的群聊。
    二 总体设计2.1 服务器端的建立服务器的功能是通过连接服务器端口实现客户端和服务器之间的的链接,当客户端成功连接到服务器端的时候,就新建一个Server_Thread线程,用于处理与客户端的通信,并启动该线程。显示一些信息,用户登录登出消息。
    2.2 客户端的建立客户端的功能是连接服务器之后,创建新客户ID,并能进行与其他用户聊天的聊天窗口。客户端会新建一个Client_Thread线程,用于客户端与服务器之间的通信,并启动线程。
    2.3 服务器端线程的建立服务端线程用于处理单个用户与其他用户进行通信,服务端线程一直处于运行状态,读取从客户端发来的消息,并对发来的消息类型进行处理,并将信息通过线程关系转发给不同的客户端。通过套接字跟迭代器遍历通知各线程用户上线,用户下线。
    2.4 客户端线程的建立客户端线程是当一个客户端建立时,客户端用于处理发送信息。当客户登入时并且输入信息该线程会读取客户写入的信息,同时更新在线客户列表实现客户的上线和下线的通知。
    2.5 程序模块划分局域网聊天程序包含以下几个模块:服务器端模块,服务器端线程模块,客户端模块和客户端线程模块。
    如下图所示:

    2.6 程序运行流程打开程序软件,要先打开服务器和客户端,在服务器上设置一些信息,然后再服务器界面上显示出来,然后服务器就处于等待客户端连接的状态,当客户端连接后,马上建立两条线程,然后就开始运行,实现通信,通信好后就结束程序。如下图所示:

    三 程序详细设计与实现3.1 程序中主要方法分析服务器端方法列表如下:



    方法名
    方法功能




    ChatServer( )
    创建服务器界面


    addWindowListener()
    用于关闭服务器窗口。


    connect()
    用于服务器和客户端的连接



    服务器线程方法列表如下:



    方法名
    方法功能




    run()
    用于实现用户上下线和聊天功能


    logout()
    方便起见给下线写的方法



    客户端方法列表如下:



    ChatClient()
    创建聊天界面,并连接到服务器




    setMonitorForSetIPJMenuItem();
    为设置ip项设置时间监听


    setMonitorForSetPortJMenuItem();
    为设置端口项设置事件监听


    setMonitorForAboutJMenuItem();
    为帮助项设置事件监听


    setMonitorForLogoutJButton();
    为登出项设置事件监听


    setMonitorForCurrentClientList();
    为当前用户列表设置事件监听


    setMonitorForSentJButton();
    为发送按钮就行事件监听


    loginButton.addActionListener(new Monitor());
    为登陆按钮设置监听


    keyPressed()
    为发送键设置的回车快捷键


    createJMenuBar()
    创建菜单栏



    客户端线程方法列表如下:



    方法名
    方法功能




    run()
    用于更新客户列表和输入和显示功能


    addDate()
    显示时间的功能



    3.2 程序实现3.2.1 服务器端ChatServer()
    该方法是服务器端ChatServer类的构造方法,继承了JFrame类,用于创建服务器界面,对窗口设置了滚动条和其规格,并设置了关闭服务器窗口的按钮。主要代码如下:
    public ChatServer() { this.setTitle("服务器"); Container container = this.getContentPane(); displayJTextArea = new JTextArea(); displayJTextArea.setEditable(false); JScrollPane jsp = new JScrollPane(displayJTextArea); jsp.setVerticalScrollBarPolicy (JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); container.add(jsp, BorderLayout.CENTER); this.setBounds(400, 150, 500, 350); this.setVisible(true); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); }
    connect()
    在服务器上记录服务器的一些信息:本机名、本机地址和本机监听的端口。服务器若一直开着,就会一直等待着,直到客户端的连接;客户端一旦连接成功,马上就会在服务器界面上显示连接客户的信息,然后同时会创建对应的线程,接下来就开始运行线程。主要代码如下:
    public void connect() { try { serverSocket = new ServerSocket(port); //记录服务器端的一些信息 displayJTextArea.append("本机名:" + InetAddress.getLocalHost().getHostName() + "\n"); displayJTextArea.append("本机地址:" + InetAddress.getLocalHost().getHostAddress() + "\n"); displayJTextArea.append("本机监听端口:" + port + "\n"); } catch (BindException e) { JOptionPane.showMessageDialog(null, "此端口已被占用,无法监听!", "提示", JOptionPane.WARNING_MESSAGE); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { } while (true) { try { socket = serverSocket.accept(); //等待客户端的连接 Date now = new Date(); SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd E kk:mm:ss"); displayJTextArea.append("\n" + f.format(now) + "\n"); displayJTextArea.append(socket.getInetAddress().getHostAddress() + " is connected" + "\n"); Server_Thread st = new Server_Thread(socket, threadList, displayJTextArea); //客户连接上,建立对应的线程 st.start(); } catch (IOException e) { e.printStackTrace(); } } }
    3.2.2 客户端ChatClient()
    该方法是客户端的构造方法,继承了JFrame类,用于创建客户端聊天界面,采用了GridBagLayout的布局,包含客户信息、在线客户列表、会话对象、聊天窗口等信息。对登陆、退出、发送和菜单等的按钮设置了监听。为方便起见,为发送按钮设置了回车的快捷键,且在聊天的界面进行了滚动条的设置。主要代码如下:
    public ChatClient() { this.setTitle("客户端"); Container container = this.getContentPane(); GridBagLayout layout = new GridBagLayout(); GridBagConstraints constraints = new GridBagConstraints(); constraints.fill = GridBagConstraints.BOTH; //组件随着所给区域可以进行扩展 container.setLayout(layout); createJMenuBar(); 。。。。。。 //中间省略语句为对界面的设置 this.setBounds(400, 100, 450, 500); this.setVisible(true); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent arg0) { System.exit(0); } }); setMonitorForSetIPJMenuItem(); //为设置ip项设置时间监听 setMonitorForSetPortJMenuItem(); //味设置端口项设置事件监听 setMonitorForAboutJMenuItem(); //为帮助项设置事件监听 setMonitorForLogoutJButton(); //为登出项设置事件监听 setMonitorForCurrentClientList(); //为当前用户列表设置事件监听 setMonitorForSentJButton(); //为发送按钮就行事件监听 loginButton.addActionListener(new Monitor()); //为登陆按钮设置监听 messageJTextField.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent e) { //为发送按钮设置的监听 if(e.getKeyChar() == KeyEvent.VK_ENTER) { sendMessage(); } } }); }
    关键方法
    public void setMonitorForSetIPJMenuItem(); // 用于为设置ip项设置时间监听public void setMonitorForSetPortJMenuItem(); //用于为设置端口项设置事件监听public void setMonitorForAboutJMenuItem(); //用于为帮助项设置事件监听public void setMonitorForLogoutJButton(); //用于为登出项设置事件监听public void setMonitorForCurrentClientList(); //用于为当前用户列表设置事件监听public void setMonitorForSentJButton(); //用于为发送按钮就行事件监听public void loginButton.addActionListener(new Monitor());//用于为登陆按钮设置监听public void messageJTextField.addKeyListener(new KeyAdapter() //用于给发送按钮设置回车快捷键
    3.2.3 服务器端线程run()
    迭代遍历,通过线程实现上线通知防止重名登入与消息的发送以及调用logout方法,选择回话对象。
    public void run() { while (true) { String msg = null; try { msg = reader.readLine(); if (msg.startsWith("login")) { loginName = msg.substring(msg.indexOf(':') + 1).trim(); if (! threadList.containsKey(loginName)) { writer.println(loginName + ": 登录成功!"); threadList.put(loginName, this); displayTextArea.append(loginName + " 进入聊天室 \n"); displayTextArea.setCaretPosition(displayTextArea. getText().length()); Iterator<Entry<String, Server_Thread>> it = threadList.entrySet().iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); Server_Thread st = (Server_Thread) entry.getValue(); if (st != this) { st.writer.println("用户上线:" + loginName); //通知各线程上线通知 writer.println("用户上线:" + st.loginName); //刷新自己的线程 } }} else { writer.println(loginName + " 已存在,请选择其他的用户名登录"); } } else if(msg.startsWith("logout")){ logout(); break; } else {String [] toClientNames; toClientNames = msg.substring(msg.indexOf('#') + 1).split("#"); String message = toClientNames[toClientNames.length - 1]; for (int i = 0; i < toClientNames.length - 1; i++) { Server_Thread st = threadList.get(toClientNames[i].trim()); st.writer.println(loginName + ": " + message); } writer.println(loginName + ": " + message); }} catch (IOException e) { logout(); break; } }}
    logout()
    迭代遍历信息,实现下线通知,删除套接字端口。
    public void logout() { Iterator it = threadList.entrySet().iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); Server_Thread st = (Server_Thread) entry.getValue(); if (st != this && st.isAlive()) { st.writer.println("用户下线:" + loginName); } } threadList.remove(loginName); if (socket != null) { try { socket.close(); }catch (IOException e1) { e1.printStackTrace(); }}
    3.2.4 客户端线程run()
    运行程序,实现对客户的登录,上线,下线以及对客户发送信息的读取,同时更新在线客户。
    public void run() { String s = null; while (true) { try { while((s = reader.readLine()) != null) { if (s.endsWith("登录成功!")) { addDate(); cc.displayTextArea.append(s + "\n"); cc.logoutJButton.setEnabled(true); cc.clientNameTextField.setEnabled(false); cc.loginButton.setEnabled(false); } else if (s.startsWith("用户上线:")) { String loginName = s.substring(s.indexOf(":") + 1); addDate(); cc.displayTextArea.append("客户:" + loginName + "上线 \n"); cc.displayTextArea.setCaretPosition(cc.displayTextArea.getText().length()); cc.currentClientList.add(loginName); continue; } else if (s.startsWith("用户下线:")) { String loginName = s.substring(s.indexOf(":") + 1); addDate(); cc.displayTextArea.append("客户:" + loginName + " 下线 \r\n");cc.displayTextArea.setCaretPosition(cc.displayTextArea.getText().length()); cc.currentClientList.remove(loginName); continue; } else { addDate(); cc.displayTextArea.append("客户" + s +"\n"); cc.displayTextArea.setCaretPosition(cc.displayTextArea.getText().length()); } } } catch (IOException e) { JOptionPane.showMessageDialog(null, "服务器异常!", "提示", JOptionPane.ERROR_MESSAGE); break; } } }
    addDate()
    显示日期,星期和时间.
    public void addDate() { Date now = new Date(); SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd E kk:mm:ss"); cc.displayTextArea.append("\n" + f.format(now) + "\n"); cc.displayTextArea.setCaretPosition(cc.displayTextArea.getText().length());}
    四 运行测试打开服务器,立即弹出设置端口的窗口,提示要设置端口

    当端口设置成功后,服务器显示一些信息

    打开客户端,弹出客户端的主界面

    用户注册新ID登陆显示

    在服务器主界面显示客户端上下线信息如下

    客户端界面显示在线客户列表及多用户聊天窗口
    5 评论 90 下载 2018-11-16 10:55:15 下载需要11点积分
  • 基于JAVA和MySQL的离散数学题库管理系统

    摘 要题库、试卷建设是教学活动的重要组成部分,传统手工编制的试卷经常出现内容雷同、知识点不合理以及笔误、印刷错误等情况。为了实现离散数学题库管理的信息化而开发了离散数学题库管理系统。
    该系统采用C/S 模式,前台采用JAVA(JBuilder2006),后台采用SQLServer2000数据库。本文详细论述了系统总体设计思想、数据库设计以及功能模块设计等。应用软件工程中的瀑布开发模型,开发实现了以下功能:题库的管理与维护、自动生成试卷、手工改动生成试卷、生成WORD试卷和答案。
    离散数学题库管理系统能够实现离散数学题库管理的信息化,规范化和试卷生成的自动化,并且在操作上实现简单、方便、快捷。
    关键词: 离散数学 题库 生成试卷
    第1章 系统结构特性设计本章主要介绍离散数学题库管理软件中后台数据库的结构设计。数据库结构设计是继需求分析和确定开发工具后的重要阶段,是管理型软件开发设计的核心和重要组成部分。数据库结构设计的好坏与否将对应用系统的运行效率以及实现的效果产生很大影响。科学、合理的数据库结构设计可以提高数据访问的速度,有效保持数据的完整性、一致性和共享性,因此数据库结构设计对系统设计来说至关重要。
    1.1 数据库概念模型根据系统的设计要求,设计了E-R图,实体为教师、课程、题库和试卷,关系为试卷抽题表。

    教师实体包含了教师编号、密码、教师姓名、住址、电话、手机、EMAIL、学历、职称和备注等属性。

    课程实体包含了课程编号、课程名、任课教师和备注等属性。

    题库实体包含了题号、课程编号、所属章节、试题内容、正确答案、分值、题型、难度系数、录入日期和备注等属性。

    试卷实体包含了试卷编号、试卷名称、课程编号、考试类型、出题教师号、试卷总分、组卷时间、和备注等属性。

    试卷抽题表关系包含了试卷编号、题目编号和备注属性。

    1.2 数据库逻辑设计在管理系统中,后台数据存储的地位相当重要合理的设计能缩减软件开发的周期和降低开发难度,并提高维护升级的可行性。而建立数据库最重要的一步是定义数据库表,数据是数据库中存储的基本对象,通过设计会以一定的组织结构存储在相关的基本表中。将基本信息分类、统计,根据数据库设计的基本原理,建立基本表构成数据库。在进行数据库的需求分析时,不但要考虑到软件系统当前要实现的功能,更要注重软件的可维护性和扩展性。
    首先将离散数学题库管理系统的数据库概念结构转化为SQL Server数据库系统所支持的实际数据模型,即:数据库的逻辑结构。创建离散数学题库管理系统中的各个数据库表。
    教师数据库表:用来记录教师的基本信息。该表的关键字字段是:教师编号。教师编号字段同时也是下面课程数据库表和试卷表的外键。



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




    教师编号
    VARCHAR
    20
    关键字,如:001


    密码
    VARCHAR
    10
    密码


    教师姓名
    VARCHAR
    20
    教师姓名


    住址
    VARCHAR
    200
    可以输入英文字符200,但是汉字只能输入100个


    电话
    VARCHAR
    15
    电话


    手机
    VARCHAR
    15
    手机


    EMAIL
    VARCHAR
    40
    EMAIL


    学历
    VARCHAR
    10
    学历


    职称
    VARCHAR
    10
    职称


    备注
    TEXT
    16
    备注



    课程数据库表:用来记录课程的基本信息,可用于存储多个课程,用于系统的扩展。该表的关键字字段是:课程编号,同时也是下面题库数据库表和试卷数据库表的外键。该表中的任课教师字段是外键,对应教师表的教师编号字段,表示该课程的任课教师。



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




    课程编号
    INT
    4
    关键字


    课程名
    VARCHAR
    30
    如:离散数学


    任课教师
    VARCHAR
    20
    外键,对应教师表的教师编号字段


    备注
    TEXT
    16
    备注



    题库数据库表:用来记录各门课程所对应的试题,是生成试卷提供试题来源。该表的关键字字段是:题号,用来唯一表示一道题目。该表中的课程编号是外键,对应课程数据库表的课程编号,表示该题目对应的是哪门课程。



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




    题号
    INT
    4
    关键字


    课程编号
    INT
    4
    外键,对应课程表的课程编号字段


    所属章节
    VARCHAR
    100
    此题所属课程的章节,比如第二章第三节,就是“2-3”


    试题内容
    TEXT
    16
    包括试题内容和四个选项内容


    正确答案
    TEXT
    16
    正确答案


    分值
    INT
    4
    题目的分数


    题型
    VARCHAR
    200
    选择题、填空题、简答题、计算题、证明题、其它


    难度系数
    DECIMAL
    5
    以往考试中该题答错人数 除以 总人数 得到的值,初次设置时根据教师的经验手动设置


    录入日期
    DATETIME
    8
    录入日期


    备注
    TEXT
    16
    备注



    试卷数据库表:记录了试卷的基本信息,用于生成试卷的标题。该表的主键字段是:试卷编号。该表中的课程编号是外键,对应课程数据库表的课程编号,表示该试卷对应的是哪门课程。



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




    试卷编号
    INT
    4
    主键


    试卷名称
    VARCHAR
    200
    试卷名称


    课程编号
    INT
    4
    外键,对应课程表的课程编号字段


    考试类型
    VARCHAR
    20
    单元测试、期中考试、期末考试以及补考等类型


    出题教师号
    VARCHAR
    200
    一人或多人 出题人默认为当前生成试卷的操作员的号。多人情况时,教师的编号如:1,2,3 表示 由1号和2号和3号老师同时出题


    试卷总分
    INT
    4
    用户设定的试卷总分


    组卷时间
    DATETIME
    8
    组卷时间


    备注
    TEXT
    16
    备注



    试卷抽题表:用来记录每张试卷对应的试题,是生成WORD文件的数据来源。该表的主键字段是:试卷编号和题目编号。这两个字段同时也是外键,分别对应试卷表的试卷编号字段和题库表中的题号字段。



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




    试卷编号
    INT
    4
    主键,同时也是外键,对应试卷表的试卷编号字段。


    题目编号
    INT
    4
    主键,同时也是外键,对应题库表中的题号字段。


    备注
    TEXT
    16
    备注



    第2章 系统行为特性设计2.1 软件结构设计本系统共分3个大功能模块。如图:

    上图即为总体的功能模块图,它清晰的显示了系统的各个模块的分布。教师登陆模块是用来验证用户是否为系统的合法用户,题库的管理与维护模块完成对题目的录入、删除、修改和查询。生成试卷模块完成根据用户输入的生成试卷要求,自动生成试卷,维护已经生成的试卷和生成WORD试卷和参考答案。
    2.2 功能子模块设计下面将详细描述每个子模块的详细设计。
    2.2.1 教师登录模块2.2.1.1 界面设计此界面为教师登录界面,在用户登录时检查用户名和密码是否有填写,如果未填写则提示并返回,检查通过之后把数据提交给服务器,打开数据库检查用户填写的信息是否正确,登录名称、密码是否相符合,若符合管理员登录信息则登录成功,进入主界面。此模块用于验证用户的信息,保证了系统内部资料的安全性。

    2.2.1.2 模块内主要算法的描述
    2.2.1.3 该模块的JAVA类设计实现该模块的JAVA类为:ui.LoginFrame和app.DBAccess类
    ui.LoginFrame类
    该类用于显示教师登陆窗口,并且负责判断用户输入的用户名密码是否正确。
    主要方法介绍:

    okButton_actionPerformed(ActionEvent e):该方法在用户点击确定按钮时被调用,取得界面上输入的用户名和密码,如果用户名或者密码不正确,则提示用户重新输入。若用户为系统合法用户,则允许用户登陆系统,打开系统主界面
    app.DBAccess类
    该类为底层数据库操作类。实现基本的数据库操作,如插入,删除,修改。
    主要方法介绍:

    getConnection():用于返回一个JDBC数据库连接(Connection)对象
    executeUpdate(Connection conn, Stringsql):执行insert、delete和update语句。对数据库表进行插入删除和更新
    executeQuery(Connection dbCon, StringquerySQL ):根据给定的sql语句,进行查询,返回DefaultTableModel对象

    2.2.2 题库的管理与维护模块2.2.2.1 界面设计此界面是题库的维护界面,是对试题的基本信息进行录入,删除和更改。
    若要添加试题,先点击添加按钮,然后在上面的试题信息部分填入试题的内容,填写好后,点击保存按钮即可将试题保存到数据库。若要修改试题,在下面的表格中选择要修改的试题,修改上面的试题内容,然后点击保存按钮即可将修改后的试题保存到数据库。若要删除试题,在下面的表格中选择要删除的试题,然后点击删除按钮,如果确认删除,系统将会把指定的试题删除。

    2.2.2.2 模块内主要算法的描述
    2.2.2.3 该模块的JAVA类设计实现该模块的JAVA类为:ui.AddTestDialog类和app.TestLibraryHandler类
    ui.AddTestDialog类
    该类负责显示题库维护窗口和响应用户的各种操作。
    主要方法介绍:

    addjButton2_actionPerformed(ActionEvente):该方法用于处理添加试题请求。首先将题库记录集(QueryDataSet)移动到最后一行,然后插入一条新记录
    deletejButton2_actionPerformed(ActionEvente):该方法用于处理删除试题请求。内部实现时首先判断用户是否选中了一条记录,若没有选中则不能删除试题,提示错误消息。然后询问用户是否确认删除,若确认删除则删除选中的试题
    savejButton1_actionPerformed(ActionEvente):该方法用于处理保存数据请求,当用户修改或者插入了一条数据后,需要点击保存按钮,也就是调用该方法,插入或者修改结果才能插入到数据库中

    app.TestLibraryHandler类
    该类主要用于处理添加试题相关的数据库操作,与界面类一起实现题库的维护和查询功能。
    主要方法介绍:

    String[] getAllCourseNames():该方法用于返回课程表的所有课程名,这个方法在添加试题和查询试题窗口中被使用
    addCourseNameItems( JComboBoxcourseNamejdbComboBox1 ):该方法用于给课程名称控件添加课程名称项。在显示添加试题和查询试题窗口时,需要先调用这个方法,将所有的课程名添加到课程名下拉框中
    getCourseIdByName( String courseName ):该方法用于根据课程名取得课程编号,在添加试题到数据库中时被调用。因为用户操作界面上输入的是课程名,而题库数据库表中保存的是课程编号,所以需要调用该方法进行转换

    2.2.3 试题查询模块2.2.3.1 界面设计此界面是试题的查询界面,该功能允许用户试题的查询条件,进行查询试题操作。该功能可用于手工改动现有试卷模块。

    2.2.3.2 模块内主要算法的描述
    2.2.3.3 该模块的JAVA类设计实现该模块的JAVA类为:ui.QueryTestDialog类
    ui.QueryTestDialog类
    该类用于实现查询已有题目功能,负责显示查询试卷对话框。
    主要方法介绍:

    okjButton1_actionPerformed(ActionEvente):该方法在提交查询按钮被点击时被调用。内部实现时,首先取得所有用户输入的查询条件,生成查询用的SQL语句。然后利用JBuilder自带的DbExpress类库中的QueryDataSet类实现用户的查询操作
    2.2.4 自动生成试卷模块2.2.4.1 界面设计此界面是自动生成试卷界面。教师在上面输入试卷的基本信息,在下面抽取试题选项中设置试题要抽取的章节,题型,与往年试卷雷同度的最大值,平均难度系数的最大值。
    其中雷同度的计算方法为:两张试卷相同的题目的数量*2 / 两张试卷总的题目数。平均难度系数的计算方法为:所有试题的难度系数的和 / 试题的总数。

    2.2.4.2 模块内主要算法的描述
    该模块为系统的核心业务模块,考虑了三年内不能出现重复的题目,与往年试卷的雷同度和试卷的平均难度。首先,统计今年,去年,和前年的试卷中包含的题目题号,这些题目号将不能用于这次的试题抽取(三年内不能出现重复的题目)。然后根据上步的结果、选中的课程名、设置的题型和章节选项执行查询,先按照章节排序,再按照题型排序,查询出的试题可以用于此次试卷的生成。
    然后按照设定的试卷总分进行循环,当抽取试题的总分不大于设定的总分,并且仍有题目可抽取时,根据查询结果的数量,生成一个随机数,抽取一道题目加到已抽取试题列表中,将该试题的分数累加到抽取试题的总分上,将该试题从待抽取列表中去掉。这样循环下去,当退出循环的时候,已抽取试题列表中已经包含了一些题目,满足了试卷总分设定要求。
    然后按照设定的最大雷同度进行循环,首先将已抽取试题列表中的试题题号与往年试卷中的题号相比较,计算出雷同度,找出往年试卷中雷同度最高的试卷。判断雷同度是否超过设定值,若超过设定值,并且仍有试题可抽取,则去掉一道与雷同度最高试卷中的雷同试题,另外抽取一道与去掉的题目题型相同并且在雷同度最高试卷中没有的题目。这样循环下去,当退出循环的时候,已抽取试题列表中的题目即会满足试卷最大雷同度设定要求,或者由于题库中试题有限,待抽取试题列表已经没有试题了。
    然后按照设定的最大平均难度系数进行循环,首先计算已生成试卷的平均难度,若难度超过设定值,并且仍有试题可抽取,则去掉一道难度超过平均值的题目,抽取另一道同类型题目。这样循环下去,当退出循环的时候,已抽取试题列表中的题目即会满足试卷最大平均难度系数设定要求,或者由于题库中试题有限,待抽取试题列表已经没有试题了。

    2.2.4.3 该模块的JAVA类设计实现该模块的JAVA类为:ui.GeneratePaperDialog类,app. MsWordHandler类和app. TestPaperHandler类
    ui.GeneratePaperDialog类
    该类用于实现自动生成试卷功能,并且负责显示自动生成试卷对话框。
    主要方法介绍:

    initUnitTree(Connection connection):该方法用于初始化表示章节的树(查询出题库表的所有章节,按照章节顺序显示),在自动生成试卷对话框初始化的时候会调用该方法,将界面中的章节树初始化(填充章节的信息)
    addUnitButton_actionPerformed(ActionEvente):该方法用于将左侧章节树中选择的章节添加到界面右侧的章节选择列表中。右侧的章节选择列表是指最后生成的试卷涵盖的章节列表
    deleteUnitButton_actionPerformed(ActionEvente):该方法用于将用户在右侧的章节选择列表中选择的项删除
    genPaperButton_actionPerformed(ActionEvente):该方法用于根据界面上输入的生成试卷条件和试卷基本信息,自动生成试卷,并且将试题和参考答案输出到WORD文件中

    app. MsWordHandler类
    该类是操作WORD文件的类,包含WORD文件的基本操作方法。
    主要方法介绍:

    MsWordHandler():构造函数。初始化 WORD应用程序,新建一个WORD文档
    insertParagraph(…):向WORD中添加一个新的段落。该方法有5个参数,分别为aParagraph,表示段落的内容;fontName表示段落的字体;isBold表示是否设定为黑体;isItalic表示是否设定为斜体;fontSize表示字体的大小
    该类还有其他一些方法,比如添加试卷的标题,添加一道大题,添加一道题目等方法,这些方法都通过调用insertParagraph(…)方法实现。在这里就不仔细讲解了

    app. TestPaperHandler类
    该类将已抽取的试题列表生成WORD文档。
    主要方法介绍:

    genWordPaper(…):根据抽取的试题,生成WORD文件。该方法共有4个参数,selectedTestItems表示已抽取的试题列表;paperTitle表示试卷标题;courseName表示课程名称;testStyle表示测试类型。该方法的具体实现:首先弹出保存文件框,让用户选择保存位置;然后计算出已抽取的试题的总分,用于WORD文件输出;然后利用循环,将选择的题目输出到WORD文件中
    addSpecifiedTestToWord(…):将指定的题型的题目添加到 WORD 文件中。调用MsWordHandler类具体实现
    addSpecifiedAnswerToWord(…):将指定的题型的题目答案添加到 WORD文件中。调用MsWordHandler类具体实现

    2.2.5 手工改动现有试卷模块2.2.5.1 界面设计此界面是手工改动现有试卷界面,在该界面中可以对试卷的基本信息进行修改,同时也可以打开试题查询界面,将试题手动添加到选中的试卷中。

    2.2.5.2 模块内主要算法的描述
    2.2.5.3 该模块的JAVA类设计实现该模块的JAVA类为:ui. MaintainPaperDialog类
    ui. MaintainPaperDialog类
    该类实现对已生成试卷进行维护的功能,负责显示维护已生成试卷对话框。
    主要方法介绍:

    deleteButton_actionPerformed(ActionEvente):该方法用于从试卷中删除一道题,实现对试卷中题目的手工删除
    addButton_actionPerformed(ActionEvente):该方法用于添加一道题到试卷中,实现对试卷中题目的手工添加。内部实现时首先打开查询试题界面,查询到想要的试题后,点击界面上的“添加该试题”按钮,即可将试题添加到试卷中
    saveButton_actionPerformed(ActionEvente):该方法用于保存试卷的基本信息
    genWordPaperButton_actionPerformed(ActionEvente):该方法用于将选中的试卷生成WORD试卷文件

    参考文献[1] Satyaraj Pantham,黄晓鸣,武清译. 深入学习:JFC Swing—Java基础类组件[M]. 北京:电子工业出版社
    [2] 萨师煊,王珊 . 数据库系统概论(第三版)[M]. 北京:高等教育出版社
    [3] 张洪斌. Java程序设计百事通[M]. 北京:清华大学出版社
    [4] 飞思科技产品研发中心. 精通JBuilder 9 [M]. 北京:电子工业出版社
    1 评论 89 下载 2018-12-27 08:47:03 下载需要16点积分
  • 基于JAVA WEB的计算机网络课程在线考试系统的设计与实现

    摘 要本系统基于B/S结构的模式开发,通过网络给广大用户提供了比较可靠、方便、快捷的在线测评平台,系统主要实现了自动抽取试题、人工出题、套题选择、自动阅卷计分、在线测试、用户信息管理、成绩存档、错题管理等功能。用户利用浏览器可以直接访问本平台,通过选择要考的套题进行测试,测试结束后系统自动为用户判卷得出测试成绩,并显示出测试中错题和相应的答案解析,使得用户非常方便完成一次计算机网络课程的在线测评。
    关键词:B/S模式;在线测试;计算机网络;
    AbstractThe system uses B/S structure of the model development, through the network to provide customers with a more reliable, convenient and fast online evaluation platform, system is mainly to achieve the automatic extraction questions, artificial out of question, sets of questions selected, automatic scoring line in mind when testing, user information management, performance archiving, error management and other functions. users can use the browser to directly access the platform, by selecting a set of questions to test, after testing the system automatically for the user graders test results obtained, and shows the test wrong questions and corresponding answers to resolve, allows users to easily complete a computer network courses online evaluation.
    Key words: B/S mode; Online Testing; Computer Network;
    1 引言1.1 研究背景计算机网络技术的飞速发展以及计算机技术的发展及计算机的日益普及,现在很多国内外的大学和社会其他部门都已经开设了远程教育,通过计算机网络实现异地教育和培训,从而为在线测评系统发展提供了坚实的基础。相对于传统的笔试,网络在线测评系统集测试、评卷、成绩统计、查看错题等为一体,突破了时间与空间的限制,使得用户在任意时刻、任意地点,只要在有网的情况,均可以完成一次测评,这不仅节省了资源,而且提高了评分的客观性、公正性和准确度,大大改善了平时考试和测试的效率。
    1.2 国内外研究现状1977年Lord经过大量的研究,提出了现代测试理论,他发现由多选题组成的计算机辅助考试,与传统的纸质考试两种不同的考试形式对测试的人来说没有特别显著的差异。而BiNET做了一个有关于自适应考试的研究,研究的内容是智力测试。到了1960年,一些学者认为如果对课间的考试采用CAT可能会更加的好。
    随着时间的发展,1996年底,国外渐渐的出现网络教学的系统和平台,像英国的OPEN COOLEGE、美国的NTU这些都是十分典型的例子。在英国的Derby大学运用网络教育的力量成功完成了以色列的本科教育;上海电视大学与澳大利亚昆士兰大学合作完成了在上海开设本科学历的教育课程。
    国内的的网上测评技术的研究与西方国家相比相对要晚一些,我国在1995年首条连通所有的计算机互联网CERNET才正式投入使用。虽然起步比较晚,但在网络远程教育方面发展的相当迅猛。北京大学、清华大学、华南理工大学、上海复旦大学、河北大学、北京医科大学、湖南大学这些高等学校都已经在自己的网站上设立了自己的测评系统。很多公司都非常热情的和高校合作开办网络教育的课程。在中国知名度最高的清华大学也在网上举办了计算机网上硕士研究生的教育,全国各地纷纷上网咨询,报名人数更是达到了上万。
    2 设计方法研究概述2.1 可行性研究2.1.1 经济可行性分析主要是对项目的经济效益进行评价,利用计算机来实现网上测试以成为适应当今教学管理的方式。开发一套能满足网上测评系统的软件是十分必要的,实现试卷管理和试卷生成自动化,在减少由于认为失误而造成损失的同时,也可以使参加测试的人快速的找出自己的薄弱知识点。本系统在经济上是可以接受的,并且本系统实施后可以显著提高测试效率,有助于提高个人的知识的学习。所以本系统在经济上是可行的。
    2.2.2 技术可行性分析软件方面:网络化测试只需要一个web浏览器即可,用户便能通过浏览器访问到测试平台,在数据库方面有Oracle,它能存储海量数据,并且对数据能够进行优化,其易用性、灵活性、安全性为数据库的开发和存储为开发创造了比较好的条件,所以在软件方面完全具有可行性。硬件方面:随着科学技术的发展,硬件发展速度突飞猛进,如今的硬件设备完全能满足系统在硬件方面的需求。
    2.2 系统开发技术系统设计基于B/S结构体系,前台采用JSP和JavaScript技术,后台运用目前主流的三层架构,数据库为ORACLE,开发工具是My Eclipse 8.5,服务器是Tomcat。
    2.2.1 B/S模式B/S(Browser/Server,浏览器/服务器)模式又称B/S结构。它是随着Internet技术的兴起,对C/S模式应用的扩展。B/S模式维护运行都比较简便,能实现从不同的地点,不同的人员,以不同的接入方式访问和操作共同的数据;但它最大的缺点是对网络的依赖性太强,这导致在没有网络的情况下是没有办法访问和操作数据。
    随着www和Internet的流行,以往的C/S模式完全无法满足全球网络互连、开放、信心共享的要求,就在此时B/S模式(浏览器/服务器)渐渐出现,它最大的特点是用户可以通过自己本机的浏览器去访问Internet上的数据、图像、动画、文本、视频点播和声音信息,这些信息都是从许多个web服务器应运而生,然而Web服务器可以通过各种各样的方式与数据服务器相连,一般数据库中都存着海量的数据。客户端除了WWW浏览器,一般无须任何用户程序,只需从Web服务器上下载程序到本地来执行,在下载过程中若遇到与数据库有关的指令,由Web服务器交给数据库服务器来解释执行,并返回给Web服务器,Web服务器又返回给用户。在这种结构中,将许许多多的网连接到一块,形成一个巨大的网,即全球网。而各个企业可以在此结构的基础上建立自己的Intranet。
    2.2.2 JSP技术JSP网页是由传统网页HTML文件中加入JSP标记和Java程序段构成。JSP(Java Server Page)是由Sun公司提出、多个互联网公司一起参与合作而建立的一种动态网页开发技术的标准。JSP规范是中间件应用服务器、Web服务器、交易系统以及软件开发工具厂商间广泛合作的成果,这种技术为创建一个动态的Web网页提供了非常方便的方法。JSP的设计目的是Web应用系统的构造变得更加方便、容易、快捷,而这些应用程序可以和各种中间件应用服务器、Web服务器、浏览器和各种开发工具协同工作。
    JSP继承了Java很多优点,用JSP开发动态网站十分方便,开发效率高。此外,JSP还具有强大的组件(Java Bean)支持此功能,可以方便地实现组件复用,进一步提高了开发效率。
    2.2.3 Oracle数据库Oracle是由美国甲骨文公司开发的一款数据库产品,它具有很多的优点,功能也非常强大,这导致Oracle受到了很多企业家的青睐,在系统开发中应用非常广泛。Oracle数据库的存储结构分为逻辑存储结构和物理存储结构,逻辑存储结构是用于描述Oracle内部组织和管理数据的方式;物理存储结构是用于描述Oracle外部即操作系统中组织和管理数据的方式。
    在启动Oracle数据库服务器时,实际上是在服务器的内存中创建一个Oracle实例(即在服务器内存中分配共享内存并创建相关的后台内存),然后由这个实例来访问和控制磁盘中的数据文件。Oracle有一个很大的内存快,成为全局区(SGA)。
    Oracle数据库始终保持一定数量的服务器进程,用户的请求首先被连接到一个称为“调度程序”的特殊服务进程,然后由调度程序为用户分配一个服务器进程为其提供服务。这意味着只需要使用很少的服务器进程,便可以为多个用户进程提供服务。
    2.2.4 自动生成试卷技术自动生成试卷的关键在于随机抽取试题,并保证抽取的试题不能重复,但是在数据库中如果不断频繁的抽取试题又显得效率比较低,所以问题的核心在于随机、不重复、高效,实现此技术主要有两种方法。
    第一种是利用java中随机函数,抽取出符合要求的试题,但为了保证抽取试题不重复,可以给每一道试题在数据库中加入一个mark字段,在抽取的过程中,如果该试题被抽取到,则将该试题的mark字段置为1,这样我们每抽取一次都会先判断这道试题的mark字段是否为1,如果为1,那么本次抽取无效进入下一次随机,否则抽取有效。这种方式需要在数据库中加入一个mark字段,并且每次随机时都需要判断mark字段的值,显得比较笨重,因此系统采用的是第二种方法。
    第二种方法更为可靠、高效、复杂,该算法主要分为三个步骤:第一步是得到随机抽取试题总数和题库中试题总数,然后生成一个1到题库试题总数的阵列,阵列模型可以由程序中数组构造;第二步是生成随机数将阵列打乱;第三步是根据要求抽取试题数,如果题库中试题总数为10题,需要抽取5题,那么最后结果为取打乱后阵列的前5个即可满足要求。
    第一步:生成1到题库总数阵列(假如题库中有十道试题)如表2-1所示。



    A1
    A2
    A3
    A4
    A5
    A6
    A7
    A8
    A9
    A10




    1
    2
    3
    4
    5
    6
    7
    8
    9
    10



    第二步:生成两个随机数,如3和6,此时交换索引为3和6中的内容,交换后阵列如表2-2所示。



    A1
    A2
    A3
    A4
    A5
    A6
    A7
    A8
    A9
    A10




    1
    2
    6
    4
    5
    3
    7
    8
    9
    10



    第三步:不断重复第二步就可以将阵列打乱,如果需要抽取的试题数为5,那么此时可以取(1,2,6,4,5),最后根据这些题号在数据库中进行相应查询即可。
    2.2.5 简答题批阅算法网络在线测试是很难实现主观题精准的批阅,因为在传统的人工阅卷过程中,不同的人批阅的结果也会不一致,用系统就更难实现了,这也是技术上的一大瓶颈。
    本系统实现了简答题批阅算法,算法的思想主要是计算两个字符串之间的Levenshtein 距离,Levenshtein 距离又称编辑距离,指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数,编辑操作包括插入、删除、替换操作,编辑距离的算法是首先由俄国科学家Levenshtein提出的,故又叫Levenshtein Distance。举个简单的例子,现在比较字符串abc和abe之间的差异,算法的实现步骤如下:
    将字符串想象成下表2-3的结构。A处 是一个标记,为了方便讲解,不是这个表的内容。




    abc
    a
    b
    c




    abe
    0
    1
    2
    3


    a
    1
    A处




    b
    2





    e
    3





    计算A处的值。它的值取决于:左边的1、上边的1、左上角的0,按照Levenshtein distance的意思:上面的值和左面的值都要求加1,这样得到都是2。A处,由于是两个a相同,左上角的值加0.这样得到0+0=0,最后算出三个值,左边计算后为2,上边计算后为2,左上角计算为0,所以A处取他们里面最小的0,可用一个公式表示A处的值:min{左边值+1,上边值+1,(0,1)}。
    计算出A处值后,变成如下表2-4。B处的值根据第二步得到。




    abc
    a
    b
    c




    abe
    0
    1
    2
    3


    a
    1
    0




    b
    2
    B处




    e
    3





    依次类推得到填写完整表如下表2-5所示。




    abc
    a
    b
    c




    abe
    0
    1
    2
    3


    a
    1
    A处0
    D处1
    G处2


    b
    2
    B处1
    E处0
    H处1


    e
    3
    C处2
    F处1
    I处1



    计算相似度。先取两个字符串长度的最大值(maxlength),操作数记为A,那么两个字符串之间的相似度可表示为:1-(A/maxLength),最后得出abc和abe之间的相似度为0.666。
    现在要解决的问题是将这种思想如何用程序实现,那么需要将二维表格在程序中表示出来,解决方案是用二维数组表示上面所示二维表,通过双层for循环和一定的算法可以计算出两个字符串的距离,这样就可以比较两个字符串之间的相似度。
    3 系统的设计与实现3.1 系统功能需求分析3.1.1 功能描述
    系统角色分为:管理员、用户
    管理员输入用户名和密码登入系统
    管理员登入系统后,可以对用户基本信息进行增删改查操作
    管理员登入系统后,可以对题库进行增删改查
    管理员登入系统后,按照一定的步骤手动生成试卷,并且可以对试卷进行增删改查
    管理员登入系统后,可以对某个试卷进行授权操作
    用户注册个人信息
    输入用户名和密码登入系统
    用户登入系统后,可以对个人信息进行修改
    用户登入系统后,可以选择某一套试题进行测试
    用户登入系统后,测试完成一套试题,可以查看此套试题成绩
    用户登入系统后,测试完成一套试题,可以查看此套试题成绩排名
    用户登入系统后,测试完成一套试题,可以查看此套试题错题

    3.1.2 参与者用例图管理员用例图如图3-1所示。

    用户用例主要包括注册、登录、修改个人信息、在线测试、查看成绩、查看错题、查看排名等。用户用例图如图3-2所示。

    3.2 系统流程图本系统拥有管理员和用户两种角色,管理员登录系统后能够进行用户信息管理、题库管理、试卷管理、考试管理;用户登录后可以进行测试信息管理、成绩管理、我的测试管理、个人信息管理。系统整体结构图如图3-3所示。

    管理员登录系统后,点击用户管理系统会查出所有的用户信息,管理员可以添加用户,也可以选中一条用户信息后,对该信息进行查看详情、删除、修改等操作。用户信息管理流程图如图3-4所示。

    管理员可以对单选题、多选题、填空题、判断题、简答题进行添加,添加之前需进行题目重复验证避免相同的题目产生。管理员添加试题流程图如图3-5所示。

    管理员手动生成试卷包括很多个步骤,首先需要填写试卷的基本信息,然后点击下一步添加各个题型的题目,题目需要管理员手动添加。管理员生成试卷流程图如图3-6所示。

    添加完一套试卷后,用户是不能直接在网上进行测评的,需要管理员选中试卷点击授权,那么此套试卷才可以在网上进行测试,点击查看详情可以查看试卷的一些基本信息。管理员试卷授权流程图如图3-7所示。

    用户登录系统后,可以选中某一试卷进行测试,测试完成后点击提交,系统会根据用户答题情况来给定分数,系统实现了简答题批阅算法,所以用户测试完一套试卷后是全自动化批阅试卷的过程。用户在线测试流程图如图3-8所示。

    当用户测试完一套试题后,点击最新成绩查询,界面上会显示出用户最近一次测试的成绩,点击历史成绩查询会将用户以前参加的所有试题都罗列出来,用户也可以选择某套试卷点击查看错题,系统会显示出这套试卷的错题信息给用户参考。用户查看成绩以及错题流程图如图3-9所示。

    3.3 系统数据分析3.3.1 数据实体图用户实体包括用户Id、用户名、密码信息。用户登陆实体如图3-10所示。

    单选题实体包括单选题主键、单选题编号、单选题题目、A选项、B选项、C选项、D选项、答案、答案解析。单选题实体如图3-11所示。

    多选题试题包括多选题主键、多选题编号、多选题题目、A选项、B选项、C选项、D选项、E选项、答案、答案解析。多选题实体图如图3-12所示。

    判断题实体包括判断题主键、判断题编号、判断题题目、判断题答案、答案解析。判断题实体图如图3-13所示。

    填空题实体包括填空题主键、填空题题目、填空题编号、填空题答案、填空题答案解析。填空题实体图如图3-14所示。

    简答题实体包括主键、简答题题目、简答题编号、简答题答案、简答题答案解析。简答题实体图如图3-15所示。

    试卷实体包括试卷主键、试卷编号、试卷题目、单择题编号集、多选题编号集、填空题编号集、判断题编号集、简答题编号集。试卷实体图如图3-16所示。

    3.3.2 数据表数据库表设计在整个软件开发过程中起着至关重要的作用,一个优秀的数据库设计可以大大简化开发,提高开发效率。本系统数据库设计共13张表,下面用二维表格一一进行描述。
    用户表t_user



    列名
    中文含义
    数据类型
    空值
    注释




    [id]
    Id
    Number
    N
    主键


    [username]
    用户名
    Varchar2(30)
    N
    唯一


    [password]
    密码
    Varchar2(30)
    N



    用户信息表t_student



    列名
    中文含义
    数据类型
    空值
    注释




    [id]
    Id
    Number
    N
    主键


    [stu_id]
    用户登录名
    Varchar2(30)
    N
    外键


    [stu_name]
    用户姓名
    Varchar2(50)
    Y



    [stu_sex]
    用户性别
    Varchar2(20)
    Y



    [stu_qq]
    用户QQ
    Varchar2(20)
    Y



    单选题表t_choice



    列名
    中文含义
    数据类型
    空值
    注释




    [id]
    Id
    Number
    N
    主键


    [choice_num]
    单选题编号
    Number
    N
    唯一


    [choice_ques]
    单选题题目
    Varchar2(50)
    N



    [a]
    A选项
    Varchar2(50)
    N



    [b]
    B选项
    Varchar2(50)
    N



    [c]
    C选项
    Varchar2(50)
    N



    [d]
    D选项
    Varchar2(50)
    N



    [choice_ans]
    单选题答案
    Varchar2(5)
    N



    [answer_anlysis]
    答案解析
    Varchar2(50)
    N



    多选题表t_multi_choice



    列名
    中文含义
    数据类型
    空值
    注释




    [id]
    Id
    Number
    N
    主键


    [mc_num]
    多选题编号
    Number
    N
    唯一


    [mc_ques]
    多选题题目
    Varchar2(50)
    N



    [a]
    A选项
    Varchar2(50)
    N



    [b]
    B选项
    Varchar2(50)
    N



    [c]
    C选项
    Varchar2(50)
    N



    [d]
    D选项
    Varchar2(50)
    N



    [e]
    E选项
    Varchar2(50)
    N



    [mc_ans]
    多选题答案
    Varchar2(5)
    N



    [answer_anlysis]
    答案解析
    Varchar2(50)
    N



    判断题表t_tfng



    列名
    中文含义
    数据类型
    空值
    注释




    [id]
    Id
    Number
    N
    主键


    [tfng_num]
    判断题编号
    Number
    N
    唯一


    [tfng_ques]
    判断题题目
    Varchar2(50)
    N



    [tfng_ans]
    判断题答案
    Varchar2(50)
    N



    [answer_anlysis]
    判断题答案解析
    Varchar2(50)
    N



    填空题表t_completion



    列名
    中文含义
    数据类型
    空值
    注释




    [id]
    Id
    Number
    N
    主键


    [completion_num]
    填空题编号
    Number
    N
    唯一


    [completion _ques]
    填空题题目
    Varchar2(50)
    N



    [completion _ans]
    填空题答案
    Varchar2(50)
    N



    [answer_anlysis]
    填空题答案解析
    Varchar2(50)
    N



    简答题表t_short_answer



    列名
    中文含义
    数据类型
    空值
    注释




    [id]
    Id
    Number
    N
    主键


    [sa_num]
    简答题编号
    Number
    N
    唯一


    [sa _ques]
    简答题题目
    Varchar2(50)
    N



    [sa _ans]
    简答题答案
    Varchar2(50)
    N



    [answer_anlysis]
    简答题答案解析
    Varchar2(50)
    N



    试卷表t_paper



    列名
    中文含义
    数据类型
    空值
    注释




    [id]
    Id
    Number
    N
    主键


    [paper_num]
    试卷编号
    Number
    N
    唯一


    [paper_name]
    试卷名称
    Varchar2(50)
    N



    [dx_num]
    单选题集
    Varchar2(50)
    N



    [mul_num]
    多选题集
    Varchar2(50)
    N



    [pd_num]
    判断题集
    Varchar2(50)
    N



    [tk_num]
    填空题集
    Varchar2(50)
    N



    [sa_num]
    简答题集
    Varchar2(50)
    N



    试卷信息表t_paper_info



    列名
    中文含义
    数据类型
    空值
    注释




    [id]
    Id
    Number
    N
    主键


    [paper_num]
    试卷编号
    Number
    N
    外键


    [dx_num]
    单选题个数
    Number
    N



    [dx_value]
    单选题分值
    Number
    N



    [mul_num]
    多选题个数
    Number
    N



    [mul_value]
    多选题分值
    Number
    N



    [pd_num]
    判断题个数
    Number
    N



    [pd_value]
    判断题分值
    Number
    N



    [tk_num]
    填空题个数
    Number
    N



    [tk_value]
    填空题分值
    Number
    N



    [sa_num]
    简答题个数
    Number
    N



    [sa_value]
    简答题分值
    Number
    N



    [total_time]
    总时间
    Number
    N



    [total_value]
    总分
    Number
    N



    [user_times]
    使用次数
    Number
    N



    [status]
    是否授权
    Number
    N



    标准答案表t_stanswer



    列名
    中文含义
    数据类型
    空值
    注释




    [id]
    Id
    Number
    N
    主键


    [paper_num]
    试卷编号
    Number
    N
    外键


    [dx_answer]
    单选题答案
    Varchar2(50)
    N



    [mul_answer]
    多选题答案
    Varchar2(50)
    N



    [pd_answer]
    判断题答案
    Varchar2(50)
    N



    [tk_answer]
    填空题答案
    Varchar2(50)
    N



    [sa_ answer]
    简答题答案
    Varchar2(50)
    N



    答卷表t_answer



    列名
    中文含义
    数据类型
    空值
    注释




    [id]
    Id
    Number
    N
    主键


    [paper_num]
    试卷编号
    Number
    N
    外键


    [stu_id]
    用户id
    Varchar2(30)
    N
    外键


    [dx_answer]
    单选题答案
    Varchar2(50)
    N



    [mul_answer]
    多选题答案
    Varchar2(50)
    N



    [pd_answer]
    判断题答案
    Varchar2(50)
    N



    [tk_answer]
    填空题答案
    Varchar2(50)
    N



    [sa_ answer]
    简答题答案
    Varchar2(50)
    N



    成绩表t_grade



    列名
    中文含义
    数据类型
    空值
    注释




    [id]
    Id
    Number
    N
    主键


    [paper_num]
    试卷编号
    Number
    N
    外键


    [stu_id]
    用户id
    Varchar2(30)
    N
    外键


    [dx_value]
    单选题得分
    Number
    N



    [mul_value]
    多选题得分
    Number
    N



    [pd_value]
    判断题得分
    Number
    N



    [tk_value]
    填空题得分
    Number
    N



    [sa_ value]
    简答题得分
    Number
    N



    [total]
    总分
    Number
    N



    错题表t_error



    列名
    中文含义
    数据类型
    空值
    注释




    [id]
    Id
    Number
    N
    主键


    [paper_num]
    试卷编号
    Number
    N
    外键


    [stu_id]
    用户id
    Varchar2(30)
    N
    外键


    [dx_answer]
    单选题错题集
    Varchar2(50)
    N



    [mul_answer]
    多选题错题集
    Varchar2(50)
    N



    [pd_answer]
    判断题错题集
    Varchar2(50)
    N



    [tk_answer]
    填空题错题集
    Varchar2(50)
    N



    [sa_ answer]
    简答题错题集
    Varchar2(50)
    N



    3.4 系统模块实现3.4.1 注册、登录页面本系统对用户来说需要先注册,然后才能登录系统在线测试。而对于管理员来说可以直接登录系统进行一系列的管理和操作。注册页面如图3-17所示。
    用户注册页面

    用户登录页面

    管理员输入正确用户名和密码登录成功后,显示主页面如图3-19所示。

    用户输入正确用户名和密码登录成功后,显示主页面如图3-20所示。

    3.4.2 管理员用户管理模块管理员登录成功后,可以对用户进行管理,主要包括分页查看所有用户信息、对某一用户进行修改操作、删除选中用户、查看某一用户详细信息。分页查看所有用户信息,删除选中用户页面如图3-21所示。

    对某一用户进行修改操作页面如图3-22所示。

    查看选中用户详细信息如图3-23所示。

    3.4.3 管理员题库管理模块管理员登录系统后,可以往题库中添加不同题型的题目,题型包括选择题、多选题、判断题、填空题、简答题。系统将五种题型的添加页面集成到一个主页面,使得题型添加时更加清晰、直观,主页面如图3-24所示。

    在添加题目操作的过程中,有时难免会出现不合法的操作,例如:题目为空、单选题的某个选项为空、单选题的选项出现重复等,当出现这些操作时,系统会响应相应的触发条件通过ajax请求后台,后台会处理这些操作给管理员提示不合法的操作信息,使界面更加友好。不合法操作如图3-25所示。

    管理员将题目添加到题库后可以查看不同题型的题目列表,同样,系统将多种题型的题目查找集成在一个主页面,通过这个主页面,管理员可以对某一具体题目进行查看、删除操作。查看多种题型题目列表主页面如图3-26所示。

    查看某一具体题目详细信息如图3-27所示。

    3.4.4 管理员试卷管理模块管理员在系统中可以自动生成试卷也可以手动添加试卷,试卷添加分为六个步骤,第一个步骤是试卷的基本信息添加,主要包括试卷的名称、测试时间、题型分配情况等一些基本信息,剩下步骤为试卷各种题型题目选择性的添加,题目来源于系统题库中,试卷添加第一个步骤如图3-28所示。

    某种题型题目添加页面如图3-29所示。

    当试卷基本信息和各种题型题目添加完成后,会请求后台程序,此时后台需要将试卷的基本信息、试卷题型题目信息、试卷标准答案录入到数据库表中,这涉及到试卷表、试卷信息表、标准答案表这三张表,在试卷表中需要将各种题型的题目存入数据库中,这就需要将单个题型的题目编号集以某种规则存入数据库表中,当程序读取这些数据时,也需要按照同样的规则进行解码,将特殊字符串转换成某种题型题目的编号集。
    管理员可以对试卷进行管理,主要包括分页查询所有试卷、查看详细信息、删除等操作,试卷分页查询和删除页面如图3-30所示。

    查看页面详细信息如图3-31所示。

    3.4.5 管理员测试管理模块管理员添加完一套试卷后,用户是不能直接在浏览器上进行测试的,需要管理员对该套试题进行授权操作,用户才能进行测试,试卷授权页面如图3-32所示。

    3.4.6 用户我的测试管理模块当用户点击我的测试模块中在线测试,会展示所有可以进行测试的试题,当然同一个人只能测试某套试卷一遍,当再次操作时,会提示不能对试卷进行重复测试,在线测试试题列表如图3-33所示。

    当用户点击在线测试试题列表中开始考试,用户便可以开始一次测试,测试完成后,系统会自动的为这次测试给出理论上的评分。在线测试页面如图3-34所示。

    当用户测试完一套试卷后,点击提交试卷,如果存在没有作答的题目,系统会给出哪种题型第几题没有作答提示,全部作答完成后试卷便会提交到后台进行处理, 首先后台需要将用户的答案保存在答题表中;其次也是最重要的需要将用户答案与后台数据库中标准答案进行比对,然后得出用户每个题型的得分,并将结果存入到成绩表中;最后根据用户所提交的答案与后台标准答案比对后,将错题信息添加到错题表中,对于错题信息应包括错题题号、用户答案、标准答案、答案解析等基本信息。在开发本系统的过程中,存在着一大难点是客观题的匹配算法,一般主观题通过系统进行匹配很少出现误差的情况,而主观题不然,如今简答题的答案不是固定不变,用户答题可以从多个角度进行阐述,只要合理即可,所以给这方面的系统带来了很大的难度,主观题的批阅给出的分数只能是一个近似值,很难达到精确的地步,这类系统在开发过程中主观题一般设计为人工阅卷与系统阅卷相结合。
    本系统实现了简答题批阅的算法,但是也只能是一个近似值,该算法首先是由俄国科学家Levenshtein提出的,故又叫Levenshtein Distance,算法的实现原理为:两个字符串之间,由一个字符串转换成另一个字符串所需要的操作数,对字符串的操作包括插入、删除、替换,最后两字符串相似度可以表示为1-操作数/两字符串中较长字符串字符数。算法实现如下:
    public static float levenshtein(String str1,String str2) { //计算两个字符串的长度。 int len1 = str1.length(); int len2 = str2.length(); //建立一个二维数组用于计算操作数 int[][] dif = new int[len1 + 1][len2 + 1]; //对数组赋初值 for (int a = 0; a <= len1; a++) { dif[a][0] = a; } for (int a = 0; a <= len2; a++) { dif[0][a] = a; } //计算两个字符是否一样,计算左上的值 int temp; for (int i = 1; i <= len1; i++) { for (int j = 1; j <= len2; j++) { if (str1.charAt(i - 1) == str2.charAt(j - 1)) { temp = 0; } else { temp = 1; } //取三个值中最小的 dif[i][j] = min(dif[i - 1][j - 1] + temp, dif[i][j - 1] + 1, dif[i - 1][j] + 1); } } //计算相似度 float similarity = 1 - (float) dif[len1][len2] / Math.max(str1.length(), str2.length()); return similarity;} //该方法计算三个整数中最大数private static int min(int... is) { int min = Integer.MAX_VALUE; for (int i : is) { if (min > i) { min = i; } } return min; }
    3.4.7 用户成绩查询模块当用户点击成绩查询模块中最新成绩查询,系统会查出用户最近一次的测试信息,查看最新成绩页面如图3-35所示。

    同样当用户点击历史成绩查询时,会查出用户以前所有测试成绩列表。

    3.4.8 用户测试信息管理模块当用户点击测试信息中成绩排行时,用户可以很清楚的知道自己测试过的试题在所有测试过人中的排名,成绩排行页面如图3-37所示。

    当用户点击测试信息中我的错题时,可以查看测试试题中自己的错题情况,从而知道自己在哪些方面存在不足,需要加强学习。错题列表如图3-38所示。

    点击错题列表中查看详情,便可以查看选中试题的错题信息,错题详情页面如图3-39所示。

    3.5 测试测试在一个软件开发周期中起着重要的作用,一个好的软件是经过专业的测试人员无数次测试才会没那么多bug,测试是为了补充系统的不足,使系统更加完美,用户的体验更好,试想一下,如果你开发的软件没有经过严格的测试,而发布在互联网进行使用,那是多么可怕的一件事,用户随意点击页面便会出现很多错误,这给用户的感觉简直就是差劲!我认为这样的软件是失败的,因此测试与开发是同等重要的,并且测试人员与开发人员必须协调好才能开发出优秀的软件。
    测试方法主要包括黑盒测试和白盒测试,但软件测试有一个致命的缺陷,即测试的不完全、不彻底性,由于任何程序只能进行少量的有限的测试,在未发现错误时,是不能说明程序中没有错误。
    测试用例如下:

    管理员输入用户名:admin,密码:admin登入系统,点击用户管理系统,查看用户列表是否显示成功;在用户列表中点击修改、查询、删除操作看是否能够执行
    管理员输入用户名:admin,密码:admin登入系统,点击题库管理,查看题库列表是否显示成功;选择不同的题型后,查看题目列表是否显示成功;在题目列表中点击查看,是否能够显示题目的详情
    管理员输入用户名:admin,密码:admin登入系统,点击试卷管理,填写试卷基本信息后,看是否能够自动生成试卷,点击手动生成试卷看是否能添加成功
    管理员输入用户名:admin,密码:admin登入系统,点击试卷授权功能,当给某一试卷授权后,检测用户登入系统是否能够对该套试卷进行测试
    用户点击注册,填写用户名:123456,密码123456进行注册,注册完成后点击登录,看是否能够正常登录
    用户输入:123456,密码:123456登入系统,点击在线测试,选择试题后,看是否能够在线考试
    用户输入:123456,密码:123456登入系统,点击查看成绩看是否能够查看当前考试的成绩

    另外在系统设计和测试的过程中,发现系统存在以下几方面的不足:

    系统如果需要做的更完美,应该可以在线测试多个科目的试题
    在主观题的批阅过程中,始终无法达到精确的地步,所以算法需要做进一步改进优化
    计算机网络测试仍然存在着局限性,比如不能对计算机网络课程中画图题、连线题进行测试,所以这是需要改进的

    4 总结与展望在这次系统的设计与开发中我遇到了很多问题,像需求不是很明确、数据库设计出现问题、软件后台开发框架不能熟练的运用、简答题的批阅算法等,每一个问题都给我带来了巨大的困惑,起初需求不是很明确,当按照任务书上功能模块进行开发时,你会发现以前写的功能模块完全没有办法实现,原因是没有好好的理解需求和认真深入分析这个系统,不明确哪些功能模块可以实现,而哪些功能模块不能实现,所以我明白软件设计过程中需求分析、概要设计是相当重要的,可以直接导致一个软件设计的成败,终于理解前辈们通过自己亲身经历写下软件工程这本书的重要性,这是留给后人最宝贵的资料。然而在数据库的设计中也给我带来了不少麻烦,刚开始我便设计数据库,才发现一个不深入了解系统的人是很难设计出数据库的,于是我花了两三天的时间,认真专研系统,理清自己的逻辑思路,按照用户注册-登录-在线测试-查看成绩-查看错题这个流程渐渐的将数据库设计完成,当然在后期中也存在了一些改动,才会有今天这个成果。刚开始系统后台框架使用的是s2sh,但在一个简单的错误调试中花费了我大量的时间,让我无法专研到系统业务逻辑的实现,于是我选择了比较直接的jsp和mvc模式开发,这大大提高了我的开发效率,所以我认为系统实现的方法应该选择合理,不然会耽搁很多时间,不能在规定的时间完成任务。
    这个系统从需求分析、数据库设计、代码开发、测试都是自己独立完成,以前没有自己独立完成一个系统,当开发完成后,心里有特别大的成就感,在遇到问题-解决问题-遇到新问题这种重复模式中,自己的能力有了很大的提高,我想程序设计者应该要勇于面对问题,并且通过自己的方式寻找解决办法,在解决问题时,你往前又迈了一大步,这对自己是一种经验的积累,同时也会让自己走得更高更远。
    参考文献[1] 吕雯雯.网上报名与在线考试系统的设计与实现[J].电脑知识与技术,2012,8(7):43-47
    [2] 魏振,王婷,宫禹.基于JSP实验系统总体设计[J].黑龙江科学,2012,6(5):20-30
    [3] 朱静.基于WEB的在线考试系统的设计与实现[J].福建电脑,2007,4(23):14-25
    [4] 郑飞.基于J2EE的医药管理系统的设计与实现[J].信息技术,2012,6(5):12-14
    [5] 唐超礼,黄友锐.基于B/S模式的教师信息管理系统的设计与实现[J].中国科技信息,2006,3(8):19-36
    [6] 吴爽.教务管理的研究与设计[J].华东师范大学,2010:10-15
    [7] 冯彦.基于JSP和Struts框架动态Web开发技术研究以及实践[J].吉林大学,2005,6(7): 33-45
    [8] 赵高丽,冀红举,宋军平.基于SQL的高校考务管理系统的设计与实现[J].河南机电高等专科报, 2006,14(2):45-78
    [9] 靳新,李莹基.JSP的网络文件管理系统的设计与实现[J].沈阳理工大学,2007,5(7),20-21
    [10] 王妍.JSP的开发技术[J].科技创新与应用,2008,3(5):31-33
    [11] 蒋毅.WEB与数据库连接技术应用对比分析 [J].计算机光盘应用,2011,11(23):16-25
    [12] 李绍静,汤玉琛,王宝盼.基于JSP技术的就业信息网的架构与实现[J].计算机与现代化,2012,6(5):12-14
    [13] 张晓孪.基于SSH的团购网站的设计与实现 [J].电子设计工程,2009,3(8):19-23
    [14] 姜南.基于JSP技术的学生信息管理系统的设计与实现[J].计算机与现化,2010,3(8):10-15
    [15] 房明.基于JSP技术的教材管理信息系统设计分析[J].山西科学,2009,6(7):33-45
    [16] 陈月霞.浅谈在线考试系统的结构与实现[J].科技风,2007,14(2):22-28
    [17] Chen, Jing M., Josef Cihlar. Retrieving leaf area index of boreal conifer forest using landsat TM images [J]. Remote Sen. Environ, 1996, 55(2): 153-162
    [18] akehurst B C, Tobacco(Second edition). New York: Longman press, 1981: 51-58
    [19] Rafael C Gonzalez, Richard E Woods, Steven L Eddins. Digital Image Processing Using MATLAB.Beijing: Publishing House of Electronics Industry, 2004: 153-222
    [20] Mckee, G.W., A coefficient for computing leaf area in hybird corn. Agron. J. 1964, 56(2): 240-241
    [21] Debayle J, Pinoli J C. Multiscale image filtering and segmentation by means of adaptive neighborhood mathematical morphology[J]. Image Processing, 2005, 3(1 l-14): 537-540
    [22] Punt T. Entropic thresholding: A new approach[J]. CGIP, 1981, 16(21): 209-320
    [23] Meyer, Elsevier Trends Division. Computer & Security. Kidington, Oxford, UK, 1982
    [24] Bonanza Drive. Database. P.O.Box 70, Park City, UT 84060, USA, 1978
    [25] James A.O’Brien. Introduction to Information Systems[M]. McGraw-Hill, 2002
    4 评论 107 下载 2019-05-19 10:31:25 下载需要20点积分
显示 75 到 90 ,共 15 条
eject