分类

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

资源列表

  • Python实现的基于Scrapy爬虫框架和Django框架的新闻采集和订阅系统

    摘要随着互联网的迅速发展,互联网大大提升了信息的产生和传播速度,网络上每天都会产生大量的内容,如何高效地从这些杂乱无章的内容中发现并采集所需的信息显得越来越重要。网络中的新闻内容也一样,新闻分布在不同的网站上,而且存在重复的内容,我们往往只关心其中的一部分新闻,网络中的新闻页面往往还充斥着大量许多与新闻不相关的信息,影响了我们的阅读效率和阅读体验,如何更加方便及时并高效地获取我们所关心的新闻内容,本系统能够帮我们做到这一点。本系统利用网络爬虫我们可以做到对网络上的新闻网站进行定时定向的分析和采集,然后把采集到的数据进行去重,分类等操作后存入数据库,最后提供个性化的新闻订阅服务。考虑了如何应对网站的反爬虫策略,避免被网站封锁爬虫。在具体实现上会使用Python配合scrapy等框架来编写爬虫,采用特定的内容抽取算法来提取目标数据,最后使用Django加上weui来提供新闻订阅后台和新闻内容展示页,使用微信向用户推送信息。用户可以通过本系统订阅指定关键字,当爬虫系统爬取到了含有指定关键字的内容时会把新闻推送给用户。
    [关键词]网络爬虫;新闻;个性化;订阅;Python
    AbstractWith the rapid development of the Internet, the Internet has greatly enhanced the production and dissemination of information, the networkwill produce a lot of content every day, how to find and collectthe information we needed from these disorganized contentefficiently is more and more important. The news content on the network is thesame, the news is distributed on different sites, and there are many duplicate content, we only care about part of thenews usually. The network news pages areoften filled with a lot of news and information is not related that impact ourreading efficiency and readingexperience. How to more convenient and efficient access to the news we are concerned about the content, thissystem can help us to do this. This system uses the web crawler to collect news on the network site. And then toclassify data and other operations like delete the duplication,store data byuse the database, and finally providepersonalized news subscription service. This system has considered how to deal with the sit&s anti-reptile strategy, toavoid being blocked by the site crawler. In the concrete implementation, I will use Python with Scrapy framework towrite the crawler, then use a specificcontent extraction algorithm to extract the target data, and finally use Django and WeUI to provide news subscription background and news contentdisplay page, use WeChat to push information to users. Users can subscribe tothe specified keywords through the system, system will push thenews to the user when the crawler system crawled the contents contains thespecified keyword.
    [Keywords] Web Crawler;News; Personalization; Subscription; Python
    第一章 引言1.1 项目的背景和意义如今我们所处的时代是一个信息时代,信息处处影响着人们的生活,无论是个人还是企业,都希望能够获取自己所关心的内容。人们获取信息的方式渐渐从传统的纸质阅读转移到了信息传播速度更快互联网的在线阅读上,而许多媒体和互联网企业都推出了各自的新闻门户来提供新闻内容阅读和检索等功能,但是这些新闻信息仍需要我们主动去访问这些网站才能获取到,而且我们还要在这些新闻中筛选出自己所关心的内容进行阅读,这样浪费了我们许多阅读之外的时间。网络中的新闻分布在不同的网站上,我们往往只关心其中的一部分新闻,网络中的新闻页面往往还充斥着大量许多与新闻不相关的信息,影响了我们的阅读效率和阅读体验,如何更加方便及时并高效地获取我们所关心的新闻内容,这是一个急需解决的问题,本系统就是为了解决这样的痛点而产生的。
    1.2 研究开发现状分析1.2.1 个性化新闻服务现状如今国内外存在众多提供个性化新闻服务的互联网公司,如著名的ZAKER和今日头条,这些公司的产品都能够根据你的兴趣爱好来展示和推荐你喜欢的内容,这种创新性已经颠覆了传统的新闻资讯平台的市场格局,大众纷纷表现出对这些个性化新闻平台的追捧。据最新的《中国互联网络发展状况统计报告》显示,截至2016年12月,中国网民规模达7.31亿,移动互联网用户规模达到6.95亿,其中新闻资讯领域行业用户规模达到6.14亿,年增长率为8.8%,在移动端渗透率达到82. 2%。 [1]新闻资讯信息的用户需求也更加细分,用户对内容的需求也更加精细,除了方便阅读、时效性高、趣味性强外,个性化推荐方式也越来越受到用户的关注。在猎豹全球智库发布的安卓2016年1月新闻类APP排行榜中,作为个性化新闻平台的今日头条、一点资讯皆排在移动资讯APP的前三位。而前三中采用传统编辑推荐方式的只有腾讯新闻,可见如今个性化新闻平台已经成为绝对的主流。
    1.2.2 网络爬虫研究现状网页抓取工具是一种根据特定规则来自动获取互联网信息的脚本或程序。[2] 网页或搜索引擎等网站通过爬虫软件来更新自己的网站内容或者是更新对其他网站的索引。一般来说,网络爬虫会保留被抓取的页面,然后用户可以通过搜索引擎后来生成的索引进行搜索。因为爬虫访问网页的方式与人类相似,而且一般比人类访问的速度要快,会消耗访问的网站的系统资源。因此爬虫在需要大量访问页面时,要考虑到规划和负载等情况,否则容易被网站禁封。网站站长可以使用robots.txt文件来告诉爬虫访问的规则。robots.txt文件是一个具有指定格式的文件,网站站长可以通过此文件来要求爬虫机器人不能访问某些目录或者只能访问某些目录。互联网上的页面极多,而且数量一直在增长,即使是像谷歌这样的爬虫系统也无法做出完整的索引,因此在某些地方会根据需求来做一些主题化的爬虫,这样的爬虫爬到的结果往往能够更加精确。
    1.2.3 项目的范围和预期结果本文描述了基于网络爬虫的新闻订阅系统的设计与实现的过程,主要工作如下:

    编写一个网络爬虫,使其能够对网络中指定站点的新闻进行自动收集并存入数据库;
    数据的去重和网络爬虫的反爬虫策略应对;
    提供一个新闻展示页面,把爬取到的新闻展示给用户;
    提供新闻订阅页面,用户可以在页面输入指定订阅的关键词;
    编写微信推送服务,把用户订阅的新闻通过微信推送给用户;
    1.3 论文结构简介本论文的结构安排如下:

    第一章,引言。主要介绍了论文选题项目的背景、意义和目的;以及对相关领域中已有的研究成果和国内外研究现状的简要评述;介绍本系统涉及的范围和预期结果等。
    第二章,技术与原理。主要介绍本系统中所用到的主要技术和理论。
    第三章,系统需求分析。使用用例析取和用例规约等系统分析方法对本系统进行了需求分析。
    第四章,新闻采集与订阅系统的设计。介绍了系统的架构与原理,讲述本系统的各大模块的设计以及数据库的设计详情。
    第五章,新闻采集与订阅系统的实现。介绍本系统具体的实现过程以及实现的效果。
    第六章,系统部署。介绍本系统的部署环境与部署方法。
    第七章,总结与展望。对本系统所做的工作进行总结,提出了需要讨论的问题和一些本系统中可以改进的地方。

    第二章 技术与原理2.1 技术选型2.1.1 Python语言介绍Python是一种面向对象、解释型的计算机程序编程语言。它包含了一个功能强大并且完备的标准库,能够轻松完成很多常见的任务。它的语法比较简单,与其它大多数程序设计语言使用大括号把函数体包起来不一样,它通过缩进来定义语句块。[4]使用P帅on能够高效灵活地实现开发的任务,内置库以及大量的第三方库能够在许多地方避免重复造轮子的现象,有时使用c++语言来实现的一个功能可能需要几十行,Python只需要几行就足够了。与传统的脚本语言相比,Python拥有更佳的可读性和可维护性。这门语言的强大吸引到了许多开发者,拥有比较热门的Python社区,许多开发者在维护着这种Python编写的库,影响力也在日益增强。在网络爬虫领域,Python这门语言的使用也比较广泛,留下了大量的前人的学习研究的资料。基于以上优点,我选择了使用Python来开发本系统的网络爬虫部分和展示部分的服务端。
    2.1.2 Scrapy框架介绍Scrapy是一个纯Python基于Twisted实现的爬虫框架,用户只需要定制开发几个模块就可以方便地实现一个爬虫,用来抓取网页内容、图片、视频等。它最初是为了网站页面抓取所设计的,也可以应用在获取网络应用API所返回的各类数据或者是编写通用的网络爬虫。Scrapy用途比较广泛,可以应用于数据挖掘、自动化测试和数据监控等场景。Scrapy提供了一些网络爬虫中比较通用的中间件和模块等,也可以方便地编写自己所需的中间件来对爬取结果进行处理,只要在配置里面引用这些中间件就可以了。使用Scrpay来编写爬虫可以降低很多需要重复编写的爬虫处理代码所带来的成本。
    2.1.3 Django框架介绍Django是最早由Python实现的最着名的Web框架之一,最初是由美国芝加哥的Python用户组来开发的,拥有新闻行业背景的Adrian Holovaty是Django 框架的主要开发人员之一。在Adrian的领导下,Django团队致力于为Web开发人员提供一个高效和完美的Python开发框架,并授权开发人员根据BSD开源协议许可证免费访问。Django是一个高效的Web框架,可以帮助我们减少重复的代码,并把更多重点放在Web应用程序上的关键之处。在架构上,Django 跟Scrapy类似,也提供了中间件等,配置的方式也是类似的,使用类似的技术架构可以减少学习成本。本系统中我选用Django作为新闻订阅的服务端来提供API。
    2.1.4 MongoDB数据库介绍MongoDB是一个由C++语言编写的高性能,无模型的开源文档型数据库,是当前NoSQL数据库产品中最具有代表性的一种。MongoDB是使用文档来作为对象存储的,一条记录对应一个文档,集合类似传统的关系型数据库中的表,集合中存放的是那些具有同一特征或者属性的文档。在一个集合中,不同文档拥有的属性可以是不同的,这就是与传统的关系型的数据库的重点了,传统的关系型数据库要求表里的数据所拥有的属性格式都是一致的,MongoDB这种灵活性更利于文档映射到一个对象或一个实体上。对于需要经常改动数据格式或者数据格式不定的一些需求来讲,这种数据格式更为合适。MongoDB在读写性能方面也远超传统的关系型数据库的代表之一的MySQL。在本系统中我使用MongoDB 来存储爬取到的数据以及用户数据等。像MongoDB这样的非关系型数据库更合适储存爬虫数据,因为爬虫数据量可能比较大,数据之间关系型也不强。 MongoDB的性能也比传统的关系型数据库代表MySQL之类要强。
    2.1.5 AJAX介绍AJAX(异步的JavaScript + XML)本身并不是一种技术,它是由Jesse James Garrett在2005年提出的一个术语,描述了一种需要结合使用大量已经存在的技术的方式,包括HTML, JavaScript, CSS, DOM, JSON, XML等,还有最重要 JavaScript中的的XMLHttpRequest对象。当这些技术以AJAX模型的方式聚合时,Web应用程序可以更迅速地,无需加载整个页面就能更新全部或者部分的用户界面。这使Web应用能够更快地响应用户行为,带来更友好的用户体验。尽管在AJAX中X代表XML,但现在JSON使用的更多,因为JSON具有许多XML不具备的优势,比如它更轻量并且是JavaScript的一部分,各个程序语言都能够轻松解析JSON格式的数据。在AJAX模型中,JSON和XML的作用都是承载信息。[6]本系统会在新闻订阅和展示部分的前端使用AJAX来跟服务端进行交互,以达到前后端分离的目的。
    2.2 相关原理介绍2.2.1 网络爬虫介绍网络爬虫(英语:web crawler),也叫网络蜘蛛(spider),是一种自动提取网页的程序,它为搜索引擎从万维网上下载网页。传统的爬虫的启动从一个或多个初始网页开始的,从这些初始网页上获得接下来要爬取的URL,在抓取网页内容的过程中,不断从当前页面的内容上抽取新的需要继续爬取URL放入队列,直到满足系统的一定停止条件。[7]网络爬虫的抓取策略大致可以分为以下三类:广度优先搜索策略、深度优先搜索策略、最佳优先搜索策略等。本系统的爬虫部分使用的爬虫策略是广度优先搜索策略,因为本系统的网络爬虫具有针对性,所以爬取的层数不会很多。
    2.2.2 关键词提取技术通过分析文本,利用关键词抽取技术可以抽取出文本的关键词,关键词能够简单地反映出文本的主要内容,使人们更加直观方便地了解到文本内容的主题。关键词提取的技术有许多种,最常用的应该是基于统计的方法的TF-IDF算法。 TF-IDF(term frequency-inverse document frequency)是一种常用的用于数据挖掘与信息检索的加权技术。[8]词语的重要性是在TF-IDF算法中主要是由它在文中出现频率决定的。
    Jieba是一个基于Python的中文分词库,支持三种分词模式:精确模式、全模式和搜索引擎模式,它能够基于Trie树结构来实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图,采用了动态规划查找最大概率
    路径,找出基于词频的最大切分组合。在本系统中,将考虑使用Jieba分词基于 TF-IDF算法的关键词抽取来抽取出爬取到的新闻内容的关键词。
    2.2.3 智能推送技术当我们使用如今的一些应用程序时,会经常收到来自这些应用的推送,过多的、不适当的推送会打扰到用户,互联网技术在最近几十年里已经得到了很大的发展,但是推送通知技术仍旧停留多年以前。为了实现智能化推送,我们需要搜集和分析能够帮助我们实现智能化推送通知的用户数据,这些数据的来源可以是用户的设置或者用户在应用中产生的数据等。在智能推送通知中,与时间相关的,个性化的,有帮助的,有联系性的是智能推送通知中四个基本的特征。
    在推送的时间上,我们可以做到时间智能化,时间智能化指的是推送的时间要恰当,推送发生在不恰当的时间比无用的垃圾推送消息造成的不良效果更验证。在不恰当的时候推送的通知不但打扰到用户,还很容易会被用户忽略。智能推送应该能够做到自动解决推送时间不恰当的问题。具体的实现可以通过一个对推送信息的重要性评估的引擎来决定消息推送的时间。
    在个性化上,我们可以把推送机器人设计成人类的形态,比起传统的系统消息,拟人化的方式能够让人更加容易接受,如苹果的Sin和微软的Cortana。当我们将来自机器智能的推送通知语言根据用户自己的特点进行调整后,用户在查看时看到的是更像交流式的风格,会感到更有亲切感,更加个人化。
    在推送的内容上也要慎重选择,根据不同用户来推送不同的内容。因为对于用户来说,只有用户关心的内容才是对用户有帮助的。拿新闻订阅应用来讲,就是用户只会对某些主题内容的新闻感兴趣,应用要做的就是把新闻的主题进行分析,打上不同的标签。然后找到用户兴趣中含有这些标签用户进行推送。如果不经处理对全部用户进行统一的推送,用户需要花费大量时间在这上面去过滤出自己感兴趣的内容。
    在推送内容的数量上也有讲究,如果一个服务高频次地的使用通知推送,用户可能会感觉到被冒犯然后会关掉它,后面的推送就都收不到了。因此,将推送的内容进行分组就很重要了。系统可以把一些相似的通知进行分组合并,可以减少对用户的打扰,在消息很多的时候这种优势就很明显了。在信息较少的时候可以选择把这些推送通知进行展开,因为此时用户可能会比较关心这些少见的内容,也是一个不错的选择。
    第三章 系统需求分析3. 1 新闻订阅系统用例析取基于网络爬虫的新闻采集与订阅系统要实现新闻数据抓取,数据过滤,数据筛选,数据展示,新闻订阅,推送等服务和功能,本系统用例图如图3.1所示:

    本系统主要用于以下几类人员:

    数据管理员,完成数据的抓取,过滤与筛选,新闻的推送,以及本系统管理维护等。
    用户,在网页上进行新闻订阅,通过微信接收订阅新闻的推送,点击进入对应新闻展示页面等。

    3.2 新闻订阅系统用例规约3.2.1 新闻订阅3.2.1.1 简要说明本用例允许用户增加或者删除自己订阅新闻的关键字,以及对已经订阅的关键字进行确认等操作。
    3.2.1.2 参与者用户。
    3.2.1.3 事件流基本事件流:用例开始于用户进入新闻订阅页面进行操作。

    订阅新闻关键字的状态共有两种,分别为“已订阅”、“未订阅”。顾客可以在相应的状态下进行操作,选择增加关键字或者删除关键字。
    如果关键字状态为“未订阅”,用户可以增加该关键字到自己的订阅列表中,本用例结束。
    如果关键字状态为“已订阅”,用户可以选择删除该关键字,本用例结束。
    无特殊要求。
    前置条件:本用例开始前用户必须是微信已登录状态。
    后置条件:如果用例成功,用户的订阅列表将被更新。
    活动图

    3.2.2 新闻推送3.2.2.1 简要说明本用例允许数据管理员根据新闻的关键字向已经订阅该关键字的用户进行推送等操作。
    3.2.2.2 参与者数据管理员。
    3.2.2.3 事件流基本事件流:用例开始于爬虫系统采集到新闻时。

    系统将新闻内容根据算法与用户订阅的新闻关键字作对比,对比结果分别为“匹配”、“不匹配”。如果匹配状态为“匹配”,系统将调用微信推送接口向用户推送该新闻,本用例结束。如果匹配状态为“不匹配”,用户将不会收到该新闻的推送,本用例结束。无特殊要求。前置条件:本用例开始前采集到的新闻必须有效。后置条件:如果用例成功,用户将收到一条新闻推送。活动图

    第四章 新闻采集与订阅系统的设计4.1 系统架构及原理本新闻采集与订阅系统分别由爬虫部分与新闻订阅和展示部分构成,在新闻订阅与展示部分采用基于C’s的架构,代码的组织方式为MVC三层结构,其中的三个层次分别为视图层(View)、控制器层(Controller)和模型层(Model)。代码整体采取前后端分离的方式,前端负责视图层,后端负责模型层和控制器层,客户端使用微信和网页实现,前后端通讯使用AJAX交换JSON的方式。系统的总体框架图如图4.1所示:

    爬虫部分使用了Python编写Scrapy框架,它的基本架构如图4.2所示,其中 Scrapy引擎的作用是控制数据的流向,是整个爬虫框架的核心。网络蜘蛛(spiders) 定义了如何爬取某个(或某些)网站,包括了爬取的动作以及如何从网页的内容中提取结构化数据。蜘蛛中间件(spider middleware)是在Scrapy引擎和网络蜘蛛间的一个钩子,它可以处理蜘蛛的输入与输出。调度器(scheduler)能够从Scrapy引擎接受请求并放入队列,在引擎请求调度器时返回对应的请求。下载器(downloader)负责下载网页,把爬取到的内容返回给Scrapy引擎和网络蜘蛛。下载器中间件(downloader middleware)是在Scrapy引擎和下载器间的一个钩子,它可以处理传入的请求跟传出的响应。Item Pipeline负责处理网络蜘蛛传过来的Item,可以在此做数据格式化,数据清理等操作。

    爬虫的整体上数据流向的开始是由Scrapy引擎让网络蜘蛛以一个初始的 URL来初始化一个请求,并设置回调函数,然后网络蜘蛛把该请求向调度器申请任务,把申请到的任务交给下载器,这里会经过一次下载器中间件,然后下载器把下载完后产生的响应再经过一次下载器中间件,然后传递给引擎,引擎接收到该响应后通过蜘蛛中间件传给网络蜘蛛处理,网络蜘蛛处理该响应,产生一个 item或者是新的请求给引擎,引擎会把传过来的item放入Item Pipeline,把传过来的新的请求传给调度器,Item Pipeline获取接收到的item对该item进行逐层处理,接着这个流程就重复直到爬取完成。
    4.2 系统模块设计4.2.1 爬虫采集模块设计使用Scrapy框架来编写爬虫首先要编写核心的蜘蛛(sPiders)的代码,Spider 类定义了如何爬取某个(或某些)网站,包括了爬取的动作以及如何从网页的内容中提取结构化数据。本系统主要针对网易新闻和腾讯新闻的科技频道进行主题式的爬虫,所以设计了两个网络蜘蛛,名字分别为Neteasespider和QQSpider,如果后续需要更多需要爬虫的站点,只要增加对应站点的网络蜘蛛就可以了,其余处理部分都是通用的。在这里选择主题式的爬虫的原因主要是一个通用爬虫对于新闻这样的每个站点的文章有固定格式的爬取解析的代价比较大,还不如手工去对需要爬取的站点进行分析,根据每个站点的特点来编写解析的代码。这样的主题式的爬虫能够提高爬虫的精确度,同时也提高了爬虫的效率,这样我们的爬虫就能够及时爬取到最新的新闻内容了。每个站点对应一个特定的网络蜘蛛还有一个好处就是如果后续需要完成分布式爬虫等需求时会很方便,因为这样的方式代码之间的祸合度较小,同时非常简洁。
    网络蜘蛛首先从一个Start url开始爬取,这里我选取了网易新闻和腾讯新闻的科技频道的首页,蜘蛛爬取这个起始URL上的页面后,对里面的内容进行解析。因为每篇新闻的URL都具有一定的格式,凡是该页面上有符合这种格式的 URL,蜘蛛都会对这些URL进行回调,继续爬取这些URL的页面,这些页面上就会包含所要获取的新闻的内容了。对于同一个新闻站点来说,一般页面上的内容的结构也是一样的,所以按照一定的规则来对这些页面上的内容进行解析,获得新闻内容原始数据,对这些数据进行格式化的处理,封装成一个item,传回给 Scrapy引擎处理。
    因为新闻具有一定时效性,一般来说我们只会关注那些新产生的新闻内容,所以本爬虫不需要考虑需要爬取过往产生的新闻的情况。本系统的爬虫部分只聚焦于每个站点的首页的新闻,因为新闻是滚动刷新的,所以我们需要定时对首页进行爬取,获取新的新闻内容。本系统设计了一个类似守护程序,来控制爬虫的启动与停止,在爬虫结束后等待一段时间再重新开始爬取。
    4.2.2 爬虫去重模块设计在爬虫过程中会遇到重复内容的情况,所以我们需要设计一个爬虫用到的去重的模块。考虑到每个URL对应的新闻内容是不变的,我们只要针对URL来进行去重即可,而不需要等到把内容取回来之后再判断内容是否已经爬取过,那样会消耗大量额外的资源,也对目标网站造成了额外的压力,显得不友好。我们选择去重的时机是Scrapy的调度器把请求分配给下载器之前,也就是说在下载器中间件中处理,在本系统中定义了一个下载器中间件RedisMiddleware,这个中间件的作用是在Redis的一个散列中判断是否存在该URL,如果不存在,把该请求传给下一个中间件处理。如果该URL存在于散列中,则忽视掉该请求,不进行后续操作。在本系统中定义了一个Item管道RedisPipeline,在爬取数据完成后,数据库处理完后Item会传到该管道,该管道的作用是把这个新闻所属URL 存入Redis的散列中,标记该URL已经爬取。
    4.2.3 防反爬虫模块设计防反爬虫是在大多数爬虫中需要考虑的情况,因为爬虫对网站服务器造成的压力比正常人要多,如果爬取频率足够高的话,会使网站访问变慢,甚至无法访问,所以网站可能会有一系列的反爬虫措施。首先我们的爬虫需要遵守网站的爬虫协议,然后把爬取速率控制好,例如间隔一秒才爬取一个页面。其次,我们需要伪装成一个浏览器,有些网站会通过HTTP请求头中的User-Agent中的信息来判断用户,我们不但需要在爬虫请求中的HTTP设置User-Agent请求头,还需要对该请求头进行更换,因此在本系统中定义了一个下载器中间件RotateUserAgentMiddleware,这个中间件的作用是在请求前在请求的HTTP请求头中设置一个轮换的随机的模拟用户浏览器的User-Agent请求头,这些 User-Agent与真实浏览器的User-Agent一致,数据来源是Python中一个叫 fake-useragent的库。后续如果对方服务器针对’P进行禁封了的话可以采用代理服务器的方式来应对,在做了以上措施的情况下本系统目前没有出现过被禁封的情况,因此该方法没有在本系统中实现。
    4.2.4 爬虫存储模块设计爬虫的数据存储是一个爬虫系统中很重要的一部分,因为爬虫的目的就是获得数据,在这里我们需要考虑数据的存储方式与储存时机。在本系统中储存部分使用了ORM(对象关系映射)的方式来实现,ORM的好处在于把数据访问的细节隐藏起来,在ORM上的操作出错的可能性会比手写数据库操作的可能性低。在ORM中,我们只需要关注数据的结构,这样一来,我们只需要编写数据储存对象的参数定义等属性跟方法就可以了,初始化、查询、更新等操作都可以由 ORM来实现。在本系统中,爬虫部分与订阅和展示部分都共用一个数据库,爬虫部分需要对数据库进行写操作,展示部分需要对数据库进行读操作。在蜘蛛解析完数据后,蜘蛛会把封装好的Item通过Scrapy引擎传给Item管道,本系统中定义了一个MongoDBPipeline,这个管道的作用是维持一个MongoDB的数据库链接,接收到传入的Item后先校验完数据的完整性,然后把合法的数据插入数据库对应的集合中,否则丢弃该Item。
    4.2.5 消息推送模块设计消息推送部分本系统使用微信来实现,需要用户关注指定公众号。本系统需要推送消息给用户时,先选择一个本系统预定义的模板,在模板中填入消息标题,内容和链接等数据后,通过微信提供的接口来进行推送。这里需要注意的是我们需要给推送的消息接口提供一个本系统所用的公众号的AccessToken,这个 AccessToken是向微信证明本系统的凭证,它有一定的有效期,需要定时刷新。
    4.2.6 消息订阅与展示模块设计消息订阅与展示模块是本系统中与用户交互的模块,这个模块负责用户订阅新闻的功能与向用户展示所需新闻内容的模块。在本系统蜘蛛解析完数据后,蜘蛛会把封装好的Item传给MongoDBPipeline储存后,会继续往下传递,传递到一个PushPipeline中,这个管道的作用是判断爬取到的数据是否包含用户所订阅的关键词,如果包含的话则调用消息推送模块把新闻消息推送给用户。在消息推送后,用户会在微信端本系统的公众号中接收到一条包含新闻消息简要内容的消息,点击该消息可以跳转到新闻展示页面。本系统提供了一个消息订阅页面,用户可以在该页面上管理自己的新闻关键词。
    4.3 数据库设计本系统存放数据用到的数据库分别是Redis和MongoDB,在本系统的数据库设计中,数据库的集合主要包括爬取到的新闻信息集合和用户订阅新闻关键词集合,系统的配置信息都写在配置文件中,就不需要使用数据库来存放了。这里选择MongoDB的原因是考虑到当爬虫的数据量和并发数很大时,关系型数据库的容量与读写能力会是瓶颈,另一方面,爬虫需要保存的内容之间一般不会存在关系。另外本系统会使用Redis中的散列类型来存放已经爬取过的URL和不合法的URL,因为判断URL是否合法或者是否已经爬取过是一个高频的操作,使用 Redis这样的高性能的内存键值对类型的数据库可以减少主数据库的压力,同时提高爬虫的性能。
    新闻信息集合



    属性名
    含义
    类型
    说明




    title
    新闻标题
    string



    content
    正文内容
    string
    纯文本


    source
    来源
    string
    新闻出处


    published
    发布时间
    timestamp
    精确到秒


    url
    原文链接
    string
    用于跳转



    用户订阅新闻关键词集合



    属性名
    含义
    类型
    说明




    open_id
    用户微信openid
    string
    唯一标识


    keywords
    订阅的关键词列表
    array
    字符串类型的数组


    tags
    订阅的标签列表
    array
    字符串类型的数组



    第五章 新闻采集与订阅系统的实现5.1 系统框架实现本新闻采集与订阅系统的爬虫部分框架是利用Scrapy自带的命令行工具来初始化,初始化后已经创建好了Scrapy引擎所需的几个重要的文件,如中间件,数据管道,配置文件等,这样做的好处是能够快速搭建起框架,并且能够达到官方定义的最佳实践。接下来我们可以在这个目录下定义自己的一些模块文件,再在这些文件中实现自己的处理函数就可以了,最终实现的爬虫部分的目录结构如图5.1所示,其中items.py是用于定义数据储存模型的文件,middlewares.py是用于定义中间件的文件,pipelines.py是用于定义数据管道的文件,settings.py是本系统爬虫部分的配置内容,spiders文件夹中存放了不同爬虫的网络蜘蛛代码, utils.py则是一些通用的函数存放的地方,wechat_config.py和wechatpush.py分别是微信推送部分的配置和推送代码。

    新闻订阅和展示部分的API服务器端则使用Django自带的命令行工具来初始化,使用django-admin startproject命令来新建一个项目,然后使用django-admin startapp命令来新建一个app,这样API服务器的基本框架就完成了,然后往创 建的目录中添加其余代码,最终实现的新闻订阅与展示部分的目录结构如图5.2 所示,其中frontend文件夹存放的是本系统的前端静态文件,分别是新闻订阅页面和新闻展示页面,init_db.py文件是一个用于初始化数据库用的脚本,lib文件夹中存放的是本系统中一些能够被公用的函数文件。manage.py是由Django生成的用于管理任务的命令行工具脚本,newsweb存放的是本项目的代码,run server.sh是一个用于启动服务器的脚本文件,web server中存放的是本系统新闻订阅与展示部分的服务端代码的主要文件,主要包括了用于配置路由 urls.py,存放新闻和订阅信息数据模型models.py和提供API的views.py。

    5.2 爬虫采集模块实现爬虫采集模块的核心的网络蜘蛛,下面以爬取网易科技频道新闻的蜘蛛为例讲解本系统爬虫采集模块的实现过程。图5.3为该蜘蛛的解析网页请求响应的代码,首选我通过分析网易科技频道新闻中的网页源码,分析得到网页中所需的新闻内容的数据所在的位置特征信息,例如通过分析发现标题位置是处于html标签下的head标签里的title标签里的文本。24-27行中的代码的作用是通过xpath 使用之前分析出来的格式来从抓取到的数据中提取出新闻相关的信息,包括新闻标题、新闻消息来源、新闻内容、新闻发布时间。29-32行的代码作用是把时间解析为时间戳,这样做的目的是为了方便把时间转换成不同的表现格式,时间表现会更为准确。34-40行的代码作用则是把数据封装成一个本系统中的新闻Item, 然后传给Item管道来处理。另外一个用于爬取腾讯新闻科技频道蜘蛛的分析方法和代码写法是类似的,在这就不详细介绍了。

    为了实现定时爬虫的功能,在本系统中实现了一个名为worker.py的守护进程脚本和一个start_crawl.py的用于调用爬虫的脚本,运行worker.py脚本后会每三十秒调用启动一次start_crawl.py,start_crawl.py每次启动会调用爬虫主程序,程序核心代码如下:

    5.3 防反爬虫模块实现为了防止反爬虫对本系统爬虫部分的影响,对于每次请求,本系统都会伪装成一个真实的用户,防止被爬取的网站通过User-Agent等信息来判断或者禁封 掉本系统的爬虫,导致后续爬虫无法正常进行。本系统在发送请求之前会在请求的头部加上User-Agent的请求头信息,这个请求头的信息会在本系统配置中的 User-Agent列表中随机选取一个,图5.5为部分User-Agent信息。除此之外,还可以利用代理服务器来代理请求,防止被爬取的网站通过IP信息来禁封本系统爬虫。

    5.4 爬虫存储模块实现爬虫储存模块的数据设计与格式等在上一章已经说明,在这介绍在数据库中的具体实现。爬虫爬取到的新闻数据会存放于MongoDB中,使用ORM来映射数据对象模型到数据库,使用的ORM框架是MongoEngine,下面通过讲解一个新闻内容的数据模型的定义来说明这种定义方式,在图5.6中的第9行,我们定义了一个父类为MongoEngine的Document类的类,这样定义就使这个类拥有了关系对象映射的能力,再在这个类中定义一个to_json的方法,作用是把本类的实例转化为一个Dict类型的数据,方便API调用时将对象转换成JSON格式的数据返回给前端。图5.7展示了部分爬取到的新闻数据的内容。

    5.5 消息推送模块实现消息推送模块使用了微信公众号的推送,在本系统中使用微信的接口测试号来代替公众号,微信的接口测试号是一种用于测试的,可以使用微信号扫一扫登录的账号,而且这种账号能够直接体验和测试公众平台所有高级接口。在申请完后登录系统,获得该系统的applD和appsecret,这两个字符串是使用该账号的凭据。需要注意的是,用户需要关注本账号后才能够收到本账号推送的消息。

    接下来我们在网页下方新增一个消息模板,填入推送新闻消息的模板内容,填写完成后记录对应的模板ID。

    获得以上信息后把信息写入消息推送模块的配置文件中,供消息推送模块调用。下面讲解消息推送模块核心部分的实现,核心部分如图5.10所示,是一个名为send_msg的函数,这个函数接收四个参数,分别为新闻标题、新闻内容、新闻的ID和订阅者的openid。订阅者的openid是用户微信的唯一标识,在测试号的页面可以查看已关注该账号的用户微信的openid。该函数的29-42行的作用是把数据封装成微信推送接口所需的格式,然后在45行使用requests模块来 POST一个请求到微信推送接口,微信推送接口收到请求后会在公众号中把该消息推送给用户。该函数使用了一个自定义的装饰器update_token来装饰,之前存放的applD和appsecret可以用来生成推送用的access token,而这个access token 有固定的存活期限的,这个装饰器的作用就是定时去获取这个access token并存放,直到过期之后再重新获取。
    爬虫模块爬取到含有用户订阅的关键词的新闻时会向该用户推送这则新闻,图5.11是用户在微信公众号上收到的该新闻的推送消息示例。

    5.6 消息订阅与展示模块实现消息订阅与展示模块主要由前端静态文件部分和后端API部分组成。在开发方式上本系统选择了使用前后端分离的方式,前端通过AJAX的方式来跟后端提供的API进行交互,后端API服务器收到请求后返回对应的JSON格式的数据给前端,前端根据数据来渲染出最终展示给用户的页面,这种前后端分离的方式有效地降低了代码之间的Wi合度。在前端实现方面,使用了jquery来对DOM元素进行操作以及进行异步请求等,另外使用了WeUI的样式库,WeUI是一套提供同微信原生一致的视觉体验的基础样式库,由微信官方设计团队为微信内网页和微信小程序量身设计,令用户的使用感知更加统一。
    接下来以用户端的角度来展示消息订阅与展示模块的实现。
    用户想要收到新闻推送,需要先关注本系统的公众号,然后打开新闻订阅页面:

    这时可以输入要订阅的关键词,这里填IT,点击添加订阅关键词,系统提示添加关键词IT成功,刷新已订阅关键词列表:

    点击已订阅关键词列表中的项会弹出对话框询问是否删除该关键词:

    点击确定,提示操作成功,同时刷新已订阅关键词列表:

    在订阅关键词后,系统爬虫爬取到相关内容时会把内容通过微信推送给用户,用户点击后可以看到新闻内容,在此页面可以点击查看原文按钮打开原新闻页面,还有可以点击订阅更多前往订阅新闻关键词的页面:

    点击查看原文,会跳转到新闻的原页面:

    第六章 系统部署6.1 部署机器概述为了运行本新闻采集与订阅系统,至少需要一台拥有公网’P的Li~服务器,这是为了用户在外网能够访问到。至于配置方面则不需要太高,在测试时我选用了一台腾讯云上的服务器,这台服务器的配置如下:



    项目
    内容




    操作系统
    Ubuntu Server 14.04.1 LTS 64位


    CPU
    1核


    内存
    1GB


    系统盘
    20GB


    公网带宽
    1Mbps



    6.2 配置环境
    安装Nginx作为反向代理服务器,并编辑Nginx相关配置文件,这样做是为了把不同的请求分发到后端不同的地方,例如请求前端文件就返回静态文件,请求API就把请求转发给API服务器,Ningx的配置文件部分内容如图6.1所示。这样就实现前后端分离而又不受到跨域请求限制的影响了。编辑完Nginx配置文件后,重启Nginx服务器。
    安装PIP, PIP是Python用于管理第三方库的一个软件,这里用于安装本系统所需的第三方库。
    使用PIP安装本系统所依赖的第三方库,包括pymongo, scrapy, redis, fake-useragent, django,mongoengine, jieba, lxml, gevent, gunicorn等。


    6.3 系统运行由于本新闻采集与订阅系统是由爬虫部分与展示部分组成,所以需要分别运行行爬虫的守护进程和后端API服务器,静态页面是由Nginx指定的一个目录来提供的,不需要后台服务器。
    使用python worker.py命令来运行爬虫的守护进程,得出以下输出:

    使用sh run_server.sh命令来运行后端API服务器,这个脚本的实际作用是使用gevent作为gunicorn的worker来运行4个后端API服务器进程,成功运行会得到以下输出:

    第七章 总结与展望7.1 总结本系统是一个基于网络爬虫实现的新闻采集与订阅系统,实现了对网络上新闻内容的自动化采集、用户新闻关键词订阅、新闻内容展示以及新闻推送等功能。为实现本系统的功能,查阅了大量学习资料,在实现方面使用了一些比较前沿的技术以及较多的第三方库,从中能够学习到很多新知识和新技能。在本文中较为完整地从系统的需求分析、不同模块的设计与实现几个方面来展示了一个完整的爬虫系统以及对应的新闻订阅API服务器等的实现过程,最后在云服务器上部署本系统并测试,达到了预期的效果。
    7.2 展望本新闻采集与订阅系统在设计上考虑了许多来降低代码之间的祸合度,同时提高代码的健壮性与性能,使本系统能够达到容易扩展以及高可用的需求,即便后续需要爬取另外一个新的新闻网站上的新闻,只需要编写对应网站的解析部分就可以了,大部分代码已经被模块化,能够被重用。对比了已有的类似的成熟大型新闻服务系统,发现还有以下能够改进的地方:

    本系统只对新闻的基本文字信息等进行了采集与展示,后续可以考虑实现对新闻中图片与视频等多媒体信息的采集。
    本系统缺乏一个较为完善的用户模块,目前用户是在配置文件中配置的,用户模块对于这类的订阅系统是比较重要的。
    订阅机制不够智能,也没有智能推荐等功能,后期可以采用机器学习等人工智能方法来实现智能化推送与推荐功能。

    除了以上几点,本系统仍然存在许多能够改进的地方,但由于本文作者水平有限以及时间限制,未能够将这些一一实现,还希望各位专家学者能够给予批评与建议。
    参考文献[1] 中国互联网络信息中心. 中国互联网络发展状况统计报告[EB/OL]. http://www.cnnic.cn/gywm/xwzx/rdxw/20172017/201701/t20170122_66448.htm, 2017年
    [2] 胡博,基于网络爬虫的内容资源评价研究[D];北京理工大学;2015
    [3] 李建中、李金宝、石胜飞,传感器网络及其数据管理的概念、问题与进展,软件学报,14(10):17 17-1727, 2003
    [4] 邝洪胜;基于Python的电商导购APP设计与实现[D];华南理工大学;2015
    [5] 基于Django的自动化运维管理系统的设计与实现[D].姚娜.西安电子科技大学2015
    [6] 关系与非关系数据库应用对比研究——以SQL Server与Mongo DB为例[D].吴德宝.东华理工大学2015
    [7] 基于网络爬虫的网站信息采集技术研究[D]. 孙骏雄. 大连海事大学2014
    [8] 基于网络爬虫的内容资源评价研究[D].胡博.北京理工大学2015
    [9] Wang J, Guo Y. Scrapy-based crawling anduser-behavior characteristics analysis on Taobao[C1//Cyber-EnabledDistributed Computing and Knowledge Discovery (CyberC), 2012 International Conference on. IEEE, 2012:44-52.
    [10] Castillo C. Effective web crawling[C1//Acm sigir forum. Acm, 2005, 39(1):55-56.
    [11]刘金红,陆余良.主题网络爬虫研究综述 [J].计算机应用研究,2007, 24(10) :26-29.
    [12]徐远超,刘江华,刘丽珍,等.基于Web的网络爬虫的设计与实现[J].微计算机信息,2007 (21): 119-121. MLA
    [13] 王成军.“今日头条”的技术逻辑:网络爬虫+矩阵筛选[J].传媒评论,2015 (10) : 34-37.MLA
    [14] Jaiswal S, Kumar R. Learning Django Web Development [M]. PacktPublishing Ltd, 2015.
    [15] Taneja 5, Gupta P R. Python as a Toolfor Web Server Application Development [J]. 2014.
    [16] Web数据挖掘及其在网络新闻文本数据中的应用[D].胡峰.电子科技大学2010
    [17] 乔峰.基于模板化网络爬虫技术的Web网页信息抽取[D].电子科技大学2012
    致谢从本论文的选题、资料收集、资料阅读、到论文编写完成的这段时间中,我收获到许多宝贵的知识与经验。在这段时间里我查阅了许多相关资料,也使用了一些他人开发的第三方程序库,这些都减轻了我的压力。在此要感谢前人的付出,留下了那么多的学习研究材料。
    在这我要特别感谢我的论文导师卞静老师,卞老师在我完成该论文期间给予了我悉心指导与帮助,在繁忙之中抽出时间来对我的论文进行了指导并提出许多宝贵的建议。卞老师拥有渊博的专业知识、严谨的治学态度和平易近人的处事作风,是我终生学习的楷模。在此向我的导师表示最诚挚的谢意和最衷心的祝愿。
    其次,我要感谢我的家人,他们一直以来都能够理解,支持并关心我,从而使我能够专心投入到学习和工作中,让我在求学的过程中感受到温暖的力量,并能够顺利完成学业。
    在我大学学习和生活中,得到了许多老师和同学的关心与帮助。感谢我的舍友,在我学习上遇到疑惑的时候能够悉心教导我,在论文编写、技术路线和具体实现上也得到了他们宝贵的建议,谢谢你们!
    最后,在此对所有在我做毕业设计期间帮助,关心和支持过我的老师、同学和朋友们,以及百忙之中抽出时间来审阅、评议本论文的各位专家们表示衷心的感谢。
    5 评论 60 下载 2018-09-30 23:27:17 下载需要12点积分
  • 基于Laravel-PHP框架的网上订餐管理系统

    摘 要随着电子商务的发展,O2O电子商务模式越来越兴起。网上订餐系统就是这种商务模式的一种体现。目前在校园周边有许多提供外卖服务的餐厅,但是大部分餐厅还是采取电话订餐、人工手写记录等较为原始的方式。这些方式不仅麻烦费时,而且,由于外卖通常具有集中性,在午餐和晚餐这两个时段,会有很多人同时打来电话。面对这种情况,餐厅要么增加同时接线的数量,这样会增加成本;要么什么都不做,这样会失去原本能够赚取的利润。网上订餐系统可以很好的解决这个问题。本毕业设计网站使用国际上非常流行的Laravel框架进行开发,大大优化路由设置,同时,简便的登录验证系统,和完善的数据库迁移功能组合在一起,使得本系统能够得到更加快速和便捷的开发与完善。利用网上订餐系统,可以同时进行并发业务处理,从而避免了因为在同一时刻有多人打入电话无法接通而导致流失顾客的情况,而且,本毕业设计还具有短信通知功能,可以在用户下单订餐、餐厅送餐时自动发送短信提醒用户,具有十分现实的意义。
    关键词:O2O;网上订餐;PHP;Laravel框架
    AbstractWith the development of e-commerce, O2O growing rise of e-commerce model. Online reservation system is a manifestation of this business model. Now we have a lot of takeout around the campus, but most still take phone ordering, handwritten notes and other artificial methods. Online reservation system can solve this problem, the network can handle concurrent operations simultaneously, thus avoiding the situation because there are many people at the same time to enter the phone unable to connect and lead to the loss of customers. Website using very popular PHP framework — Laravel , can greatly optimize the routing settings, simple login authentication system, database migration evening, these powerful features are combined to develop faster and more convenient and improve the system.
    Key words:O2O; online meal ordering; PHP; Laravel framework
    1 绪论1.1 课题的背景和意义随着电子商务的发展,O2O电子商务模式逐渐兴起。网上订餐系统就是这种商务模式的一种体现。现在我们校园周边有好多外卖,但是大部分还是采取电话订餐、人工手写记录等方式。这种方式不仅麻烦费时,而且,由于外卖通常具有集中性,在午餐和晚餐这两个时段,会有很多人同时打来电话。面对这种情况,餐厅要么增加同时接线的数量,但是这样会增加成本;要么什么都不做,这样会失去原本能够赚取的利润。
    网上订餐系统可以很好的解决这个问题,网络可以同时进行并发业务处理,从而避免了因为在同一时刻有多人打入电话无法接通而导致流失顾客的情况。同时,电子化的订餐方式也便于进行数据收集和分析。因此,本毕业设计可以实现网络同步订餐,用户只要在网上订餐,便与通过电话订餐方式一样可以获得送餐服务,而且更加方便快捷。
    1.2 网站设计任务一个网站的前端是非常重要的,它是用户直接面对的。一个优秀的前端设计,可以让用户体验提升不少。所以,在此次毕业设计里面,前端的设计占了很大部分,涉及到了很多方面的技术。
    页面前端使用 HTML配合JavaScrip等技术来支持前端的运作,并使用Ajax技术向服务器Post数据,使得页面可以在不刷新的情况下,与服务器进行数据交互。网站结构被设计成顾客可以在网站上注册后,直接在网页上订餐。餐厅可以在网站上注册后,可以在后台管理的自己餐厅的各项设置,包括餐厅名字、营业时间、餐厅的介绍、餐厅电话(手机号、座机)等信息,还可以定制自己的起送要求等。在定制过这些信息之后,餐厅用户就可以上传自己的食品信息了,上传食品信息之后,再上传食品图片,最后,在后台里再点击餐厅上线按钮,这样,餐厅里面的食品就可以正常发布了。对不同角色的用户权限进行了控制,使得所有商品信息可以及时的更新,所有的订单可以及时进行处理,真正实现了网上办公,减少工作成本、提高工作效率。
    1.3 主要架构以及采用的技术介绍此次毕业设计的开发环境是,Window 8.1 ,开发语言是 PHP ,数据库采用开源的 MySql,服务器使用的是著名的开源服务器 Apache。采用 Wamp 开发环境包安装的,这样在安装之后不需要单独配置PHP、Apache以及MySql的环境变量。Wamp集成PHP、Apache、MySql配置在一起,开发过程中可以非常方便的修改各个配置信息,并且,Wamp还附带phpMyAdmin工具,可以通过网页非常方便的对数据库进行各项操作。
    在此次毕业设计的开发中并没有采用任何IDE(集成开发环境,Integrated Development Environment)来帮助开发,仅使用文本编辑器 Sublime Text 2 来写PHP、Mysql、HTML、Javascript代码,调试使用Chrome 34.0.1847.131 m 版本。因此开发也可以在Linux下进行,并且网站的服务器也是可以架设在Linux系统下的。
    本次毕业设计使用了一个名为 Laravel 的PHP框架,这个框架是在PHP 版本5.3以后发布的,这说明它具有非常多的优势相对于别的PHP框架。
    之所以采用PHP语言进行开发,是因为根据Alexa统计,在2013年,大约有40%的网站是采用PHP配合MySql数据库进行开发的,作为即将毕业的我很好奇,使用这么广泛的技术到底是什么样子的,希望能从本次毕业设计的开发中学习到很多知识。
    1.3.1 基于 B/S 的体系结构在 B/S 体系结构系统中,用户通过浏览器向分布在网络上的服务器发出请求,服务器对浏览器的请求进行处理,然后将用户所需信息返回到浏览器。B/S 结构简化了客户机的工作。服务器将担负更多的工作,对数据库的访问和应用程序的执行将在服务器上完成。浏览器发出请求,而其余如数据请求、加工、结果的返回以及动态网页生成等工作全部由Web Server完成。实际上 B/S 体系结构是把两层 C/S 结构的事务处理逻辑模块从客户机的任务中分离出来,由 Web 服务器单独组成一层来负担其任务,这样客户机的压力减轻了,把负荷分配给了Web 服务器。
    这种三层体系结构如图1-1所示。

    1.3.2 PHPPHP(全称:PHP:Hypertext Preprocessor,即“PHP:超文本预处理器”)是一种开源的通用计算机脚本语言,尤其适用于网络开发并可嵌入HTML中使用。PHP的语法借鉴吸收了C语言、Java和Perl等流行计算机语言的特点,易于一般程序员学习。PHP的主要目标是允许网络开发人员快速编写动态页面,但PHP也被用于其他很多领域。PHP最初是由勒多夫在1995年开始开发的。而现在PHP的标准由PHP Group和开放源代码社区维护。PHP以PHP License作为许可协议,不过因为这个协议限制了PHP名称的使用,所以和开放源代码许可协议GPL不兼容。PHP的应用范围相当广泛,尤其是在网页程序的开发上。一般来说PHP大多运行在网页服务器上,通过运行PHP代码来产生用户浏览的网页。PHP可以在多数的服务器和操作系统上运行,而且使用PHP完全是免费的。根据2007年4月的统计数据,PHP已经被安装在超过2000万个网站和100万台服务器上。如图1-2所示。

    1.3.3 Bootstrap 前端开发框架页面使用最的 Bootstrap V3版本,它是Twitter推出的一个开源的用于前端开发的工具包。它由Twitter的设计师Mark Otto和Jacob Thornton合作开发,是一个CSS/HTML框架。Bootstrap提供了优雅的HTML和CSS规范,它即是由动态CSS语言Less写成。Bootstrap一经推出后颇受欢迎,一直是GitHub上的热门开源项目,包括NASA的MSNBC(微软全国广播公司)的Breaking News都使用了该项目。
    国内外有很多优秀的企业都是用了 Bootstrap 来作为网站的前端开发框架,Twitter自己的页面就是采用Bootstrap开发,国内的豆瓣的开发者后台也是采用Bootstrap写的。使用动态CSS语言Less开发的好处在于,可以像编程一下来书写CSS代码,使得开发效率大大提高。
    1.3.4 JavaScriptJavaScript,一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML网页上使用,用来给HTML网页增加动态功能。然而现在JavaScript也可被用于网络服务器,如Node.js。
    在本次毕业设计中,使用了非常流行的jQuery库。jQuery是一套跨浏览器的JavaScript库,简化HTML与JavaScript之间的操作。由John Resig在2006年1月的BarCamp NYC上发布第一个版本。目前是由 Dave Methvin 领导的开发团队进行开发。全球前10000个访问最高的网站中,有65%使用了jQuery,是目前最受欢迎的JavaScript库。
    jQuery 是开源软件,使用MIT许可证授权。jQuery的语法设计使得许多操作变得容易,如操作文档对象(document)、选择DOM元素、创建动画效果、处理事件、以及开发Ajax程序。jQuery 也提供了给开发人员在其上创建插件的能力。这使开发人员可以对底层交互与动画、高级效果和高级主题化的组件进行抽象化。模块化的方式使 jQuery 函数库能够创建功能强大的动态网页以及网络应用程序。
    本系统使用了两个版本的jQuery,前台用的是最新的2.1.0版本,后台用的是2.0.3版本,使用jQuery最大的好处在于,用考虑浏览器的兼容性问题,这样就不必在各种浏览器下面进行调试。
    1.3.5 Ajax介绍AJAX即“Asynchronous JavaScript and XML”(异步的JavaScript与XML技术),指的是一套综合了多项技术的浏览器端网页开发技术。Ajax的概念由Jesse James Garrett所提出。
    传统的Web应用允许用户端填写表单(form),当提交表单时就向Web服务器发送一个请求。服务器接收并处理传来的表单,然后送回一个新的网页,但这个做法浪费了许多带宽,因为在前后两个页面中的大部分HTML码往往是相同的。由于每次应用的沟通都需要向服务器发送请求,应用的回应时间依赖于服务器的回应时间。这导致了用户界面的回应比本机应用慢得多。
    与此不同,AJAX应用可以仅向服务器发送并取回必须的数据,并在客户端采用JavaScript处理来自服务器的回应。因为在服务器和浏览器之间交换的数据大量减少(大约只有原来的5%),服务器回应更快了。同时,很多的处理工作可以在发出请求的客户端机器上完成,因此Web服务器的负荷也减少了。
    此次毕业设计中,Ajax库使用的是jQuery中的库,所有与服务器进行交互的数据一律都采用了json格式,避免出现格式不统一的情况发生。
    1.3.6 Laravel——PHP框架Laravel是一套web应用开发框架,它具有富于表达性且简洁的语法。Laravel的开发者们相信,开发过程应该是愉悦、创造性的体验。Laravel努力剔除开发过程中的痛苦,因此提供了验证(authentication)、路由(routing)、session和缓存(caching)等开发过程中经常用到的工具或功能。
    在本次毕业设计的开发中,Laravel的学习成本最大,因为Laravel出现的比较晚,是在PHP5.3以后出现的。这是它的优势,也是它的劣势。
    优势是Laravel没有其他PHP框架的那些包袱,很多框架因为出现的早,还必须支持PHP4.0,这使得框架本身变得非常臃肿。
    劣势在于它太年轻了,而且,国内使用Laravel开发的并不多,以至于在开发过程中遇到问题的时候,只能去英文的stackflow.com上去寻找答案,Stack Overflow 是一个程序设计领域的问答网站。
    Sitepoint网站做了一个小的调查,看看PHP开发者们最喜欢使用哪个PHP框架。调查结果显示,最流行的PHP框架前三甲为:Laravel、Phalcon、Symfony2。

    1.3.7 PHP依赖管理包Composer是PHP中的一个依赖管理工具. 它可以让你声明自己项目所依赖的库,然后它将会在项目中为你安装这些库。
    2 需求分析2.1 可行性分析2.1.1 技术可行性分析可行性分析是在系统开始实施之前,进行系统可行性的提前设想、估算以及研究的一种方法。在项目开始实施之前,进行可行性分析是非常有必要的。通过可行性分析可以提前了解整个项目成功实施的可能性,以及在项目实施期间可能遇到的阻力。当然,系统项目实施中,特别是作为第一次独立来完成这个订餐系统的我来说,可能会遇到各种各样的问题,更加需要一个长远的计划和在系统实施之前的可行性分析。
    系统的实施架构是Wamp,即:Windows系统,Apache服务器,Mysql数据库,PHP语言。这是一套在Windows平台非常成熟的架构,对于硬件和网络的要求不是非常高,作为学生或者一般的网站创建者来说足够应付了。
    2.1.2 经济可行性分析从硬件角度上来分析,实际上此次毕业设计的实施,只需要一台服务器即可,也就是本人的电脑。
    从版权保护角度上来分析,服务器使用的框架是开源的PHP框架——Laravel,它使用MIT许可协议。MIT是开源许可协议中非常宽松的一种。服务器使用Apache,Apache使用Apache 2.0许可协议。PHP使用PHP license许可证。Bootstrap前端开发框架是开源的,jQuery是使用的是MIT许可协议。所以,无需进行任何支付,即可使用上面的框架和库。
    2.2 业务流程分析未注册登录用户,可以在不注册、不登录的情况下,浏览主页和所有处于销售状态的食品。用户注册之后就可以进行更进一步的操作,比如在个人信息页面查看网站活动,修改个人信息等。餐厅用户在注册之后,可以进入属于自己的餐厅后台进行相应的操作,比如设置餐厅的名字、开始营业时间、结束营业时间、餐厅的描述等一系列的设置,并且可以上传食品信息,并上传食品对应的照片文件。
    2.2.1 用户注册在主页或者其他页面进行浏览不需要注册,但是一旦用户有更进步的操作时,就必须注册才可以进行。
    每个页面的右上角都有注册和登录按钮,用户点击注册按钮之后,就会被引导至注册页面。
    在注册页面,需要用户填写用户名、密码、电子邮箱、选择所在地区、生日、手机号、以及验证码等信息。
    填写完毕,用户点击提交信息按钮后,页面会用Ajax向后台post数据,在后台Laravel会先验证用户提交的信息是否规范,比如:被要求输入的内容用户是否已经输入了,用户名在用户表中是否是唯一的,邮箱在用户表中是否是唯一的,用户名不能小于六位不可以大于十二位,密码以及确认密码的内容是否一致,密码是否大于六位小于十二位等各项验证。
    Laravel已经封装好了各种正则表达式验证条件,所以本系统不用自己再重复去写相对应的正则表达式了,引用写好的验证规则后,直接提交给Laravel中的validator类去验证即可,如果验证失败,会自动返回错误信息。
    当验证失败的时候,系统会返回用户注册的页面,附带着用户之前输入过的内容,以及错误信息。由于Laravel默认的语言包是英文的,所以,Laravel的错误信息默认也是英文的,本系统已经准备好了中文的语言包(app/lang下),并且在 app/config/app.php 中设置好了对应的语言包,这样,返回的错误信息就会是之前设定好的内容了。
    当本系统设定的验证全部通过之后,才会进入到真正的注册步骤——写入数据库。
    最后提示用户成功注册,并跳转到主页。如图2-1所示。

    2.2.2 用户登录用户可以在主页直接输入账号、密码、以及验证码,来实现登录。验证码的作用是为了避免用户信息被暴力破解。当用户访问别的需要登录验证的页面时,会被跳转到一个登录页面。当用户成功登录之后,主页以及食品页中本来显示用户登录的地方就会变成“欢迎回来,(用户名)”等字样。如图2-2所示。

    2.2.3 用户邮箱验证以及用户请求再次发送邮箱验证信在用户注册信息提交给服务器,服务器判断注册信息无误之后,用户成功注册,并且,系统会在数据库 confirmemail表里生成一个用户名对应验证码的一条数据,之后自动向用户注册时所填写的邮箱,发送一封带有唯一验证码的验证邮件,用户只有在点击这个验证之后,才完成邮箱的验证。
    当用户因为某种原因没有成功接收到服务器发送的验证邮件,用户可以在后台再次请求发送验证邮件,这时候服务器会再次生成一个唯一验证码并且在confrimemail表中重写上一次生成的验证码,最后把验证邮件发送到用户的邮箱中,整个过程都是使用Ajax方式,用户不需要等待,只需要向服务器发送请求即可。

    2.2.4 用户订餐流程未登录的用户可以浏览主页的所有内容和食品页面的所有内容。当用户想要有更进一步操作的时候,就必须登录了。
    在用户订餐的时候,如果用户未登录,订餐按钮会提示用户登录,并跳转到登录页面。未登录的用户可以选择登录或者注册一个账号。
    当用户登录之后,可以选择先将想要购买的食品放在购物车中。用户放入购物车的食品会以Ajax方式提交给服务器,这样可以不必刷新页面。当用户已经选中足够的食品后,可以选择结算。
    用户会被引导至结算页面,在这个页面如果用户之前有输入过订餐地址的话,会有订餐地址显示出来,如果没有的,则需要用户输入送餐地址,最后生成订单。

    2.2.5 餐厅管理员登陆流程未注册的餐厅管理员无法登录后台,想要加入的餐厅可以在后台登录页面直接进行初步注册,在注册信息都验证通过之后,就可以登录后台了。或者也可以在前台进行餐厅注册。
    餐厅管理员在注册之后,就可以登录后台进行餐厅信息的设置和上传食品了。
    2.2.6 用户评价流程用户在一份订餐订单完成之后,就可以对该订单进行评价,未完成的订单无法进行评价。
    2.2.7 订单管理流程订餐的顾客可以在后台查看自己所有的订单,可以对订单进行评价或者在订餐未完成之前取消订单。
    2.2.8 食品信息上传只有登录的餐厅管理员可以对食品信息进行上传,修改和删除,同时,可以在图片上传页面上传食品对应的图片。所有的图片都会被无损处理成600PX*600PX样式,以此来使得图片在任何地方显示正常。
    2.3 系统流程图分析系统流程图的重要性在于,它是描述系统逻辑模型的主要手段。通过对整个订餐系统的了解,把系统分为几个重要的功能模块,明确各个模块之间相互协调,制作出数据的流程图。在绘制数据流程图的过程中,各个符号对应关系如下:

    2.3.1 顶层数据流程图顶层数据流程图包含网站服务的范围、页面信息的输入以及输出,充分阐释了网站所应该设定的边界,可以抽象出整个网站。网站的顶层数据流程图如下图所示。它包含的实体有,顾客,餐厅、网站管理员。主要的数据流有会员信息、餐厅信息、餐厅上传的食品信息,最后完成订餐,网站管理员进行全局的控制。

    2.3.2 第 1 层数据流程图在顶层数据流程图的下面是中层数据流程图,它是由若干个数据流程图组成的。它不但细化了顶层数据流程图的内容,同时又是使得下一层可以继续分解。此次毕业设计订餐网站在将顶层数据流程图分解之后,得到了三个一层数据流程图。分别是顾客信息、菜品信息、网站管理员。
    第1层客户信息数据流程图

    第1层菜品信息数据流程图

    第1层管理员数据流程图

    2.3.3 第 2 层数据流程图将第 1 层顾客信息流程图分解得到了顾客的第2 层流程图,如图 2-10 所示。

    将第 1层的菜品管理数据流程图分解得到了餐厅管理菜品的第2 层数据流程图,如图 2-11 所示。

    将第 1 层网站管理员的数据流程图分解得到了管理员的第2层数据流程图,如图 2-12所示。

    2.4 软硬件需求分析因为开发没有使用任何IDE进行,所以仅仅使用文本编辑器就可以完成开发,不过为了提高效率,本系统使用的是Sublime Text 2,如果在Linux平台下可以是用Vim。
    服务器使用的Apache for windows的版本,windows版本在XP以上都可以运行。
    开发环境是直接使用网上非常有名的Wamp,W指windows环境,a指Apache服务器,m指Mysql,p指PHP,这个环境安装包会自动配置好Mysql和PHP的环境变量,以及Apache的服务器配置信息,而且,非常方便在开发中进行各项管理。
    另外,为了在开发过程中便于调试,数据库与服务器在同一台电脑上。

    数据库及应用服务器
    CPU:P4 以上 2M L2cache 硬盘空间:>=10G 内存:>=512M 操作系统:windows2003 及以上版本或 Linux、Unix 数据库:Mysql

    3 系统设计3.1系统功能图
    网站的系统功能一共分为三个部分,第一部分是订餐顾客,第二部分是餐厅用户,第三部分是网站管理员。
    具体功能描述如下:

    订餐顾客

    订餐顾客可以注册和登录网站,来进行订餐订餐顾客可以浏览的食品,同时也可以把希望要订餐的食品放入到购物车中订餐顾客可以登录自己的个人信息页面,查看和修改自己登录是填写的注册信息,并且可以查看自己所有的订单状况
    餐厅用户

    餐厅用户可以在网站上进行注册和登录,以此来在网站上发布食品餐厅用户可以在网站后台餐厅管理页面进行一系列的操作。查看以及修改餐厅的各项信息,餐厅的上线以及下线餐厅用户可以在后台上传食品信息以及食品的图片餐厅用户可以在后台查看所有的评论,并且可以对评论进行回复
    网站管理员

    网站管理员在登录之后,可以在后台进行会员信息的查看以及管理网站管理员在登录之后,可以在后台进行餐厅信息的查看以及管理网站管理员在登录之后,对主页的广告进行管理可以对餐厅或者用户发送站内信对于所有的菜品进行管理

    3.2 系统结构设计3.2.1 订餐顾客登录模块订餐顾客在注册之后可以,进行登录。登录模块的作用是用户登录,用户在页面上填写个人账户与密码信息后,提交给服务器,服务器判断用户提交的信息,如果用户提交的信息正确,那么就成功登录系统,并被引导至主页。否则回到登陆页面,然后显示相应的错误信息。

    3.2.2 菜品管理模块餐厅用户和网站管理员登录成功后,即可进入属于各自的后台管理页面。在各自的后台管理页面,可以对菜品进行管理,增加、修改或者删除菜品,如下图所示:

    3.2.3 会员管理网站管理员进入后台后,可以对所有的会员信息进行浏览和管理。对于长期不上线或者不正常行为的会员进行禁止登录,使得该会员不能登录,只有管理员才可以解除登录限制。
    如图所示:

    3.2.4 网站后台管理模块网站管理员在登录网站后台系统之后,可以对会员信息、餐厅信息、所有的订单信息、菜品信息、评论信息等进行查看、修改或者删除等操作。还可以对指定类型的用户(餐厅或者是订餐的顾客)发送站内信、发布网站活动信息等事项操作。还可以对网站主页的广告内容进行定制。
    3.2.5 订单管理当餐厅用户登录之后,可以查看订单信息,并且对已经进行配送完成的订单修改相应的订单状态。
    对于因为意外而无法完成的订餐,取消掉订单。
    如果所示:

    3.2.6 评论管理餐厅用户在登录餐厅后台之后,可以查看所有该餐厅食品的评论,并且对评论进行回复网站管理员在登录网站后台之后,查看到所有的评论,并且可以对评论进行删除操作。
    如图所示:

    3.2.7 网站活动模块网站管理员在登录网站后台操作页面之后,可以发布、修改或者删除网站的活动。所有的用户在登录之后,进入个人信息页面都可以看到网站当前的活动信息。如图所示:

    3.2.8 广告管理模块网站管理员在登录网站后台管理页面之后,可以对网站主页显示的广告进行管理,修改网站主页广告的图片、或者链接。
    4 数据库设计4.1 数据流需求分析根据之前设计的网站模块以及功能要求,在网站整体设计上建立数据库的逻辑结构,以及相互之间的关系。在实体数据库中就可以相应的实现了。
    综上所述,网站所需要的基本表有:用户表,网站活动表,站内信表,确认邮箱表,餐厅表,顾客表,密码重置表,食品评论表,餐厅评论表,食品表,订单表,地址表,购物车表。共计13张表。
    各模块需求数据库表的逻辑如下所示:

    会员模块:该模块涉及到用户表、顾客表、食品表、地址表、购物车表、订单表、食品评论表、餐厅评论表,等这八张表
    餐厅模块:该模块涉及到用户表、餐厅表、食品表、地址表、食品评论表、餐厅评论表等六张表
    网站管理员模块:该模块涉及到用户表、网站活动表、站内信表、餐厅表、顾客表、食品评论表、餐厅评论表、食品表、订单表、地址表等9张表

    4.2 数据库E-R图ER 图是用来描述某一组织的概念模型,提供了表示实体、属性和联系的方法。构成ER 图的基本要素是实体、属性和关系。实体是指客观存在并可相互区分的事物;属性是指实体所具有的每一个特性。本网站使用的E-R图如下所示:
    站内信的E-R图,如图所示,包含了站内信自身的ID,站内信的发送者,站内信的接受者,站内信的标题,站内信的内容,站内信是否是可回复的。
    如图所示。

    会员个人信息的E-R图,如图所示,包含了会员的ID,用户名,性别,手机号,手机号验证状态,邮箱,邮箱验证状态,所在地区,生日,以及地址ID。

    餐厅的E-R图,如下图所示,包含了餐厅ID,地址ID,名字,用户名,手机号,手机号验证状态,座机号码,送餐需求(起送数量或者起送金额的下限),邮箱,邮箱验证状态,开始营业时间,关门时间,所在地区,以及餐厅描述。
    如图所示。

    菜品的E-R图,如图所示,它包含了菜品的ID,属于的餐厅的用户名,菜品的名字,价格,库存数量,描述,图片名称,菜品的状态,菜品属于的类型,以及菜品图片保存的名字。
    如图所示。

    网站活动的E-R图,如上图所示,它包含了活动的ID,活动的标题,活动的内容,以及活动的图片所在的地址。
    如图所示。

    给餐厅的评论的E-R图,如下图所示,它包含了评论的ID,被评论的餐厅名,评论的内容,以及提交这份评论的用户名。
    如图所示。

    给菜品的评论的E-R图,如图所示,它包含了评论的ID,被评论的菜品名,评论的内容,以及提交这份评论的用户名。

    订单的E-R图,如下图所示,它包含了订单的ID,购买菜品的ID,菜品名,购买数量,订单状态以及送餐地址。
    如图所示。

    4.3 数据库文件设计根据之前的数据库需求分析,得出网站各个数据库表的设计,如下面的表所示:
    表 4.1地址表 addresss



    字段
    类型

    主键
    注释




    Id
    int(10)


    自增,地址ID


    username
    varchar(255)


    属于的用户的用户名


    address
    varchar(255)


    地址信息


    created_at
    timestamp

    0000-00-00 00:00:00
    创建时间


    updated_at
    timestamp

    0000-00-00 00:00:00
    更新时间



    表4.2 餐厅评论表cffs



    字段
    类型

    主键
    注释




    id
    int(10)


    自增,菜品评论ID


    foodname
    varchar(255)


    评论的菜品名


    comment
    text


    评论的内容


    username
    varchar(255)


    评论的用户ID


    created_at
    timestamp

    0000-00-00 00:00:00
    评论的创建时间


    updated_at
    timestamp

    0000-00-00 00:00:00
    评论的更新时间



    表4.3 菜品评论表cfrs



    字段
    类型

    主键
    注释




    id
    int(10)


    自增,餐厅评论ID


    restaurantname
    varchar(255)


    餐厅名称


    comment
    text


    评论内容


    username
    varchar(255)


    评论的用户名


    created_at
    timestamp

    0000-00-00 00:00:00
    评论的创建时间


    updated_at
    timestamp

    0000-00-00 00:00:00
    评论的更新时间



    表4.4 邮箱验证表confirm_emails



    字段
    类型

    主键
    注释




    id
    int(10)


    邮箱验证码的ID,自增


    username
    varchar(255)


    属于的用户名


    confirm_code
    varchar(255)


    验证码


    created_at
    timestamp

    0000-00-00 00:00:00
    验证码的创建时间


    updated_at
    timestamp

    0000-00-00 00:00:00
    验证码的更新时间



    表4.5 手机验证表confirm_mobiles



    字段
    类型

    主键
    注释




    id
    int(10)


    手机验证码的ID,自增


    username
    varchar(255)


    验证码属于的用户名


    confrim_code
    varchar(255)


    生成的6位验证码


    created_at
    timestamp

    0000-00-00 00:00:00
    验证码的创建时间


    updated_at
    timestamp

    0000-00-00 00:00:00
    验证码的更新时间



    表4.6 顾客信息表customers



    字段
    类型

    主键
    注释




    id
    int(10)


    顾客的ID


    username
    varchar(255)


    顾客使用的用户名


    sex
    varchar(2)


    性别


    mobile
    varchar(255)


    手机号


    mobile_status
    varchar(255)


    手机号验证状态


    birthday
    date


    生日


    email
    varchar(255)


    邮箱地址


    email_status
    varchar(255)


    邮箱的验证状态


    status
    varchar(255)


    账户的状态


    district
    varchar(255)


    所在地区


    addressid
    varchar(255)


    地址ID


    created_at
    timestamp

    0000-00-00 00:00:00
    创建时间


    updated_at
    timestamp

    0000-00-00 00:00:00
    更新时间



    表4.7 网站活动表events



    字段
    类型

    主键
    注释




    id
    int(10)


    活动的ID,自增


    title
    varchar(255)


    活动的标题


    content
    text


    活动的内容


    imgaddress
    varchar(255)


    活动图片的地址


    created_at
    timestamp

    0000-00-00 00:00:00
    活动创建时间


    updated_at
    timestamp

    0000-00-00 00:00:00
    活动更新时间



    表4.8菜品销量表foodcount



    字段
    类型

    主键
    注释




    foodid
    varchar(255)


    菜品的ID


    foodname
    varchar(255)


    彩屏的名字


    sum(count)
    double

    NULL
    菜品的销量



    表4.9 菜品信息表foodinfos



    字段
    类型

    主键
    注释




    id
    int(10)


    菜品详细信息ID


    belongto
    varchar(255)


    菜品属于的餐厅用户名


    name
    varchar(255)


    菜品的名字


    price
    varchar(255)


    菜品的价格


    stock
    varchar(255)


    菜品的库存数量


    note
    varchar(255)


    菜品的描述


    savename
    varchar(255)


    菜品图片的存储名称


    status
    varchar(255)


    菜品的状态


    restaurantname
    varchar(255)


    菜品属于餐厅的名字


    moring
    varchar(255)


    餐厅开始营业时间


    night
    varchar(255)


    餐厅结束营业时间


    demand
    varchar(255)


    餐厅是是否有起送要求


    typeofdemand
    varchar(255)


    起送要求类型


    demandfornum
    varchar(255)


    起送要求数量


    demandformoney
    varchar(255)


    起送要求金额


    addressid
    varchar(255)


    餐厅地址


    mobile
    varchar(255)


    手机号


    phone
    varchar(255)


    座机号



    表4.10菜品表foods



    字段
    类型

    主键
    注释




    id
    int(10)


    菜品的ID


    belongto
    varchar(255)


    菜品属于的餐厅用户名


    name
    varchar(255)


    菜品名


    price
    varchar(255)


    菜品价格


    stock
    varchar(255)


    菜品库存


    note
    varchar(255)


    菜品描述


    foodimg
    varchar(255)


    菜品图片名


    status
    varchar(255)


    菜品状态


    savename
    varchar(255)


    菜品图片保存名


    type
    varchar(255)


    菜品类型


    created_at
    timestamp

    0000-00-00 00:00:00
    菜品创建日期


    updated_at
    timestamp

    0000-00-00 00:00:00
    菜品更新日期



    表4.11站内信表messages



    字段
    类型

    主键
    注释




    id
    int(10)


    站内信ID


    sent
    varchar(255)


    站内信发送者


    receive
    varchar(255)


    站内信接受者


    title
    varchar(255)


    站内信标题


    content
    text


    站内信内容


    status
    varchar(255)


    是否可以回复


    created_at
    timestamp

    0000-00-00 00:00:00
    站内信创建日期


    updated_at
    timestamp

    0000-00-00 00:00:00
    站内信修改日期



    表4.12 数据迁移表migrations——Laravel数据迁移



    字段
    类型

    主键
    注释




    migration
    varchar(255)


    数据库表迁移的名字


    batch
    int(11)


    迁移的分支



    表4.13 订单表orders



    字段
    类型

    主键
    注释




    id
    int(10)


    订单的ID


    foodid
    varchar(255)


    订单菜品的ID


    foodname
    varchar(255)


    菜品名字


    count
    varchar(255)


    购买的数量


    addressid
    varchar(255)


    送餐地址ID


    status
    varchar(255)


    订单状态


    restaurantname
    varchar(255)


    被订餐的餐厅名


    created_at
    timestamp

    0000-00-00 00:00:00
    订单的创建日期


    updated_at
    timestamp

    0000-00-00 00:00:00
    订单的修改日期



    表4.14重置密码表resets



    字段
    类型

    默认
    注释




    id
    int(10)


    密码重置ID


    username
    varchar(255)


    用户名


    email
    varchar(255)


    邮箱


    reset_code
    varchar(255)


    重置码


    created_at
    timestamp

    0000-00-00 00:00:00
    重置密码申请日期


    updated_at
    timestamp

    0000-00-00 00:00:00
    重置密码更新日期



    表4.15 餐厅详细信息表restaurantprofiles



    字段
    类型

    主键
    注释




    username
    varchar(255)


    餐厅用户名


    email
    varchar(255)


    邮箱


    email_status
    varchar(255)


    邮箱验证状态


    restaurantname
    varchar(255)


    餐厅名字


    describe
    text


    餐厅自我描述


    moring
    varchar(255)


    餐厅开始营业时间


    night
    varchar(255)


    餐厅结束营业时间


    typeofdemand
    varchar(255)


    起送要求类型


    demandfornum
    varchar(255)


    起送数量要求


    demandformoney
    varchar(255)


    起送金额要求


    mobile
    varchar(255)


    餐厅手机号


    mobile_status
    varchar(255)


    手机号状态


    phone
    varchar(255)


    座机号码


    status
    varchar(255)


    餐厅状态


    address
    varchar(255)


    餐厅地址



    表4.16 用户表users



    字段
    类型

    主键
    注释




    id
    int(10)


    用户的ID


    username
    varchar(32)


    用户名


    password
    varchar(64)


    密码


    role
    varchar(255)


    身份


    remember_token
    varchar(255)


    Laravel本次密码对应的token


    created_at
    timestamp

    0000-00-00 00:00:00
    用户创建日期


    updated_at
    timestamp

    0000-00-00 00:00:00
    用户修改日期



    5 网站的功能实现5.1 首页功能的实现网上订餐系统的主页主要包括主打菜品的推荐、今日销量榜、月销量榜、季度销量榜、购物车和用户登录注册板块。主打菜品模块主要是销量最高的三个菜品显示成幻灯片形式在主页展示;然后在幻灯片的右边显示按照分类推荐的菜品;今日销量榜主要显示当日销量最好的菜品;月销量榜按照销量排布显示上个月菜品的销量;季度销量榜按照季度销量来显示菜品;用户可以将食品存入购物车内,统一结算,同样的,购物车内的菜品可以被修改和删掉;登录注册板块分别向已注册和未注册用户提供系统登录和会员注册功能, 如图所示:

    5.2 会员注册模块未注册的用户可以在会员注册页面进行注册。会员注册页面交互友好,可以向用户提供用户名、密码等信息的输入建议,并可提供相应的纠错功能,保证注册信息正确、合法。
    如图所示。

    5.3 会员模块会员在成功注册完成之后,可以从主页或者其他页面进行登录,如图所示:

    会员在成功登录之后,可以进入自己的个人信息页面查看自己的站内信,网站活动,订单,个人信息以及登出。
    如图所示。

    5.4 餐厅后台模块想要加入到网站的餐厅可以去餐厅注册页面注册,注册页面如图所示,依旧是非常友好的tip提示方式。
    在餐厅注册过之后,就可以登录后台了,餐厅后台登录页面如图所示:

    在餐厅后台登录页面,为了用户体验的友好,同时还提供餐厅的注册和忘记密码的功能页面,它们都是在同一个页面上实现的。如图所示,是一个简单的餐厅注册页面,餐厅在这个页面注册之后,还需要在后台完善相应的信息,在此之后餐厅就可以正式上线了。
    下图所示是餐厅后台登录页面的忘记密码功能,只需要提供注册时候使用的邮箱,就可以进行密码的重置了。服务器会向该邮箱发送一份密码重置信,在进入到邮箱查看到密码重置新之后,点击密码重置信上面的地址,就可以跳转到密码重置页面了。
    如图所示。

    当餐厅用户完成登录之后,就会被引导至餐厅后台主页界面。如下图所示:

    因为本系统使用的电脑屏幕分辨率是1600*900,所以显示会比较松散一些,该页面采用了Bootstrap响应式布局,在IPAD等移动设备上也可以正常显示。
    餐厅信息设置页面,如下图所示:

    5.5 菜品管理模块餐厅在登录后台之后,可以对菜品进行管理,首先是菜品总览,总揽页面如图所示:

    在菜品管理模块之中的第二个是菜品的管理,包含了菜品信息的上传、修改、和删除。如下图所示:

    该模块最后一个功能是上传菜品的图片,页面采用JavaScript控件完成,传输方式采用Ajax,该控件支持直接拖放式的图片上传,避免繁琐的文件查找操作。页面如图所示:

    5.6 购物车模块顾客可以在页面中选中菜品后,可以先把菜品放进购物车里面,继续浏览,最后再去购物车页面进行下单操作,也可以直接去下单。
    在购物车页面还可以对选中的菜品数量进行修改,菜品数量的改变会自动修改单项菜品的总价以及订单的总价。同样的,删除操作也会有同样的效果。
    购物车的设计是数据全部放进数据库中,所以需要用户必须登录之后才可以使用购物车。当用户退出之后,购物车里面的内容还会保留下来,直到用户下一次登录时查看。
    如图所示:

    5.7 订单模块用户在选中菜品之后,可以从购物车里进行下单,也可以从页面中进行下单。但用户下单成功之后,会有短信通知到用户和对应的餐厅。餐厅就开始准备菜品。
    当餐厅菜品准备完成,开始配送的时候,餐厅只需要在后台修改订单状态为配送状态,服务器会自动发送短信到该订单顾客的手机上,通知改顾客菜品已经开始配送,请准备好相应的零钱等信息。
    一旦送餐完成,餐厅修改订单状态为送餐完成,这样订单就完成了。
    在下单之前,顾客必须验证手机号才可以进行下单,验证手机号页面如图所示:

    5.8 评价模块在完成一项订单之后,顾客可以对此次的菜品以及菜品进行评价。
    同时,当顾客评论完成之后,顾客的评论就会显示在菜品页面中。同时,餐厅也可以在后台查看到顾客给菜品的评价。
    如图所示:

    5.9 短信通知模块当顾客注册、订餐下单、餐厅配送、订单完成等情况发生时,会自动有短信通知顾客。
    当有餐厅用户注册、顾客订餐时,也会自动有短信通知到餐厅。
    短信模块专门为了与顾客和餐厅进行短信通知使用。它包含以下功能:验证手机号,会发送6位验证码到注册的手机上,只有正确在网页上输入验证码才可以通过验证。通知顾客下单成功功能,当顾客成功下单之后,不仅在网页上会有提示,短息模块还可以发送下达订单成功短息,通知顾客下单成功,短信中还包含部分订单关键信息。通知餐厅有顾客下单功能,与通知顾客下单成功功能类似,用来通知餐厅的。开始配送通知功能,当餐厅准备好菜品开始配送的时候,会激发此功能,此功能会向顾客发送餐厅已经开始配送的短信,其中包含部分订单信息以便顾客了解。
    如图5-20所示:

    5.10 管理员模块管理员可以对网站进行各项管理,查看所有的顾客和餐厅信息,并进行相应的操作。控制网站活动。
    在管理员模块中,查看以及修改顾客信息,查看和修改餐厅信息。给某个用户发送站内信。增加、修改或者删除网站的活动。查看所有的评论。以及进行广告的控制。

    6 总结与展望Laravel作为2014年使用率最高的PHP框架,能够学习并使用Laravel开发此次系统,恐怕是本毕业设计最大的收获了。
    其实,从一开始选择使用何种PHP框架来进行开发,我一直也犹豫过,像国内势头正旺的ThinkPHP或者Yii。ThinkPHP中文PHP框架,易学易用,完善的中文开发文档,遇到问题或者bug可以非常容易的在中文社区得到解答。但是我最后选择了外国人开发Laravel,不仅仅因为它广泛,而是我希望能够挑战自己。
    6.1网站结构设计回顾一开始,本人对于网站的结构是什么太多想法的,按照之前的设计做就好了。但是,实际上对于网站我还是有一个最初的想法,就是顾客——餐厅,这样的设计方式,一开始整体都是对于顾客来设计的,从注册、登录,当然,自始至终我都是非常关注显示效果的,不过后来因为时间有限,我必须加快进度,所以有些东西就必须有舍有得了。
    网站结构第一保证顾客可以很容易的注册,和验证。每个注册的页面我都用JavaScript制作tooltip来弹出小提示用户。之后,顾客还可以非常方便的订餐,不需要考虑太多东西,就可以订餐,这是我希望做的。
    第二个需要保证的就是餐厅的部分了,订餐网站没有了餐厅就不是订餐网站了。对于餐厅我找一个后台管理模板,对于这个模板修改了好几天,再加上后来信息的打入,jqGrid的配置使用、信息的传输、操作的响应,还有dropzone的使用,确实让我花费了一些时间。
    这样做都是为了让餐厅的后台尽可能的好看,以及对于餐厅的管理员来说友好的使用,所有的功能更加的清晰和完善。
    在对顾客友好的方面,本系统有一个设计,那个用户注册不光会有一封邮件确认信,还有一封站内信,让用户觉得你不是注册就完了,“欢迎来到这个大家庭中!”,希望顾客能够在这里有一个归属感,这里不仅仅只是一个订餐的地方。
    参考文献[1]王衍,姚建荣,管理信息系统教程,浙江科学技术出版社
    [2]王珊,数据库系统概论,北京教育出版社
    [3]孟宪虎、马雪英、邓绪斌,大型数据库系统管理、设计与实例分析,电子工业出版社
    [4]卞文志,网上订餐将成为餐饮业利润第二落点[J].烹调知识.2007,(4):26~27
    [5]田杰,乔东亮,秦必瑜,电子商务:模式系统及其运营,中国传媒大学出版社,2009-10-01
    [6]李建忠,电子商务网站建设与管理,清华大学出版社,2012-01-01
    [7]赵祖荫 主编,张瑜,张玮颖 等编著,电子商务网站建设实验指导(第二版),清华大学出版社,2008-3-1
    [8]张波, O2O:移动互联网时代的商业革命, 机械工业出版社
    [9]列旭松,陈文 著,PHP核心技术与最佳实践,机械工业出版社,2012-11-1
    [10] Shawn McCool 著 ,Laravel Starter , Packt PublishingLimited
    [11] (美)弗兰纳根 著,淘宝前端团队 译 ,avaScript权威指南(第6版) , 机械工业出版社,2012-4-1
    [12] (美)凯西恩 著,陈升想 等译,ML 5应用开发实践指南,机械工业出版社,2013-4-1
    [13] 高洛峰 编著,细说PHP(第2版),电子工业出版社,2012-10-1
    [14] 单东林 张晓菲 魏然 编著,锋利的jQuery(第2版),人民邮电出版社,2012-7-1
    [15] (澳)威利,(澳)汤姆森 著,武欣 等译, php和mysql web开发,机械工业出版社,2009-4-1
    3 评论 25 下载 2019-04-12 09:36:10 下载需要16点积分
  • 基于JSP的在线调查问卷系统

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

    总体架构图如下所示:

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

    Logininfo表
    示例值:

    Questions表
    示例值:

    Papers表
    示例值:

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

    用户注册

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

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

    发布问卷页面

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

    填写问卷示例

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

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

    1.背景与意义1.1 项目开发意义随着以信息网络技术为代表的科学技术的迅猛发展,21 世纪,我们已步入了一个以网络应用为核心的数字化革命时代,全球经济一体化程度进一步加强,金融企业的经营环境发生了巨大变化。传统产业的运作模式已经让位于知识经济 和信息经济。在未来的市场竞争中谁掌握和应用好网络银行这一现代化的营销方 式和手段,谁就能在激烈的竞争中取胜,反之则会被淘汰。大力发展网络银行对 银行业的发展具有重要的作用。
    网络银行的兴起与电子计算机信息技术和电子商务的发展有密切的关系。 电子商务是网络银行产生的商业基础,可以说没有电子商务的发展,就不会有网 络银行的兴起,电子商务是一种伴随因特网的普及而产生的新型贸易方式,它是当代信息技术和网络技术在商务领域广泛应用的结果。
    电子商务技术的发展催生了网络银行。通常说,电子商务对银行的要求有 两方面: 一是要求银行为之提供相互配套网上的支付系统; 另一面是要求银行 提供与之相适应的虚拟金融服务。电子商务是一种网上交易方式。所有的网上交易都由两个环节组成的,一是交易环节,二是支付环节,前者是在客户与销售之间完成,后者需要通过银行网络完成。
    1.2 国内外现状及技术综述我国的网上银行产生于上世纪九十年代后期,虽然起步较晚,但发展的势头却很迅猛。1997年招商银行率先在国内推出了网上银行业务,开了我国网上银行的先河,并通过网上银行推出信息咨询、个人银行、企业银行、网上证券等多项服务。2003年的“非典”在我国暴发,激起了网上银行业务的迅速发展。据中国人民银行统计,到 2008年底,我国境内已有70多家银行的分支机构开展了实质性的网上银行业务, 当年交易额已超过90万亿元人民币,较上年增长70.79%。据统计,2002-2008年间,中国网上银行交易额年均增长率高达115%。
    根据IRESEARCH艾瑞市场咨询研究成果显示:2008年,中国国内个人网上银行用户规模为4469万户;国内网上银行使用人数与2007年相比有了大幅度增长,抽查样本中,同比增长了1.7倍,网上银行使用企业数增长了近3倍。我国网上银行走了十多年历程,取得的成效是显而易见的,但也受多种困难的挑战和制约,还存在不少问题,突出有以下几点:
    1.2.1 网上银行发展的基础比较薄弱基础设施落后。主要是指硬件不硬,我国的网络建设除了省、市级以上的大中城市和东部沿海城市发展较快外,其他地方仍然存在着网络覆盖面窄、速度较慢、容量较小、频带不宽、网络吞吐能力有限的现象。目前我国电话、电脑和网络总体普及率不高, 远低于美国2000年的水平。同时软件过软,特别是在软件开发方面,重复开发过多,造成了巨大浪费。
    网上银行使用对象少。经济总量大,人均量很小的现实使我国Internet的社会普及程度较低,电子商务不活跃,导致网上银行缺乏人气基础。资料显示,目前美国使用互联网的成年人已经超过了 1亿,接近国民人口的一半,我国不足四分之一。并且,网民中有三分之一是学生,他们使用网上银行服务的机率很小,绝大多数网民上网的主要目的在于娱乐和获取信息。
    市场主体发展不健全。目前国内网上银行是在现有银行的基础上格局上发展起来的,通过网上银行延伸服务即所谓的传统业务挂靠的电子银行系统,大多数只满足于存款、汇款、汇兑、代收费等业务,只是一个简单化的传统业务外挂,严格说只能算柜面业务的 “上网银行”,总体服务层次低,缺乏内涵,缺乏特色。少数银行对网上银行发展方向认识模糊,仅把它当作扩大传统业务的手段,没有意识到这是一场金融界的革命。
    1.2.2 网上银行的发展环境待完善法律法规滞后。 网上银行在有关服务承担者的资格、交易规则、交易合同的有效成立、交易双方当事人权责等方面,比传统银行更复杂,难以界定,必须通过法制的手段来解决。发达国家和地区的金融监管,当局大都针对网上银行业务制定了系统的监管法规、风险监管指引和监管手册。例如,美国联邦储备委员会于1997年12月发布了《网络信息安全最佳实务指引》,美国货币监管署于1998年8月发布了《网上银行业务检查手册》。2001年中国人民银行虽然颁发了《网络银行业务管理暂行办法》,之后又出台了 《电子银行业务管理办法》等法规,但网上银行的发展十分迅速,有些规定难以适应新形势发展需要,必须与时俱进,制定出台适应网上银行发展的规章制度。
    安全保障令人担忧。网络安全事关网上银行的生死存亡, 是网上银行发展的核心问题。安全既是个技术问题,也是个管理问题。 只有保证了安全才能谈得上盈利,资金安全对银行客户、商家永远是至关重要的。从 2004年8月到2008年10月期间,全国感染各类网上银行木马病毒及其变种的用户数量增长了600倍,用户每月感染病毒及其变种的数量约为160种。中国金融认证中心2007年调查时就发现,超过50% 的人不打算使用或者不敢使用网上银行,2008 年不但未好转, 反而更加严重。
    2.需求分析2.1 总体需求本系统的用户可以分为两类,普通用户和管理员用户。消费者和商家都可以注册为普通用户,当以商家身份注册时,需要银行管理员的审核通过。管理员提供给商家支付链接。
    管理员可以审核用户的注册,开通账户、冻结账户以及审核账户的安全性。本系统给电商平台提供支付链接,认证支付信息并自动更改用户的账户余额等信息。
    所有用户都可以进入银行系统查看账户信息并转账。
    2.2 功能需求2.2.1 银行系统
    注册:用户上传实名身份信息,设置登陆密码和支付密码,审核通过后开通账户,并提供给用户唯一 ID,用于登陆
    登陆:用户输入 ID 和密码,验证成功后进入系统界面。
    修改个人信息:可修改手机号、邮箱等信息,但是身份证号和姓名信息一旦注册后不可修改
    修改密码:登陆密码和支付密码必须验证原密码后才可修改
    银行卡管理:用户验证支付密码之后可开通一张新的银行卡,并提供给用户唯一卡号,用于转账、存款和取款时识别银行卡。一个用户可申请多张银行卡,每张卡的金额独立。用户可随时登陆系统查看自己的余额和卡状态
    转账:用户选择自己的银行卡,输入对方银行卡号,再输入支付密码后确认转账。余额不足、支付密码错误、卡号错误时都不能转账
    存取款:此功能是为方便用户给银行卡添加一定的金额(银行卡新申请时余额为 0),在实际网上银行系统中并无此功能(实际的银行系统存取款需要到实体 ATM 机进行)
    查询转账记录:转账记录包括流水号、转账人、源卡号、目的卡号、转账金额、转账时间。用户只可查看和自己的银行卡号有关的转账记录
    查看存取款记录:存取款记录包括流水号、操作、银行卡号、金额、本次余额和存取款时间

    2.2.2 电子商城接口给电子商城提供支付接口(127.0.0.1:8001/pay?xxx=xxx&xxx=xxx)。消费者首先在银行系统注册并添加银行卡,获取用户 ID 和银行卡号。在电子商城产生订单后使用支付接口将支付信息和订单摘要发送给银行(SET 协议验证),用户界面将跳转到银行系统,输入支付密码后完成支付。
    2.3 安全需求2.3.1 账户安全只有上传个人资料管理员审核之后才能允许注册。所有账户必须保证身份信息真是可靠。
    用户的资料以及转账记录不能被其他人监视。只有本人登陆后才可查看。
    用户的密码信息,包括登陆密码和支付密码,不以明文方式存储。只存储摘要。
    2.3.2 订单安全银行系统不能查看商家和客户之间的订单信息,只能查看转账信息,但是系统可以验证订单信息是否被伪造。这里使用双签名技术,并使用 SET 协议保证订单全程的安全。

    2.3.3 通信安全银行系统的使用中,客户端和服务器之间所有的通信信息都经过加密,可对抗旁路攻击。
    电商平台和银行系统之间的通信必须保证机密性、完整性。
    电商平台的用户生成订单后会点击支付链接,这时电商平台和银行系统之间开始展开秘密通信。
    首先电商平台和银行系统互相查看各自的 CA 证书并获取公钥,银行用私钥加密一条随机消息串发送给电商,电商用银行的公钥解密,这样双方有了共同的秘密消息,之后双方利用此秘密消息作为私钥,加密双方的通信。
    共同私钥定时更换,比如十分钟更换一次。
    2.3.4 数据库安全银行数据库作为整个网上交易系统中最为重要的数据库,需要有加密技术来支持,并且及时备份。
    2.4 性能需求
    能够同时满足 1000 人的访问
    用户认证过程需要安全可靠,速度快,普通用户登录时间小于 3s
    系统可以 24 小时不间断工作
    可以和电商平台对接
    平台兼容性好,能够在各种浏览器上运行

    3.概要设计3.1 硬件环境云服务器:

    有独立 IP 和域名
    网络带宽不低于 10Mbps
    内存 8G
    硬盘 500G

    3.2 开发环境
    操作系统:Windows 10 Pro
    数据库:Mysql
    服务器:Django
    语言:Python3.6 + html + JavaScript + css

    3.3 用户环境Windows、Mac、Linux、Android、IOS,通过浏览器访问。支持的浏览器为 IE、火狐、谷歌浏览器。
    3.4 业务数据流
    3.5 功能模块划分
    3.6 功能模块定义3.6.1 管理员模块管理员模块需要经过银行管理员登陆并认证后操作。管理员可以审核用户注册、获取用户异常,并根据异常信息冻结账户,所有的操作记录数据库。
    3.6.2 用户操作用户包括电商用户和普通用户,都可以进行状态修改,比如修改个人信息、修改密码。有敏感操作时需要转到认证模块作安全认证。
    3.6.3 身份认证银行系统的敏感操作之前需要有安全认证。验证内容包括数字证书是否真实、是否过期,登陆状态是否正常。
    3.6.4 订单审核执行 SET 协议,判断订单信息是否真实,再执行支付操作,转账信息写入数据库,并更改账户余额。
    3.6.5 通信模块电商平台根据提供的支付链接转到银行系统,此后双方执行类似于 SSH 的协议互相认证身份并协商出临时对称密钥,用于加密之后的通信。
    3.7 功能模块划分3.7.1 用户基本信息表Users



    字段
    类型
    长度
    是否主键
    是否非空
    备注




    uID
    int
    32


    用户 ID


    uName
    Varchar
    32


    用户姓名


    Uphone
    Varchar
    32


    用户手机号


    Uemail
    Varchar
    32


    用户邮箱


    uPassword
    Varchar
    128


    登陆密码


    uPaypasswd
    Varchar
    128


    支付密码


    Time
    Date



    创建时间


    Status
    Varchar
    32


    用户状态



    3.7.2 管理员基本信息表Admins



    字段
    类型
    长度
    是否主键
    是否非空
    备注




    aID
    int
    32


    管理员 ID


    aName
    Varchar
    32


    用户姓名


    aPassword
    Varchar
    64


    用户密码



    3.7.3 转账信息Transfer



    字段
    类型
    长度
    是否主键
    是否非空
    外键
    备注




    Serial
    int
    32



    流水号


    Suser
    int
    32


    Users
    发起者 ID


    Duser
    int
    32


    Users
    接收者 ID


    Scard
    int
    32


    Crashcard



    dcard
    int
    32


    Crashcard



    mID
    Varchar
    32



    电商 ID


    Amount
    Float




    金额


    sBalance
    Float




    发起者本次余额


    dBalance
    Float




    接收者本次余额


    Time
    Date




    日期


    Remark
    Varchar
    128



    备注



    3.7.4 银行卡信息


    字段
    类型
    长度
    是否主键
    是否非空
    外键
    备注




    kID
    int




    银行卡号


    Balance
    Varchar
    32



    余额


    User
    int



    Users
    用户 id


    Time
    Date




    创建时间


    Status
    Varchar
    32



    卡状态



    3.7.5 存取款信息


    字段
    类型
    长度
    是否主键
    是否非空
    外键
    备注




    Serial
    int




    流水号


    User
    int



    Users
    用户 ID


    Amount
    Varchar
    32



    存取款金额


    Balance
    Float




    用户本次剩余金额


    Type
    Varchar
    8



    存/取


    Datafrom
    Varchar
    32



    存取款来源


    Time
    Date




    日期



    4.详细设计4.1 注册4.1.1 页面设计

    4.1.2 实现方法输入地址 127.0.0.1:8001,自动跳转到登陆页面,点击注册按钮进入注册页面。
    传输安全:将 CA 服务器提供的证书放到 html 页面,用户客户端提交表单时首先提取证书中的公钥字段,利用公钥加密表单,传输到服务器。服务器接收到信息后首先用私钥解密,再执行下一步操作。
    前端加密 Signup.html
    <script> function formAck() { alert("success"); var cert=document.getElementById("cert").value; #从 html 中获取证书 var certInfo=JSON.parse(cert).info.certInfo var pubKey=JSON.parse(certInfo).PublicKey #从证书中获取公钥 var encrypt = new JSEncrypt(); encrypt.setPublicKey(pubKey); var data={ name:$('#name').val(), idcard:encrypt.encrypt($('#idcard').val(), true), phone:encrypt.encrypt($('#phone').val(), true), email:encrypt.encrypt($('#email').val(), true), passwd:encrypt.encrypt($('#passwd').val(), true), paypasswd:encrypt.encrypt($('#paypasswd').val(), true) }; console.log(data) $.ajax({ url:"/signup/", type:"POST", data:data, success:function (data1) { alert(data1) window.location.href="/login/" } }) }</script>
    后端加密 Views.py
    def signup(request): if request.method=="GET": return render(request, "signup.html") if request.method=="POST": name = request.POST.get("name", None) idcard = tools.DecodeDecrypt(request.POST.get("idcard", None)).decode() phone = tools.DecodeDecrypt(request.POST.get("phone", None)).decode() email = tools.DecodeDecrypt(request.POST.get("email", None)).decode() passwd = tools.DecodeDecrypt(request.POST.get("passwd", None)).decode() paypasswd = tools.DecodeDecrypt(request.POST.get("paypasswd",None)).decode()
    数据库存储密码:登陆密码和支付密码不能直接存入数据库,而是存加 salt 的哈希值。

    4.2 登陆4.2.1 页面设计
    4.2.2 实现方法用户点击登陆后,客户端向服务器发送一个 post 请求,包含 公钥加密后的ID 和登陆密码。服务器接收后,用系统私钥解密,解密成功后:

    验证登陆密码的加 salt 哈希和数据库存储是否一致,一致的话执行下一步操作,不一致返回登陆界面
    服务器设置 session,添加用户 ID 和 name 字段,之后每次操作验证登陆信息时,检查这两个 session 值是否存在即可
    服务器返回“success“字段,客户端接收后执行 href=”/viewuserinf/“ ,执行信息查看操作
    传输安全:用户在登陆界面提交的表单,前端用公钥加密,服务器用私钥解密,具体操作同注册的传输安全

    4.3 信息查看4.3.1 页面设计
    4.3.2 实现方法请求查看页面的请求类型全部为 get 型,url 为 127.0.0.1:8001/viewuserinf/,服务器接收到该请求后,首先验证session 的 id 字段是否存在,存在才可继续查看,不存在则清楚所有 session 并返回登陆界面。
    Views.py
    def viewuserinf(request): if request.method=="GET": try: id_session = request.session["id"] tmp = Users.objects.get(id=int(id_session)) return render(request,"user_inf_show.html",{"inf":tmp}) except: return render(request, "login.html") return render(request, "login.html")
    4.4信息修改4.4.1 页面设计
    4.4.2 实现方法由于用户姓名、身份证号是认证信息,不可修改,登陆密码和支付密码不在此模块。所以这里只能修改手机号和电子邮箱。
    获取信息修改页面的请求方式是 get,用户点击“信息修改”按钮或者直接在浏 览 器 地 址 栏 中 输 入 url : http://127.0.0.1:8001/edituserinf/ ,就会返回信息修改页面。
    信息修改的表单提交使用 post 请求,用户输入的表单信息用公钥加密后传输,服务器接收后用私钥解密,然后检查 session 的 id 字段是否存在,存在则修改成功,返回信息查看界面,否则返回登陆界面。
    4.5 更改密码4.5.1 页面设计

    4.5.2 实现方法获取修改密码界面的请求方式是 get,用户在登陆状态下,点击“修改密码”或 者 在 浏 览 器 地 址 栏 输 入 url:127.0.0.1:8001/editpasswd/获得界面。用户可选择登陆密码和支付密码,更改密码必须输入原密码。
    表单提交的请求方式是 post 请求,客户端使用公钥加密表单,服务器接收请求后用私钥解密,之后:

    检查服务器 session 中是否存在 id 字段,存在继续下一步,不存在返回登陆界面
    MD5加盐计算密码哈希值,与数据库存储的哈希值对比,相等,执行下一步,否则返回信息修改界面重新提交
    计算新密码的加 salt 哈希值,存入数据库。修改完成后,如果是修改支付密码,返回信息查看界面,如果是修改登陆密码,删除 session 后返回登陆界面

    安全设计 :客户端公钥加密传输表单,客户端私钥解密,保证传输安全。修改密码必须验证原密码,并且密码只存储哈希值,保证密码数据库安全。
    4.6 银行卡管理4.6.1 页面设计查看所有个人银行卡:

    添加银行卡:

    4.6.2 实现方法用户获取银行卡管理界面的请求方式为 get,在登陆状态下点击“银行卡管理”或者 url 输入 127.0.0.1:8001/cardmanage/ 进入银行卡管理界面。服务器将银行卡信息返回给用户,每张银行卡信息包括卡号、建立时间、余额和状态。由于涉及到金额,银行卡一旦添加不可删除。
    在银行卡管理模块可以选择添加银行卡,获取页面的请求方式仍是 get。获取到界面后,用户必须输入支付密码,点击确认添加,向服务器发送 post 请求,表单内容为 公钥加密后的支付密码。
    服务器接收到请求后,首先检查 session 的 id 字段是否存在,存在执行下一步,否则删除全部 session 返回登陆界面。解密表单内容,获取明文支付密码,计算加 salt 哈希值,对比数据库支付密码哈希值,相同后即可分配银行卡。
    银行卡添加成功后,分配一个唯一卡号,状态默认为正常,余额默认为 0。随后返回银行卡管理界面。
    4.7 转账4.7.1 页面管理

    4.7.2 实现方法在登录状态下,用户通过点击“转账”或者输入 url: 127.0.0.1:8001/transfer/向服务器发送 get 请求,进入转账界面。
    用户选择本方卡号,输入对方卡号、转账金额、支付密码后确认转账,javascrpt使用公钥加密表单后传输给服务器。服务器接收并私钥解密后:

    检查登陆状态,即检查 session 的 id 字段是否存在,不存在返回登陆界面,存在则进入下一步
    计算用户输入的 paypasswd 的加 salt 哈希值,与数据库提取的密码哈希值对比,相同则进入下一步,不同则返回转账界面重新输入
    将此转账信息写入数据库,再将对应的银行卡做余额更改。执行成功后进入转账查询界面。

    安全:

    客户端公钥加密后传输,防止旁路攻击
    密码存哈希值,明文不出现数据库
    转账记录表和银行卡表中记录的更改在确认转账可以执行后,才一起更改防止数据不同步

    tmp1 = Transfer(time=time, scard=CrashCard.objects.get(id=scard), dcard=CrashCard.objects.get(id=dcard), suser=Users.objects.get(id=uid), duser=Users.objects.get(id=CrashCard.objects.get(id=dcard).user.id), amount=amount, scbalance=CrashCard.objects.get(id=scard).balance - amount, dcbalance=CrashCard.objects.get(id=dcard).balance + amount)CrashCard.objects.filter(id=scard).update(balance=scbalance - amount)CrashCard.objects.filter(id=dcard).update(balance=dcbalance + amount)tmp1.save()
    4.8 存款4.8.1 页面设计
    4.8.2 实现方法在登录状态下,用户点击“存款”或者输入 url: 127.0.0.1:8001/ userdeposit/向服务器发送 get 请求,进入存款界面。
    在存款界面,输入存款卡号和金额,用 RSA 公钥加密表单,传输给服务器。
    服务器解密后,获取卡号和金额,更改数据库银行卡表单,完成操作。返回存取款查询界面。
    4.9 取款4.9.1 页面设计
    4.9.2 实现方法取款操作和存款操作的实现方法类似。不同的内容为:

    取款的 url 为 127.0.0.1:8001/userdraw/
    取款需要验证支付密码,支付密码需要计算加 salt 哈希值与数据库存储哈希值对比

    4.10 转账查询4.10.1 页面设计
    4.10.2 实现方法在登录状态下,用户点击转账查询或者输入url: 127.0.0.1:8001/ viewtransfer/向服务器发送get请求,进入转账查询界面。
    服务器检查登陆状态,即验证 session 的 id 字段是否存在。存在则将该用户的转账记录返回客户端。
    4.11 存取款查询4.11.1 页面设计
    4.10.2 实现方法在登录状态下,用户点击转账查询或者输入url:127.0.0.1:8001/ viewdrawdeposit/向服务器发送get请求,进入转账查询界面。
    存取款查询的实现方法与转账查询方法基本相同。
    5.结束语
    常规网站的设计如果不考虑安全,那么网站能用但是风险极高
    加密传输可使用 RSA 公钥前端加密,后端解密
    本次项目的实现让我了解了很多信息安全的知识,增加了动手能力
    本门课程收获很大

    参考文献[1]翟健宏. 信息安全导论. 北京:科学出版社. 2011.7
    [2]William Stallings. 密码编码学与网络安全-原理与实践. 北京:电子工业出版社.2006.11
    2 评论 29 下载 2019-04-12 21:33:15 下载需要13点积分
  • 基于Python实现的疲劳驾驶检测

    摘 要相比于完全把神经网络当成黑盒来做训练,本文尝试了一种混合的思路:先通过人脸特征点检测获得特征点,再通过特征点预估人脸位置、角度、眼睛开合度等参数,再通过一个LSTM网络进行参数的训练,并对视频做分类。
    一、相关工作2018年CES Asia展会上,科大讯飞展示了他们的驾驶员疲劳检测系统。他们的系统能通过计算机视觉的方法,从摄像头中获取人脸朝向、位置、瞳孔朝向、眼睛开合度、眨眼频率、瞳孔收缩率等数据,并通过这些数据,实时地计算出驾驶员的注意力集中程度。我在现场体验了他们的系统,非常灵敏准确。

    二、总体思路受到科大讯飞DEMO的影响,我做本期末报告时,也希望使用这种基于特征检测、参数计算的方法。我认为,这种方法不是完全黑盒的(相比于纯CNN网络来训练图片),在可解释性上可能会好一些,此外,这种方法还能够检测并记录别的体征数据,这些体征数据也有许多挖掘价值。
    我做的实验分为以下三步:

    通过图片特征点检测的方法获得人脸特征点(如眼、鼻、嘴、轮廓)这一步可以使用著名的dlib (King, 2018)来解决,有效果较好的已训练的模型:shape_predictor_68_face_landmarks.dat。使用它,可以得到68个人脸关键点。
    预处理,通过68个关键点判断人脸的朝向、位置、眼睛开合度信息判断人脸朝向和位置的主要难度在于估计人脸的三维信息,若有三维信息,就可以用OpenCV的函数solvePnP,来计算出一个物体的朝向和位置。但是,因为单目摄像机的深度信息是缺失的,不能真正得到3d数据,所以在解人脸朝向时,需要配合一些人体测量学的统计数据(鼻根到人脸各个器官之间的距离)才行。眼睛开合度的计算比较简单,因为已经有特征点数据,所以计算眼皮之间的高度,除以眼角之间的宽度即可。为了增加特征点数量,减少遗漏掉的信息量,68个特征点也首尾相减(转换为位移),一并算入特征当中。对第二步得到的6个人脸纬度信息、2个眼睛开合度信息,和68个特征点位移信息(每个特征点换为x、y位移两个feature),一幅图144个feature,放进LSTM神经网络中进行训练,并预测。
    对图片进行人脸特征点位置检测人脸特征点检测用到了dlib,dlib有两个关键函数:dlib.get_frontal_face_detector()和dlib.shape_predictor(predictor_path)。前者是内置的人脸检测算法,使用HOG pyramid,检测人脸区域的界限(bounds)。后者是用来检测一个区域内的特征点,并输出这些特征点的坐标,它需要一个预先训练好的模型(通过文件路径的方法传入),才能正常工作。

    使用预训练好的模型shape_predictor_68_face_landmarks.dat,可以得到68个特征点位置的坐标,连起来后,可以有如图所示的效果(红色是HOG pyramid检测的结果,蓝色是shape_predictor的结果,仅把同一个器官的特征点连线)。

    三、对特征点进行预处理,得到人脸6维信息、眼睛开合度疲劳驾驶打盹时,人脸会朝下垂,有时会轻微晃动,眼睛会微眯。这和人清醒时目光向前或略微向上,头部稳定转动很不一样。这是我们对疲劳驾驶直观的理解。这些信息放入LSTM网络里训练,让机器自动辨别这些信息,有可能能达到很好的效果。因此,从图片中采集这些信息很重要。
    先讨论人脸6维信息的获得。如前文所述,单目摄像机不含有深度信息,单目的图像信息是无法估算人脸朝向的(因为相当于3维坐标投影到2维平面上,无法还原)。要把2维信息近似还原成3维信息,需要一些额外的信息(或先验知识),如人体测量学中的人脸五官平均距离 (Wikipedia, 2018)。
    这里参考了一篇论文 (Lemaignan S. G., 2016),和他的代码实现 (Lemaignan, 2018)。代码结合OpenCV和Wikipedia给出的人脸五官距离平均值,来对人脸进行建模。我基于作者的代码进行了改造,使其可以批量预处理数据集中的视频截图,并以数组的方式输出人脸6维信息数据。具体的改造和代码运行方法请看我提交的源码。
    使用本算法批量处理数据集中的所有图片。处理完成之后,便额外得到了6维特征,效果如下:

    接下来,计算眼睛开合度信息。68特征点数据分布如图所示 (Rosebrock, 2017):

    右眼开合度可以通过以下公式得到(左眼同理):

    头部6维信息、加眼睛开合度两维信息,共8维信息。如果有可能,还应该采集瞳孔朝向、瞳孔收缩率等信息,但我并没有能成功。如前文所述,一副图片只抽8个特征,信息丢失可能比较多,因此,我把68个坐标点进行一下处理,也作为特征加进去。考虑到坐标本身意义并不大,坐标位移意义反而大一些,我把这些坐标点首尾相减,换算成了位移。一个位移有x、y两个分量,所以这又是136个特征。这样,预处理就完成了。把一张图抽取为144个和脸有关的feature,可以屏蔽掉许多图片细节,如光照、肤色、头的位置(和身高有关)、背景里窗帘的飘动……(尽管可能丢掉有用的信息)。更加重要的是,一张图片变为144个数字,大大简化了输入数据,每一帧输入数据变简单,就让处理帧和帧之间关系(时序信息)变得可能(计算量不至于过大)。
    五、训练LSTM网络模型并进行分类我大学期间并没怎么接触过机器学习,所以这一步更多是依样画瓢,理解不深入。我进行了一些调查后,发现了LSTM网络,可以用来处理时序信息。我尝试了Tensorflow,但感觉还是比较难上手,后来切换到了Keras,用了Keras封装的更加高层、易懂的API。
    Keras的LSTM层输入要求是三维的数据:(样本编号,时间帧编号(timestep),特征向量),预处理完的数据正好是这样三维的,大多数的shape为:(?, 64, 144)。
    我基本就是参考Keras文档中的示例代码,搭建了一个LSTM网络 (Keras, 2018)。在LSTM层后,添加了一层Dense层,模型就搭建完成了。
    训练时,我跑了500个epoch,最终结果为:测试集上78.12%的正确率。而且因为把图片都抽成特征了,所以训练的速度非常快。效果还是比较可喜的。
    六、不足之处和提升空间的讨论LSTM的使用可能不足
    我对机器学习方面的知识所知甚少。特征提取完之后,我在模型搭建和训练这一步做得很有可能不好。如果有机器学习方面才华横溢的人能指点一下,结果很可能能有所提升。也可以试着把LSTM换成别的,如SVM、简单RNN等(疲劳驾驶检测其实可能不需要Long-term memory)。
    单目摄像机获得信息少,人脸信息估计较差
    因为人脸信息估计用到了统计学数据,但这个数据不是很精确,所以最终得到的角度估计效果并不是很好(一些帧存在跳跃现象)。换成双目摄像机,或者RGB-D摄像机,相信特征点提取的效果会好很多。如果疲劳驾驶检测要被广泛投入生产应用,那么升级硬件设备是可行的。
    基于人脸检测的图像处理健壮性略差
    用HOG pyramid方法,一些帧中检测不出人脸(可能因为光照、帽子等原因),虽然这些帧不多,但是它们对整体效果可能有比较大的影响。这些帧,我目前的处理方法是跳过(可能导致时序上不连续)。也可以尝试使用插值的方法来弥补缺失的帧。
    特征抽取仍然不足
    科大讯飞做的系统,可以抽取图片中眼球方向、瞳孔收缩率作为特征。然而本文并没能够抽取出这些特征,因此可能遗漏掉关键的信息。
    七、总结本文尝试了一种基于特征和参数估计的方法,最后一步分类时,仍然用到了深度学习的方法。受限于个人技术能力,许多可能可以进一步提升准确率的工作还没有做,本文分析了这些可能的改进策略。总体而言,实验结果还是不错的,准确率较高,模型训练快速。这足以说明,先提取特征点再使用机器学习的方法,是一条值得探索的路。
    6 评论 104 下载 2019-05-22 10:45:40 下载需要15点积分
  • 基于C#与opencv的图像处理应用程序

    一、实验方案设计
    总体思路

    采用C#Form窗体应用程序进行实验,实现对两幅有重叠区域的图片进行分析处理,并无缝拼接
    关键步骤

    调用Windows文件系统接口打开图片文件,并输出到界面对两幅图片色彩度、大小等数据进行分析,以便进行相应处理分析图片重叠区域若图片高度相同,则按正常情况拼接若两幅图片色彩度不同,则以色彩度较高的图片为准进行拼接若两幅图片大小不同,则将较小图片放大后与另一张图片进行拼接调用Windows文件系统接口保存图片,图片名、路径自命名附加功能编写,设计图片按角度旋转、左右上下翻转、灰度化处理等

    二、关键代码阐述打开图片文件,处理时将图片副本进行处理、输出显示,以便还原图片状态
    //打开图片(采用输入流打开,防止文件被锁定而导致只能另存为无法保存)private void button1_Click(object sender, EventArgs e){ if (openFileDialog1.ShowDialog() == DialogResult.OK) { path = openFileDialog1.FileName; name = openFileDialog1.FileNames.ToString(); FileStream file = new FileStream(path, FileMode.OpenOrCreate); pictureBox1.Image = Image.FromStream(file); bitmap = (Bitmap)pictureBox1.Image; w = bitmap.Width; h = bitmap.Height; pictureBox1.Image = bitmap.Clone() as Image; bar = (Bitmap)pictureBox1.Image.Clone(); file.Close(); }}
    图片拼接。传入两个Image图片,对图片list遍历拼接
    private Image JoinImage(List<Image> imageList, int a){ //图片列表 if (imageList.Count <= 0) return null; if (a == 0) { //横向拼接 int width = 0; //计算总长度 foreach (Image i in imageList) { width += i.Width; } //高度不变 //int height = imageList.Max(x => x.Height); int height = imageList[1].Height; //构造最终的图片白板 Bitmap tableChartImage = new Bitmap(width, height); Graphics graph = Graphics.FromImage(tableChartImage); //初始化这个大图 graph.DrawImage(tableChartImage, width, height); //初始化当前宽 int currentWidth = 0; foreach (Image i in imageList)
    保存图片,图片名、路径自命名
    //另存为private void button8_Click(object sender, EventArgs e){ if (pictureBox1.Image == null) { MessageBox.Show("请导入图片文件"); } else { saveFileDialog1.InitialDirectory = ""; saveFileDialog1.Filter = "Bitmap (*.bmp)|*.bmp|JPEG (*.jpg)|*.jpg|EMF (*.emf)|*.emf|PNG (*.png)|*.png|GIF (*.gif)|*.gif|TIFF (*.tif)|*.tif"; if (saveFileDialog1.ShowDialog() == DialogResult.OK) { string folderP = saveFileDialog1.FileName; Image img = pictureBox1.Image; img.Save(folderP); } }}
    附加功能编写,设计图片按角度旋转、左右上下翻转、灰度化处理等
    //任意角度旋转private void button3_Click(object sender, EventArgs e){ if (textBox1.Text == ""&& pictureBox1.Image == null) { MessageBox.Show("请导入图片文件"); } else if(textBox1.Text == "" && pictureBox1.Image != null) { MessageBox.Show("请输入旋转角度"); } else { Bitmap a = new Bitmap(pictureBox1.Image);//得到图片框中的图片 pictureBox1.Image = Rotate(Convert.ToInt32(textBox1.Text),a); bar = (Bitmap)pictureBox1.Image.Clone(); }}//灰度化处理private void button5_Click(object sender, EventArgs e){ if (pictureBox1.Image == null) { MessageBox.Show("请导入图片文件"); } else { Bitmap c = new Bitmap(pictureBox1.Image); pictureBox1.Image = GetGrayImage(c) as Image; bar = (Bitmap)pictureBox1.Image.Clone(); }}
    三、结论/程序运行情况正常拼接

    不同色彩度图片拼接

    不同大小图片拼接

    图片保存

    附加功能:灰度化、翻转、角度旋转

    四、小结
    了解到了许多数字图像处理相关方面的知识
    对Windows系统中调用、处理文件等方面有了更深的理解
    对openCV库有一定的认识
    代码遇到问题时要抓住步骤核心分析
    2 评论 17 下载 2019-03-18 15:07:11 下载需要12点积分
  • 基于react框架和MYSQL数据库的社团管理系统

    一、技术简介1.1 ReactReact 可以非常轻松地创建用户交互界面。为你应用的每一个状态设计简洁的视图,在数据改变时 React 也可以高效地更新渲染界面。以声明式编写UI,可以让你的代码更加可靠,且方便调试。创建好拥有各自状态的组件,再由组件构成更加复杂的界面。无需再用模版代码,通过使用JavaScript编写的组件你可以更好地传递数据,将应用状态和DOM拆分开来。
    1.2 JSX一种 JavaScript 的语法扩展。 我们推荐在 React 中使用 JSX 来描述用户界面。
    JSX 是在 JavaScript 内部实现的。我们知道元素是构成 React 应用的最小单位,JSX 就是用来声明 React 当中的元素。与浏览器的 DOM 元素不同,React 当中的元素事实上是普通的对象,React DOM 可以确保 浏览器 DOM 的数据内容与 React 元素保持一致。
    1.3 webpackwebpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
    1.4 npmnpm 是 JavaScript 世界的包管理工具,并且是 Node.js 平台的默认包管理工具。通过 npm 可以安装、共享、分发代码,管理项目依赖关系。
    1.5 YarnYarn 对代码来说是一个包管理器,可以通过它使用全世界开发者的代码, 或者分享自己的代码。Yarn 做这些快捷、安全、可靠。
    通过Yarn可以使用其他开发者针对不同问题的解决方案,使开发过程更简单。 使用过程中遇到问题,可以将其上报或者贡献解决方案。一旦问题被修复, Yarn会更新保持同步。
    1.6 iViewiView 是一套基于 Vue.js 的开源 UI 组件库,主要服务于 PC 界面的中后台产品。
    1.7 Ant Designantd服务于企业级产品的设计体系,基于确定和自然的设计价值观上的模块化解决方案,让设计者和开发者专注于更好的用户体验。
    1.8 Eggegg.js是阿里推出的基于koa的node开发框架。为企业级框架和应用而生。Egg 的插件机制有很高的可扩展性,一个插件只做一件事(比如 Nunjucks 模板封装成了 egg-view-nunjucks、MySQL 数据库封装成了 egg-mysql)。Egg 通过框架聚合这些插件,并根据自己的业务场景定制配置,这样应用的开发成本就变得很低。
    Egg 奉行『约定优于配置』,按照一套统一的约定进行应用开发,团队内部采用这种方式可以减少开发人员的学习成本,开发人员不再是『钉子』,可以流动起来。没有约定的团队,沟通成本是非常高的,比如有人会按目录分栈而其他人按目录分功能,开发者认知不一致很容易犯错。但约定不等于扩展性差,相反 Egg 有很高的扩展性,可以按照团队的约定定制框架。使用 Loader 可以让框架根据不同环境定义默认配置,还可以覆盖 Egg 的默认约定。
    1.9 JSON Web TokenJSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。它是一个很长的字符串,中间用点(.)分隔成三个部分。客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。
    1.10 KnexKnex.js是为Postgres,MSSQL,MySQL,MariaDB,SQLite3,Oracle和Amazon Redshift设计的“包含电池”SQL查询构建器,其设计灵活,便于携带并且使用起来非常有趣。它具有传统的节点样式回调以及用于清洁异步流控制的承诺接口,流接口,全功能查询和模式构建器,事务支持(带保存点),连接池 以及不同查询客户和方言之间的标准化响应。
    二、系统概要设计系统的设计主要前台和后台两个部分
    2.1 系统需求分析
    登录/登出
    社团信息管理

    新增/查询/编辑/注销社团移除社团成员关键字查询社团信息
    公告管理

    新增公告预览/查询/删除已创建的公告公告流量统计
    管理员管理

    添加/删除/编辑管理员权限验证
    个人信息管理

    用户名编辑修改密码

    2.2 可行性分析这里讲的可行性分析的任务是从技术上、经济上分析需解决的问题是否存在可行性。其目的是在尽可能短的时间内用尽可能小的代价确定问题是否有解。
    技术上的可行性分析主要分析技术条件能否顺利完成开发工作,硬、软件能否满足开发者的需要等。
    React是一个用于创建可重用且有吸引力的JavaScript框架。它非常适合代表经常变化的数据的组件。使用React,您可以通过将它们分解为组件而不是使用模板或HTML来构建可重用的用户界面。

    灵活性和响应性:它提供最大的灵活性和响应能力
    虚拟DOM:由于它基于文档对象模型,因此它允许浏览器友好地以HTML,XHTML或XML格式排列文档
    丰富的JavaScript库:来自世界各地的贡献者正在努力添加更多功能
    可扩展性:由于其灵活的结构和可扩展性,React已被证明对大型应用程序更好
    不断发展: React得到了Facebook专业开发人员的支持,他们不断寻找改进方法
    Web或移动平台: React提供React Native平台,可通过相同的React组件模型为iOS和Android开发本机呈现的应用程序

    无论是Web还是本机移动开发,React都是大多数用户界面设计平台的理想选择。
    本系统数据库使用的MySQL,MySQL是最流行的关系型数据库管理系统,在WEB应用方面MySQL是最好的关系型数据库,轻量、开源、简便易用,使用Navicat Premium 12做数据库图形化管理更高效率进行前后端开发。
    2.3 Server端模型
    由前台客户端发起请求来请求数据,Egg服务器判断是否在白名单或请求头中的token是否有效,若满足条件之一,则放行请求,根据router访问对应的controller,controller为数据的处理层,将数据处理好后通过service对数据库进行访问与操作,然后将service返回的结果在controller进行再次处理与封装,然后将响应数据和状态码(默认200)返回前台
    三、数据库设计3.1 数据概念结构设计E-R模型是数据进行第一层抽象的表示方法。它的主要成分包括:实体、联系和属性。我们可以用E-R图将内容表达出来,辅助设计的实现[6]。
    3.2 数据库关系设计该系统数据库关系图如下所示:

    3.3 数据字典管理员表(admin)



    字段
    类型
    主键
    允许空值
    备注




    id
    int(11)
    P

    自动递增


    login_name
    varchar(255)





    name
    varchar(255)





    password
    varchar(255)





    role
    int(1)


    1:超级管理员 2:管理员


    isDel
    int(1)


    默认0



    学生表(student)



    字段
    类型
    主键
    允许空值
    备注




    stu_id
    varchar(255)
    P




    stu_name
    varchar(255)





    password
    varchar(255)





    sex
    int(1)


    0:男 1:女


    role
    int(1)


    0:未审核 1:家庭成员 2:业主


    tel
    varchar(255)





    社团表(community)



    字段
    类型
    主键
    允许空值
    备注




    id
    int(11)
    P

    自动递增


    title
    varchar(255)





    desp
    varchar(255)





    belong_dept
    int(11)





    manage_dept
    int(11)





    chairman_stu_id
    int(11)





    type
    int(11)





    create_time
    varchar(13)





    status
    int(1)


    0:未审核 ; 1:已审核 ; 2:已注销



    社团-学生表(community_student)



    字段
    类型
    主键
    允许空值
    备注




    id
    int(11)
    P

    自动递增


    stu_id
    int(11)





    community_id
    int(11)





    role
    int(11)


    0:成员; 1:社团管理员


    isDel
    int(11)





    社团类型表(community_type)



    字段
    类型
    主键
    允许空值
    备注




    id
    int(11)
    P

    自动递增


    type_name
    varchar(255)





    isDel
    int(11)


    默认0



    部门表(dept)



    字段
    类型
    主键
    允许空值
    备注




    id
    int(11)
    P

    自动递增


    dept_name
    varchar(255)





    isDel
    int(11)


    默认0



    公告表(notice)



    字段
    类型
    主键
    允许空值
    备注




    id
    int(11)
    P

    自动递增


    title
    varchar(255)





    author
    varchar(255)





    content
    text





    create_time
    varchar(255)





    isDel
    int(11)





    公告日志表(notice_log)



    字段
    类型
    主键
    允许空值
    备注




    id
    int(11)
    P

    自动递增


    notice_id
    int(11)





    stu_id
    int(11)





    create_time
    varchar(255)





    四、后台设计在接口设计方面,使用restful API设计原则,访问同一资源的不同操作时,使用同一命名空间,使用不同的请求方式区分不同的操作。
    数据中均没有使用物理删除,只做了逻辑删除,保证数据可回溯。
    新增与更新,都使用同一个接口,根据是否有id去判断是更新还是新增
    4.1 Egg本系统后台采用egg.js编写,egg继承于koa,操作与配置更加简洁,每个请求发送至后台时,先通过编写好的中间件(middleware),然后根据访问的路由(router)去执行对应的控制器(controller),控制器中只做数据操作,不对数据库进行直接操作,将数据整理为服务(service)所需要的形式,直接发送给对应的服务,服务对数据库进行直接操作,然后将结果直接返回给控制器,控制器再将结果响应给前台。
    如此,完成了一次请求
    4.2 权限校验已登录的用户,在请求时的请求头会带Authorization字段,若请求在白名单内,则不需要通过jwt中间件,直接放行,否则要校验此字段,字段里是bare + 登录时生成的json web token。
    jwt中间件对token进行解码后,判断是否合法并且在有效期内,通过则放行,不通过则直接返回状态码401(无权限)。
    代码实现:

    4.3 连接数据库本系统通过knex对数据库进行操作,以函数式编程的方式,简化了手写sql语句的操作,使代码更具语义化与可读性。
    配置MySQL数据库

    4.4 上传图片前端将图片以表单提交的形式传至后台,后台接受一个文件流,将其重命名后存放到目的位置,之后将完整路径发送至前端。

    五、页面设计页面采用蚂蚁金服出品的Ant Design UI 组件库,提供了完善的设计原则、最佳实践和设计资源文件(Sketch 和 Axure),来帮助业务快速设计出高质量的产品原型。
    5.1 登录页面
    输入用户名密码,点击登录,在对密码进行MD5加密后将login_name和password发送至后台,后台进行校验,匹配后将Json Web Token响应回来,将这个token存至cookie中,设定7天的过期时间,当前端再次发起其他请求时,将这个token带到请求头的Authorization字段中,供后台解析。
    若cookie中无请求头,则中止请求,使页面跳转回login页面,重新登录。

    5.2 主页
    antd支持layout和grid两种页面布局,这里采用layout布局,侧边栏通过递归一个JSON对象进行渲染对应的列表内容。

    获取到用户信息时,判断用户的角色,只有超级管理员才可显示管理员管理页签。
    顶部header下拉菜单可以直接跳转到个人信息或者退出登录。

    侧边栏通过collapsed状态进行切换开启或关闭状态。


    主题内容部分采用react-router-dom路由切换,根据url变化切换content内容。

    当页面均无法匹配到对应路由的时候,则进入noFound页面
    5.3 社团管理
    社团列表页面,做了关键字查询与分页功能,分页功能默认每页10条,可更改。

    点击编辑按钮可对当前社团进行更改。

    对每一项均做了填写校验。

    在选择社团主席时,输入学号进行远程搜索,动态选择。
    此处使用Lodash中的防抖功能对输入进行了优化,减少了多次请求造成的性能问题,也避免因请求返回次序不同造成的数据错误。



    当点击详情按钮时,可显示社团内成员,并进行了分组,可对成员进行直接移除。
    5.4 公告管理5.4.1 新增公告
    此处使用react-draft-wysiwyg富文本编辑器制作新增公告功能。编辑好的内容会以HTML标签字符串的形式发送给后台。当发送空值时内容为 ’<p></p>’,此时发布会提示没有添加正文,是否确定提交。

    由于富文本中添加图片是一个比较复杂的操作,此富文本编辑器默认仅可选择在线图片,可增加选取本地图片的选项,但是需要自己后台支持。

    在此处选择图片时,图片限制不可超过500KB并且只可选择’jpg’, ‘jpeg’, ‘png’, ‘gif’这四种格式的图片,选择成功后,会自动将图片上传至服务器,服务器会将处理好的图片的url返回至前台并显示在虚框内,点击添加即可显示到富文本编辑器中,发布时此处会变为<img />标签。
    5.4.2 公告列表
    在此处使用了骨架屏,在数据未完整请求到时,显示骨架,并且为骨架添加必要的延迟,避免白页与页面闪烁。


    当骨架结束后,页面显示内容,对数据进行必要的处理后,点击预览按钮可以显示手机模拟器,预览本条公告。

    手机页面可以进行滚动,但由于在电脑浏览器端显示滚动会有滚动条,很难去掉,有兼容性问题,为了提高体验,显示滚动条,然后将内层盒子扩大出一个滚动条的宽高,再将外层盒子进行over-flow设置为hidden,超出部分不可见,更好地实现模拟手机的滚动功能。


    点击删除按钮时会弹出提示。

    确定后才会删除(逻辑删除)
    5.4.3 流量统计
    默认显示一周以内的公告流量数据,此处使用echarts制作环形图,点击右侧可进行过滤上部时间picker可以选择时间范围,默认为一周内。通过此功能,可以对公告的阅读量进行统计,以便推出更受欢迎的公告资讯。
    5.5 管理员管理只有超级管理员可进入此tab,普通管理员进入不显示这个菜单项,如果在url处输入对应路径,会进入no permission(无权限)页面。


    进入管理员管理页面后,可操作其他管理员但不可操作自己与其他超级管理员。


    此处填写表单均做了表单校验,新增与编辑同理。
    5.6 个人信息
    此处分为基本信息模块与密码模块,基本信息模块可修改用户基本信息,此处只设置了姓名,还可以增加手机号,性别,个性签名,身份证号等等。
    密码模块必须正确输入之前的密码,两次新密码必须一致,而且要满足以字母开头,长度在6~18之间,只能包含字母、数字和下划线才可提交。


    原密码错误会提示错误。
    1 评论 11 下载 2019-08-11 08:41:12 下载需要11点积分
  • 基于C#的超市进存销管理系统

    第一章需求分析1.1 需求分析1.2 用例模型及分析类图的描述1.2.1 用例Use Case:账号密码登录
    参与者:用户
    主事件流:

    用户选择账号登录选项并输入账号密码
    将用户输入的EmpLoginName和EmpLoginPwd与数据库中相应的字段进行匹配
    若匹配成功,则跳转页面,转到主窗口。反之,则提示登陆失败

    1.2.2 用例图用例模型本系统以管理员对数据库的操作为主,实现用例图如下:

    根据对用例的分析,做出用例图如上,管理员主要利用本系统,实现对进货信息、库存信息、销售信息和职工信息、供应商信息的管理。系统采用VS环境开发,实现C/S结构,管理员对各个信息的修改都直接写入数据库。
    1.3 分析类1.3.1 用户登录模块用户登录用例图
    用户登录的用例图,如图1-3-1-1所示:

    用户登录时序图
    如图1-3-1-2所示,表示用户登录的时序图。

    用户登录分析类图(协作图)
    如图1-3-1-3所示,表示用户登录的协作图。

    1.3.2 进货模块进货用例图
    进货的用例图,如图1-3-2-1所示:

    用户登录时序图
    如图1-3-2-2所示,表示用户登录的时序图。

    用户登录分析类图(协作图)
    如图1-3-2-3所示,表示用户登录的协作图。

    1.3.3 销售模块进货用例图
    进货的用例图,如图1-3-3-1所示:

    用户登录时序图
    如图1-3-3-2所示,表示用户登录的时序图

    用户登录分析类图(协作图)
    如图1-3-3-3所示,表示用户登录的协作图

    1.3.4 库存模块进货用例图
    进货的用例图,如图1-3-4-1所示:

    用户登录时序图
    如图1-3-4-2所示,表示用户登录的时序图。

    用户登录分析类图(协作图)
    如图1-3-4-3所示,表示用户登录的协作图。

    1.3.5 职工管理模块进货用例图
    进货的用例图,如图1-3-5-1所示:

    用户登录时序图
    如图1-3-5-2所示,表示用户登录的时序图

    用户登录分析类图(协作图)
    如图1-3-5-3所示,表示用户登录的协作图

    1.3.6 供应商管理模块进货用例图
    进货的用例图,如图1-3-6-1所示:

    用户登录时序图
    如图1-3-6-2所示,表示用户登录的时序图

    用户登录分析类图(协作图)
    如图1-3-6-3所示,表示用户登录的协作图

    第二章 概要分析2.1 系统架构设计
    2.2 数据库设计2.2.1 数据库总体概念设计数据库总体E-R图如图2-2-1所示。

    2.2.2 数据库概念设计通过对于系统的需求分析,整套系统可以设计出六个实体,他们分别是职工实体、供应商实体、进货实体、销售实体、库存实体。
    系统的使用者涉及到多种用户,多以需要一个用户表来保存登陆账号和登陆密码。
    职工表E-R图

    职工数据库表

    供应商表E-R图

    供应商数据库表

    进货表E-R图

    进货数据库表

    销售表E-R图

    销售表

    库存数据库表E-R图

    库存数据库表

    2.3 系统类图设计分析系统,本系统主要包含数据库类和操作类。数据库类包括有进货信息数据库、销售信息数据库、库存信息数据库。操作类主要是对数据库的操作,包括有添加进货、销售、库存、职工、供应商详细信息两个操作。其中添加进货单可以对进货、销售、库存信息数据库执行添加,修改,删除、查找的操作,添加职工、供应商信息可以对物品信息数据库执行添加修改删除的操作。操作类还包含对数据的查询操作,可以根据关键字进行查询;分析以上各个类,作出类图如2-4所示。

    第三章 系统详细设计及实现3.1 系统功能描述本系统主要实现登陆注册模拟超市进货增删改查、销售增删改查、库存增删改查以及对超市内员工的增删和超市供应商的增删。
    3.2 用户登录界面用户登录界面如图3-2所示。

    3.3 职工管理功能职工管理如图3-3所示。

    3.4 供应商管理功能供应商管理如图3-4所示。

    3.5 进货管理功能进货增删改管理如图3-5-1所示。

    进货查询如图3-5-2所示。

    3.6 销售管理功能销售增删改管理如图3-6-1所示。

    销售查询如图3-6-2所示。

    3.7 库存管理功能库存增删改管理如图3-7-1所示。

    库存查询如图3-7-2所示。

    3.8 系统主页面系统主页面如图3-8所示。

    3.9 退出系统退出系统功能如图3-9所示。
    2 评论 28 下载 2019-09-02 12:26:43 下载需要9点积分
  • 基于Android Studio实现的2048游戏

    1 需求分析1.1 背景与意义1.1.1 手机应用市场发展现状随着4G越来越普及以及手机应用的日益丰富还有智能水平的不断提高,从便携性和随身性这两方面来考虑,电脑所带来的体验已经不能跟手机相提并论了,它已经完美的超越了电脑。
    现如今Android、苹果等各智能手机已经基本占领整个手机市场,从而使得更多应用的出现,而手机游戏应用在其中占领主要位置。
    随着Android智能手机的普及以及游戏种类的多元化,使得Android手机游戏用户规模保持着稳步增长之势。
    1.1.2 国内外现状目前国内外的Android开发还是主要以应用开发为主,主要分成三类:企业应用、通用应用及游戏应用。企业应用的开发主要是一些大公司为了自己的品牌而开发的;通用应用主要是一些创业型公司或者独立开发者为了自己盈利开发的应用;游戏应用目前和通用应用相同。
    2048小游戏是一款最近风靡全球的手机游戏,简单的游戏模式和趣味的玩法,几乎游戏下载排行榜的前20名都可以看到“它的身影”。
    1.1.3 此游戏的意义现如今,手机游戏已在我们的生活中占据一席之地,并在一步步的壮大。可以说,随着它的迅猛发展,现今的手机游戏已经不单单是一种缓解压力的工具,而是形成了一种文化现象。随着游戏软件在市场的一步步壮大,与其有关的文化也随之传播。
    2048游戏的制作属于电子游戏中益智类小游戏,它做到了娱乐性、趣味性、教育性相统一。益智类的游戏即是需要去开动大脑思考从而获得游戏的胜利。简单的益智类游戏可以使玩家在娱乐中不断地开发大脑。这样一来就实现了在娱乐中学习。
    1.2 系统需求分析1.2.1 系统功能需求分析系统主要实现以下的几个功能:呈现游戏界面、重新开始游戏、当前分数和最高分数、游戏帮助等功能。
    重新开始游戏是当玩家无法满足当前进度时点击此按钮就会重新开始游戏,如果玩家处于不同关卡时提示重新开始游戏还是停留在此关卡。游戏帮助是当新手玩此游戏时无法知道游戏玩法时给予相应的提示。呈现游戏界面是游戏开始时主界面在游戏区域会生成4x4的矩阵同时在矩阵里面随机生成两个2或4的游戏卡片。当前分数和最高分数是显示此局玩家所获得的分数和历史上最高的分数,如果当前的分数超过最高的分数,那么最高分数显示当前的分数。如下图所示:

    1.2.2 游戏的基本规则在开始游戏后玩家通过滑动屏幕来操控卡片的移动方向,当卡片滑动中如果有两张卡片相同且他们中间也没有其他卡片时,在滑动的过程中这两张卡片会合并,显示为这两张卡片之和。在滑动过程中有三张卡片相同时只会合并向滑动方向两张卡片。在滑动中如果有两张卡片一样同时又有一张卡片的值跟这两张卡片相加的值时,滑动只会使那两张相同的卡片合并而不会接着让合并后的卡片和另一张卡片合并。
    2 系统分析与设计2.1 系统流程设计游戏进入开始页面,能够进入游戏的主界面并开始普通开局,从主界面能够重新开始游戏、查看帮助和进入关卡选择界面。当玩家点击重新开始按钮会弹出相应的对话框让玩家选择,如果玩家选择“是”时则重新开始游戏,如果选择“否”则返回游戏界面不做任何处理。在开始界面按返回按钮时则会退出游戏。
    游戏流程如下图所示:

    2.2 系统模块设计从总体出发,将该系统划分为三大模块:“菜单设计”、“界面设计”和“算法设计”。
    2.2.1 菜单设计菜单的实现是在游戏界面,可进一步划分为三个模块,分别是:“重新开始”、“退出游戏”、“游戏帮助”,如图所示:

    2.2.2 界面设计


    开始界面
    游戏界面









    2.2.3 算法设计当有两张卡片相同时,向它们可以碰撞的方向滑屏,卡片会移动到最底边并生成其两倍数字的卡片,并且生成一个“2”或者“4”的卡片。如图所示:



    生成2
    生成4









    当有两张卡片相同时,且在它们相同的方向有张跟他们之和的卡片,向它们可以碰撞的方向滑屏,相同的卡片会移动到无法移动的位置并生成其两倍数字的卡片,但合成的方向不会跟那两张数字的卡片合并,并且生成一个“2”或者“4”的卡片。如图所示:



    生成2
    生成4









    当界面上没有空位并且两两相邻的卡片不相同时游戏结束。如图所示:

    2.3 本章小结本章主要对游戏所实现的功能进行需求分析,分析了图形的特点和实现的可行性。对系统的性能进行了详细的分析。对系统的流程,系统所需的图形文件,系统的总体架构和系统用例进行了设计。通过本章的分析、设计能更加具体的了解系统功能,对系统所要实现的功能和图形文件有了更深的认识。为下一章系统功能的具体实现提供了可靠的参考依据。
    3 系统实现3.1 开始界面的实现游戏的主界面是按钮,只是为了实现界面的跳转,当玩家点击开始游戏就会调用loginActivity.java,此函数让页面跳转到游戏界面开始游戏,代码及图片如下所示:
    public class loginActivity extends MainActivity { protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.login); }}

    3.2 游戏界面的实现游戏界面主要是在activity_main.xml中当前分数、最高分数、重新开始按钮、退出游戏按钮、游戏帮助按钮、帮助按钮,当跳转到游戏界面时就会调用并执行MainActivity.java函数来展示游戏界面,代码及图片如下所示:
    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);}

    3.3 游戏滑动卡片移动的实现当玩家滑动屏幕时,主要通过GameView函数来监听玩家手指滑动的位置,先通过获取开始坐标和结束坐标,然后通过比较结束坐标跟开始坐标的差值来判断玩家是怎么滑动屏幕的。判断出玩家的滑动轨迹后,通过调用swipeLeft、swipeRight、swipeUp、swipeDown方法来实现卡片的移动,代码及图片如下所示:
    private void initGameView(){ setColumnCount(4); //将面板设置成4列 setBackgroundColor(0xffbbada0); System.out.println("initGameView"); setOnTouchListener(new View.OnTouchListener() { /* * startX:手机刚开始在屏幕上的X坐标 * startY:手机刚开始在屏幕上的Y坐标 * offsetX,offsetY,分别是手指在屏幕上的X,Y上的偏移量 */ private float startX,startY,offsetX,offsetY; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: startX = event.getX(); startY = event.getY(); break; case MotionEvent.ACTION_UP: offsetX = event.getX() - startX; offsetY = event.getY() - startY; if(Math.abs(offsetX) > Math.abs(offsetY)){ if(offsetX < -5){ swipeLeft(); System.out.println("Left"); }else if(offsetX > 5){ swipeRight(); System.out.println("Right"); } } else{ if(offsetY < -5){ swipeUp(); System.out.println("Up"); }else if(offsetY > 5){ swipeDown(); System.out.println("Down"); } } break; } return true; } });}//向左滑动public void swipeLeft(){ boolean meger = false; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { for (int x1 = x+1; x1 < 4; x1++) { if(cardsMap[x1][y].getNum()>0){ if(cardsMap[x][y].getNum()<=0){ /* * 将下标为(x,y)所在位置的卡片上的数字 * 设置为,坐标为(x1,y)所在位置的卡片上的值; * 第二步,将坐标(x1,y)所在位置的卡片上的数字 * 设置为0 * (即:变成空卡片) */ cardsMap[x][y].setNum( cardsMap[x1][y].getNum()); cardsMap[x1][y].setNum(0); x--; meger =true; break; }else if(cardsMap[x][y].equals(cardsMap[x1][y])){ cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); cardsMap[x1][y].setNum(0); MainActivity.getMainActivity(). addScore(cardsMap[x][y].getNum()); meger = true; } break; } } } } if(meger){ addRandomNum(); checkComplete(); }}//向右滑动public void swipeRight(){ boolean meger = false; for (int y = 0; y < 4; y++) { for (int x = 3; x >=0; x--) { for (int x1 = x-1; x1 >= 0; x1--) { if(cardsMap[x1][y].getNum()>0){ if(cardsMap[x][y].getNum()<=0){ /* * 将下标为(x,y)所在位置的卡片上的数字 * 设置为,坐标为(x1,y)所在位置的卡片上的值; * 第二步,将坐标(x1,y)所在位置的卡片上的数字 * 设置为0 * (即:变成空卡片) */ cardsMap[x][y].setNum( cardsMap[x1][y].getNum()); cardsMap[x1][y].setNum(0); x++; meger =true; break; }else if(cardsMap[x][y].equals(cardsMap[x1][y])){ cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); cardsMap[x1][y].setNum(0); MainActivity.getMainActivity(). addScore(cardsMap[x][y].getNum()); meger =true; }break; } } } } if(meger){ addRandomNum(); checkComplete(); }}//向上滑动public void swipeUp(){ boolean meger = false; for (int x= 0; x< 4; x++) { for (int y = 0; y < 4; y++) { for (int y1 = y+1; y1 < 4; y1++) { if(cardsMap[x][y1].getNum()>0){ if(cardsMap[x][y].getNum()<=0){ /* * 将下标为(x,y)所在位置的卡片上的数字 * 设置为,坐标为(x1,y)所在位置的卡片上的值; * 第二步,将坐标(x1,y)所在位置的卡片上的数字 * 设置为0 * (即:变成空卡片) */ cardsMap[x][y].setNum( cardsMap[x][y1].getNum()); cardsMap[x][y1].setNum(0); y--; meger =true; break; }else if(cardsMap[x][y].equals(cardsMap[x][y1])){ cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); cardsMap[x][y1].setNum(0); MainActivity.getMainActivity(). addScore(cardsMap[x][y].getNum()); meger =true; } break; } } } } if(meger){ addRandomNum(); checkComplete(); }}//向下滑动public void swipeDown(){ boolean meger = false; for (int x = 0; x< 4; x++) { for (int y = 3; y>= 0;y--) { for (int y1 = y-1; y1 >=0; y1--) { if(cardsMap[x][y1].getNum()>0){ if(cardsMap[x][y].getNum()<=0){ /* * 将下标为(x,y)所在位置的卡片上的数字 * 设置为,坐标为(x1,y)所在位置的卡片上的值; * 第二步,将坐标(x1,y)所在位置的卡片上的数字 * 设置为0 * (即:变成空卡片) */ cardsMap[x][y].setNum( cardsMap[x][y1].getNum()); cardsMap[x][y1].setNum(0); y++; meger =true; break; }else if(cardsMap[x][y].equals(cardsMap[x][y1])){ cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); cardsMap[x][y1].setNum(0); MainActivity.getMainActivity(). addScore(cardsMap[x][y].getNum()); meger =true; } break; } } } } if(meger){ addRandomNum(); checkComplete(); }}



    效果1
    效果2









    3.4 重新开始游戏功能的实现当玩家点击游戏界面的重新开始游戏时,会弹出给玩家选择的对话框,让玩家选择“是”时游戏会重新开始,代码及图片如下所示:
    public void onClick(View view){ AlertDialog.Builder dialog3 = new AlertDialog.Builder(this); dialog3.setTitle("提示:"); dialog3.setMessage("你确定重新开始吗?"); dialog3.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); dialog3.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); dialog3.show(); }

    3.5 退出游戏功能的实现当玩家中途有事想退出游戏时会弹出给玩家选择的对话框,让玩家选择“是”时游戏会退出,代码及图片如下所示:
    public void onClick(View view){ AlertDialog.Builder dialog = new AlertDialog.Builder(this); dialog.setTitle("提示:"); dialog.setMessage("你确定要离开吗?"); dialog.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { System.exit(0); } }); dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); dialog.show(); }

    3.6 游戏帮助功能的实现当新玩家进入到游戏且不知道此游戏玩法时,玩家可以点击游戏帮助按钮来了解游戏玩法,点击按钮时游戏会弹出对话框显示游戏玩法,代码及图片如下所示:
    public void onClick(View view){ AlertDialog.Builder dialog2 = new AlertDialog.Builder(this); dialog2.setTitle("hey,guy!"); dialog2.setMessage("这么简单的游戏你确定需要帮助?"); dialog2.setNegativeButton("继续玩~", new DialogInterface.OnClickListener({ @Override public void onClick(DialogInterface dialog, int which) { } }); dialog2.show();}

    3.7 本章小结本章主要阐述本游戏相关功能的实现,详细的讲述了主界面的实现和各按钮功能的实现。
    4 测试本章主要对系统的功能进行测试,此次测试只是进行简单的调试,来确定游戏的各项功能是否能够正常运行。
    4.1 游戏流程测试该测试主要验证游戏能否实现场景的切换,当界面在开始界面时只显示按钮画面,当玩家点击此界面的开始按钮时跳转到游戏界面,如图所示:



    效果1
    效果2









    4.2 游戏模式该测试主要是测试游戏能否正常运行,当玩家滑动屏幕时能否正常的移动和当卡片相同时是否能够相加,还有就是测试游戏是否能正常结束。



    效果1
    效果2









    4.3 本章小结本章是对游戏系统进行简单的测试,通过测试可以看出此游戏可以正常的工作,同时一些功能也能够实现。
    5 总结本次课程设计的内容大部分都是参照课堂所讲以及一些网站给出的各种建议写的,在写的过程中遇到了很多问题,学到了很多东西。期间大概是因为基础不够好,只是找错误就花了很长时间。不过正因为这些错误,才能学到更多的知识,才能把知识点掌握的更牢靠,对于一些没有实现的功能,之后我一定会多花费些时间研究出来。我的课程设计优化的空间还相当大,希望老师能给出指导!
    8 评论 406 下载 2018-12-20 18:49:18 下载需要8点积分
  • 基于PHP和MYSQL数据库实现的网上图书管理系统

    一、系统需求分析1.1 系统功能结构模块
    系统设置:图书馆信息,用户设置,参数设置,书架设置图书借还:图书借阅,图书续借,图书归还系统查询:图书档案查询,图书借阅查询,节约到期查询
    1.2 功能需求
    系统管理:定义读者类别并设置参数,添加、修改和删除读者信息图书续借和预约:实现图书的续借、预约等功能图书检索:按书名或作者等信息进行检索借阅查询:查询个人借阅情况、未付罚款情况其他要求:读者未登录时,只能检索图书,登录后才能使用预约、续借和取消预约图书,查询个人借阅史以及修改密码功能
    二、概念结构设计2.1 bookcase


    Name
    Code
    Data Type
    Length
    Precision
    Primary
    Foreign Key
    Mandatory




    id
    书号
    char(10)
    10

    TRUE
    FALSE
    TRUE


    name
    书名
    char(10)
    10

    FALSE
    FALSE
    TRUE



    2.2 bookinfo


    Name
    Code
    Data Type
    Length
    Precision
    Primary
    Foreign Key
    Mandatory




    Barcode
    条形码
    char(10)
    10

    TRUE
    FALSE
    TRUE


    bookname
    书名
    char(10)
    10

    FALSE
    FALSE
    TRUE


    typeid
    图书类型
    char(20)
    20

    FALSE
    FALSE
    FALSE


    author
    作者
    FLOAT


    FALSE
    FALSE
    TRUE


    Page
    页数
    FLOAT


    FALSE
    FALSE
    TRUE


    bookcase
    书架
    char(Max)
    Max

    FALSE
    FALSE
    FALSE


    press
    出版社
    char(20)
    20

    FALSE
    FALSE
    FALSE



    2.3 borrow


    Name
    Code
    Data Type
    Length
    Precision
    Primary
    Foreign Key
    Mandatory




    id
    登陆账号
    char(10)
    10

    TRUE
    FALSE
    TRUE


    readerid
    读者证
    char(10)
    10

    TRUE
    FALSE
    TRUE


    bookid
    条形码
    char(20)
    20

    TRUE
    FALSE
    FALSE


    borrowtime
    借书时间
    char(10)
    10

    FALSE
    FALSE
    FALSE


    backtime
    还书时间
    char(10)
    10

    FALSE
    FALSE
    FALSE


    ifback
    是否归还
    char(5)
    5

    FALSE
    FALSE
    FALSE



    2.4 manager


    Name
    Code
    Data Type
    Length
    Precision
    Primary
    Foreign Key
    Mandatory




    id
    登陆账号
    char(10)
    10

    TRUE
    FALSE
    TRUE


    name
    登录名
    char(10)
    10

    FALSE
    FALSE
    TRUE


    pwd
    密码
    char(10)
    10

    FALSE
    FALSE
    FALSE



    2.5 reader


    Name
    Code
    Data Type
    Length
    Precision
    Primary
    Foreign Key
    Mandatory




    id
    登陆账号
    char(10)
    10

    TRUE
    FALSE
    TRUE


    name
    登录名
    char(10)
    10

    FALSE
    FALSE
    TRUE


    sex
    性别
    char(10)
    10

    FALSE
    FALSE
    FALSE


    tel
    电话号
    char(11)
    11

    FALSE
    FALSE
    FALSE


    E-mail
    邮箱
    char(20)
    20

    FALSE
    FALSE
    FALSE



    2.6 ER图
    三、逻辑结构设计3.1 登录页面展示
    3.2 登录后首页面
    3.3 图书查询页面
    3.4 借阅历史页面
    3.5 用户管理页面
    3.6 图书借阅页面
    3.7 图书续借页面
    3.8 图书归还页面
    四、物理结构设计
    Sql脚本文件
    /*==============================================================*//* DBMS name: MySQL 5.0 *//*==============================================================*/drop table if exists book_type;drop table if exists tb_bookcase;drop table if exists tb_bookinfo;drop table if exists tb_borrow;drop table if exists tb_library;drop table if exists tb_manager;drop table if exists tb_publishing;drop table if exists tb_reder;drop table if exists tb——readertype;/*==============================================================*//* Table: book_type *//*==============================================================*/create table book_type( id int not null, typename varchar(30), primary key (id));/*==============================================================*//* Table: tb_bookcase *//*==============================================================*/create table tb_bookcase( id int not null, name varchar(30), primary key (id));/*==============================================================*//* Table: tb_bookinfo *//*==============================================================*/create table tb_bookinfo( bookname varchar(70), id int not null, price float(8), inTime date, author varchar(30), primary key (id));/*==============================================================*//* Table: tb_borrow *//*==============================================================*/create table tb_borrow( id int not null, readerid int, bookid int, borrowTime date, backTime date, ifback smallint, operator varchar(30), primary key (id));/*==============================================================*//* Table: tb_library *//*==============================================================*/create table tb_library( id int not null, libraryname varchar(50), tel varchar(20), adress varchar(100), email varchar(100), createData date, introduce text, primary key (id));/*==============================================================*//* Table: tb_manager *//*==============================================================*/create table tb_manager( id int not null, name varchar(30), pwd varchar(30), primary key (id));/*==============================================================*//* Table: tb_publishing *//*==============================================================*/create table tb_publishing( ISBN varchar(20), pubname varchar(30));/*==============================================================*//* Table: tb_reder *//*==============================================================*/create table tb_reder( rid int not null, name varchar(20), sex varchar(4), birthday date, tel varchar(20), email varchar(100), createData date, operator varchar(30), remark text, vocation varchar(50), primary key (rid));/*==============================================================*//* Table: tb——readertype *//*==============================================================*/create table tb——readertype( id int not null, name varchar(50), number int, primary key (id));
    五、总结在这个过程中,我们可以获得了解数据库,创建数据库,构建数据库的过程,整个过程中,获得的不仅是代码的实现,以及界面的构造和创建。在数据库和php的连接过程上才是整个设计的关键所在,数据库作为一个基础知识为系统的创建以及数据的收集整理提供了很大的作用。在今后的学习上更应该注意各个软件的结合才行。
    4 评论 151 下载 2018-12-05 09:24:24 下载需要8点积分
  • 基于JAVA和MYSQL的医院简易挂号管理系统

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



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




    KSBH
    CHAR(6)



    科室编号,数字


    KSMC
    CHAR(10)



    科室名称


    PYZS
    CHAR(8)



    科室名称的拼音字首



    T_BRXX (病人信息表)



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




    BRBH
    CHAR(6)



    病人编号,数字


    BRMC
    CHAR(10)



    病人名称


    DLKL
    CHAR(8)



    登录口令


    YCJE
    DECIMAL(10,2)



    病人预存金额


    DLRQ
    DateTime



    最后一次登录日期及时间



    T_KSYS (科室医生表)



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




    YSBH
    CHAR(6)



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


    KSBH
    CHAR(6)



    所属科室编号,第2索引


    YSMC
    CHAR(10)



    医生名称


    PYZS
    CHAR(4)



    医生名称的拼音字首


    DLKL
    CHAR(8)



    登录口令


    SFZJ
    BOOL



    是否专家


    DLRQ
    DATETIME



    最后一次登录日期及时间



    T_HZXX (号种信息表)



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




    HZBH
    CHAR(6)



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


    HZMC
    CHAR(12)



    号种名称


    PYZS
    CHAR(4)



    号种名称的拼音字首


    KSBH
    CHAR(6)



    号种所属科室,第2索引


    SFZJ
    BOOL



    是否专家号


    GHRS
    INT



    每日限定的挂号人数


    GHFY
    DECIMAL(8,2)



    挂号费



    T_GHXX (挂号信息表)



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




    GHBH
    CHAR(6)



    挂号的顺序编号,数字


    HZBH
    CHAR(6)



    号种编号


    YSBH
    CHAR(6)



    医生编号


    BRBH
    CHAR(6)



    病人编号


    GHRC
    INT



    该号种的挂号人次


    THBZ
    BOOL



    退号标志=true为已退号码


    GHFY
    DECIMAL(8,2)



    病人的实际挂号费用


    RQSJ
    DATETIME



    挂号日期时间



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

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

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

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

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




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




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


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


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




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



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




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


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


    内一科
    000002
    扁鹊
    普通号
    23
    23


    保健科
    000003
    华佗
    专家号
    10
    20



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

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

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

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

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

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



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




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


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


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


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


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


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


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


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


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



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

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



    项目
    版本




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


    JDK (Linux)
    OpenJDK 1.8.0_172, Java 8


    集成开发环境
    IntelliJ IDEA 2018.1.3


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


    JRE (Linux)
    OpenJDK Runtime Environment 1.8.0_172-b11


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


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


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


    数据库 (Windows)
    MariaDB 10.3.7 x64



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

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

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














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

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


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


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

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

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

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

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

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


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

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

    前提条件

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

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

    一、系统分析1.1 问题描述
    客户端

    实现简易版的局域网聊天器实现富文本内容聊天智能聊天机器人群发消息传送文件等功能
    服务器端

    实现群发通知管理聊天线程

    1.2 系统功能分析
    客户端功能

    登陆注册发送表情消息发送文本消息截取图片图片处理震动效果发送文件群发消息设置聊天文本样式
    服务器端

    广播通知

    1.3 开发平台及工具介绍
    Eclipse Mars2
    二、系统设计2.1 系统总体结构设计系统采用自己设计的网络消息传输协议,系统采用CS架构模式实现数据传送。


    2.2 系统各个类及类之间关系设计


    注:

    界面一般是继承了JFrame或JWindowJList、JTable所用的model和渲染器renderer都是自己重写的其余的一些比较琐碎的关系理起来比较复杂程序中的控件大多是自己自定义改写的
    2.3 数据存储的设计(文件等)
    采用键值对的方式存储账号密码
    截图默认保存在ScreenCut/+文件名.jpg
    用到了多种流操作,以及网络传输最关键的套接字操作

    2.4 界面设计
    自定义渲染和数据模型,实现JList、JTable的外交改变
    最长用的是在渲染器中继承JTable实现Renderer接口


    三、系统实现


    四、系统测试模块测试与系统测试:
    4.4 登陆测试
    4.5 注册测试
    4.6 表情测试
    4.7 震动测试震动效果无法截图!
    4.8 截图测试

    4.9 滤镜效果测试


    4.10 设置测试
    4.11 机器人聊天测试

    4.12 文件传输测试



    4.13 服务器管理界面测试

    五、总结通过这次的课程设计,可以说是开阔了自己的眼界,可以总结为以下几个方面:

    对JAVA体系的更深入的了解、对JAVA图像处理初步认识、对JAVA网络通信流的操作、流的套接更进一步深刻了解
    对网络通信的理解,CS、BS架构模式的了解
    对设计模式的初步认识与使用,线程管理这块单例模式的功能
    对JAVA的MVC模式的更深刻了解,层与层的分工明确,效率高,易管理,让人惊叹
    对线程的理解更深刻了,深谙UI主线程与处理耗时操作的子线程的逻辑处理关系
    对网络协议的初步了解,关于协议的定义了解,以及各种传送协议的效率比较有了大体。印象,Socket通信UDP和TCP通信机制初步了解
    对系统的架构设计有了初步认识,缓存机制,分布式系统等,虽然代码中还未实现,程序也并不是面向抽象编程和面向接口编程,代码低耦高聚效果一般,但仍然受益

    知识方面,在课程设计的任务中主要负责jlist jtable覆盖重写、基础类的继承重写、接口实现、界面设计与美化等。玩了半个假期后很多学过的知识都记不清楚了,所以打码的过程中经常翻书,让我又重温了知识;一部分知识书上没有,还需要上网查询或者找同学帮忙解决。有很多瓶颈时候,但坚持过去,看到一起完成的作品会有很大的满足感;其他方面:经过这次课程设计任务,我又一次认识到了团队合作的力量和重要性。一起讨论问题:苦恼过,失落过,兴奋过,到最后的成就感,让我成长,也对自己有了很大的信心。
    在这次课程设计,我们一起讨论要实现这个系统的哪些功能,把各自的想法说出来研究,我们还根据各自所学之长来分配工作,让我意识到在团队合作里每个人都能分享自己的想法、找到自己的位置发挥所长很重要,这样才能让我们更好地完成我们的工作。在完成我们的任务的过程中,我把每个功能逐步实现,比如在实现登录功能的时候,我会先把输入正确的账号和密码登录成功的功能实现,然后再实现判断输入的账号和密码是否一致,若不一致就返回重新输入账号密码这一功能,这让我在发现错误的时候更加容易找出并解决。在此过程虽然遇到许多困难,但是我都会去研究课本和课件里的例题或者上网去看教学视频,一步一步测试,自己实在无法解决了就去找同学帮助。
    经过这次课程设计,我对Java有了更深的了解,但这还远远不够,为了未来的发展,我必须更加努力地去学习更广更深的知识。
    4 评论 118 下载 2018-11-06 09:45:15 下载需要7点积分
  • 基于J2EE的新闻管理系统的设计与实现

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

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

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

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

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

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

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

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

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

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

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

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

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



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




    CID
    int
    11
    评论编号


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


    CCONTENT
    varchar
    3000
    评论内容


    CDATE
    datetime
    0
    评论日期


    CAUTHOR
    varchar
    100
    发表评论的用户



    新闻信息表(news)



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




    NID
    int
    11
    新闻编号


    NTID
    int
    11
    所属分类号


    NTITLE
    varchar
    200
    新闻标题


    NAUTHOR
    varchar
    50
    作者


    NCREATEDATE
    datetime
    0
    发布时间


    NCONTENT
    mediumtext
    0
    新闻内容



    用户信息表(news_users)



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




    USID
    int
    11
    用户编号


    UNAME
    varchar
    20
    用户名


    UPWD
    varchar
    20
    用户密码



    分类信息表(topic)



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




    TID
    int
    11
    主题编号


    TNAME
    varchar
    50
    主题名



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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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



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




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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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



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

    1 问题分析和任务定义1.1 问题描述很多涉及图上操作的算法都是以图的遍历操作为基础的。试写一个程序,演示在连通的无向图上访问全部结点的操作。
    1.2 基本要求以邻接多重表为存储结构,实现连通无向图的深度优先和广度优先遍历。以用户指定的结点为起点,分别输出每种遍历下的结点访问序列和相应生成树的边集。
    1.3 测试数据任选国内城市,起点为合肥,暂时忽略里程。
    1.4 问题分析及任务定义此程序需要完成以下操作:使用文件读取数据,以邻接多重表为存储结构,构成一个连通的图。用户输入一个起始点,从起始点开始对图分别进行深度优先和广度优先遍历。分别输出每种遍历下的结点访问序列和相应的生产树的边集。
    程序的执行流程如下图所示。

    1.5 实现本程序需要解决的问题
    如何利用从文件读取的数据构成无向图
    如何实现从用户指定的点开始遍历
    遍历完后如何输出遍历过得点的序列和边集
    如何利用图形化动态的演示遍历过程
    如何提高用户体验

    本程序的难点在于如何创建邻接多重表,和如何遍历所有城市。
    设图的结点20-30个,每个结点用一个编号表示(如果一个图有n个结点,则它们的编号分别为1,2,…,n)。通过输入图的全部边(存于数据文件中,从文件读写)输入一个图,每个边为一个数对,可以对边的输入顺序作出某种限制。注意,生成树的边是有向边,端点顺序不能颠倒。
    2 数据结构的选择和概要设计城市与城市之间是没有方向的,构成的无向图采用邻接多重表来实现,主要表示无向图的的各个边和结点,并通过对邻接多重表的操作实现对无向图的深度优先和广度优先遍历。创建AMLGraph类,其包含的属性和方法如下图所示。

    其中adjMulList是顶点数组指针,所用的顶点结点以顺序方式存储在一维数组中;vexnum和edgenum是无向图的结点个数和边个数;cityMap类是用来存储所有从文件中读取的城市名和坐标信息的类,points、dfs_str、bfs_str是用来存储遍历的城市的坐标和名称的变量。
    GreatAMLGraph函数用来构建邻接多重表,LocationVex函数通过城市名找到该城市在表结点的位置。AMLGraph、~AMLGraph函数分别是类的构造函数和析构函数,BFS_Traverse、DFS_Traverse分别是广度优先和深度优先遍历的函数。
    VexNode结构体是点结点(城市结点),name是城市的名称,firstEdge是EdgeNode类型的指针,指向该顶点的第一条边的结点。
    EdgeNode结构体是边结点,isVisited为标志域,用来标记该条边是否已被访问过;ivex为顶点域,指示依附于这条边的一个顶点的位置(序号);jvex指示另一个顶点的位置;ilink为链域,指向依附于第一条边的结点。
    3 详细设计和编码3.1 邻接多重表的建立
    从文件中读取所有城市名、坐标和线路信息。利用头插法建立邻接多重表。
    for (int i = 0; i < edgenum; ++i){ EdgeNode * e = new EdgeNode; e->isVisited = false; string v1, v2; inFile >> v1 >> v2; int a = LocationVex(v1); int b = LocationVex(v2); e->ivex = a; e->jvex = b; e->ilink = adjMulList[a].firstEdge; e->jlink = adjMulList[b].firstEdge; adjMulList[a].firstEdge = e; adjMulList[b].firstEdge = e;}
    3.2 深度优先遍历先调用DFS_Traverse函数,初始化visited[i]数组,再调用DFS(i),其中i为用户指定城市的索引。在DFS函数中,先访问表结点中第i个点,在判断该顶点的另一端是否被访问,如果没有访问,就在调用DFS(i->jvex),形成递归,直到访问到该顶点的另一端被访问过后,在访问与i相连的其它边,当与i相连的所有边都被访问完时,结束循环。
    while (e){ if (e->ivex == i) { if (!visited[e->jvex]) DFS(e->jvex); e = e->ilink; } else { if (!visited[e->ivex]) DFS(e->ivex); e = e->jlink; }}
    e为EdgeNode类型的指针变量。时间复杂度为O(n+edgeNum)。
    3.3 广度优先遍历先调用BFS_Traverse函数,初始化visited[i]数组,再调用BFS(i),其中i为用户指定城市的索引。BFS函数中,先访问表结点中第i个点,并将该点放入队列q中,在循环中不断取出队列的第一个元素,直到队列为空时,所以点遍历完成,结束该循环。取出队列第一个元素后,再判断该顶点的另一端是否被访问,如果没有访问,就遍历该点,并将该点放入队列,当队列第一个元素的所有相连的点都被访问过后,循环结束,再从队列中取出第一个元素,进行循环遍历。
    while (!q.empty()){ p = q.front(); q.pop(); EdgeNode * e = adjMulList[p].firstEdge; while(e) { if (e->ivex == p) { if (!visited[e->jvex]) { visited[e->jvex] = 1; //std::cout << adjMulList[e->jvex].name + " "; bfs_str.append(adjMulList[e->jvex].name.substr(0, 2) + "->"); q.push(e->jvex); } e = e->ilink; } else if (e->jvex == p) { if (!visited[e->ivex]) { visited[e->ivex] = 1; bfs_str.append(adjMulList[e->ivex].name.substr(0, 2) + "->"); q.push(e->ivex); } e = e->jlink; } }}
    分析上面算法,每个顶点至多进一次队列,遍历过程实质上仍是寻找每个顶点的邻接点的过程,因此时间复杂度和深度优先搜素一样。
    4 上机调试过程调试过程中,一方面是解决产生的bug,另一个面是调整文件中的数据,保证数据的合理性。
    点的名称及坐标

    无向图的边

    5 测试结果及其分析程序运行界面

    遍历演示


    本程序以图形化的形式演示,用户能够任意指定起始点开始遍历,遍历的结果也清晰可见。其中显示了两种遍历的城市编号的序列和遍历的边集。
    6 用户使用说明本程序是在windows7下的Qt creator5.4.1环境下编写的,因为Qt本身就是跨平台图形界面软件,所以本程序支持跨平台运行,支持的平台包括Windows、Mac OS、Linux等桌面操作系统。
    执行本程序后,窗口上回现实所有城市的名称、编号和路线,输入框中默认填写的合肥的编号,该输入框支持模糊查询,可以输入城市名称、城市编号或编号加名称。点击按钮“演示”后,会以文本形式显示遍历城市的序列,以图形化的方式,显示遍历的城市之间的连线。并且可以反复搜索遍历,具有良好的用户体验。在该可执行文件目录下的map.txt是本程序的所依赖的数据来源,文件中的数据可供用户或开发者调整修改。
    参考文献[1] 王昆仑, 李红. 数据结构与算法. 北京: 中国铁道出版社, 2006年5月
    [2] Kay_Sprint. 邻接多重表存储无向图以及有关操作[EB/OL]. http://www.2cto.com/database/201111/110964.html, 2011-11-13/2017-2-16
    2 评论 44 下载 2018-10-31 11:48:00 下载需要9点积分
  • 基于C#实现并对比三种基本的字符串匹配算法-RK算法-KMP算法-朴素算法

    1 需求分析1.1 系统目标
    实现题目说所要求的三种匹配算法的算法设计,算法实现,程序能够稳定,准确的运行并实现字符串匹配的功能,做出相应的窗体界面程序
    分析完成三种算法的时间复杂度,通过程序实验实现三种算法之间用时的比较
    按时撰写完成课程设计的文档和进度表
    优化设计程序的健全度和用户体验

    1.2 系统功能需求
    文本的输入选择功能

    可以选择键入英文文本或者从文件中读入英文文本
    错误检查功能

    可以检查输入的英文文本以及输入的模式串中是否有非英文文本字符,如果有提示修改并重新输入
    字符串匹配算法选择功能

    提供朴素算法、Rabin-Karp算法、KMP算法,3种算法进行比较这四个选择
    重复匹配功能

    如果文本中多次出现需要匹配的模式串,输出重复出现的次数,以及每次在主串中匹配成功的初始位置
    时间的计算和比较

    选择一种算法匹配,如果匹配成功,输出该算法匹配成功所花费的时间,如果匹配失败,则输出匹配失败。选择3种算法比较,如果匹配成功,输出3种算法匹配成功耗时和耗时最长和最短的算法的名字,如果匹配失败,则输出匹配失败
    显示文本功能

    匹配之后会显示每次在主串中匹配成功的位置,点击位置,会弹出文本框,显示匹配上的位置

    1.3 系统关键技术
    hash散列法。Rabin-Karp 算法的实现原理需要用到hash散列法,将所有的字符分别映射到(0.1.2…n)中。文本的匹配转换成数字的匹配,文本字符串右移通过减去最高位,乘上进制数,再加上下一位字符对应的hash值,实现巧妙的右移
    在RK算法中会出现一个问题,一旦模式串的长度过大,减去最高位,乘上进制数,再加上下一位字符对应的hash值,实现右移的时候有可能会溢出,使得该算法失效,于是使用求余的方法来解决,mod一个比较合适的质素,可以避免其溢出
    KMP的关键以及精华在于next数组。Next[i] = j 表示0…j-1与i-j ….i-1这两段匹配串是相同的。Next数组的定义为Next[0] = -1,Next[1] = 0;接下来的Next都通过递推的方式求出。

    2 算法设计2.1 系统整体思路由于选题原因,开发设计从三个方面分别进行,分别是:朴素匹配算法的设计和实现,KR算法的设计和实现,KMP算法的设计和实现。
    2.2 关键数据结构设计顺序结构存储字符串,next数组。
    2.3 朴素算法2.3.1 算法基本思想将主串S中某个位置i起始的子串和模式串P相比较。即从 j=0 起比较 S[i+j] 与 P[j],若相等,则在主串 S 中存在以 i 为起始位置匹配成功的可能性,继续往后比较( j逐步增1 ),直至与P串中最后一个字符相等为止,否则改从S串的下一个字符起重新开始进行下一轮的”匹配”,即将串T向后滑动一位,即 i 增1,而 j 退回至0,重新开始新一轮的匹配。
    2.3.2 算法流程图
    2.4 Rabin-Karp算法2.4.1 算法基本思想预处理长度与模式串长度相同的主串长度,每一字符哈希映射对应0…N中的一个。根据所在的位乘上相应的进制数相加成一个整型数。匹配转换成两个整型数的比较,如果两个整型数相等,说明他们哈希值相同,有可能是相同的串,于是深入匹配这两段串,如果匹配失败,模式串往后移开始新一轮的匹配。
    2.4.2 算法流程图
    2.5 KMP算法2.5.1 算法基本思想用模式串预处理Next数组,Next[i] = j 表示0…j-1与i -j -1….i-1这两段匹配串是相同的。每次匹配失败后,模式串并不是直接重头开始,而是从Next数组里找出起始位置,这样减少了不必要的匹配,节省了时间。
    2.5.2 算法流程图
    3 算法实现3.1 开发语言及工具
    开发语言:C#
    开发工具:visual studio

    3.2 算法关键代码3.2.1 朴素算法关键代码将主串S中某个位置i起始的子串和模式串P相比较。即从 j=0 起比较 S[i+j] 与 P[j],若相等,则在主串 S 中存在以 i 为起始位置匹配成功的可能性,继续往后比较( j逐步增1 ),直至与P串中最后一个字符相等为止,否则改从S串的下一个字符起重新开始进行下一轮的”匹配”,即将串T向后滑动一位,即 i 增1,而 j 退回至0,重新开始新一轮的匹配。
    匹配部分的代码:

    3.2.2 Rabin-Karp算法关键代码预处理最高位和主串哈希值以及模式串哈希值的代码。
    预处理长度与模式串长度相同的主串长度,每一字符哈希映射对应0…N中的一个。根据所在的位乘上相应的进制数相加成一个整型数。

    匹配转换成两个整型数的比较,如果两个整型数相等,说明他们哈希值相同,有可能是相同的串,于是深入匹配这两段串,如果匹配失败,模式串往后移开始新一轮的匹配,以为通过主串减去最高位,乘上进制数再加上最低位。

    3.2.3 KMP算法关键代码预处理next数组的代码。
    通过递推往下求next数组,当p[i] == p[k] 则说明p[0..k] == p[i-k..i],于是就有next[i+1] = k+1;

    每次匹配失败后,模式串并不是直接重头开始,而是从Next数组里找出起始位置,这样减少了不必要的匹配,节省了时间。

    3.3 主要功能界面3.3.1 文本输入的选择功能可以选择从文件中导入英文文本,或者手动输入英文文本。

    选择从文件中导入后的界面

    选择手动输入后的界面

    3.3.2 错误检查功能检查输入的文本和匹配字符串中是否有非英文字符,若有,则提示出错。


    3.3.3 字符串匹配算法选择功能可以选择相应的算法进行字符串匹配。

    3.3.4 重复匹配功能当匹配字符串在文本中多次出现,则输出匹配成功的次数,和每次匹配成功的起始位置。


    若匹配失败,则输出匹配失败。


    3.3.5 时间的计算和比较选择单独是算法,则是输出第一次匹配成功所花费的时间。


    选择3种算法进行比较,则输出3种匹配所花费的时间和匹配耗时最多和最少的算法名称。


    3.3.6 显示文本功能
    点击下面的数字,可以显示匹配上的串在文本中的位置。

    4 算法分析4.1 算法复杂性分析4.1.1 朴素算法朴素的字符串匹配过程可以形象的看成一个包含模式的“模板”P沿文本T移动,同时对每个位移注意模板上的字符是否与文本中的相应字符相等。外层循环的次数最多为len(s) - len(p),内层循环的次数最多为len(p),最坏情况下的时间复杂度:O((len(T) - len(P) + 1) * len(P))。
    4.1.2 Rabin-Karp算法Horner法则p = p[m] + 10(p[m -1] + 10(p[m-2]+…+10(p[2]+10p[1])…)),求出模式字符串的哈稀值p,而对于文本字符串来说,对应于每个长度为m的子串的 哈稀值为t(s+1)=10(t(s)-10^(m-1)T[s+1])+T[s+m+1],然后比较此哈稀值与模式字符串的哈稀值是否相等,若不相同, 则字符串一定不同,若相同,则需要进一步的按位比较,所以它的最坏情况下的时间复杂度为O(mn)。
    4.1.3 KMP算法KMP算法之所以叫做KMP算法是因为这个算法是由三个人共同提出来的,就取三个人名字的首字母作为该算法的名字。其实KMP算法与BF算法的区别就在于KMP算法巧妙的消除了指针i的回溯问题,只需确定下次匹配j的位置即可,使得问题的复杂度由O(mn)下降到O(m+n)。
    4.2 算法优缺点分析4.2.1 朴素算法的优缺点
    优点:朴素算法简单易懂,代码容易实现
    缺点:时间复杂度太高,字符串和英文文本中连续相同的子串太多的时候花费时间比较大

    4.2.2 Rabin-Karp算法优缺点
    优点:思路新颖,用hash映射后的值进行字符串匹配,巧妙移位,代码不难实现
    缺点:因为用到hash,会出现冲突,进行多次不必要的深度匹配,浪费了时间。进制数和质素需要适当的选取

    4.2.3 KMP算法的优缺点
    优点:运用next数组很快的找到匹配失败后应该重新匹配的启示位置,而不是重头再来。节省了时间
    缺点:求next数组需要一定的时间开销

    总的来说,字符串和英文文本有较少的连续相同子串的时候,朴素是不错的选择,这个时候朴素的时间可以接近o(n),而Rabin-Karp和KMP都需要启动时间,就有可能比朴素慢。当字符串和英文文本有较多的连续相同子串的时候,KMP是个不错的选择,他的next数组就能很好的解决匹配失败后字符串该从哪里开始的问题,使时间接近于o(n)。而这时候朴素的复杂度是接近o(n^2)的。RK算法适合较长的英文文本匹配,这样可以忽略他的启动时间,文本较短的时候会跑不过朴素,重复较多的常文本也许会跑不过KMP,其他请客都比这两个算法要快。
    5 项目总结经过了一个月的努力,终于成功的完成了整个项目系统。一开始对RK,KMP算法的一无所知,在查阅了大量资料,翻阅了许多博客后,学会了这些算法,并且知道了这些算法的优缺点和适合在什么场合使用。小组三人分工合作,让我们体会到了在完成项目的过程中合作的难度和重要性。
    同时,在代码初步完成后,我们进行了大量的测试工作,我们曾经以为KMP算法不管在什么情况下都是耗时最少的,朴素算法不管在什么情况下都是耗时最多的,RK算法则处于两者之间。测试后我们发现我们错了,每种算法在不同的情况下会有不同的效果,并没有绝对的谁会最快,谁会最慢,测试工作完成后,发现命令行操作界面并不美观,也不适合广大用户,于是我们对用户体验进行优化,做了一个系统界面,把所有的功能都实现,方便用户使用。
    在这一过程中,我们发现了大量的不足,同时也了解到要完成一个健壮性极强,用户体验很好的软件需要些什么。经过许多讨论和修改,最终完成了界面的制作。总之,在这次课程设计中,我们不仅学会了新的算法,还了解了算法的本质,学会对算法进行纵向比较,也学会了如何完成一个优秀的软件。总之,收获良多。
    3 评论 6 下载 2018-11-05 18:07:17 下载需要5点积分
显示 0 到 15 ,共 15 条
eject