分类

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

资源列表

  • 基于java的仿HTTP协议设计

    Overview课程PJ, 模仿HTTP协议, 并Java Socket编程简单实现协议. 课程设计协议MyHTTP是一个简化版的HTTP协议, 是作为HTTP协议阅读后的一次总结和练手. 文档对Demo运用到的操作进行着重描述, 同时简单描述HTTP其他重要的操作. 本次项目做的Demo, 实现了一个支持HTTP 请求的服务端, 服务端保存了一份学生名单, 因为兼容http请求, 因此可接受来自浏览器的请求. 利用浏览器来作为客户端. 完成对学生学号,姓名的插入和插片的插入以及通过学号来查看学生信息.
    Part I: 协议介绍AbstractHTTP是一个应用层的协议, 是一个用来构建分布协作, 处理富媒体的系统. 它是一个通用的无状态的协议.
    What is MyHTTPHTTP(Hypertext Transfer Protocol.) 是一个用来传输文件和其他数据的协议, 我们这里称其为Resource(资源). 浏览器通过HTTP服务器来把请求(Request)发送到HTTP服务器. 服务器进行处理, 然后将应答(Response) 返回用户. HTTP监听端口80, MyHTTP使用端口 10080.
    MyHTTP 的一般结构和HTTP一样, MyHTTP采用Client-Server模型. 客户端把请求信息发送到HTTP服务器, 服务器返回应答信息. MyHTTP在应答结束后,关闭连接. 因此说这是一个无状态的协议.
    请求和应答的一般结构

    an initial line,
    zero or more header lines,
    a blank line (i.e. a CRLF by itself),
    an optional message body (e.g. a file, or query data, or query output).

    Request Line请求行包括三个部分 1. 方法名, 2. 请求资源地址, 和请求的HTTP版本, (祝, 因为实现的服务器要兼容浏览器请求, 因此, 浏览器版本沿用HTTP请求, HTTP/1.1)
    GET /path/to/file/index.html HTTP/1.1
    HTTP的请求包括

    GET
    HEAD
    POST
    PUT
    DELETE
    TRACE
    CONNECT

    这边我只关注和实现了GET & POST. GET 用来请求资源. POST 用来新增资源. 提交请求到服务端.这里我实现的Demo里, 运用GET来进行对已插入信息的浏览. 运用POST来完成插入新条目, 上传图片的操作.
    Response Line应答行又叫状态行,
    HTTP/1.1 200 OK or HTTP/1.1 404 Not Found
    包括三部分分别是

    执行HTTP的HTTP版本
    状态码
    可读提示

    状态包含:

    1xx indicates an informational message only
    2xx indicates success of some kind
    3xx redirects the client to another URL
    4xx indicates an error on the client’s part
    5xx indicates an error on the server’s part

    本项目里只用到了200 及 404 分别表示请求成功和没找到资源.
    Header lineHeader lines 提供了请求或者响应主题的信息. 本项目中用到了

    Content-Type来区分,请求的资源是文本还是图片
    Content-Length来, 对请求进行切割分段

    详细一览
    Request部分


    Header
    解释
    示例




    Accept
    指定客户端能够接收的内容类型
    Accept: text/plain, text/html


    Accept-Charset
    浏览器可以接受的字符编码集。
    Accept-Charset: iso-8859-5


    Accept-Encoding
    指定浏览器可以支持的web服务器返回内容压缩编码类型。
    Accept-Encoding: compress, gzip


    Accept-Language
    浏览器可接受的语言
    Accept-Language: en,zh


    Cookie
    HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。
    Cookie: $Version=1; Skin=new;


    Content-Length
    请求的内容长度
    Content-Length: 348


    Content-Type
    请求的与实体对应的MIME信息
    Content-Type: application/x-www-form-urlencoded


    Date
    请求发送的日期和时间
    Date: Tue, 15 Nov 2010 08:12:31 GMT


    From
    发出请求的用户的
    Email From: user@email.com


    Host
    指定请求的服务器的域名和端口号
    Host: www.zcmhi.com


    Referer
    先前网页的地址,当前请求网页紧随其后,即来路
    Referer: http://www.zcmhi.com/archives/71.html


    User-Agent
    User-Agent的内容包含发出请求的用户信息
    User-Agent: Mozilla/5.0 (Linux; X11)



    Response部分


    Header
    解释
    示例




    Content-Encoding
    web服务器支持的返回内容压缩编码类型。
    Content-Encoding: gzip


    Content-Language
    响应体的语言
    Content-Language: en,zh


    Content-Length
    响应体的长度
    Content-Length: 348


    Content-Type
    返回内容的MIME类型
    Content-Type: text/html; charset=utf-8


    Date
    原始服务器消息发出的时间
    Date: Tue, 15 Nov 2010 08:12:31 GMT



    Message Body一个HTTP信息包含一个主题, 主体的土体类型, 该如何解析通过header Content-Type & Content-Length来描述比如:

    Content-Type = text/html or image/gif. 那么客户端或者服务端就知道该如何解释拿到的数据
    Content-Length 用来标记body的字节树, 在Socket编程时, 会发现如果没有这个字节数, 那么会导致, 服务端不知道数据读完了没有,从而也就不知道合适开始处理数据并进行回复. 导致阻塞.

    Part II MyHTTP Demo总览包含四个文件

    Server.java, 服务器, 监听10080端口, 当有新的请求来的时候,启动新的线程来处理该请求
    ServerThread, 具体的处理线程. 对请求进行分类,区分GET or POST区分图片请求
    ServerCenter, 具体的业务逻辑, 把通过Socket传来的数据进行保存, 图片及姓名信息. 包括一个对返回HTML的渲染.
    封装简单的工具, 包括时间转化函数, byte转字符串, 读入byte数组及, 在处理表单提交是的, 处理富媒体的时候, 分段读取的工具类

    遇到的困难
    图片处理是, 不得不对, 字节流进行处理, 很容易错误.
    在读入文件时, Java InputStream.read接口接口在buffer返回的数字是读到的内容数, 所以不是说打开一个很大的buffer就可以读到.

    byte [] bytes = new byte[contentLenth];is.read(bytes); 不一定能够读到contentLength个字节.
    在服务端接受客户传来的数据时, 如何判定终止比较trick. 尝试了通过特殊的bye字符串来进行通讯, 但是这样实现出来不能够兼容浏览器请求, 最后想到了可以通过Content-Length header的信息来结束通讯,关闭socket
    如何使用
    git clone
    运行Server.java
    打开浏览器127.0.0.1:10080/index.html可查看创建页面, 填写姓名, 学号, 上传图片
    创建成功后, 比如创建了11300240057学号, 127.0.0.1:10080/queryById/1003545371 可得到查看页面.

    参考文献
    http://jmarshall.com/easy/http/http://tools.ietf.org/html/rfc2616https://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.htmlhttp://bbs.csdn.net/topics/390290625?page=1#post-393011354
    1 评论 0 下载 2019-05-22 13:47:34 下载需要8点积分
  • 基于C#和Sql Server的图书管理系统

    1 课程设计意义与目标1.1 课程设计的意义《可视化编程技术课程设计》是在学生学习完《可视化编程技术》以后进行的设计性集中实践课程,通过课程集中实践,目的是使学生能加深对理论教学内容的理解,学会可视化编程技术的综合应用,培养学生分析问题的解决问题的能力。
    1.2 课程设计的目标通过课程集中实践,要求学生加深对讲授内容的理解,累积经验、学会独立上机调试程序;并且逐步达到综合运用封装、继承和多态等C#难点知识,更深地理解面向对象程序设计的基本概念与方法,从而学会利用C#语言解决一般应用问题,能设利用可视化编程技术开发复杂和综合性的计算机管理信息系统,并为后续专业课程的学习奠定程序设计基础。
    2 课程设计的题目2.1 设计题目概述
    图书管理系统
    2.2 开发环境搭建
    开发语言:C#
    开发工具:Visual Studio 2010
    数据库管理工具:SQL Server 2008

    3 系统的设计与实现3.1 物理数据模型设计




    3.2 主要界面设计
    界面中用了textbox,label,combobox,textbox用于获取数据输入,combobox用于数据选取,button用于单击事件。在用户类别可以选择用户类型,管理员。

    界面中用了textbox,label,combobox,dataGridView,textbox用于获取数据输入,combobox用于数据选取,button用于单击事件,dataGridView用于数据显示。
    功能:可以增加,修改,删除图书。

    界面中用了textbox,label,combobox,dataGridView,textbox用于获取数据输入,combobox用于数据选取,button用于单击事件,dataGridView用于数据显示,用户借书,管理员可以查看用户的借书记录。

    密码修改:可以更改当前用户登录的密码,旧密码符合条件,新密码和旧密码不能相同,新密码和确认密码的相同的条件。

    界面中用了textbox,label,combobox,dataGridView,textbox用于获取数据输入,combobox用于数据选取,button用于单击事件,dataGridView用于数据显示,用户借书,管理员可以查看用户的借书记录。模糊查询在下面有具体介绍。

    管理员信息管理:可以对管理员进行增添改查。

    书库管理:对书库进行增删改查。

    书库查询:按地区分类和按书库编号分类,第二个combobox会自动加载所有记录的值供你选择。

    书库管理:用来增加书库,删除,修改。

    用户管理:对用户的增删改查。

    用户登录之后的界面。

    管理员登录之后的界面。
    4 调试过程中出现的问题及解决办法4.1 数组索引超出界限解决方法:利用断点调试,重新赋值。

    4.2 从试图获取数据时,应添加新的字段
    5 个人体会及建议在这次课设中,基本都是在学习新知识的过程,从powerdesigner到动软生成软件,让我知道了这个工具的强大之处,渐渐开始会用一点,在第一天晚上想重做一遍学生信息管理系统,不料,动软生成的路径没改,直接给覆盖了,所以只能重头再来,在这时就有想法想做个不一样的系统,上学期用C++做了个图书管理系统,有点印象,就选择做这个,一开始一直模范着你给的day1,day2,day3,看不懂BLL,DAL,MODEL之间的关系,经过思考,理解了他们之间的关系,BLL负责储存方法相当于API,DAL负责储存数据,MODEL负责各个对象的类,后面理解了就开始自己写,用户负责借书,用户的增删改,添加用户,管理员负责查询书库,书库的增删改查,查询图书,图书的增删改查,借书记录的增删改查,在这个过程中不仅了解了动软生成软件的机制,而且可熟练的利用这个工具,在这个工具的基础之上,我写出了更多好用的函数供自己使用。在windows应用开发上了解更多控件和控件属性的使用和结合,可以做出功能和界面相对完整的程序,总之,在这次课设中受益匪浅。
    3 评论 21 下载 2019-03-10 21:27:29 下载需要8点积分
  • 基于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方法,一些帧中检测不出人脸(可能因为光照、帽子等原因),虽然这些帧不多,但是它们对整体效果可能有比较大的影响。这些帧,我目前的处理方法是跳过(可能导致时序上不连续)。也可以尝试使用插值的方法来弥补缺失的帧。
    特征抽取仍然不足
    科大讯飞做的系统,可以抽取图片中眼球方向、瞳孔收缩率作为特征。然而本文并没能够抽取出这些特征,因此可能遗漏掉关键的信息。
    七、总结本文尝试了一种基于特征和参数估计的方法,最后一步分类时,仍然用到了深度学习的方法。受限于个人技术能力,许多可能可以进一步提升准确率的工作还没有做,本文分析了这些可能的改进策略。总体而言,实验结果还是不错的,准确率较高,模型训练快速。这足以说明,先提取特征点再使用机器学习的方法,是一条值得探索的路。
    1 评论 1 下载 2019-05-22 10:45:40 下载需要15点积分
  • 基于C++的吃豆人小游戏的设计与实现

    一 游戏介绍游戏的目的就是控制游戏的主角小精灵吃掉藏在迷宫内所有的豆子,并且不能被幽灵抓到,总共有三个关卡。
    二 系统设计2.1 系统总体架构系统总体架构如下表所示:



    玩家
    地图
    敌军




    方向控制
    围墙绘制
    自动行走


    碰撞检测(吃豆子)
    豆子绘制
    碰撞检测(抓人)


    碰撞检测(与敌人相撞)
    地图绘制



    2.2 系统文件结构
    /头文件/GMap.h 声明地图类
    /头文件/Object.h 声明玩家和敌人类
    /源文件/GMap.cpp 实现地图类
    /源文件/GObject.cpp 实现敌人类

    2.3 系统类图系统类图如下所示:


    三 系统实现3.1 系统开发环境
    操作系统:Windows 10
    开发环境:Visual Studio 2017
    开发语言:C++

    3.2 系统功能开发3.2.1 制作游戏窗口修改函数HWND hWnd = CreateWindowW()中的参数把窗口调到所需要的大小
    3.2.2 建立游戏循环创建win32 程序时,自动生成了一个消息循环,可把它作为游戏循环使用1
    3.2.3 使用GDI绘图画玩家交替画出半圆、大嘴、圆三种图形
    3.2.4 地图类设计在地图类中增加一个父类,并派生出三个子类,存放三关数据。
    定义A为真,B为假以绘制地图
    3.2.5 可移动对象设计由一个共同父类GObeject派生出玩家类和敌人类。
    四 系统运行于测试点击“.exe”文件进入游戏,通关则进入下一关,角色死亡则退出游戏。
    游戏界面如下图所示:

    五 参考文献:[1] 《C++ primer》
    [2] 《Effective C++》
    [3] 《C++ 项目开发|实战入门》
    3 评论 39 下载 2018-11-13 14:11:57 下载需要7点积分
  • 基于规则的专家系统的图形检测

    一、概述此项目具体要求为实现一个基于规则的专家系统, 用来进行简单直线型几何图形的形状检测。
    实现的重点在于规则的表示、推理引擎的构建、知识库的构建、图片的预处理和用户界面。
    项目实现语言为Python,图片预处理用到了OpenCV, 用户界面用到了wxPython。
    图形检测专家系统的运作流程为:

    通过图片预处理得到一组基本事实(即图形中各线段端点坐标)
    处理这一组基本事实,产生专家系统的数据库
    推理引擎读取外部的规则文档,产生知识库
    推理引擎读入数据库
    采用后向链接推理技术进行推理
    推理过程中记录触发的规则和符合规则的事实
    绘制出用户所要检测的图形的位置
    在用户界面中显示出来

    图形检测专家系统还提供另外的功能,包括:

    提供规则编辑器,用于增添新的规则
    展示目前的规则库
    展示当前检测图片的事实库

    图形检测专家系统目前支持检测的图形包括:

    三角形

    锐角三角形直角三角形钝角三角形等腰三角形
    直角等腰三角形锐角等腰三角形钝角等腰三角形
    等边三角形
    四边形

    平行四边形
    矩形正方形菱形
    梯形
    等腰梯形直角梯形

    五边形

    正五边形
    六边形

    正六边形

    图形检测专家系统支持不同位置,各种形态,各种大小的图形检测,且支持一张图片多个图形的检测。
    二、图形检测专家系统的结构图形检测专家系统的结构尽可能模仿了书中展示的基于规则的专家系统的基本结构。具体结构如下:

    图形检测专家系统也由5部分组成:知识库Knowledge base、数据库Database、推理引擎Inference engine、解释设备Explanation facilities、用户界面User interface。
    对应的项目文件夹分别为rules、facts、engine、GUI。
    另外,由于图形的特殊性,项目文件中还包含图片预处理器。
    三、规则的构建和表示因为专家系统需要支持动态的加载知识库,所以检测规则不能硬编码在程序中,而是需要长期存储在外部文件中,并在推理引擎中加载。
    基于以上原因,首先构建了一个Rule类用来表示某条规则。Rule类包含id(规则编号),antecedent(规则前项),consequent(规则后项),description(规则描述) 这四个类成员。
    其中, 考虑到图形检测规则的特点,规则前项之间用与逻辑连接。
    一条典型的规则如下所示:
    { IF: ['the shape is triangle', 'lines are all equal'] THEN: 'the shape is equilateral triangle' DESCRIPTION: 'equilateral triangle' }以上规则用来判断一个图形是等边三角形,其他的规则也类似。在用户界面部分提供了规则编辑器的功能,能够在现有的知识库文件的基础上添加新的规则。
    四、知识库的表示知识库也就是此图形检测专家系统的规则集合。知识库以 txt格式存储,包含了判断图形所需的所有规则。
    程序运行时,推理引擎从该知识库文件中读取所有规则,并相应地构建所有规则的Rule实例。
    五、图片的预处理此图形检测专家系统的直接输入是要检测的图片。为了得到关于图片的数据库,首先需要对图片进行一定程度的预处理。
    采用的图片处理库是OpenCV,分别尝试了两种得到数据的方法:

    霍夫变换:cv2.HoughLines2()
    轮廓检测:cv2.findContours()

    霍夫变换
    霍夫变换比较基础,能够得到图片中所有线段的端点坐标。
    但是霍夫变换存在几个比较明显的问题:

    参数很难调:在最初的霍夫变换检测线段的尝试中,不同的参数会得到不同的线段集合,不同的图片在同一个参数下检测出来的线段集合质量也参差不齐,很难找到一个合适的霍夫变换参数
    调整霍夫变换的结果很麻烦:由于得到的线段端点并不很精确,故需要再人为地判断这些端点之间的关系。如判断两个端点是否足够临近,以致能够认为是同一个端点时,需要人为地设置一个临近阈值。但是该临近阈值对于不同的图片有不同的判断结果。有时候阈值太大,以至于将非同一个端点误判为同一个端点,而有时候阈值太小,以至于没有将所有临近端点都判断出来。这个问题在图片预处理中很关键,尤其是在判断两直线夹角时
    当图片中有多个图形时,处理遇到瓶颈:由于霍夫变换得到的是图片中所有的线段,而不能区分哪些线段属于哪一个图形,故需要另外人为判断线段集合的图形归属问题。这带来了很大的工作量

    基于以上问题,和实际尝试中不尽如人意的检测结果,决定放弃使用霍夫变换作为图片预处理的手段。
    轮廓检测
    轮廓检测也比较基础,相对来说还比霍夫变换简单许多。轮廓检测也是得到线段的端点坐标。但不同于霍夫变换,轮廓检测返回的结果是图形的轮廓顶点(需要经过一个近似的步骤cv2.approxPolyDP())。
    也就是说,图片中每个图形都有各自的顶点。更进一步,可以从顶点得到图形的所有边和边与边的关系(夹角大小,是否平行等)。通过这些预处理步骤,可以得到关于图片的基础事实,用来构成以下的数据库。
    因为 轮廓检测的返回值不再有临近端点归并问题, 线段集合的图形归属问题, 所以最终的图片预处理技术以轮廓检测为基础。
    在图片的预处理这一步走了很多弯路,但最终得到了满意的处理结果。
    六、数据库的表示数据库以轮廓为单位,包含了每个轮廓中所有边和角的关系。抽象来讲,数据库包含了每个图形的基本事实。一个典型的数据库如下:
    Contour #0 { --About Lines-- 4 lines < 2 lines are equal (84, 156)-->(365, 155): Length: 281.00, Angle:-0.20 (366, 252)-->(85, 253): Length: 281.00, Angle:-0.20 \> <4 closure lines (84, 156)-->(365, 155): Length: 281.00, Angle:-0.20 (365, 155)-->(366, 252): Length: 97.01, Angle:89.41 (366, 252)-->(85, 253): Length: 281.00, Angle:-0.20 (85, 253)-->(84, 156): Length: 97.01, Angle:89.41 \> --About Angles-- < 1 angle is right angle (84, 156)-->(365, 155): Length: 281.00, Angle:-0.20 (365, 155)-->(366, 252): Length: 97.01, Angle:89.41 \> < 2 pairs of parallel lines (84, 156)-->(365, 155): Length: 281.00, Angle:-0.20 (366, 252)-->(85, 253): Length: 281.00, Angle:-0.20 (365, 155)-->(366, 252): Length: 97.01, Angle:89.41 (85, 253)-->(84, 156): Length: 97.01, Angle:89.41 \> } Contour #1 { --About Lines-- 3 lines some line facts here --About Angles-- some angle facts here }以上数据库是测试用例产生的数据库的一部分。数据库一方面用来检查图片预处理的准确度,另一方面也用来展示给用户查看。
    七、推理引擎的构建 : 后向链接推理技术前向链接和后向链接的抉择
    正如书上给的建议,首先分析我们判定图形形状时解决问题的方式。
    如果要我们判定一个图形,比方说判定一个正方形,我们首先会证实是否是矩形,然后四边是否长度相等。这样的推理方式是从一个假设出发,去找论据,也即后向链接的推理技术。
    另一方面,从项目目标的角度考虑,需要用户选择要检测的图形,然后推理引擎查找相关的事实来支持要检测的假设。所以这也要求图形检测专家系统使用后向链接技术的推理引擎。
    后向链接是目标驱动的推理技术,从复杂度上讲,后向链接比前向链接更高效,因此后向链接也会是推理技术的首选。
    后向链接的实现
    参考书上给的后向链接推理技术的例子,后向链接推理的实现需要有栈结构。
    在推理引擎的实现中,使用了Python的list类型数据结构来模拟栈的操作,提供了将条件压入推理栈,弹出推理栈栈顶条件,获取推理栈栈顶条件,判断推理栈是否为空四个栈操作。
    推理引擎的推理机制

    首先,推理引擎在启动时会加载规则库和数据库,只要检测的图片不变,加载的规则库和数据库就不再重新载入
    之后,根据用户想要检测的形状,设置推理引擎的推理目标,作为第一个压入推理栈的条件
    然后,启动推理引擎:

    Step1:取出推理栈栈顶条件,去和规则库中的规则后项进行匹配。如果匹配成功,则获得该条匹配的规则的所有前项。如果匹配失败,表示所有规则都不适用,直接退出后向链接推理循环Step2:将所有前项逐条和数据库中的事实进行匹配。如果匹配,则说明该前项已经在数据库中被满足,如果不匹配,则说明该前项也是推理的条件之一,将其压入推理栈。对匹配的规则的所有前项都执行这样的操作Step3:重复执行上述Step1和Step2操作,直到遇到下面两种情况:
    推理栈为空,则说明所有推理已进行彻底,推理目标可达,该目标的后向链接推理成功没有能够匹配的规则,则说明没有充分的事实来支持推理目标,推理目标不可达,该目标的后向链接推理失败


    八、用户界面用户界面包含了以下部分:

    源图片
    检测结果的展示图片
    检测结果的成功或失败报告
    检测过程中被匹配的事实
    检测过程中被触发的规则
    能够检测的图形的树形列表
    选择原图片的按钮
    打开规则编辑器的按钮
    展示所有规则的按钮
    展示所有关于源图片的事实的按钮

    用户主界面如下图所示:

    规则编辑界面如下图所示:

    展示所有规则和所有事实的界面如下图所示:

    九、测试用例9.1 单个图形的测试三角形

    锐角三角形

    直角三角形

    钝角三角形

    等腰三角形

    等腰直角三角形

    等腰锐角三角形

    等腰钝角三角形

    等边三角形

    四边形

    平行四边形

    矩形

    正方形

    菱形

    梯形

    等腰梯形

    直角梯形

    五边形

    正五边形

    六边形

    正六边形

    9.2 混合图形的测试








    十、总结图形界面中的Matched Facts文本框和Hit Rules文本框可以作为此图形检测专家系统的解释设备。
    以上即是图形检测专家系统的全部内容。
    其中推理引擎稍作改进可以作为一个通用的后向链接推理的专家系统框架。
    专家系统的设计参考了《人工智能 - 智能系统指南》(原书第3版) 第2章。
    1 评论 1 下载 2019-05-21 21:07:24 下载需要13点积分
  • 基于Android系统手机通讯录管理软件的设计与开发

    摘要谷歌在安卓领域投入了大量精力来开发,使得安卓技术得以广泛推广,现安卓移动平台设备在市场上已经得到大量推广及普及。在Android移动终端操作系统的快速发展,Android的各种手机软件也大量增长。当然,在手机终端中,手机通讯录是手机终端必不可少的基础功能,其质量直接影响着用户对手机使用的体验与感觉。手机通讯管理软件不仅仅只是能够简单添加联系人以及联系方式的功能,而今已发展成为多种形式,丰富了联系人的信息,存储了更多的内容。此课程设计研究的这个项目,主要实现添加联系人的多种联系方式的功能。
    本软件采用Android Studio+Android SDK集成环境,应用程序编程语言采用Java高级语言开发。通过对通讯录中的联系人的管理,来方便用户通讯更加便捷,联系人的数据保存更加安全。在对Android手机通讯管理软件进行详细的系统设计时,对功能进行详细的划分并对其功能做了详细的介绍,列出了一些主要功能流程图。
    关键词:通讯录 Android 数据库 SQLite
    第一章 绪论1.1 项目研究背景经过多年的发展,移动终端不再仅是通讯网络的终端,还将成为互联网的终端。因此,移动终端的应用软件和需要的服务将会有很大的发展空间。
    Android是一套真正意义上的开放性移动设备综合平台,它包括操作系统、中间件和一些关键的平台应用。Android最大特点在于它是一个开放的体系架构,具有非常好的开发和调试环境,而且还支持各种可扩展的用户体验,Android里面具有非常丰富的图形系统,对多媒体的支持功能和非常强大的浏览器。
    Android平台的开放性等特点既能促进技术的创新,又有助于降低开发成本,还可以使运营商能非常方便地制定特色化的产品。
    1.2 项目研究的目的及意义随着4G网络的使用,移动终端不再仅是通讯网络的终端,还将成为互联网的终端。在Google和Android手机联盟的共同推动下,Android在众多手机操作系统中脱颖而出,受到广大消费者的欢迎。
    手机通讯录作为手机的基本功能之一,每天我们都在频繁地使用着。根据手机功能使用调查显示,有9成以上的消费者使用手机通讯录功能。随着手机通讯录功能的不断加强与完善,手机通讯录对于人们的意义,已不仅仅像记事簿一样显示通讯地址,而是向着个性化、人性化的方向发展。通讯录从无到有,大大丰富了内容,同时结构也发生了革命性变化,而且随着手机的发展,相信更优秀的通讯录会越来越受到社会各层人士的喜爱。
    1.3 系统主要实现内容通过对Android技术的相关研究,了解Android源码实现原理以及过程,从而设计出一款能够使用的手机通讯录。
    这款手机通讯录实现的相关内容如下:

    简洁、实用的操作界面
    联系人的增删改查
    分类的增删改查
    呼叫联系人
    登录、注册、修改密码
    群组的增删改查
    导入导出联系人
    支持模糊查询手机通讯录

    第二章 系统分析2.1 系统可行性分析2.1.1 技术可行性Java 应用编程接口为Java应用提供了一个独立于操作系统的标准接口,可分为基本部分和扩展部分。在硬件或操作系统平台上安装一个Java平台之后,Java 应用程序就可运行。现在Java平台已经嵌入了几乎所有的操作系统。这样Java程序可以只编译一次,就可以在各种系统中运行。
    本软件用的是Java开发语言,在Android Studio集成开发环境下,调试容易。当前的计算机硬件配置或则现有安卓手机的硬件配置也完全能满足开发的需求,因此技术上是绝独可行的。
    2.1.2 经济可行性开发该系统所需的相关资料可以通过已存在的相关系统进行调查采集,所需的软件系统、硬件平台等都易于获得,且不需要Android平台机器,用模拟器即可实现开发研究,开发成本低,容易实现,从经济角度来看,该系统可行。
    2.1.3 操作可行性不管是安卓平台的手机,还是计算机,其成本的下降,导致计算机,安卓手机购买成本的降低.这套系统是利用自己的计算机,且使用安卓模拟器,使开发出来的系统有友好的用户界面、操作简单,因此在操作上是可行的。
    2.2 Android通讯录的使用意义该系统针对的主要用户是Android手机用户。Android手机通信管理系统包括以下主要内容:联系人增删改查、呼叫联系人、分类增删改查、多条件搜索、导入导出联系人、修改密码等功能。要设计一个良好的手机通讯录,就必须首先明确该应用环境对系统的要求。
    第三章 系统概要设计3.1 系统总体设计Android手机通讯管理软件主要功能模块包括:联系人增删改查、呼叫联系人、分类增删改查、多条件搜索、导入导出联系人、修改密码等。

    3.2 处理流程设计3.2.1 业务流程图用户首次进入手机通讯管理软件后,会进入用户注册界面,当用户注册成功之后,输入密码即可看到联系人列表界面。联系人列表界面右下方显示增加联系人按钮。上方可以进行联系人的多条件搜索。同时长按某个联系人可实现编辑删除功能。当然点击联系人也可以看到详细信息。界面中显示我的群组列表,打开之后即可进行群组的增删改查功能。点击菜单键,显示通讯录的导入导出功能以及修改密码功能。
    3.2.2 数据增加流程图添加联系人时,数据由用户输入,点击确定按钮,判断数据是否合法(及用户名是否为空),合法则插入到数据库;不合法,提示错误信息,让用户重新输入。流程如图所示:

    3.2.3 数据修改流程图编辑联系人时,点击编辑联系人菜单,输入修改后的数据,点击确定按钮,判断数据是否合法,合法,则更新数据库;不合法,则返回错误信息。 流程如图所示:

    3.2.4 数据删除流程当用户选定一个联系人时,单击删除联系人菜单,提示用户是否删除,点击确定按钮,则从数据库中删除此条记录。数据删除流程如图所示:

    3.3 数据库设计3.3.1 SQLite数据库简介SQLite,是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低。
    本系统采用的是Android系统自带的SQLite轻型数据库数据库。因此占用资源非常小。
    3.3.3 数据库表结构首先创建数据库,在数据库中创建表用来存储联系人数据,其中包括联系人姓名、手机号、群组ID、地址等联系方式。创建群组表用来保存ID和群组名称等信息。两个表联合配合。表结构如图所示:

    第四章 系统详细设计4.1 联系人浏览模块进入手机通讯管理软件后,看到的第一个界面是联系人列表界面。该列表是由ListView控件生成的,打开数据库(如果数据库不存在则创建数据库,并创建数据表),查找数据库中所有的联系人,并把联系人姓名和移动电话号码以及职位这填充到ListView的adapter中。每一行显示一个联系人的姓名和手机号码,联系人的显示的顺序是根据插入数据库的顺序显示的。点击某个联系人会进入查看联系人界面,可以查看联系人的详细信息,对联系人进行编辑、删除、拨打电话、导入导出通讯录等。

    点击[菜单]按钮时,就会显示主菜单项,其中包括:修改密码、导出数据、导入数据。
    点击添加按钮,会进入添加联系人界面,可以输入联系人相关信息,完成联系人添加功能。点击上方搜索栏目,会进入联系人查找界面,可以进行联系人查找,搜索想要找的联系人。
    点击菜单按钮,打开修改密码、导出通讯录、导出通讯录等功能。

    长按列表的某一行时,会弹出长按菜单,其中包括:拨号、编辑联系人、删除联系人。点击查看联系人菜单会进入查看联系人界面。点击编辑联系人菜单会进入编辑联系人编辑界面。点击删除联系人时,会弹出对话框,询问是否删除联系人,点击确定,则从数据库中删除该联系人。

    4.2 查看联系人模块在联系人浏览界面点击某个联系人,则会跳转到该界面。该界面使用TextView把从数据库中调出的联系人的详细信息显示出来,这里面包括联系人姓名、手机号、地址等详细信息。

    4.3 编辑联系人模块编辑联系人界面使用EditView控件显示并修改联系人的详细信息。联系人的所有信息,处于可编辑状态,手机号和座机号的EditView设定为只能输入数字。修改完信息后点击确定按钮,触发确定按钮点击监听事件,从而对数据库中该联系人的信息进行更新, 然后自动返回联系人浏览界面。点击取消按钮会返回联系人浏览界面。

    4.4 查找联系人模块这里采用的查找方法是SQL模糊查询,可以只输入联系人姓名中的一部分,即可查找到所有包含该部分的联系人,并在ListView中显示出来所有的联系人的姓名和手机号码。可实现查找职位、手机号码、名字等信息。

    4.5 修改密码点击菜单,可以查看该软件的修改密码、导入导出等情况。并可实现全部功能。

    4.6 分类管理点击我的群组界面,可以查看群组并且显示群组。在里面可以对群组进行增删改查操作。
    2 评论 19 下载 2019-01-30 17:26:14 下载需要12点积分
  • 基于PyQt5实现的python电梯调度程序

    1. 使用说明1.1 项目简介电梯作为人们出行的重要工具之一,在人们日常生活中扮演着重要的角色。而电梯的调度算法是决定电梯运行效率的关键,一个高效的调度算法对电梯能否有效地运行起到重要的作用。因此,设计一套良好的调度算法具有十分重要的意义。
    1.2 项目目的1.2.1 学习调度算法
    1.2.2 通过实现电梯调度,体会操作系统调度过程
    1.2.3 学习特定环境下多线程编程方法
    1.3 项目功能要求1.3.1 基本任务某一层楼20层,有五部互联的电梯。基于线程思想,编写一个电梯调度程序。
    1.3.2 功能描述每个电梯里面设置必要功能键:如数字键、关门键、开门键、上行键、下行键、报警键、当前电梯的楼层数、上升及下降状态等。
    每层楼的每部电梯门口,应该有上行和下行按钮和当前电梯状态的数码显示器。
    五部电梯门口的按钮是互联结的,即当一个电梯按钮按下去时,其他电梯的相应按钮也就同时点亮,表示也按下去了。
    所有电梯初始状态都在第一层。每个电梯如果在它的上层或者下层没有相应请求情况下,则应该在原地保持不动。
    调度算法自行设计
    1.4 操作手册1.4.1 数字键每部电梯中都设有1-20的数字键,点击数字键,电梯到达指定楼层。如图操作:

    1.4.2 上下行健每个楼层设有上行和下行键,点击上下行健,所有电梯都会接收到请求,调度算法进行调度,安排电梯到达该楼层,如图操作:

    2. 程序设计与实现2.1 设计2.1.1开发环境及语言
    开发环境:pycharm
    开发语言:python

    本项目采用PyQt5实现图形化用户界面,达到电梯调度可视化的目的。
    2.1.2 算法设计对于单部电梯采用LOOK算法:先讨论最短寻找楼层时间优先算法(SSTF):
    最短寻找楼层时间优先(SSTF-Shortest Seek Time First)算法,它注重电梯寻找楼层的优化。
    最短寻找楼层时间优先算法选择下一个服务对象的原则是最短寻找楼层的时间。
    这样请求队列中距当前能够最先到达的楼层的请求信号就是下一个服务对象。
    在重载荷的情况下,最短寻找楼层时间优先算法的平均响应时间较短,但响应时间的方差较大,原因是队列中 的某些请求可能长时间得不到响应,出现所谓的“饿死”现象。
    再讨论扫描算法(SCAN):
    扫描算法(SCAN)
    扫描算法(SCAN) 是一种按照楼层顺序依次服务请求,它让电梯在最底层和最顶层之间连续往返运行,在运行过程中响应处在于电梯运行方向相同的各楼层上的请求。
    它进行寻找楼层的优化,效率比较高,但它是一个非实时算法。扫描算法较好地解决了电梯移动的问题,在这个算法中,每个电梯响应乘客请求使乘客获得服务的次序是由其发出请求的乘客的位置与当前电梯位置之间的距离来决定的。
    所有的与电梯运行方向相同的乘客的请求在一次电向上运行或向下运行的过程中完成,免去了电梯频繁的来回移动。
    扫描算法的平均响应时间比最短寻找楼层时间优先算法长,但是响应时间方差比最短寻找楼层时间优先算法小,从统计学角度来讲,扫描算法要比最短寻找楼层时间优先算法稳定。
    而LOOK算法是对扫描算法的一种改进算法:
    对LOOK算法而言,电梯同样在最底层和最顶层之间运行。
    但当 LOOK 算法发现电梯所移动的方向上不再有请求时立即改变运行方向,而扫描算法则需要移动到最底层或者最顶层时才改变运行方向。
    比较多种算法,要避免“饿死”现象,且最大限度地缩短平均响应时间,提高稳定性,考虑采用LOOK算法
    【参考:我猜,每个程序员对着电梯都想过调度算法吧! https://blog.csdn.net/gitchat/article/details/80202416】
    在单部电梯LOOK算法的基础上,对于多部电梯寻求最短时间调度:对于每部电梯,为其设计一对上下行序列数组,其中上行序列数组正序排列,下行序列数组倒序排列,电梯根据目前状态以及两数组中内容执行动作。
    当某楼层有上行或下行请求发出时,先考虑每部电梯在完成当前序列的过程中能否响应该请求,计算出符合此条件的电梯的响应距离,再考虑剩余电梯从其当前位置到序列终点与终点到该请求位置的响应距离之和,最后比较每部电梯的响应距离,将该请求分配给具有最短响应距离一部电梯。
    2.1.3 数据结构设计本项目要求对每部电梯的状态进行实施监测,需要存储电梯的运行状态,且每部电梯还需要有对应的调度命令,采用python内置的list以及dictionary来存储数据。
    2.1.4 类结构设计UI类
    class Ui_MainWindow(object):
    类成员
    def setupUi(self, MainWindow): # 设置主窗口UI,加载所需的背景,button以及Label
    调度类
    class elevator_schedul():
    类成员
    属性
    self.isUp = {} # 电梯上行标志数组self.isDown = {} # 电梯下行标志数组self.last_isUp = {} # 电梯前一次上行标志数组self.last_isDown = {} # 电梯前一次下行标志数组self.location = {} # 电梯所在层数数组self.upfloor = [[0] * 21 for i in range(6)] # 记录某电梯将处理但未处理的楼层上行请求self.downfloor = [[0] * 21 for i in range(6)] # 记录某电梯将处理但未处理的楼层下行请求self.upSequence = [[] for i in range(6)] # 电梯上行序列数组self.downSequence = [[] for i in range(6)] # 电梯下行序列数组
    方法
    # 监听上行按钮def upbutton_listen(self, btn_number):# 监听下行按钮def downbutton_listen(self, btn_number):# 监听电梯楼层数字按钮,elevator_number:电梯序号,btn_number:按钮楼层号def numberbtn_listen(self, elevator_number, btn_number):# 创建线程def thread(self, elevator_number):# 加载上行序列动画def elevator_up_anim(self, elevator_number):# 加载下行序列动画def elevator_down_anim(self, elevator_number):# 执行完上行动作恢复静止后,处理执行动作时产生的但未处理的请求# 此时执行动作时产生的但未处理的下行请求可能在任意位置,但执行动作时产生的但未处理的上行请求只可能在下方def elevator_finish_up(self, elevator_number):# 执行完下行动作恢复静止后,处理执行动作时产生的但未处理的请求# 此时执行动作时产生的但未处理的上行请求可能在任意位置,但执行动作时产生的但未处理的下行请求只可能在上方def elevator_finish_down(self, elevator_number):# 每趟动画执行完后,对该趟动画执行时产生的未能执行的数据进行处理def finish_anim(self, elevator_number):# 加载电梯动画def elevator_anim(self, elevator_number):
    主窗口界面类
    class myWindow(QtWidgets.QMainWindow):
    类成员
    self.ui = Ui_MainWindow() # 创建UIself.ui.setupUi(self) # 设置UIself.schedul = elevator_schedul(self.ui) # 创建调度逻辑
    2.2 主要功能实现2.2.1 监听上下行按钮【以上行为例】
    2.2.2 监听数字按钮
    2.2.3 执行完上下行动作恢复静止后,处理执行动作时产生的但未处理的请求【以上行为例】# 此时执行动作时产生的但未处理的下行请求可能在任意位置,但执行动作时产生的但未处理的上行请求只可能在下方def elevator_finish_up(self, elevator_number): i = 20 while i >= 1: # 倒序处理执行动作时产生的但未处理的下行请求 if self.downfloor[elevator_number][i] == 1: if i > self.location[elevator_number]: # 上方存在执行动作时产生的但未处理的下行请求 self.upSequence[elevator_number].append(i) # 将最高楼层的下行请求加入上行序列,继续上行 self.upSequence[elevator_number] = list(set(self.upSequence[elevator_number])) self.isUp[elevator_number] = True # self.ui.isup_label[elevator_number].setPixmap(QtGui.QPixmap("icon/isup.png")) # self.ui.isdown_label[elevator_number].setPixmap(QtGui.QPixmap("icon/isnotdown.png")) break # 上方不存在执行动作时产生的但未处理的下行请求 self.downfloor[elevator_number][i] = 0 self.downSequence[elevator_number].append(i) # 将记录的上方的上行请求加入上行序列,开始上行 self.downSequence[elevator_number] = list(set(self.downSequence[elevator_number])) self.downSequence[elevator_number].sort() self.downSequence[elevator_number].reverse() self.isDown[elevator_number] = True # self.ui.isup_label[elevator_number].setPixmap(QtGui.QPixmap("icon/isnotup.png")) # self.ui.isdown_label[elevator_number].setPixmap(QtGui.QPixmap("icon/isdown.png")) i = i - 1 # 不存在下行请求,处理执行动作时产生的但未处理的上行请求(该请求只可能在下方) if self.isDown[elevator_number] == False and self.isUp[elevator_number] == False: for i in range(1, 21): # 正序处理 if self.upfloor[elevator_number][i] == 1: self.downSequence[elevator_number].append(i) # 将最底楼层的下行请求加入下行序列,开始下行 self.downSequence[elevator_number] = list(set(self.downSequence[elevator_number])) self.isDown[elevator_number] = True # self.ui.isup_label[elevator_number].setPixmap(QtGui.QPixmap("icon/isnotup.png")) # self.ui.isdown_label[elevator_number].setPixmap(QtGui.QPixmap("icon/isdown.png")) break
    3. 测试3.1 功能键测试上行:测试用例:五部电梯处于随机状态,按下某一楼层上行按钮
    预期结果:程序正常运行,具有最短响应距离的电梯处理请求:
    测试结果:电梯1响应,符合预期


    下行:测试用例:五部电梯处于随机状态,按下某一楼层下行按钮
    预期结果:程序正常运行,具有最短响应距离的电梯处理请求:
    测试结果:电梯4响应,符合预期


    数字键测试用例:五部电梯处于随机状态,按下某一电梯数字按钮
    预期结果:程序正常运行,该电梯正确处理请求:
    测试结果:电梯正确响应,符合预期

    0 评论 1 下载 2019-05-21 15:09:40 下载需要3点积分
  • 基于C++实现的教职工信息管理系统

    一、实验内容教职工信息管理系统用于管理教职工信息,能够根据工号、姓名、科室精确查询职工信息;能分系部进行职称统计,计算各职称的人数;根据职工的职称排序输出;根据工号修改或删除职工信息。
    二、运行环境
    软件环境

    操作系统:windows 8.1开发环境:visual studio 2015
    硬件环境

    处理器:Intel(R) Core(TM) i5-4200U CPU @ 1.60GHz 2.30GHz内存:4.00GB系统类型:64位操作系统

    三、课题分析3.1 主要功能
    设计菜单实现功能选择
    输入功能

    输入职工信息,并保存到文件中
    查询功能

    能够根据工号精确查询职工信息能够根据姓名、科室查询职工信息分系部进行职称统计,计算各职称的人数
    根据职工的职称排序输出
    根据工号修改职工信息
    根据工号删除职工信息

    3.2 程序菜单项
    四、主要模块功能4.1 类的编写教职工管理系统 包括两个类 employee类与empNode类。Employee包含教职工的所有基本信息,以及更改和查看基本信息的所有方法;empNode类为链表,节点值是一个employee对象,以及指针指向下一个节点;data.txt 用于储存教职工所有基本信息。


    4.1.1 employee类class employee{public: employee(); //默认构造函数 employee(string na,bool sex,long long jobNu,long long phoneNu,string depart,string title); ~employee(); //显示教职工信息 void display(); //返回工号 long long getJobNumber(); //返回科室 string getDepartment(); //返回姓名 string getName(); //返回职称 string getTitle(); //返回性别 bool getSex(); //返回电话号码 long long getPhoneNumber(); //返回职称等级 int getlevelOfTitle(); //用于修改姓名 void setName(const string a); //修改性别 void setSex(const bool a); //修改工号 void setJobNumber(const long long a); //修改电话号码 void setPhoneNumber(const long long a); //修改所属部门 void setDepartment(const string a); //修改职称 void setTitle(const string a); //输入所有信息 void setAllFromeCin();private: string name;//姓名 bool sex;//性别 1---男 0----女 long long jobNumber;//工号 long long phoneNumber;//电话号码 string department;//所在部门科室 string title;//职称 int levelOftitle;//职称等级};
    4.1.2 empNode类链表用于程序运行中储存每一个教职工的信息,考虑到信息量比较大所以使用链表,对于增删比较容易。
    class empNode{public: empNode(); empNode(const employee &item, empNode *nextNode = NULL) :emp(item), next(nextNode) {} //find***按照相应的变量查找 void findName(string name); void findJobNumber(long long jobNumber); void findDepartment(string department); void findTitle(string title); //统计概览 各个职称人数与各个部门人数 void overView(); //将链表中的值写入文件 void write(); //修改某个工号的个人信息 void change(long long); //删除某个工号 void erease(long long); //按照职称排序输出 void paixushuchu(); ~empNode(); employee emp;//节点值 empNode *next;private:};
    4.2 程序流程读入文件(将data.txt文件中的数据读入链表)
    开始小过场(简单的文字效果)

    显示菜单(signal1作为一级菜单的选择信号)

    可以从一级菜单选择相应个功能,若为非法输入程序会有提示,例如:


    添加:选择后即可按照系统提示输入教职工信息
    查找:跳转进入二级菜单选择具体查找方式
    修改:按提示输入工号若该工号存在则修改,若不存在则回到一级菜单
    按职称排序输出:系统对所有教职工按等级排序输出
    删除:输入工号,若工号存在则删除对应条目,不存在则调回一级菜单

    二级查询菜单

    接下来的流程取决于用户的选择,用户可以自由选择各项功能;程序从用户得到输入,查询或对链表进行增删改,再显示处理结果。
    所有的输入都进行过滤防止非法字符导致的程序崩溃,在删除前会让用户再次确认,显示结果有些会在显示一到两秒内自动跳转到上级菜单,有些会让用户确认后返回;直到用户在一级菜单输入-1退出一级菜单,退出菜单后将链表中的内容更新到data.txt文件中。
    结束的文字效果

    五、实验调试用于过滤非法输入:
    while (!(cin >> signal2)){ cout << "请输入合法字符" << endl; cin。clear(); cin。ignore();}
    菜单:提供与用户互交的接口,读取用户需求并调用链表的方法实现这些需求
    链表:具体的数据结构,并提供具体的实现方法(是这个程序设计的难点与重点)
    Employee:结构化的储存程序所处理的对象,提供写入及查看基本参数的方法
    Data。txt:以文本形式储存数据
    string TITLE[4] = { "教授","副教授","讲师","助教" };//职称列表
    在程序中我将职称这分为以上四项。因为教职工的职称是相对固定的。不会无缘无故多出副讲师之类的职称。而且这么做易于进行排序。在employee类的成员变量中有一项是levelOfTitle就是通过对比字符串表得到的,在进行排序的时候就可以简单的依据levelOfTitle排序。
    六、实验总结优点
    改进了用户体验(有开场的类似动画的文字效果),与程序的稳定性(解决非法输入问题)。
    缺点
    对于大量的长短不一样的文本显示效果没有对齐,看上去比较凌乱。
    收获
    实践是检验真理的唯一途径,实际操作中会遇到很多课本上没有提到的问题,这时候要学会自己解决或者学会使用Baidu与Google。 通过这次C++的大型实验,我深刻的明白到:课本知识与实践能力相结合的重要性。会读程序的人并不一定会编程序。要想把一门专业课程学好,必须增强自己的动手实践能力,而不是一天到晚只知道看书,那种行为只不过是“纸上谈兵”。看再多的书都不如自己亲手试一试。俗话说的好:会打仗的士兵才是好士兵。再者,课本上的知识不一定是完全准确的,只有自己动手进行试验过才知道。实践是检验真理的唯一标准,这话不假。
    1 评论 2 下载 2019-05-21 12:13:17 下载需要11点积分
  • 基于VC++的MFC类库实现的简单FTP客户端

    1 FTP客户端设计思想在WINDOWS环境下,使用VC++开发工具实现一个FTP客户端软件。在本次FTP的设计中主要使用WinInet API编程,无需考虑基本的通信协议和底层的数据传输工作,MFC提供的WinInet类是对WinInet API函数封装而来的,它为用户提供了更加方便的编程接口。而在该设计中,使用的类包括 CInternetSession类、CFtpConnection类和CFtpFileFind类,其中,CInternetSession用于创建一个Internet会话; CftpConnection完成文件操作; CftpFileFind负责检索某一个目录下的所有文件和子目录。
    程序的功能:

    登陆到FTP服务器
    检索FTP服务器上的目录和文件
    根据FTP服务器给的权限,会相应地提供:文件的上传、下载、重命名、删除等功能

    2 Ftp客户端的各个子模块主要函数功能分析及流程图2.1 对程序的外观进行修改2.1.1 添加背景图为CMyFtpView类窗口,添加一个位图背景显示,首先为CmyFtpView添加WM_ERASEBKGND消息响应函数OnEraseBkgnd。该函数的前提是所需的位图已经导入资源中。
    2.1.2 添加时钟显示功能首先为CMainFrame类,设置一个定时器,然后为该类响应WM_TIMER消息,在OnTimer函数中实现功能。
    2.1.3 修改菜单栏、状态栏在资料对话框或源程序代码中采取针对性的操作,得以实现。
    2.2 连接到FTP服务器功能的实现2.2.1 生成连接对话框新建一个对话框(CConnectDlg)用来输入服务器的站点,用户名和密码信息,然后通过该对话框连接到服务器.主要的函数void CConnectDlg::OnConnect() 实现的功能就是更新当前的输入。
    2.2.2 连接CMyFtpView::OnConnect()该函数是菜单项“连接”的响应函数,主要生成“连接”CConnectDlg对话框,从而建立FTP连接。
    2.2.3 连接时间void CMyFtpView::OnTimer对CMyFtpView定时器,所发送的WM_TIMER消息进行响应,主要用于监视FTP连接是否成功连接。
    2.3 FTP客户端文件的显示查询实现2.3.1 查询函数OnQuary该函数是“查询”按钮BN_CLICKED的响应函数,主要调用ListContent函数为实现查询的功能
    2.3.2 显示当前目录下所有的子目录与文件ListContent参数所代表的是要查询的目录名,实现的方法主要是通过CftpFileFind类对象得以实现,返回给用户的信息有:目录或文件名、文件最后修改的时间以及文件的大小和类型。
    流程图如下所示:

    2.3.3 下一级目录函数OnNextdirectory该函数是“下一级目录”BN_CLICKED的响应函数,当用户选中一个子目录时,点击按纽就会进入该目录,调用了主要函数:GetCurrentDirectory 、SetCurrentDirectory、ListContent。
    流程图如下所示:

    2.3.4 上一级目录函数OnLasttdirectory该函数是“上一级目录”BN_CLICKED的响应函数,点击按纽就会返回到该目录的上一级目录,调用了主要函数:GetCurrentDirectory 、SetCurrentDirectory、ListContent。
    流程图如下所示:

    2.4 FTP客户端部分功能实现2.4.1 下载函数OnDownLoad为了下载列表中的某一个文件,首先判断是否选中了项目,否则提示没有选择文件,然后得到选择的项目的类型是否是文件,,如果是文件,则得到下载的文件名,下载文件(调用CFtpConnect类中的GetFile函数下载文件)如果选中的是目录,则弹出对话框,不能下载目录。
    流程图如下所示:

    2.4.2 上传函数OnUpLoad上传函数首先得获得想要上传的本地文件的路径名和文件名,弹出打开对话框,找到所要上传的文件后使用PutFile函数上传文件(调用CFtpConnect类中的PutFile函数),等函数上传完后提示是否上传成功,最后调用查询函数,显示新的文件列表。
    流程图如下所示:

    2.4.3 删除函数OnDelete删除函数首先判断是否选择项目,如果没有,则弹出对话框没有选择文件。选择了项目后,得到选择项的类型,如果是目录,则提示不能删除目录,然后用m_pConnection->Remove删除文件并提示是否删除成功,最后调用查询函数,更新文件列表。
    2.4.4 重命名函数OnRename:重命名文件需要新建立一个对话框(CNewNameDlg),后选择要重命名的文件,没有选择项目,提示没有选择文件,激活控件后,弹出新建的对话框,输入新的文件名后用m_pConnection->Rename重新命名文件,最后调用查询函数,更新文件列表。
    3 主要的数据结构分析CMyFtpView类
    CConnectDlg m_ConDlg; //用于连接CFtpDlg m_FtpDlg; //用于创建一个CFtpDlg对话框,进行操作控制CString m_FtpWebSite; //服务器站点,用于输入服务器的站点名称或IP地址CString m_UserName; //登陆服务器的用户名称CString m_UserPwd; //登陆服务器的密码CInternetSession * m_pSession; //通过CConnectDlg 的设置,得到一个Internet会话CFtpConnection* m_pConnection; //通过m_pSession来实现一个FTP连接
    CFtpDlg类
    CButton m_BtnQuery; //查询按扭CButton m_BtnUpLoad; //上传按扭CButton m_BtnDownLoad; //下载按扭CString m_NewFileName; //保存文件的新名称CListCtrl m_FtpFile; //用于显示目录和文件信息CFtpConnection* m_pConnection; //代表所建立的FTP连接CFtpFileFind* m_pFileFind; // CFtpFileFind指针,用于查找文件
    4 Ftp客户端的各个子模块设计过程及代码分析4.1 对程序的外观进行修改4.1.1 删除工具栏在CmainFrame的OnCreate函数中,删除与工具栏m_wndToolBar相关的代码,因为在本程序中没有提供相应的工具栏。
    4.1.2 修改菜单将原有的菜单项删除,增加“连接”和“退出客户端”子菜单项,(去掉Pop-up前的勾,同时赋以ID值),同时,为“连接”和“退出客户端”子菜单项添加COMMAND消息响应,响应的类分别为CMyFtpView类和CMainFrame类.响应函数为OnConnect和OnExit,其中:
    OnExit函数代码如下:
    void CMainFrame::OnExit() { //退出程序的响应函数 if(IDYES==MessageBox("确定要退出客户端吗?","警告",MB_YESNO|MB_ICONWARNING)) CFrameWnd::OnClose();}
    4.1.3 添加位图背景为CMyFtpView类窗口,添加一个位图背景显示,首先为CmyFtpView添加WM_ERASEBKGND消息响应函数,代码如下:
    //用于添加背景图BOOL CMyFtpView::OnEraseBkgnd(CDC* pDC) { CBitmap bitmap; //前提IDB_BITMAP2代表的位图已经导入资源中 bitmap.LoadBitmap(IDB_BITMAP2); CDC dcCompatible; dcCompatible.CreateCompatibleDC(pDC); //创建与当前DC(pDC)兼容的DC,先用dcCompatible准备图像,再将数据复制到实际DC中 dcCompatible.SelectObject(&bitmap); CRect rect; GetClientRect(&rect); //得到目的DC客户区大小 BITMAP bmp; // BITMAP结构体,用于保存位图的信息 bitmap.GetBitmap(&bmp); //将兼容DC中的位图Copy到目标DC中 pDC->StretchBlt(0,0,rect.Width(),rect.Height(),&dcCompatible,0,0, bmp.bmWidth, bmp.bmHeight,SRCCOPY); return true;}
    修改主窗口的大小,在PreCreateWindow函数中添加:cs.cx=450; cs.cy=550;
    4.1.4 修改状态栏使之只具有时间显示窗格,首先MainFrame.cpp中修改indicators,如下:
    static UINT indicators[] ={ ID_SEPARATOR, // status line indicator IDS_TIMER,};
    同时,在资源视图的String Table中添加字符串资源:IDS_TIMER,Caption为:时间。
    然后,添加时钟显示功能:

    在CMainFrame的OnCreate中添加代码:SetTimer(1,1000,NULL)来设置一个定时器
    为CMainFrame添加WM_TIMER的响应函数,代码如下:

    void CMainFrame::OnTimer(UINT nIDEvent) { //用于在状态栏显示当前时间 CTime t=CTime::GetCurrentTime(); CString str=t.Format("%H:%M:%S"); CClientDC dc(this); CSize sz=dc.GetTextExtent(str);//得到Str的长度,用于控制时间窗格 m_wndStatusBar.SetPaneInfo(1,IDS_TIMER,SBPS_NORMAL,sz.cx); m_wndStatusBar.SetPaneText(1,str);//将当前时间显示在时间窗格中 CFrameWnd::OnTimer(nIDEvent);}
    4.1.5 改变应用程序窗口标题标题改为“FTP客户端”在CmyFtpApp的InitInstance函数中添加代码:m_pMainWnd->SetWindowText(“FTP客户端”);
    4.2 连接到FTP服务器功能的实现4.2.1 插入一个对话框
    对各控件进行变量设置(注:在IDC_EDIT3编辑框的Styles选项中,选中PassWord),如下图所示:

    4.2.2 新建一个类管理对话框在打开ClassWizard时,系统提示是否新建一个类管理对话框,选择“是”,类名为:CconnectDlg,基类为:CDialog。
    4.2.3 CConnectDlg函数对按钮“连接”的鼠标的点击,进行响应,函数如下:
    void CConnectDlg::OnConnect() { UpdateData(); CDialog::OnOK();}
    4.2.4 添加public成员变量首先在CMyFtpView.h中添加public成员变量:
    CConnectDlg m_ConDlg; //管理连接对话框CFtpDlg m_FtpDlg; //管理CFtpDlgCString m_FtpWebSite; //保存Ftp服务器站点Cstring m_UserName; //保存用户名CString m_UserPwd; //保存用户密码CInternetSession* m_pSession; //用于Internet连接CFtpConnection* m_pConnection; //用于建立Ftp连接// 注: CFtpDlg为后建立的新类
    并在构造函数中初如化:
    CMyFtpView::CMyFtpView(){ m_FtpWebSite = _T(""); m_UserName = _T(""); m_UserPwd = _T(""); m_pSession = NULL; m_pConnection = NULL;}
    4.2.5 修改CMyFtpView类的OnConnect函数:代码如下:
    void CMyFtpView::OnConnect() { //生成一个模态对话框 if (IDOK==m_ConDlg.DoModal()) { m_pConnection = NULL; m_pSession = NULL; m_FtpWebSite = m_ConDlg.m_FtpWebSite; m_UserName = m_ConDlg.m_UserName; m_UserPwd = m_ConDlg.m_UserPwd; m_pSession=new CInternetSession(AfxGetAppName(), 1, PRE_CONFIG_INTERNET_ACCESS); try { //试图建立FTP连接 SetTimer(1,1000,NULL); //设置定时器,一秒发一次WM_TIMER CString str="正在连接中...."; ((CMainFrame*)GetParent())->SetMessageText(str); m_pConnection=m_pSession->GetFtpConnection(m_FtpWebSite, m_UserName,m_UserPwd); } catch (CInternetException* e) { //错误处理 e->Delete(); m_pConnection=NULL; } }}
    4.2.6 添加响应函数:为CMyFtpView类添加WM_TIMER消息的响应函数,代码如下:
    void CMyFtpView::OnTimer(UINT nIDEvent) { static int time_out=1; //用于判断是否超时 time_out++; //每秒增加一次 if (m_pConnection == NULL) { CString str="正在连接中...."; ((CMainFrame*)GetParent())->SetMessageText(str); //在状态栏中显示,连接状态 if (time_out>=60) //设置超时的时间为1分钟 { ((CMainFrame*)GetParent())->SetMessageText("连接超时!"); KillTimer(1); //关闭定时器 MessageBox("连接超时!","超时",MB_OK); //提醒用户 } } else //如果连接成功,执行如下 { CString str="连接成功!"; ((CMainFrame*)GetParent())->SetMessageText(str); KillTimer(1); //连接成功之后,不用定时器来监视连接情况 //同时跳出操作对话框 //将FTP连接交给CFtpDlg m_FtpDlg.m_pConnection = m_pConnection; //创建非模态对话框CFtpDlg m_FtpDlg.Create(IDD_DIALOG2,this); m_FtpDlg.ShowWindow(SW_SHOW); } CView::OnTimer(nIDEvent);}
    4.3 FTP客户端主要功能的实现4.3.1新插入一个对话框资源:新插入一个对话框资源,界面如下:

    各控件变量信息如下图所示:

    4.3.2 建立新类CFtpDlg管理该对话框建立新类CFtpDlg管理该对话框,基类:CDialog。
    构造函数代码:
    CFtpDlg::CFtpDlg(CWnd* pParent /*=NULL*/): CDialog(CFtpDlg::IDD, pParent){ m_pConnection = NULL; m_pFileFind = NULL;}
    4.3.3 初始化对话框为CFtpDlg添加WM_INITDIALOG响应函数OnInitDialog,代码如下:
    BOOL CFtpDlg::OnInitDialog() { CDialog::OnInitDialog(); //设置CListCtrl对象的属性 m_FtpFile.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); //设置列 m_FtpFile.InsertColumn(0,"文件名",LVCFMT_CENTER,200); m_FtpFile.InsertColumn(1,"日期",LVCFMT_CENTER,100); m_FtpFile.InsertColumn(2,"字节数",LVCFMT_CENTER,100); //初如化CftpFileFind类对象m_pFileFind m_pFileFind = new CFtpFileFind(m_pConnection); //调用OnQuary函数查询FTP服务器当前目录下的目录和文件信息 OnQuary(); return TRUE; }
    4.3.4 查询函数OnQuary为查询按纽添加BN_CLICKED响应函数OnQuary,代码如下:
    void CFtpDlg::OnQuary() { ListContent("*"); }
    手动为CFtpDlg添加函数ListContent:
    void CFtpDlg::ListContent(LPCTSTR DirName){ m_FtpFile.DeleteAllItems(); BOOL bContinue; bContinue=m_pFileFind->FindFile(DirName); if (!bContinue) { //查找完毕,失败 m_pFileFind->Close(); m_pFileFind=NULL; } CString strFileName; CString strFileTime; CString strFileLength; while (bContinue) { bContinue = m_pFileFind->FindNextFile(); strFileName = m_pFileFind->GetFileName(); //得到文件名 //得到文件最后一次修改的时间 FILETIME ft; m_pFileFind->GetLastWriteTime(&ft); CTime FileTime(ft); strFileTime = FileTime.Format("%y/%m/%d"); if (m_pFileFind->IsDirectory()) { //如果是目录不求大小,用<DIR>代替 strFileLength = "<DIR>"; } else { //得到文件大小 if (m_pFileFind->GetLength64() <1024) { strFileLength.Format("%d B",m_pFileFind->GetLength64()); } else { if (m_pFileFind->GetLength64() < (1024*1024)) strFileLength.Format("%3.3f KB", (LONGLONG)m_pFileFind->GetLength64()/1024.0); else { if (m_pFileFind->GetLength64()<(1024*1024*1024)) strFileLength.Format("%3.3f MB", (LONGLONG)m_pFileFind->GetLength64()/(1024*1024.0)); else strFileLength.Format("%1.3f GB", (LONGLONG)m_pFileFind->GetLength64()/(1024.0*1024*1024)); } } } int i=0; m_FtpFile.InsertItem(i,strFileName,0); m_FtpFile.SetItemText(i,1,strFileTime); m_FtpFile.SetItemText(i,2,strFileLength); i++; } }
    4.3.5 下一级目录函数OnNextdirectory为”下一级目录”按纽添加BN_CLICKED响应函数OnNextdirectory,代码如下:
    void CFtpDlg::OnNextdirectory() { static CString strCurrentDirectory, strSub; //声明2个静态变量,// strCurrentDirectory表示当前目录名,strSub表示选定的文件名 //首先得到当前目录,保存在strCurrentDirectory m_pConnection->GetCurrentDirectory(strCurrentDirectory); strCurrentDirectory+="/"; //在当前取得的目录名后添加“/” //得到所选择的文本,即所要进入的下一级目录名 int i=m_FtpFile.GetNextItem(-1,LVNI_SELECTED); //判断文件是否选中 strSub = m_FtpFile.GetItemText(i,0);//将选中的文件名保存至strSub if (i==-1) { AfxMessageBox("没有选择目录!",MB_OK | MB_ICONQUESTION); } else { //判断是不是目录 if ("<DIR>"!=m_FtpFile.GetItemText(i,2))//显示文件的第三列非<DIR> { AfxMessageBox("不是子目录!",MB_OK | MB_ICONSTOP); } else { //设置当前目录 m_pConnection->SetCurrentDirectory(strCurrentDirectory+strSub); //对当前目录进行查询,更新ClistCtrl控件的内容 ListContent("*"); } }}
    4.3.6 上一级目录函数OnLasttdirectory为”上一级目录”按纽添加BN_CLICKED响应函数OnLastdirectory,代码如下:
    //返回上一级目录void CFtpDlg::OnLastdirectory() { static CString strCurrentDirectory; //声明为静态变量 m_pConnection->GetCurrentDirectory(strCurrentDirectory); if (strCurrentDirectory == "/") { AfxMessageBox("已经是根目录了!",MB_OK | MB_ICONSTOP); } else { //调用函数GetLastDiretory,得到上一级目录名 GetLastDiretory(strCurrentDirectory); //设置当前目录为上一级目录 m_pConnection->SetCurrentDirectory(strCurrentDirectory); //对当前目录进行查询,更新ClistCtrl控件的内容 ListContent("*"); }}
    为CFtpDlg类添加一工具函数GetLastDiretory用于得到上一级目录的名称。
    //用于得到上一级目录的字符串表示void CFtpDlg::GetLastDiretory(CString &str){ int LastIndex=0;//定义一个初始整形变量 for (int i=0; i<str.GetLength(); i++)//定义i取得当前地址字符串长度 { if (str.GetAt(i)=='/')//追溯至数组的最后一个“/” LastIndex = i;//得到当前的数值“i” } //删除最后一个’/’之后的字符串 str = str.Left(LastIndex);//自带的left()函数:返回参数前的所有字符串 if (LastIndex == 0)//当追溯的本身即为根目录 str="/";}
    4.4 FTP客户端部分功能的实现4.4.1 下载函数OnDownLoad为”下载”按纽添加BN_CLICKED响应函数OnDownLoad,代码如下:
    void CFtpDlg::OnDownload() { int i=m_FtpFile.GetNextItem(-1,LVNI_SELECTED); //先判断是否已经选中文件 if (i==-1) //如果没有被选中 { //弹出对话框提示没有选择文件 AfxMessageBox("没有选择文件!",MB_OK | MB_ICONQUESTION); } else { //如果选中了文件,则得到选择项的类型,判断是不是文件 CString strType=m_FtpFile.GetItemText(i,2); if (strType!="<DIR>") //选择的是文件 { CString strDestName; //下载后的文件名 CString strSourceName; //原文件名 //得到所要下载的文件名 strSourceName = m_FtpFile.GetItemText(i,0); CFileDialog dlg(FALSE,"",strSourceName); //弹出SAVE AS对话框 if (dlg.DoModal()==IDOK) { //获得下载文件在本地机上存储的路径和名称 strDestName=dlg.GetPathName(); //调用CFtpConnect类中的GetFile函数下载文件 if (m_pConnection->GetFile(strSourceName,strDestName)) AfxMessageBox("下载成功!",MB_OK|MB_ICONINFORMATION); else AfxMessageBox("下载失败!",MB_OK|MB_ICONSTOP); } } else { //选择的是目录 AfxMessageBox("不能下载目录!\n请重选!",MB_OK|MB_ICONSTOP); } }}
    4.4.2 上传函数OnUpLoad为”上传”按纽添加BN_CLICKED响应函数OnUpload,代码如下:
    void CFtpDlg::OnUpload() { //获得当前输入 CString strSourceName; //原文件名 CString strDestName; CFileDialog dlg(TRUE,"","*.*"); if (dlg.DoModal()==IDOK) { //获得待上传的本地机文件路径和文件名 strSourceName = dlg.GetPathName(); strDestName = dlg.GetFileName(); //调用CFtpConnect类中的PutFile函数上传文件 if (m_pConnection->PutFile(strSourceName,strDestName)) AfxMessageBox("上传成功!",MB_OK|MB_ICONINFORMATION); else AfxMessageBox("上传失败!",MB_OK|MB_ICONSTOP); } //更新ClistCtrl的内容 OnQuary();}
    4.4.3 删除函数OnDelete为”删除”按纽添加BN_CLICKED响应函数OnDelete,代码如下:
    //删除选择的文件void CFtpDlg::OnDelete() { int i=m_FtpFile.GetNextItem(-1,LVNI_SELECTED); if (i==-1) { AfxMessageBox("没有选择文件!",MB_OK | MB_ICONQUESTION); } else { CString strFileName; strFileName = m_FtpFile.GetItemText(i,0); if ("<DIR>"==m_FtpFile.GetItemText(i,2)) { AfxMessageBox("不能删除目录!",MB_OK | MB_ICONSTOP); } else { if (m_pConnection->Remove(strFileName)) AfxMessageBox("删除成功!",MB_OK|MB_ICONINFORMATION); else AfxMessageBox("无法删除!",MB_OK|MB_ICONSTOP); } } OnQuary();}
    4.4.4 重命名函数OnRename新插入一个对话框资源,界面如下:

    控件变量信息如下图所示:

    改写对话框的OnOK函数,代码如下:
    void CNewNameDlg::OnOK() { UpdateData(); CDialog::OnOK();}
    为”重命名”按纽添加BN_CLICKED响应函数OnRename,代码如下:
    void CFtpDlg::OnRename() { CString strNewName; CString strOldName; //得到CListCtrl被选中的项 int i=m_FtpFile.GetNextItem(-1,LVNI_SELECTED); if (i==-1) { AfxMessageBox("没有选择文件!",MB_OK | MB_ICONQUESTION); } else { strOldName = m_FtpFile.GetItemText(i,0);//得到所选择的文件名 CNewNameDlg dlg; if (dlg.DoModal()==IDOK) { strNewName=dlg.m_NewFileName; if (m_pConnection->Rename(strOldName,strNewName)) AfxMessageBox("重命名成功!",MB_OK|MB_ICONINFORMATION); else AfxMessageBox("无法重命名!",MB_OK|MB_ICONSTOP); } } OnQuary();}
    4.4.5 退出函数OnExit为”退出”按纽添加BN_CLICKED响应函数OnExit,代码如下:
    void CFtpDlg::OnExit() { m_pConnection = NULL; m_pFileFind = NULL; DestroyWindow(); //销毁对话框资源}
    5 测试程序5.1 连接操作
    5.2 连接成功后
    此后可根据FTP服务器所提供的权限进行相应的操作。
    6 整个设计过程中遇到的主要问题6.1 如果已经连上了某服务器,而在没有退出程序之前,再点连接,就会有问题了
    原因
    CFtpDlg在调用OnExit函数的时候仅仅是隐藏了对话框,并没有销毁它,导致了m_FtpDlg的重复创建m_FtpDlg.Create(IDD_DIALOG2,this);此行代码是问题关键,点退出时,并没有销费
    解决之道
    OnExit函数中调用DestryWindow,而不是CDialg::OnCancel;

    6.2 在进入下一级目录的函数编写过程中,只能进入第二层目录
    原因
    假设当前目录为 “/”,进入第一层子目录”FTP”之后,当前目录变为“/FTP”,再想进入FTP目录下的”MyFtp”子目录的时候,之前的代码,仅仅是实现了“/FTP”+”MyFtp”简单加法,即当前目录为”/FTPMyFtp”,虽然是不对的。
    解决之道
    在获取子目录名称之前,使当前目录所代表的字符串加上符号‘/’ ,代码表示为:

    strCurrentDirectory+="/";
    6.3 在返回上一级目录的函数编写过程中,无法返回到根目录
    原因
    比如:在”/FTP”之下,返回到上一级目录,原代码将导致当前目录strCurrentDirectory为空,如果运行m_pConnection->SetCurrentDirectory(strCurrentDirectory),显然也是不对的
    解决之道
    在GetLastDiretory中添加判断:当前目录是否为空,如果是,则设strCurrentDirectory=”/”;代码实现为:

    if (LastIndex == 0) str="/";
    7 总结在这次课程设计中,我们小组通过从各个方面查找资料,了解了WinInet API编程的基本知识,熟悉了MFC编程中的一些控件知识,通过这次设计锻炼了我们组员的团队协作能力。
    通过对FTP这种大型的设计,我们组成员深感我们平时的编程习惯与良好的编程习惯相差甚远,小组成员决定在以后的编程过程中养成良好的编程习惯,这样有助于自己所编的程序清晰明了便于该错还有助于别人来立解你的程序。同时通过这次课程设计我们形成了通过从各方面查找资料来丰富自己的知识的能力。
    3 评论 25 下载 2018-10-31 22:08:14 下载需要10点积分
  • 基于C++的库存管理系统设计与实现

    一 需求分析1.1 总体要求运用面向对象程序设计知识,利用C++语言设计和实现一个“库存管理系统设计”,主要完成对商品的销售、统计和简单管理。在实现过程中,需利用面向对象程序设计理论的基础知识,充分体现出C++语言关于类、继承和封装等核心概念,每一个类应包含数据成员和成员函数。
    1.2 功能分析超市中商品分为四类,分别是食品、化妆品、日用品和饮料。每种商品都包含商品名称、价格、库存量和品牌等信息。
    本系统要求具备如下主要功能:
    1.2.1 商品简单管理功能
    添加功能:主要完成商品基本信息的添加
    查询功能:可按商品类别、商品名称、生产厂家、进货日期进行查询。若存在相应信息,输出所查询的信息,若不存在该记录,则提示“该记录不存在!”
    修改功能:可根据查询结果对相应的记录进行修改
    删除功能:主要完成商品信息的删除。先输入商品类别,再输入要删除的商品名称,根据查询结果删除该物品的记录,如果该商品不在物品库中,则提示“该商品不存在”

    1.2.2 进货功能按要求添加相应商品的信息到库存中。可按要求输入商品编号,商品名称,生产厂家,商品价格,商品数量,商品类别,入库时间等商品基本信息。
    1.2.3 出货功能出货时可按照商品名称查找相应商品,显示相关商品库存量等基本信息。若有库存量则输入出售数量,出售价格以及出库时间,计算销售额,利润。如果库存量不足则提示出货失败,结束出货。
    1.2.4 统计功能输出当前库存中所有商品的总数及详细信息;能统计每种商品一周时间内的销售额和利润;能统计每类商品的一周时间内的销售额和利润。输出统计信息时,要按从大到小进行排序。(根据个人能力,至少实现一种统计功能)
    二 程序设计与实现2.1 概要设计在定义商品的类别时采用了枚举类型,并定义Food=1,因此在程序中阿拉伯数字1,2,3,4即分别代表食品,化妆品,日用品,饮料这四种商品。
    系统类的关系图如下所示:

    2.1.1 系统的类层次在定义商品基本信息时采用了结构体类型,即定义了一个structGoods,其中包含类别,名称,品牌,价格,数量等信息,同时包含struct Date表示入库时间,包含enum GoodsType表示商品类别。
    定义class GoodsManage包含各成员函数进行对商品信息的管理,其中包含DisplayMainMenu(),AddGoodsInfo(),DisplayGoodsInfo(),SearchByCode()等成员函数。
    系统的类层次关系图如下图所示:


    2.1.2 主程序流程如下图所示:

    2.2 详细设计2.2.1 各类的描述商品类别
    //商品类别enum GoodsType{ Food=1, //食品 Cosmetic, //化妆品 Commodity, //日用品 Drink //饮料};
    入库时间
    //入库时间struct Date{ int year; int month; int day;};
    ((商品基本信息**
    //商品基本信息struct Goods{ string code; //商品编号 string name; //商品名称 string brand; //生产厂家 double price; //商品价格 int num; //商品数量 GoodsType type;//商品类别 Date date; //入库时间 Goods *next;};
    商品售出信息
    //商品售出信息struct SellRecord{ Goods sellGoods; //已出售的商品 int sellNum; //出售数量 double sellPrice;//出售价格 Date date; //出库日期 SellRecord *next;};
    商品管理
    //商品管理class GoodsManage{public: GoodsManage(); ~GoodsManage(){} void DisplayMainMenu(); //主菜单显示 void AddGoodsInfo(); //添加商品信息 void DisplayGoodsInfo();//浏览商品信息 void SearchByCode(); //按照商品编号搜索商品信息 void SearchByName(); //按照商品名称搜索商品信息 void SearchByType(); //按照商品类别搜索商品信息 void SearchByBrand(); //按照商品品牌搜索商品信息 void EditGoodsInfo(); //编辑商品信息 void DeleteGoodsInfo(); //删除商品信息 void SellGoodsInfo(); //出售商品信息 void SaveGoodsInfo(); //保存商品信息private: int amount; //商品量 int DeleteAmount; Goods *head; Goods *DeleteHead;};
    2.2.2 成员函数定义构造函数
    //定义构造函数GoodsManage::GoodsManage(){ amount=0; DeleteAmount=0; head=new Goods; head->next=NULL; DeleteHead=new Goods; DeleteHead->next=NULL;}
    2.主菜单显示函数
    //定义主菜单函数void GoodsManage::DisplayMainMenu(){ cout<<" ━═☆┈━═☆┈━═☆┈━═☆┈━═☆┈━═☆┈━═☆┈━═☆━═☆\n"; cout<<" ┋ ┋\n"; cout<<" ┋ 欢迎使用商品库存管理系统 ┋\n"; cout<<" ┋ ┋\n"; cout<<" ┋ ┋\n"; cout<<" ┋ 【商品进货】…(a) ┋\n"; cout<<" ┋ ┋\n"; cout<<" ┋ 【商品编辑】…(b) ┋\n"; cout<<" ┋ ┋\n"; cout<<" ┋ 【商品删除】…(c) ┋\n"; cout<<" ┋ ┋\n"; cout<<" ┋ ┋【按照编号查询】…(d) ┋\n"; cout<<" ┋ ┋ ┋\n"; cout<<" ┋ ┋【按照名称查询】…(e) ┋\n"; cout<<" ┋ 【商品查询】┋ ┋\n"; cout<<" ┋ ┋【按照类别查询】…(f) ┋\n"; cout<<" ┋ ┋ ┋\n"; cout<<" ┋ ┋【按照品牌查询】…(g) ┋\n"; cout<<" ┋ ┋\n"; cout<<" ┋ 【商品出货】…(h) ┋\n"; cout<<" ┋ ┋\n"; cout<<" ┋ 【商品统计】…(i) ┋\n"; cout<<" ┋ ┋\n"; cout<<" ┋ 【信息保存】…(j) ┋\n"; cout<<" ┋ ┋\n"; cout<<" ┋ ┋\n"; cout<<" ┋ 退出系统…(k) ┋\n"; cout<<" ┋ ┋\n"; cout<<" ━═☆┈━═☆┈━═☆┈━═☆┈━═☆┈━═☆┈━═☆┈━═☆━═☆\n"; cout<<"\n 请输入你要进行的操作编号:";}
    添加商品信息函数
    //定义添加商品信息函数voidGoodsManage::AddGoodsInfo(){ char c,c1; Goods tail=head,p; bool flag; cout<<" ☆☆☆☆☆☆现在进行商品信息的添加☆☆☆☆☆☆ "<<endl; while(tail->next!=NULL) tail=tail->next; do { flag=0; p=new Goods; cout<<"请选择商品类别:"<<endl; cout<<"1.食品 2.化妆品3.日用品 4.饮料"<<endl; cout<<"请输入相应编号:"; do { cin>>c1; if(c1>='1'&&c1<='4')//判断用户输入编号是否存在 flag=1; else { cout<<"您输入的编号不存在!"<<endl; cout<<"请选择正确的商品类别:"<<endl; } }while(flag==0);//输入编号存在时跳出循环 if(c1=='1') p->type=Food; if(c1=='2') p->type=Cosmetic; if(c1=='3') p->type=Commodity; if(c1=='4') p->type=Drink; cout<<"商品类别("<<p->type<<")"<<endl;//表示商品类别 cout<<"请输入商品编号: "; cin>>p->code; do { Goods *q=head->next; while(q!=NULL&&q->code!=p->code) q=q->next; if(q==NULL) flag=1; else { cout<<"存在该编号的货物!!!请重新输入编号:"; cin>>p->code; } }while(flag==0); cout<<"请输入商品名称:"; cin>>p->name; cout<<"请输入生产厂家:"; cin>>p->brand; cout<<"请输入商品价格:"; cin>>p->price; cout<<"请输入商品数量:"; cin>>p->num; cout<<"请输入入库时间(年/月/日):"; cin>>p->date.year>>p->date.month>>p->date.day; tail->next=p; p->next=NULL; tail=p; amount++;//商品量加一 cout<<"数据输入成功!!!想继续添加吗(y/n):"; cin>>c; while(c!='y'&&c!='n') { cout<<"指令错误!!!!!<请输入y/n>"<<endl; cout<<"数据添加成功!!!想继续输入吗(y/n):"; cin>>c; } }while(c=='y'); cout<<endl; cout<<"……信息处理完毕……"<<endl; cout<<"……按任意键返回主菜单……"<<endl; getchar(); getchar();}
    统计商品信息函数
    //定义商品信息浏览函数void GoodsManage::DisplayGoodsInfo(){ Goods *p=head; cout<<" ☆☆☆☆☆☆现在进行商品信息的浏览☆☆☆☆☆☆ "<<endl; cout<<setiosflags(ios::left)<<setw(10)<<"编号"<<setw(16)<<"名称"<<setw(10)<<"生产厂家"<<setw(10)<<"价格"<<setw(10)<<"商品类别"<<setw(10)<<"数量"<<setw(10)<<"入库时间"<<endl; while(p->next!=NULL) { p=p->next; cout<setiosflags(ios::left)<<setw(10)<<p-code<<setw(16)<<p->name; cout<<setw(10)<<p->brand<<setw(10)<<p->price<<setw(10)<<p->type; cout<<setw(10)<<p->num<<p->date.year<<"/"<<p->date.month<<"/"<<p->date.day<<endl; } cout<<endl; cout<<"……信息统计完毕……"<<endl; cout<<"……按任意键返回主菜单……"<<endl; getchar(); getchar();}
    按照编号查找商品信息函数
    //按照商品编号查找商品信息void GoodsManage::SearchByCode(){ char c; Goods *p; bool flag; string FoundCode; cout<<" ☆☆☆☆☆☆现在进行商品信息的查找☆☆☆☆☆☆ "<<endl; do { p=head; flag=0; cout<<"请输入您要查找的商品编号:"; cin>>FoundCode; while(p->next!=NULL) { p=p->next; if(p->code==FoundCode) { flag=1; cout<<setiosflags(ios::left)<<setw(10)<<"编号"<<setw(16)<<"名称"<<setw(10)<<"生产厂家"<<setw(10)<<"价格"<<setw(10)<<"商品类别"<<setw(10)<<"数量"<<setw(10)<<"入库时间"<<endl; cout<setiosflags(ios::left)<<setw(10)<<p-code<<setw(16)<<p->name; cout<<setw(10)<<p->brand<<setw(10)<<p->price<<setw(10)<<p->type; cout<<setw(10)<<p->num<<p->date.year<<"/"<<p->date.month<<"/"<<p->date.day<<endl; break; } if(flag==0) { cout<<"对不起,您查询的商品不存在!!!"<<endl; cout<<"您想要继续查找吗(y/n):"; cin>>c; while(c!='y'&&c!='n') { cout<<"指令错误!!!<请输入y/n>:"<<endl; cout<<"您想要继续查找吗(y/n):"; cin>>c; } } } }while(c=='y'); cout<<endl; cout<<"……信息查找完毕……"<<endl; cout<<"……按任意键返回主菜单……"<<endl; getchar(); getchar();}
    按照名称查找商品信息函数
    //按照商品名称查找商品信息void GoodsManage::SearchByName(){ char c; Goods *p; bool flag; string FoundName; cout<<" ☆☆☆☆☆☆现在进行商品信息的查找☆☆☆☆☆☆ "<<endl; do { p=head; flag=0; cout<<"请输入您要查找的商品名称:"; cin>>FoundName; while(p->next!=NULL) { p=p->next; if(p->name==FoundName) { flag=1; cout<<setiosflags(ios::left)<<setw(10)<<"编号"<<setw(16)<<"名称"<<setw(10)<<"生产厂家"<<setw(10)<<"价格"<<setw(10)<<"商品类别"<<setw(10)<<"数量"<<setw(10)<<"入库时间"<<endl; cout<setiosflags(ios::left)<<setw(10)<<p-code<<setw(16)<<p->name; cout<<setw(10)<<p->brand<<setw(10)<<p->price<<setw(10)<<p->type; cout<<setw(10)<<p->num<<p->date.year<<"/"<<p->date.month<<"/"<<p->date.day<<endl; break; } if(flag==0) { cout<<"对不起,您查询的商品不存在!!!"<<endl; cout<<"您想要继续查找吗(y/n):"; cin>>c; while(c!='y'&&c!='n') { cout<<"指令错误!!!<请输入y/n>:"<<endl; cout<<"您想要继续查找吗(y/n):"; cin>>c; } } } }while(c=='y'); cout<<endl; cout<<"……信息查找完毕……"<<endl; cout<<"……按任意键返回主菜单……"<<endl; getchar(); getchar();}
    按照类别查找商品信息函数
    //按照商品类别查找商品信息void GoodsManage::SearchByType(){ char c; Goods *p; bool flag; int FoundType; cout<<" ☆☆☆☆☆☆现在进行商品信息的查找☆☆☆☆☆☆ "<<endl; do { p=head; flag=0; cout<<"请输入您要查找的商品类别:"; cin>>FoundType; while(p->next!=NULL) { p=p->next; if(FoundType==1&&p->type==Food) { flag=1; cout<<setiosflags(ios::left)<<setw(10)<<"编号"<<setw(16)<<"名称"<<setw(10)<<"生产厂家"<<setw(10)<<"价格"<<setw(10)<<"商品类别"<<setw(10)<<"数量"<<setw(10)<<"入库时间"<<endl; cout<setiosflags(ios::left)<<setw(10)<<p-code<<setw(16)<<p->name; cout<<setw(10)<<p->brand<<setw(10)<<p->price<<setw(10)<<p->type; cout<<setw(10)<<p->num<<p->date.year<<"/"<<p->date.month<<"/"<<p->date.day<<endl; } else if(FoundType==2&&p->type==Cosmetic) { flag=1; cout<<setiosflags(ios::left)<<setw(10)<<"编号"<<setw(16)<<"名称"<<setw(10)<<"生产厂家"<<setw(10)<<"价格"<<setw(10)<<"商品类别"<<setw(10)<<"数量"<<setw(10)<<"入库时间"<<endl; cout<setiosflags(ios::left)<<setw(10)<<p-code<<setw(16)<<p->name; cout<<setw(10)<<p->brand<<setw(10)<<p->price<<setw(10)<<p->type; cout<<setw(10)<<p->num<<p->date.year<<"/"<<p->date.month<<"/"<<p->date.day<<endl; } else if(FoundType==3&&p->type==Commodity) { flag=1; cout<<setiosflags(ios::left)<<setw(10)<<"编号"<<setw(16)<<"名称"<<setw(10)<<"生产厂家"<<setw(10)<<"价格"<<setw(10)<<"商品类别"<<setw(10)<<"数量"<<setw(10)<<"入库时间"<<endl; cout<setiosflags(ios::left)<<setw(10)<<p-code<<setw(16)<<p->name; cout<<setw(10)<<p->brand<<setw(10)<<p->price<<setw(10)<<p->type; cout<<setw(10)<<p->num<<p->date.year<<"/"<<p->date.month<<"/"<<p->date.day<<endl; } else if(FoundType==4&&p->type==Drink) { flag=1; cout<<setiosflags(ios::left)<<setw(10)<<"编号"<<setw(16)<<"名称"<<setw(10)<<"生产厂家"<<setw(10)<<"价格"<<setw(10)<<"商品类别"<<setw(10)<<"数量"<<setw(10)<<"入库时间"<<endl; cout<setiosflags(ios::left)<<setw(10)<<p-code<<setw(16)<<p->name; cout<<setw(10)<<p->brand<<setw(10)<<p->price<<setw(10)<<p->type; cout<<setw(10)<<p->num<<p->date.year<<"/"<<p->date.month<<"/"<<p->date.day<<endl; } if(flag==0) { cout<<"对不起,您查询的商品不存在!!!"<<endl; cout<<"您想要继续查找吗(y/n):"; cin>>c; while(c!='y'&&c!='n') { cout<<"指令错误!!!<请输入y/n>:"<<endl; cout<<"您想要继续查找吗(y/n):"; cin>>c; } } } }while(c=='y'); cout<<endl; cout<<"……信息查找完毕……"<<endl; cout<<"……按任意键返回主菜单……"<<endl; getchar(); etchar();}
    按照品牌查找商品信息函数
    //按照品牌查找商品信息void GoodsManage::SearchByBrand(){ char c; Goods *p; bool flag; string FoundBrand; cout<<" ☆☆☆☆☆☆现在进行商品信息的查找☆☆☆☆☆☆ "<<endl; do { p=head; flag=0; cout<<"请输入您要查找的商品品牌:"; cin>>FoundBrand; while(p->next!=NULL) { p=p->next; if(p->brand==FoundBrand) { flag=1; cout<<setiosflags(ios::left)<<setw(10)<<"编号"<<setw(16)<<"名称"<<setw(10)<<"生产厂家"<<setw(10)<<"价格"<<setw(10)<<"商品类别"<<setw(10)<<"数量"<<setw(10)<<"入库时间"<<endl; cout<setiosflags(ios::left)<<setw(10)<<p-code<<setw(16)<<p->name; cout<<setw(10)<<p->brand<<setw(10)<<p->price<<setw(10)<<p->type; cout<<setw(10)<<p->num<<p->date.year<<"/"<<p->date.month<<"/"<<p->date.day<<endl; break; } if(flag==0) { cout<<"对不起,您查询的商品不存在!!!"<<endl; cout<<"您想要继续查找吗(y/n):"; cin>>c; while(c!='y'&&c!='n') { cout<<"指令错误!!!<请输入y/n>:"<<endl; cout<<"您想要继续查找吗(y/n):"; cin>>c; } } } }while(c=='y'); cout<<endl; cout<<"……信息查找完毕……"<<endl; cout<<"……按任意键返回主菜单……"<<endl; getchar(); getchar();}
    编辑商品信息函数
    //定义编辑商品信息函数void GoodsManage::EditGoodsInfo(){ char c; Goods *p; bool flag=0; string EditCode; cout<<" ☆☆☆☆☆☆现在进行商品信息的编辑☆☆☆☆☆☆ "<<endl; do { p=head->next; flag=0; cout<<"请输入您要修改的货物编号:"; cin>>EditCode; while(p->next!=NULL&&p->code!=EditCode) p=p->next; if(p->code==EditCode) { flag=1; cout<<setiosflags(ios::left)<<setw(10)<<"编号"<<setw(16)<<"名称"<<setw(10)<<"生产厂家"<<setw(10)<<"价格"<<setw(10)<<"商品类别"<<setw(10)<<"数量"<<setw(10)<<"入库时间"<<endl; cout<setiosflags(ios::left)<<setw(10)<<p-code<<setw(16)<<p->name; cout<<setw(10)<<p->brand<<setw(10)<<p->price<<setw(10)<<p->type; cout<<setw(10)<<p->num<<p->date.year<<"/"<<p->date.month<<"/"<<p->date.day<<endl; cout<<"确认修改吗?<y/n>"; cin>>c; while(c!='y'&&c!='n') { cout<<"指令错误!!!!<请输入y/n>:"; cin>>c; } if(c=='y') { cout<<"请输入商品名称:"; cin>>p->name; cout<<"请输入生产厂家:"; cin>>p->brand; cout<<"请输入商品价格:"; cin>>p->price; cout<<"请输入商品数量:"; cin>>p->num; cout<<"请输入入库时间(年/月/日):"; cin>>p->date.year>>p->date.month>>p->date.day; cout<<"修改成功!"<<endl; } else cout<<"取消成功!"<<endl; } if(flag==0) { cout<<"对不起,您修改的货物不存在!!"<<endl; } cout<<"您想要继续修改吗?(y/n):"; cin>>c; while(c!='y'&&c!='n') { cout<<"指令错误!!!<请输入y/n>:"<<endl; cout<<"您想要继续修改吗?(y/n):"; cin>>c; } }while(c=='y'); cout<<endl; cout<<"……信息编辑完毕……"<<endl; cout<<"……按任意键返回主菜单……"<<endl; getchar(); getchar();}
    删除商品信息函数
    //定义商品信息删除函数void GoodsManage::DeleteGoodsInfo(){ Goods q=head,p,*tail=DeleteHead; p=new Goods; char c; string Dename; bool flag=0; while(tail->next!=NULL) tail=tail->next; cout<<" ☆☆☆☆☆☆现在进行商品信息的删除☆☆☆☆☆☆ "<<endl; do { cout<<"请输入您要删除的商品名称:"; cin>>Dename; while(q->next!=NULL&&q->next->name!=Dename) q=q->next; if(q->next!=NULL) { flag=1; cout<<"确认删除吗?<y/n>"; cin>>c; while(c!='y'&&c!='n') { cout<<"指令错误!!!!<请输入y/n>:"; cin>>c; } if(c=='y') { p=q->next; q->next=q->next->next; tail->next=p; tail=p; tail->next=NULL; DeleteAmount++; amount--; cout<<"删除成功!!"<<endl; } else cout<<"取消成功!!!"<<endl; } if(flag==0) { cout<<"对不起,您删除的商品不存在!!!"<<endl; } cout<<"您想要继续删除吗?(y/n):"; cin>>c; while(c!='y'&&c!='n') { cout<<"指令错误!!!<请输入y/n>:"<<endl; cout<<"您想要继续删除吗?(y/n):"; cin>>c; } flag=0; q=head; }while(c=='y'); cout<<endl; cout<<"……信息删除完毕……"<<endl; cout<<"……按任意键返回主菜单……"<<endl; getchar(); getchar();}
    出售商品信息函数
    //定义商品出库函数void GoodsManage::SellGoodsInfo(){ int sellNum,year,month,day; doublesellPrice,sum=0.0,profit=0.0; char c; Goods *p; bool flag=0; string EditName; cout<<" ☆☆☆☆☆☆现在进行商品的出售☆☆☆☆☆☆ "<<endl; do { p=head->next; flag=0; cout<<"请输入您要出售的商品名称:"; cin>>EditName; while(p->next!=NULL&&p->name!=EditName) p=p->next; if(p->name==EditName) { flag=1; cout<<setiosflags(ios::left)<<setw(10)<<"编号"<<setw(16)<<"名称"<<setw(10)<<"生产厂家"<<setw(10)<<"价格"<<setw(10)<<"商品类别"<<setw(10)<<"数量"<<setw(10)<<"入库时间"<<endl; cout<setiosflags(ios::left)<<setw(10)<<p-code<<setw(16)<<p->name; cout<<setw(10)<<p->brand<<setw(10)<<p->price<<setw(10)<<p->type; cout<<setw(10)<<p->num<<p->date.year<<"/"<<p->date.month<<"/"<<p->date.day<<endl; cout<<"确认出售吗?<y/n>"; cin>>c; while(c!='y'&&c!='n') { cout<<"指令错误!!!!<请输入y/n>:"; cin>>c; } if(c=='y') { cout<<"请输入出售的商品数量:"; cin>>sellNum; if(sellNum<=p->num) { p->num=p->num-sellNum; cout<<"请输入出售的商品价格:"; cin>>sellPrice; cout<<"请输入出货日期:"; cin>>year>>month>>day; sum=sellNum*sellPrice; profit=sellNum*(sellPrice-p->price); cout<<"此次销售额为: "<<sum<<endl; cout<<"此次利润为: "<<profit<<endl; cout<<"出货日期为:"<<year<<"/"<<month<<"/"<<day<<endl; } else { cout<<"库存不足!出库失败!"<<endl; } } else cout<<"取消成功!"<<endl; } if(flag==0) { cout<<"对不起,您出售的货物不存在!!"<<endl; } cout<<"您想要继续出售吗?(y/n):"; cin>>c; while(c!='y'&&c!='n') { cout<<"指令错误!!!<请输入y/n>:"<<endl; cout<<"您想要继续出售吗?(y/n):"; cin>>c; } }while(c=='y'); cout<<endl; cout<<"……出库完毕……"<<endl; cout<<"……按任意键返回主菜单……"<<endl; getchar(); getchar();}
    保存商品信息函数
    //定义商品信息保存函数void GoodsManage::SaveGoodsInfo(){ Goods *p=head; cout<<" ☆☆☆☆☆☆现在进行商品信息的保存☆☆☆☆☆☆ "<<endl; ofstream output("货物信息.txt",ios::out);//定义输出文件"货物信息.txt" if(!output) { cerr<<"打开文件<货物信息.txt>失败!!!"<<endl; } output<<amount<<"\n"; cout<<setiosflags(ios::left)<<setw(10)<<"编号"<<setw(16)<<"名称"<<setw(10)<<"生产厂家"<<setw(10)<<"价格"<<setw(10)<<"商品类别"<<setw(10)<<"数量"<<setw(10)<<"入库时间"<<endl; while(p->next!=NULL) { p=p->next; output<<p->code<<"\t"<<p->name<<"\t"<<p->brand<<"\t"<<p->price<<"\t"<<p->num<<"\t"<<p->type<<"\t"<<p->date.year<<"\t"<<p->date.month<<"\t"<<p->date.day<<"\n"; cout<setiosflags(ios::left)<<setw(10)<<p-code<<setw(16)<<p->name; cout<<setw(10)<<p->brand<<setw(10)<<p->price<<setw(10)<<p->type; cout<<setw(10)<<p->num<<p->date.year<<"/"<<p->date.month<<"/"<<p->date.day<<endl; } cout<<endl; cout<<"成功将货物信息保存到<货物信息.txt>"<<endl; cout<<"……信息保存完毕……"<<endl; cout<<"……按任意键返回主菜单……"<<endl; getchar(); getchar(); output.close();//关闭输出文件}
    2.2.3 算法流程图添加商品信息函数流程如下所示:

    浏览商品信息函数流程如下所示:

    按照商品编号搜索商品信息函数流程如下所示:

    按照商品名称搜索商品信息函数流程如下所示:

    按照商品类别搜索商品信息函数流程如下所示:

    按照商品品牌搜索商品信息函数流程如下所示:

    编辑商品信息函数流程如下所示:

    删除商品信息函数流程如下所示:

    出售商品信息函数流程如下所示:

    保存商品信息函数流程如下所示:

    三 运行测试程序主菜单

    添加商品信息

    编辑商品信息

    删除商品信息

    按照编号搜索商品信息

    按照类别搜索商品信息

    按照名称搜索商品信息

    按照品牌搜索商品信息

    出售商品信息

    保存商品信息

    统计商品信息
    3 评论 33 下载 2018-10-18 22:21:00 下载需要14点积分
  • 基于JSP实现的课程资源管理系统网站

    一、系统需求1.1 用户信息管理
    用户:系统管理员、教师、学生
    登录:用户进行账号、密码等信息填写登陆后,教师、学生可以查看账号信息或进行课程、教学资源、作业管理等操作,系统管理员登录后可以行使增删账号的权限
    忘记密码:教师、学生填写学/工号和姓名,重置密码为学/工号后六位,系统管理员只允许后台操作重置密码
    修改密码:填写账号、当前密码、新密码

    1.2 课程管理规定每名教师可以教授多门课程,一门课程可以由多名老师授课,学生可以选修多门课程,每门课程可以被多名学生选择,课程名可以相同,但课程号唯一,对应特定的授课教师。
    1.3 教学资源的管理
    课件管理:教师每门课程只能有一个课件,每个课件可以有多个章节,教师可以上传/下载授课课程对应的课件。学生可以搜索、下载、在线查看其选修课程的课件
    作业管理:每门课程每个课时有相应的作业,教师可以发布作业要求、查看学生作业提交状态、下载学生的作业、对作业进行评分、给出批改意见并做统计分析。学生可以查看课程的作业要求,进行作业的提交,查看作业的批改情况

    1.4 教学信息发布老师可以发布其教授课程的学生成绩,或对学生的成绩进行修改。学生可以查询自己选修课程的成绩,并对教师进行教学评价。
    二、系统架构2.1 构架该系统采用表示层、业务逻辑层、数据访问层三层构架。
    在系统主页面,用户可以通过已有的账号密码进行登录,验证成功则进入个人信息页面;也可以进行忘记密码之后的重置操作,验证成功则完成重置并返回系统主页面再次登录
    在个人信息页面,用户可以修改当前账号密码,验证成功则完成修改则返回系统主页面。在此之外,不同身份的用户可以有不同的操作。

    管理员:查看现有帐号信息,对帐号进行增、删等操作
    教师:查看课程信息,包括预览、下载课件,查看作业情况(提交、批改意见、评分)等;修改课程信息,包括上传、重传课件,下载作业,提交作业批改意见、评分,发布新作业要求,更新系统公告等
    学生:查看课程信息,包括预览、下载课件,查看作业情况(提交、批改意见、评分)等;修改课程信息,包括上传、重传作业等

    2.2 系统流程
    表示层效果采用HTML5、CSS等语言和前端框架jQuery,实现用户交互界面。交互界面包括用户登录界面,个人信息展示页面,课程、课件、作业查看页面等
    业务逻辑层利用Servlet,JSP来处理来自前端的请求,获取数据库数据,并作出相应的处理,将处理数据提交到前端,显示给用户
    数据访问层利用Hibernate架构操作数据库,通过应用程序经过Hiberante持久层来访问数据库。数据访问层的关键是确定表结构和表属性,便于业务逻辑层进行对数据库的查询,良好的数据库结构,对数据操作有很大的用处

    2.3 系统结构
    三、数据库设计与构架3.1 E-R图
    3.2 物理设计admin(管理员账号信息表)



    adm_id
    password




    varchar
    varchar



    teacher(教师账号信息表)



    tea_id
    name
    password




    varchar
    varchar
    varchar



    student(学生信息表)



    stu_id
    name
    password




    varchar
    varchar
    varchar



    course(课程信息表)



    course_no
    title
    credit
    tea_id




    varchar
    varchar
    decimal(3,1)
    varchar



    stu_course(选课信息表)



    course_no
    stu_id
    grade
    tea_evaluation




    varchar
    varchar
    decimal(3,1)
    decimal(3,1)



    courseware(课件信息表)



    course_no
    file_title






    varchar
    varchar



    tea_homework(发布作业情况表)



    course_no
    homework_no




    varchar
    varchar



    stu_homework(提交作业评分表)



    course_no
    homework_no
    stu_id
    status
    grade
    opinion




    varchar
    varchar
    varchar
    bit
    decimal(3,1)
    varchar



    四、模块设计4.1 用户模块
    4.2 教学信息模块
    4.3 作业管理模块
    4.4 课件管理模块
    1 评论 80 下载 2018-11-06 12:56:48 下载需要5点积分
  • 基于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.
    1 评论 1 下载 2019-05-20 22:08:31 下载需要15点积分
  • 基于java和Sql Server数据库的停车场管理系统

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

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

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

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

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

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

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

    4.2 界面设计登陆界面

    管理员主界面

    普通用户主界面

    车辆入场界面

    车辆出场界面

    计费标准界面

    当场在场信息界面

    用户历史信息界面

    用户个人信息界面

    普通用户个人信息界面

    出入场信息界面

    当前可用车位信息界面

    用户注册界面

    用户修改界面

    用户充值界面

    管理员注册界面

    更改口令界面

    计费标准管理界面

    关于界面

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


    用户表:users








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


    cardid
    int
    不可

    主键,用户的停车卡号


    name
    Nvarchar(20)
    不可

    用户姓名


    password
    Nvarchar(20)


    用户密码


    cardtype
    Nvarchar(20)


    停车卡类型


    userstype
    Nvarchar(20)


    用户类型


    carid
    int


    用户车牌号


    tel
    int


    用户电话号码


    overage
    int


    用户余额






    车位信息表:sit_infor








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


    stationid
    int
    不可

    主键,车位号


    stationtype
    Nvarchar(20)
    不可

    车位类型






    停车收费卡收费表:charger








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


    cardtype
    Nvarchar(6)


    车卡类型


    stationtype
    Nvarchar(20)


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


    charge
    int


    价格






    停车表:park








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


    cardid
    int


    车卡号(外键)


    stationid
    int


    车位号(外键)


    parkid
    int

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


    startpark
    datetime


    停车开始时间


    endpark
    datetime


    停车结束时间


    fee
    int


    停车的收费


    sumpark
    int


    停车总时间



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

    摘 要互联网的迅速发展为人们提供了更多的购物方式,网上商店就是目前最主流的网上购物方式之一。本网上购物系统的设计源于对网上购物需求的增加,由于地理位置购物不便,购物管理不规范,管理工作效率低的现状开发设计而成,人们可以足不出户,在电脑前就可以获得自己所需要的商品。网上购物将传统的购物流程数字化,可以大量减少人力、物力;另一方面突破了时间和空间的限制,使得交易活动可以在任何时间、任何地点进行,极大地方便了消费者,使购物过程变得轻松、快捷、方便,从而大大提高了效率。本论文设计就是利用JSP技术开发网上购物系统的事例。
    本网上购物系统采用模块化程序设计方法,使用Oracle10g进行数据库开发。本系统充分利用了Jsp+Sruts+Javabean+Jstl+Hibernate+Orcle的简单组合,采用MVC设计模式,具备数据查询、修改、增加、删除、维护等功能,可以实现会员信息管理管理、订单管理、产品信息管理、购物车管理等功能。系统具有高可靠性、可扩展性和重用性的特点,为顾客提供一个便利的购物平台。界面设计使用了Dreamwaver;工具运用了Eclipse、JDK和Tomcat,后台数据库使用了Oracle。
    关键词:网上购书系统;Hibernate;Struts;Oracle10g;MVC模式
    ABSTRACTWith the development of the internate technology,It provides much more shopping styles .Shopping online is one of the most popular shopping style in the world. The e-commerce portal system design stems from domestic demand to increase in online shopping, shopping inconvenient Because of its geographical location, shopping management was not standardized, low-efficient management of the development and design from the status quo.
    The reference to e-commerce portal system is modular in design procedures, the use of Oracle10g database development. The system made full use of Jsp + struts + Javabean + Jstl + Hibernate + Orcle a simple combination of using MVC design pattern, a data query, modify, add, delete, maintenance, and other functions, members can achieve the management information management, order management, product Information management, shopping cart management functions. to provide customers with the A convenient shopping platform. Interface design uses Dreamwaver; tools used Eclipse, JDK and Tomcat, background database using Oracle.
    Keywords: Online bookstores; Hibernate;Struts; Oracle10g; MVC model
    1 概述1.1 课题的提出电子商务始于20世界70年代,但当时主要是电子数据交换(EDI)贸易,应用不是很广泛而且交易量很小。随着Internet的不断普及,人们对网络应用的要求已经不再是浏览网站新闻、收发电子邮件,日益忙碌的人们开始追求利用互联网这一快捷而且强大的平台足不出户地进行网上购物。下面我们就以网上购书来比较网络销售较之传统市场营销所具有的特点:
    第一、从间接经济到直接经济,交易成本降低
    传统的市场营销模式必须有许多中间环节,图书出版商与消费者之间存在大量的批发商、零售商为中介,这就决定了其“间接经济”的特点。网络购书的出现从根本上减少了传统售书的中间环节,缩短了供与求之间的距离,同时也大大减少了各种不必要的消耗,使我们进入“直接经济”时代。网上书店的网上服务也可以提供全新的服务方式。网上购书使得买卖双方的交易成本大大降低,具体表现在:

    购书者和售书者通过网络进行商务活动,无需中介者参与,减少了交易的有关环节,所以网上书店的书的价格比传统书店低
    售书方可以通过互联网进行书籍的介绍,宣传,避免了在传统方式下做广告等大量费用
    互联网使买卖双发即使沟通供需信息,使无库存销售成为可能,从而使库存成本降为零
    传统的售书平台使地面地铺,新的网上书店的售书平台则使在网吧、家庭或者办公室

    第二、让购书者的购买区域从当地扩展到全球
    由于传统售书模式的限制,购书者往往只能在当地书店选购书籍,很少有人会为了买一本书特地去别的省市,即便让人代购也烦人烦己,而且各个书店的进货渠道有所不同,使得书店销售的书目品种存在差异,这就会让购买者要多跑几家才可能买到想要的书。互联网能够把全世界的顾客送到地球上开设的任何一家网络书店,消费者只需要在
    电脑面前就跨市、跨省甚至跨国选购自己想要的书籍,这家网上书店如果需求,只需要鼠标一点即可进入另外一家网上书店,方便快捷,省钱省力。
    第三、大小书店公平竞争,交易透明化
    互联网为所有书店提供了平等的竞争环境。在传统售书行业中,出版商和销售商必须投入巨大资金和人力去建立其营销网络,对于一些中小书店来说,是一个非常庞大的障碍。然后现在,互联网使最小的书店也可以与最大的书店一样平等地出现在全世界的客户面前,像销售渠道之类的障碍在网络经济时代完全瓦解了。买卖双方整个交易过程都在网络上进行。通畅、快捷的信息传输可以保证各种信息之间相互核对,可以防止伪造信息的流通。
    1.2 课题研究的目的和方法系统的主要设计目的就是利用现代化的电子及网络技术,为企业和客户搭建一个互动平台——网上购书系统。降低企业运营成本的同时,方便客户购书,达到双赢的目的。一方面,企业减少了地面店铺的租凭费用,减少了宣传货物的广告费用,减少了雇佣员工的费用;另一方面,电子及网络技术使得企业运作更加快捷方便,为企业赢得宝贵的时间和商机。对于客户来说,客户省去了逛书店的时间,同时可以将自己的需求迅速地反馈给企业,使自己的需求可以更好地得到满足。
    本系统是在Windows XP环境下开发。本文的设计方法是建立在MVC模式下的:用JSP做显示,用Struts做控制,用JavaBean连接Oracle数据库,并用Hibernate实现数据持久化,实现客户的注册、登陆、查找、购买、购物车管理、订单管理等功能,最终实现网上购书系统。
    2 开发技术与工具2.1 开发技术2.1.1 Struts技术Struts2的体系与Struts1体系的差别非常大,因为Struts2使用了WebWork的设计核心,而不是Struts1的设计核心。Struts2中大量使用拦截器来处理用户的请求,从而允许用户的业务逻辑控制器与Servlet API分离。
    Struts2框架的大概处理流程如下:   

    加载类(FilterDispatcher)   
    读取配置(struts配置文件中的Action)   
    派发请求(客户端发送请求)
    调用Action(FilterDispatcher从struts配置文件中读取与之相对应的Action )
    启用拦截器(WebWork拦截器链自动对请求应用通用功能,如验证)
    处理业务(回调Action的execute()方法)
    返回响应(通过execute方法将信息返回到FilterDispatcher)
    查找响应(FilterDispatcher根据配置查找响应的是什么信息如:SUCCESS、ERROER,将跳转到哪个jsp页面)
    响应用户(jsp—->客户浏览器端显示)

    Struts框架的工作流程图

    2.1.2 Hibernate技术Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。
    Hibernate的核心接口一共有5个,分别为:Session、SessionFactory、Transaction、Query和Configuration。这5个核心接口在任何开发中都会用到。通过这些接口,不仅可以对持久化对象进行存取,还能够进行事务控制。下面对这五个核心接口分别加以介绍。
    Session接口
    Session接口负责执行被持久化对象的CRUD操作(CRUD的任务是完成与数据库的交流,包含了很多常见的SQL语句。)。但需要注意的是Session对象是非线程安全的。同时,Hibernate的session不同于JSP应用中的HttpSession。这里当使用session这个术语时,其实指的是Hibernate中的session,而以后会将HttpSession对象称为用户session。
    SessionFactory接口
    SessionFactory接口负责初始化Hibernate。它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式。需要注意的是SessionFactory并不是轻量级的,因为一般情况下,一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。
    Configuration接口
    Configuration接口负责配置并启动Hibernate,创建SessionFactory对象。在Hibernate的启动的过程中,Configuration类的实例首先定位映射文档位置、读取配置,然后创建SessionFactory对象。
    Transaction接口
    Transaction接口负责事务相关的操作。它是可选的,开发人员也可以设计编写自己的底层事务处理代码。
    Query和Criteria接口
    Query和Criteria接口负责执行各种数据库查询。它可以使用HQL语言或SQL语句两种表达方式。要使用Hibernate技术需要将相应的JAR包放在开发路径下。
    2.2 开发工具2.2.1 开发工具-Tomcat直接运行下载的apache-tomcat-6.0.18.exe文件,按照一般的Windows程序安装步骤即可安装好Tomcat,安装时它会自动寻找JDK的位置。安装过程中需要选择一个文件夹作为Tomcat的安装目录。我选择安装的位置是C:\Program Files\Apache Software Foundation\Tomcat 6.0。
    安装完成以后,添加一个Tomcat的环境变量,添加方法和JDK的环境变量的添加方法相同,设置变量名为TOMCAT_HOME,变量值为C:\Program Files\Apache Software Foundation\Tomcat 6.0。
    设置完毕后就可以运行Tomcat服务器了。Tomcat成功启动后,在浏览器中输入http://localhost:8080/ ,如果出现欢迎界面,则说明Tomcat安装成功。
    2.2.2 开发工具-Oralce概论
    ORACLE 数据库系统是美国ORACLE公司(甲骨文)提供的以分布式数据库为核心的一组软件产品,是目前最流行的客户/服务器(CLIENT/SERVER)或B/S体系结构的数据库之一。比如SilverStream就是基于数据库的一种中间件。ORACLE数据库是目前世界上使用最为广泛的数据库管理系统,作为一个通用的数据库系统,它具有完整的数据管理功能;作为一个关系数据库,它是一个完备关系的产品;作为分布式数据库它实现了分布式处理功能。但它的所有知识,只要在一种机型上学习了ORACLE知识,便能在各种类型的机器上使用它。
    特点

    完整的数据管理功能

    数据的大量性数据的保存的持久性数据的共享性数据的可靠性
    完备关系的产品

    信息准则—-关系型DBMS的所有信息都应在逻辑上用一中方法,即表中的值显式地表示保证访问的准则视图更新准则—-只要形成视图的表中的数据变化了,相应的视图中的数据同时变化数据物理性和逻辑性独立准则

    2.2.3 开发工具-MyEclipseMyEclipse企业级工作平台(MyEclipse Enterprise Workbench ,简称MyEclipse)是对EclipseIDE的扩展,利用它我们可以在数据库和JavaEE的开发、发布以及应用程序服务器的整合方面极大的提高工作效率。它是功能丰富的JavaEE集成开发环境,包括了完备的编码、调试、测试和发布功能,完整支持HTML,Struts,JSP,CSS,Javascript,Spring,SQL,Hibernate。
    3 需求分析3.1 系统概述本系统使用java语言及周边技术制作,为广大消费者提供一个网上购书的平台,便于对订单管理形成规范化,使信息资源可以有效的利用,极大的提高效率,减少工作量。该系统的功能模块主要由:用户信息自管理模块、购物车管理模块、订单管理模块、短信息模块、留言板模块,图书管理模块和订单处理模块组成。在后续章节中将详细介绍这些功能模块,系统结构总框架设计如图3.1所示:

    3.2 技术可行性分析使用java语言要比使用其他编程语言效率高,没有指针,代码中不进行内存管理,完全面向对象的语言由JVM和垃圾回收机制实现内存管理,跨平台一处编写处处运行,而且是多线程,在J2EE开发中使用一系列的框架从而使代码更加条理清晰,系统性能更加强大稳定,为编程人员提供快速和标准的应用接口,大大提高了应用软件的生产率。
    在Web层使用Struts框架在持久化层使用Hibernate技术实现数据库中的表和代码中的实体类进行映射,对于业务逻辑和数据访问使用Javabean技术进行管理,层与层之间相互调用,所使用的模式有MVC模式,模型层就是业务逻辑层,处理业务逻辑、封装和传递数据,控制层由Struts框架下的Action完成,控制用户请求的转发,根据不同的要求转发到相应的显示层JSP进行显示。
    MVC具体的处理过程如下:首先控制器接收用户的请求,并决定该调用哪个模型来进行处理;然后模型根据用户请求进行相应的业务逻辑处理,并返回数据最后控制器调用相应的视图来格式化模型返回数据;最后通过视图呈现给用户。
    Struts有自己的控制器,同时整合了其他的一些技术去实现模型层和视图层,在模型层Struts可以很容易的与数据访问技术相结合,包括EJB、JDBC;在视图层Struts可以JSP,XSL等等这些表示层组相结合。
    Struts框架是一个开源框架可以免费获得,使用WEB框架可以大大的提高开发软件的效率,在Struts框架中由Action实现控制转发请求,一般对每一个功能模块对应一个Action,从而使WEB开发变得轻松,愉快,在本系统的开发中充分利用了过滤器和监听器等功能是系统更加灵活的运行。
    3.3 业务流程分析为了提供系统的安全性,本系统使用用户的密码登陆方式登陆系统,增加系统数据的安全性、保密性,只有合法的用户才可以登陆系统。本系统主要功能是实现会员能够进行网上购书,为了更加完善系统的功能,又加入了留言板和收发信息等小模块。后台管理是为了给管理员提供方便,使系统功能功能更加完善。系统是建立在Struts框架上的,其中前台运用了Struts1框架,后台运用了Strusts2框架。系统结构总流程设计,如图3.2所示:

    用户通过用户管理模块可以进行用户注册和登陆,用户通过购物车模块可以实现购买图书、修改购买图书数量等操作,用户通过订单管理模块实现将用户确认的订单保存到数据库,并且可以实现对用户订单和订单明细的查看操作。用例图如图3.3、图3.4所示:
    管理员用例图

    用户用例图

    4 概要设计4.1 数据库设计数据访问层负责对业务层提供数据操作,也就是它负责和底层的数据库打交道。业务层或者通用层中所有的对象都通过数据访问层的对象访问数据库。数据访问层中的类是按业务对象来组织的,每个业务对象中包含的数据可能存在不同的几种数据表中,它由数据访问类统一组织成一个概念中的对象,它相当于是一个面向对象的数据库层,负责映射面向对象与关系数据库间的关系。
    4.2 基本实体-联系图(ER图)考虑到用户需求的各种实体,本系统规划出的实体有用户信息实体,产品信息实体、订单信息实体、订单明细信息实体,等等实体之间通过外键建立联系,在数据库中Hibernate技术,对数据库中的数据进行封装,一般是一张表影射成一个POJO类,通过类与类之间的关系来确立表之间的关系,在数据访问层通过HQL语句对数据库进行增删改查,通过Hibernate技术中相关的知识将数据信息持久化到数据库中,其中实体图如图4.1、图4.2、图4.3、图4.4、图4.5、图4.6所示:

    说明:记录用户的基本信息

    说明:记录图书的基本信息

    说明:记录用户订单时的一些基本信息,客户编号参照客户的ID号

    说明:记录订单明细的一些基本信息,订单编号参照订单信息的ID号,图书编号参照图书表的ID号

    说明:记录用户留言时的一些基本信息

    说明:记录用户发送和接受短息时的一些基本信息
    基于系统的功能分析,其E-R图如4.7所示:

    4.3 数据库逻辑结构设计数据库在信息系统中占有及其重要的地位,数据库结构设计的好坏关系到系统的运行效率、存储数据的效率、系统的复杂程度等,合理的数据库结构设计可以提高系统性能。本网上购物系统数据分为前台和后台数据,分别是商品数据、订单数据、客户数据,订单明细数据,短信息数据,留言板数据等。将以上的数据库概念结构转化为关系数据模型,即数据库的逻辑结构。各个数据的字段设置如下表所示:
    customer表



    字段名
    字段类型
    约束或索引
    描述




    ID
    Number(Sequence)
    PK
    记录流水号


    Name
    Varchar2(20)

    用户名


    Password
    Varchar2(20)

    用户密码


    Zip
    Varchar2(20)

    邮编


    Address
    Varchar2(50)

    地址


    Telephone
    Varchar2(20)

    电话


    Email
    Varchar2 (30)

    电子邮件



    说明:ID用oracle的sequence的自增长
    book表



    字段名
    字段类型
    约束或索引
    描述




    ID
    Number(Sequence)
    PK
    记录流水号


    Name
    Varchar2(100)

    商品名


    Price
    Number(8,2)

    价格


    Author
    Varchar2(30)

    作者


    Publish
    Varchar2(50)

    出版社



    说明:ID用oracle的sequence的自增长
    Orderform表



    字段名
    字段类型
    约束或索引
    描述




    ID
    Number(Sequence)
    PK
    记录流水号


    Cost
    Number(8,2)

    订单总额


    Orderdate
    Date

    下单时间


    Customerid
    Number
    FK
    记录流水号


    Status
    Varchar2(40)

    订单状态



    说明:ID用oracle的sequence的自增长,Customerid参照用户的ID,Status标记订单的发送状态:未发送和已发送
    Orderline表



    字段名
    字段类型
    约束或索引
    描述




    ID
    Number(Sequence)
    PK
    记录流水号


    Num
    Number

    数量


    Orderid
    Number
    FK
    订单的流水记录号


    Bookid
    Number
    FK
    商品的流水记录号



    说明:ID用oracle的sequence的自增长,Orderid参照订单表的ID,Bookid参照书籍的ID
    MessageRecord表



    字段名
    字段类型
    约束或索引
    描述




    ID
    Number(Sequence)
    PK
    记录流水号


    Sender
    Varchar2(20)
    Not Null
    发件人登录名


    Receiver
    Varchar2(20)
    Not Null
    收件人登录名


    SendDate
    Date
    Default=当前时间 , Not Null
    发送日期


    Title
    Varchar2(100)
    Not Null
    短信标题


    Content
    Varchar2(300)
    Not Null
    短信内容


    Status
    Number
    Default=0
    0-未阅1-已阅读


    SenderStatus
    Number
    Default=0
    0-未删1-已删除


    ReceiverStatus
    Number
    Default=0
    0-未删1-已删除



    说明:ID用oracle的sequence的自增长,Status用0、1标记邮件是未读还是已读,SenderStatus用0、1标记在发送者端邮件是未删除还是已删除,ReceiverStatus 用0、1标记在接收者端邮件是未删除还是已删除
    ForumMessage表



    字段名
    字段类型
    约束或索引
    描述




    ID
    Number(Sequence)
    PK
    记录流水号


    Sender
    varchar2
    Not Null
    记录发送者


    Title
    varchar2
    Not Null
    标题


    SendDate
    Date
    Not Null
    发送日期


    Content
    varchar2
    Not Null
    发送内容



    说明:ID用oracle的sequence的自增长
    4.2 Web系统安全性的考虑4.4.1 本系统中基本的安全性的实现
    利用一个后台服务器端的功能组件实现随机产生一个验证码,由于验证码是机器随机产生的,因此暴力破解程序无法预料到具体是什么,所以可以防止暴力破解
    系统的每个功能都必须经过身份验证后才能访问,没有认证的请求会被过滤掉,这是最基本的安全要求
    所有功能都通过Struts的Action来进行访问,不直接以jsp的形式向用户提供功能访问,这样一方面可以防止向用户暴露程序的资源名称,另一方面也可更方便的进行权限控制
    对用户的请求进行与其身份相匹配的识别

    4.4.2 对Struts的ActionServlet设置Filter利用该Filter来检查用户的权限,这样既可以防止用户登陆后跨url访问。在本项目中添加一个WebBBSFilter组件来监控后台管理的URL。
    4.4.3 防止绕过权限认证的直接资源访问虽然前面的设计中,已经要求所有的功能都通过struts的Action来进行访问,但是还是不能排除恶意用户可能会知道程序资源名称(jsp文件),如果这类用户直接输入jsp文件的url访问,有可能会对系统形成威胁。
    5 详细设计及实现5.1 用户管理模块主页中由列出了系统推荐最新上架的商品和一些特价商品,任何游客都可以浏览主页的信息,但是要想使用本网上购物系统的功能必须登录成功才行。下面是本网上网书系统的主界面,如图5.1所示:

    当客户登录成功后,用户可以输入要购买的商品数量点击购买即可将商品添加到购物车里,用户也可以查看或修改用户个人信息,也可以根据需要点击相应的链接发送短信息进入留言板,浏览货物信息等。在购物界面可以添加货物到购物车此处设计成一个Map集合,存放订购信息,Key为货号,Value为货物整个对象,可以循环购买货物,在没有提交确认前可以删除不需要的货物,提交确认后,网站会再一次确认你的地址,电话等,可以修改这些信息,以便,货物可以按时送到。
    5.1.1 用户登录模块在登录界面上可以实现两种用户的登陆,一是客户登陆,二是管理员的登陆。如果客户输入用户名和密码都正确,进入网上购物系统;管理员如果输入的用户名和密码正确则进入后台管理系统。如果用户名和密码不正确,提示用户失败登录,并重新登录。如果用户名和密码为空,通过Ajax验证提示用户输入用户名和密码。如果用户不存在还可以点击用户注册进入用户注册界面。在登录页面上还有一个Checkbox,如果用户登陆的时候选上的话,利用Cookie保存用户名和密码,则下次该用户再访问登录页面的时候,就可以实现自动登陆。如图5.2所示:

    在登录界面上用户可以输入用户名和密码进行登录,如果用户名和密码正确,将成功跳转到图书系统主页面,如果不正确,提示给用户错误信息,并且还跳转到登录界面继续登录。
    具体实现过程:首先客户端验证通过JavaScript来完成,比如用户没有输入用户名时会提示客户用户名不能为空,密码为空时提示密码不能为空。只有用户名和密码都填写好以后才能进行客户端数据的提交,这样使得操作更加方便并且提高效率。当数据提交以后,程序将数据提交给配置文件Struts-Config.xml中定义Struts高级特性UserDynamicForm,其类型为DynaActionForm,在UserDynameicForm中的Form-property属性中接收JSP界面中提交的用户名和密码,其类型为String类型。在UserAction中通过Login方法传入UserDynameicForm的用户名和密码,并且判断输入的用户名和密码是否正确,Login方法会调用ICustomerService接口中的Login方法实现登录的合法性验证,在此Service方法中首先要调用Dao方法中的FindCustomerByName 方法判断数据库Customer表中是否存在名字为Name的记录,如果不存在则提示用户输入的用户名不存在,如果存在,继续判断密码是否于数据库中的密码相同,相同的时候表示登录成功跳转到购书系统的主界面,否则跳转到登录界面继续登录。在登录成功以后在Login方法中把用户信息提交到Session范围内,以供程序后继使用用户的个人信息。
    5.1.2 用户注册模块第一次登陆的用户必须先注册,与注册界面有关的为Register.jsp,完成注册功能时需要在Struts-Config.xml中配置一个DynaActionForm,在Action包中的UserAction中定义一个Register方法,调用相应的Dao和Service方法实现注册。对注册的用户进行合法性的验证,满足所有的条件的用户才能注册成功。用户名作为用户登录的唯一标识。在验证注册新用户的过程中加入新加入了验证码验证的过程,如果在用户名不冲突验证码输入正确的情况下,才能注册成功,否则重新注册。注册界面如图5.3所示:

    具体实现的过程:在注册界面中,对于带有红色星号的项必须填写,其具体的客户端验证通过JavaScript完成,如果没有填写在提交的时候系统会提示用户填写相关的项目。在JavaScript文件的Base.js中定义了一个ValidateRegisterForm函数,专门对注册界面提交的表单进行合法性验证,在JSP页面中通过Form表单的Onsubmit属性对把数据提交给Base.js进行判断,若验证通过,转回Form中执行Action属性,跳转UserAction的Register方法中,在Register中接收到UserDynamicForm中的JSP页面提交的相关数据,创建Customer对象并将提交的数据封装在Customer类中,调用Service中的Register方法对业务逻辑进行进一步的验证,完全符合条件的情况下才能注册成功,否则继续进行注册。代码实现过程中出现的问题:在对用户注册的合法性验证过程中,从JSP页面中提交的数据信息必须和传入JavaScript代码中属性的名称必须一致。
    用户部分还有检查是否登录的功能,通过UserAction中CheckLogin方法实现,判断在Session对象内是否存在Customer对象,如果存在可以直接进入购书系统的主界面,如果不存在将跳到Login.jsp界面提示用户通过登录的方式进入系统。其主要实现同登录的实现。
    5.1.3 用户退出系统操作当用户退出系统时,用户必须重新登陆才可以进行网上购物等功能。用户单击系统顶部导航栏中退出按钮,会触发相应的ExitAction,用户退出系统,返回到主界面。如果用户想使用网站的其他功能必须重新登陆,成功登陆后进行相应的其他功能操作。
    该功能主要是让Session失效,通过Session.invalidate()方法实现。
    实现代码如下:
    public class ExitAction extends Action{ public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response) throws Exception{ request.getSession().invalidate(); return new ActionForward(“/login.jsp”); }}
    5.1.4 找回密码当客户忘记密码的时候,可以访问找回密码页面,输入会员的帐号、密码提示问题、密码提示答案进行提交,系统对这些信息进行判断,如果正确,则产生一个新的密码返回给用户,并在页面上显示,提示用户下次要妥善保管好自己的密码,并将数据库中的密码修改成新密码。如果不正确,则提示用户。如图5.4所示:

    5.1.5 用户信息修改在整个购书系统中还可以对用户的个人信息进行动态的显示和修改,以及在密码丢失的情况下找回密码的功能。
    用户的个人信息可以动态的显示在页面上,通过JSP页面向UserAction中传入新的需要修改的用户信息,并从Session对象中取出登录成功时存放在Session对象中的Customer对象信息,如果登录用户的密码输入正确时就可以对用户的个人信息进行修改,调用IOrderService中的UpdatePassword方法对输入的密码进行合法性的验证。个人信息列表如图4-5所示:

    5.2 购物车管理模块跟踪用户选择的商品,用户在购物车中保存浏览商店时所选中的商品。每个用户都有自己临时的一个购物车。可以查看购物车,可以向购物车中添加选中的商品,修改选中的商品的数量,删除已选择的商品或者清空购物车重新选购商品。
    购物车的代码实现如下:
    public class CartAction extends DispatchAction { public ActionForward addOrderLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { DynaActionForm cartDynamicForm = (DynaActionForm) form; HttpSession session = request.getSession(); ServletContext stx = session.getServletContext();Map<Long,Book> books = (Map<Long,Book>)stx.getAttribute("books"); ShoppingCart cart = (ShoppingCart)session.getAttribute("cart"); String bookid = cartDynamicForm.getString("bookid"); String num = cartDynamicForm.getString("num"); Book book = (Book)books.get(Long.parseLong(bookid)); Orderline line = new Orderline(); line.setBook(book); line.setNum(Long.parseLong(num)); cart.addLine(line); return mapping.findForward("addSuccess"); } public ActionForward deleteOrderLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { DynaActionForm cartDynamicForm = (DynaActionForm) form; HttpSession session = request.getSession(); ShoppingCart cart = (ShoppingCart)session.getAttribute("cart"); String lineid = request.getParameter("lineid"); cart.dropLine(Long.parseLong(lineid)); return mapping.findForward("deleteSuccess"); } public ActionForward editOrderLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { DynaActionForm cartDynamicForm = (DynaActionForm) form; HttpSession session = request.getSession(); ShoppingCart cart = (ShoppingCart)session.getAttribute("cart"); String lineid =cartDynamicForm.getString("lineid"); String num =cartDynamicForm.getString("num"); Orderline orderline = cart.getOrderline(Long.parseLong(lineid)); orderline.setNum(Long.parseLong(num)); return mapping.findForward("editSuccess"); } public ActionForward clearCart(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { DynaActionForm cartDynamicForm = (DynaActionForm) form; HttpSession session = request.getSession(); ShoppingCart cart = (ShoppingCart)session.getAttribute("cart"); cart.removeAll(); return mapping.findForward("clearSuccess"); }}
    购物车的实现是本系统的核心技术部分,首先是购物车列表的动态显示,使用JSP中Use Bean标签实现。
    图书列表的动态显示是在WEB应用启动的时候完成的,使用了创建事件监听器的方式实现。具体实现:创建一个ContextListener类,继承系统提供的ServletContextListener类,定义ContextInitialized方法对图书列表信息进行初始化工作,在此方法中调用IOrderService接口中的ListAllBook方法,从数据库中取出所有的图书信息,并把图书信息存放在ServletContext范围内的Application对象中,存放在ServletContext范围内的对象的生命周期为从WEB服务器的启动到WEB服务器的关闭时注销,因此解决了在整个系统运行的过程中都有图书信息的存在,而且不用在每次用到图书信息的时候去数据库中查询调用数据,减少了与数据库的交互性并能显著提高系统的运行效率。采用ContextDestroyed方法删除存放在ServletContext范围中的图书信息。
    5.2.1 添加购物车如果用户想购买商品可以直接点击右侧加入到购物车,所选择的商品便通过以下代码加入到用户自己的购物车中,如图5.6所示:

    Action实现代码如下:
    public ActionForward addOrderLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { DynaActionForm cartDynamicForm = (DynaActionForm) form; HttpSession session = request.getSession(); ServletContext stx = session.getServletContext(); Map<Long,Book> books = (Map<Long,Book>)stx.getAttribute("books"); ShoppingCart cart = (ShoppingCart)session.getAttribute("cart"); String bookid = cartDynamicForm.getString("bookid"); String num = cartDynamicForm.getString("num"); Book book = (Book)books.get(Long.parseLong(bookid)); System.out.println("num is"+num); System.out.println("bookid is"+bookid); Orderline line = new Orderline(); line.setBook(book); line.setNum(Long.parseLong(num)); System.out.println("orderline is "+line); cart.addLine(line); return mapping.findForward("addSuccess");}
    5.2.2 查看购物车用户购买商品后可以点击“查看购物车”查看购物车里的商品系统会跳转到购物车页面。购物车是通过一个监听器在系统启动时就在当前会话中创建一个购物车,当用户打开浏览器时系统自动把创建购物车放到Session中。当用户关闭浏览器时系统自动删除购物车。如图5.7所示:

    监听器(Listener)代码实现如下:
    public class SessionListener implements HttpSessionListener{ public void sessionCreated(HttpSessionEvent arg0) { HttpSession session = arg0.getSession(); ShoppingCart cart = new ShoppingCart(); session.setAttribute("cart", cart); }
    5.2.3 清空购物车如果客户看到自己又购物车里不想买的东西又可以点击“清空购物车”,来清空购物车中的商品,或者也可以点击“清除”按钮来清除某一件商品。
    Action代码实现如下:
    public String clearCart() { ActionContext context=ActionContext.getContext(); ShoppingCart cart =(ShoppingCart)context.getSession().get("cart"); cart.removeAll(); return "success";}
    代码说明:从Session中获得购物车,直接调用ShoppingCart中的RemoveAll()方法即可。
    5.2.4 修改购物车如果想修改自己购买商品的数量可以输入具体的商品数量,并单击保存修改,如果想继续购买产品单击继续购物又可以跳转到购买页面,如果不想购买先前购物车里的产品单击清空购物车即可,最后确定购买,便可提交订单,生成定单就这么简单,在单击“提交定单”后进入确认定单页面,如图4-7所示。
    当用户在购物车页面中点击“提交定单”按钮时便可以跳转到提交定单页面。其中当单击右侧的取消按钮时调用下面的Action修改这条购物清单,具体代码实现类似于清空购物车调用业务逻辑层相应的业务逻辑方法,然后在调用数据访问层的方法,从而作用于数据库中的数据,在业务层通过底层数据访问层利用HQL 语句查询实现对数据库中数据的同步和持久化。
    5.3 订单管理模块当确认订单后,系统根据购物车中的数据生成一个订单和一个订单明细表,并将所购买的商品信息加入到相应顾客的订单信息中,并清空购物车中的所有商品。其中在订单确认提交前可以对用户信息进行修改,这样方便了实际中客户信息变化的情况,增加了系统的功能,提高了系统的通用性。订单确认成功后便可以显示该用户的订单明细,可以供用户查看订单信息,以便再进行购买。系统返回到商品列表界面时,用户可以查询自己的订单情况,进而查询订单明细。
    5.3.1 生成定单当用户在购物车页面中点击提交定单按钮时便可以为客户生成一个订单,保存到数据库中,并可以列出该客户的基本信息和所购买的商品。如图5.8所示:

    当该用户确认提交的定单之后,系统便会设置定单信息,包括金额,下单时间,客户信息等,并保存该定单信息,之后便会清空当前购物车中的内容。
    代码实现如下:
    public ActionForward confirm(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { DynaActionForm orderDynamicForm = (DynaActionForm) form; HttpSession session = request.getSession(); ShoppingCart cart = (ShoppingCart) session.getAttribute("cart"); Customer customer = (Customer) session.getAttribute("customer"); double cost = cart.getCost(); Orderform order = new Orderform(); order.setCost(cost); order.setCustomer(customer); order.setOrderdate(new java.util.Date()); Collection<Orderline> c = cart.getOrderlines(); for (Orderline orderline : c) { orderline.setOrderform(order); order.getOrderlines().add(orderline); } IOrderService orderService = (IOrderService) BeanFactory.getBean(BeanFactory.ORDERSERVICE); try { orderService.saveOrder(order); request.setAttribute("message", "提交订单成功"); request.setAttribute("order", order); cart.removeAll(); return mapping.findForward("confirmSuccess"); } catch (OrderServiceException e) { request.setAttribute("message", e.getMessage()); return mapping.findForward("confirmFailure"); }}
    5.3.2 查看定单用户在购物的过程中客户可以查看自己所有的定单有时查看自己所下的定单,显示客户的所下的定单。首先获得Session中当前的客户信息,然后根据客户ID调用Service层的ListAllorder()方法,从数据库中找出该客户所有的定单,再把从数据库中找出来的信息放到ActionContext中,再通过JSP显示出来。也可以点击“继续购物”返回购物首页。如图图5.9所示:

    5.4 短信息管理模块5.4.1 新建短信客户与客户,客户与售货员及店长之间可以通过发送短信息进行交流,如果用户的短信息没有填写主题系统将提示用户填写主题,系统会判断接收者是否存在,如果存在,则发送,并且提示用户成功;如果不存在提示用户接收方不存在。如图5.10所示:

    此处主要是用javascript作验证:
    <script type="text/javascript"> function sendInfo(form){ var receiver=form.receiver.value; var title =form.title.value; if(/^\s*$/.test(receiver)){ alert("please input the receiver!"); return false; }if(/^\s*$/.test(title)){ if (confirm("确定信息主题为空?")==false){ return false; } } }</script>
    而发送的信息首先是将信息的内容、发送者、主题、信息状态通过业务逻辑层调用数据持久层将信息保存在Messagerecord表中进行持久化。
    5.4.2 已接收短信显示当前客户接收的所有短信(包括新短信和已读短信),并且可以删除某条短信,和查看某条短信的详细信息。
    它实现的方法主要是根据(收件人)从数据库中找出该用户所有的短信息,并可以根据信息的状态可以区分已读和未读的短信息。当用户登录成功后即可在左边的导航栏的收件箱中显示该用户未读的短信息。用户可以查看短信息的内容或删除某条信。如图5.11所示:

    5.4.3 已发送短信显示当前客户已发送的所有短信(已经删除的除外),并且可以删除短信息。如图5.12所示:

    5.5 客户留言坂模块客户可以在这里在线留言,向店长反应商品的质量,服务态度,信用度等。当用户发表自己的留言后便可以看到自己刚才的留言,还可以查看到其他用户的留言信息,所有的信息都是根据发表的时间先后顺序排列的,后发表的排在前面。如图5.13所示:

    实现的方法与短信息类似,首先也是将用发表留言的时间,内容等信息保存到数据库中,通过Action调用业务逻辑层的方法,业务层再调用数据层的方法,当用户信息发表成功之后系统会按发表时间分页显示所有的留言信息,每页显示4条。
    5.6 订单处理模块这个模块主要实现了对定单的处理,包括定单的删除、发货、查询订单的详细信息等。另外,系统还实现了对所查纪录进行分页显示的功能。
    5.6.1 查看所有定单此模块主要用于查询,所有管理员都可以查看定单的基本信息,并实现了分页显示的功能,可以查看这些定单的详细信息,对这些定单进行删除和发货等操作。界面如图5.14所示

    5.6.2 处理定单点击“处理订单”后会显示所有未发货的定单,并且可以查看这些定单的详细信息,对这些定单进行处理操作,并实现了分页显示的功能。主要是通过商品的发货状态来进行查找,实现方法与其他条件查询功能类似。界面如下图5.15所示:

    5.7 图书管理模块5.7.1 添加新图书如果有新货要上架,就可以通过该模块添加新商品,管理员在JSP页面的表单中输入图书名称,图书作者,出版社,价格信息,并将表单提交到添加商品的Action中,通过Action去调用业务逻辑层和数据持久层的保存方法,将该商品数据库中,从而可以让客户在前台可以浏览到该商品。如图5.16所示:

    5.7.2 编辑图书可以再重新编辑图书的各个属性,管理员可以根据市场行情改变图书的价格或者其他属性。如图5.17所示:

    5.7.3 搜索图书功能:该模块主要实现用户搜索所要的图书,即用户可以根据自己的需要输入自己想要书的信息,提交即可搜索对应的书本。本搜索采用的是动态的模糊搜索,即读者只知道模糊的书本信息,输入后也可以查询到与输入字段相关的图书信息。如果搜索的信息不存在,就会弹出页面显示提示信息:搜索的图书不存在。如图5.18所示:

    关键性代码如下:
    public Page findSelectbook(String name, String author, String publish, long sortID, int findPage) throws MessengerServiceException { String strSql = null; strSql = "from Book where"; strSql = strSql + " name like '%" + name + "%'"; strSql = strSql + " and author like '%" + author + "%'"; strSql = strSql + " and publish like '%" + publish+ "%'"; if (sortID != 0) strSql = strSql + " and SortID =" + sortID; Transaction tran = new HibernateTransaction(); tran.beginTransaction(); Page page = null; try { page = page.findPage(strSql, findPage); tran.commit(); } catch (Exception e) { e.printStackTrace(); tran.rollback(); }}
    5.8 关键技术及系统安全性能5.8.1系统关键技术创建业务逻辑层类
    新建一个类。类名设定为“***Serivice”在这个类中定义本系统所用到的业务逻辑方法,由web层中的action进行调用相应的方法,实现web层和业务逻辑层之间的相互调用,降低层层之间的偶合性。
    创建过滤器类和监听器类
    本系统通过EncodeFilter来解决编码问题,并关掉Session.相关代码如下:
    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { arg0.setCharacterEncoding("UTF-8"); arg1.setCharacterEncoding("UTF-8"); arg2.doFilter(arg0, arg1); HibernateSessionFactory.closeSession();}
    本系统另外一个亮点是使用了监听器功能:
    当用户关闭浏览器时系统自动删除购物车,用户打开浏览器时系统自动创建购物车放到Session中代码实现;启动WEB服务时,将图书加入ServletContext中,以便提高系统效率。其中过滤器和监听器必须在配置文件中作相应的配置才有作用,在Web.xml中配置
    数据验证
    Ajax它是Asynchronous JavaScript and XML的英文缩写,翻译过来就是“异步的JavaScript and XML”。可以说它是一种技术,更可以说它是一种技巧。其实它是多种技术的综合,包括JavaScript、XHTML和CSS、DOM、XML和XSTL、XMLHttpRequest。其中:使用XHTML和CSS标准化呈现,使用DOM实现动态显示和交互,使用XML和XSTL进行数据交换与处理,使用XMLHttpRequest对象进行异步数据读取,使用JavaScript绑定和处理所有数据。
    本系统采用Ajax的异步请求局部刷新的技术进行用户注册信息数据(用户名唯一性)的验证。对用户注册模块的用户名作验证,检测昵称是否存在,电话号码是否全为数字,邮箱地址是否合法等。
    5.8.2 系统安全性能为了保证系统的安全性,操作人员进入本系统前必须输入与相关用户名对应的有效密码,并且对输入的数据进行字符的过滤,不知道密码的非操作人员进入本系统后,仅仅只能看到系统产品的信息,没有权限执行用户管理模块,购物车管理模块,订单管理模块,留言板模块等,不能在本系统中进行购物,不能对数据库中的数据进行增加,删除,改写,查询等操作,只有用户登陆后并且用户名和密码正确无误才可以有使用本系统的权限,才能够享受本平台提供的各项功能,方便、快速、高效的进行购物管理等功能。
    6 系统测试与运行6.1 系统测试
    用户注册:测试邮箱格式是否正确
    发送消息:编辑发送消息按钮,看是否成功
    购物车提交订单:点击提交订单之后,弹出确认界面,可以选择确认订单继续购物

    6.2 系统部署及运行说明打开PL/SQL Developer,点击“文件”—》“新建”—》“命令窗口”,弹出下图界面:

    然后把SQL语句复制进去就把数据库还原进去了;进入Tomcat6的webapps目录

    将本系统提供的目录下的estore.war复制到webapps下,如图所示

    进入Tomcat目录下的bin,双击tomcat6.exe,开启tomcat服务,看到如下界面,则说明服务启动成功

    7 总结和展望通过这次毕业设计我觉得自己从中学到了很多。首先我对JavaWeb开发有了更深层的理解,对网站的架构以及架构模式的理解更深了一步,代码的编写让我能更为熟练的运用所学知识。我的热情并不会因为毕业设计的结束而结束,我会继续完善它,因为它是我的财富,对我来说学是无止境的,今后我会给自己一个不同的定位,使自己在今后的工作中、学习中不断提高,不断前进。
    网站的设计、编写是一个辛苦而漫长的过程。从最初的构想开始,到中间的代码编写、完善再到最后的调试、完成,应该说这一路走下来,其中的甘苦真的只有自己来体会,当每个模块一步一步出现在我眼前时,我高兴得忘记这其中的处理那一片片程序异常时的痛苦。购物车、留言板、发信息等都是现在时兴的话题和技术,但对于我来说,没有太多可以借鉴的东西和事物,摸石头过河,既有艰难也有成功后的快乐,还有与同学们一起讨论的豁然开朗!在购物车制作中,考虑周全是一个很重要的问题,很多东西也话不一定马上用的到,比如很多的表和字段,但这些必须先要预留出来,这样对于下一步来说是很有利的,网站的编写过程也就是一个不断完善的的过程。
    这个系统一开始是用JSP和Servlet写的,在JSP页面中嵌入了很多Java代码,那样不便于维护,后来又改用了Action进行控制,在JSP页面中又改为了EL表达式,而在学Struts2之后,在JSP页面中又改用了OGNL表达式,这样使JSP页面的汉字和Java代码更少了。
    购物车模块是首先设计出来的,并尝试过用了好几种方式实现,在这个基础上我考虑到一些现实的需要增加了一些功能,比如留言板,短信息等,为我的购物系统增加了不少吸引顾客的功能!购物车完全用Struts框架来实现,并使用了新的技术JSTL标签库的功能,使得JSP页面上只有少量的Java代码和中文,这个网站还有很多很多的不足,比如:管理员模块功能简单,没有实现文件上传得功能,页面不够华丽,没有考虑到对数据库的备份操作以及权限的分配,系统安全性不高等问题,有待我去改善。
    对于这个网站的完成,这只是一个开始。我以后更要在工作中积累经验和学习更深层次的知识,不断的充实自己,做出更好的系统软件。
    参考文献[1] Ivor Horton著.Java 2 入门经典 JDK5[M].潘晓雷 于浚泊,王丹等译.北京:机械工业出版社,2005.1-1058
    [2] 刘甲耀,严桂兰.Core Java应用程序设计教程[M].北京:电子工业出版社,2005.2.97-304
    [3] 孙卫琴.精通Struts:基于MVC的Java Web设计与开发[M].北京:电子工业出版社,2004.8.7-35
    [4] 菜剑,景楠. Java Web应用开发:J2EE和Tomcat第2版[M].北京:清华大学出版社,2005.1.35-250
    [5] 孙卫琴,李洪成.Tomcat与Java.Web开发技术详解[M].北京:电子工业出版社,2004.4.29-134
    [6] 殷兆麟,张永平,姜淑娟.Java网络高级编程[M].北京:清华大学出版社,北京交通大学出版社,2005.5.94-235
    [7] Marco Pistoia,Nataraj Nagaratnam等著.企业级Java安全性:构建安全的J2EE应用[M].尹亚,明喻卫,严进宝译.北京:清华大学出版社,2005.3,72-109
    [8] 《深入浅出Java语言程序设计》 李云山,吕杰武.中国青年出版社,2003.2
    [9] 《Java程序设计实践教程》 刘万军.清华大学出版社,2006.9
    [10]林邦杰.JAVA程序设计入门教程.中国青年出版社,2001,416-528
    1 评论 2 下载 2019-05-20 13:19:08 下载需要14点积分
  • 基于C语言实现的线性表综合题

    介绍
    按照输入的顺序建立顺序表
    对顺序表进行排序(直接插入、冒泡、选择、快速、合并)
    按照由大到小的顺序建立一个单链表
    链表逆置
    将顺序表和链表合并成一个有序表
    结果输出

    1 解题思路通过建立一个数组和一个结构体,数组用以保存顺序表,而在结构体内建立数据域和指针域用以保存链表。首先设定序表长度并要求输入数据,建立输出顺序表函数,在通过关于顺序表的五种排序的子函数选择其一进行排序,最后通过输出函数输出;再建立链表,使数据输入链表且由大到小输出,并设计链表逆置函数;最后再写出函数将已有的顺序表和链表合并为一张有序表并输出。而在主函数中通过switch函数来选择所需要的步骤。
    2 函数调用图
    3 各函数功能// 建立顺序表int createList (int arr[]); // 建立顺序表int createList (int arr[]); // 排序列表,流程控制,并且建立快速排序和归并排序所需数组int sort(int arr[]); // 直接插入排序int insertSort(int arr[]); // 冒泡排序int bubbleSort(int arr[]); // 直接选择排序int selectionSort(int arr[]); // 快速排序int quickSort(int arr[], int M, int N); // 归并排序递归int merge(int r[], int r2[], int S, int M, int N); // 归并排序int mergeSort(int r[], int r2[], int S, int N); // 建立链表int createNode(Node *L); // 对链表节点进行倒序int sortNode(Node *L); // 结合两张表int combine(int arr[], Node *L2); // 主函数,建立链表节点,流程控制int main();
    4 测试







    5 评论 36 下载 2018-11-07 15:27:31 下载需要3点积分
显示 15 到 30 ,共 15 条
eject