分类

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

资源列表

  • 基于Python实现的简单生命游戏

    一、引言1.1 开发背景康威生命游戏,又称康威生命棋,是英国数学家约翰•何顿•康威在1970年发明的细胞自动机。 它最初于1970年10月在《科学美国人》杂志上马丁•葛登能的“数学游戏”专栏出现。在游戏的进行中,杂乱无序的细胞会逐渐演化出各种精致、有形的结构;这些结构往往有很好的对称性,而且每一代都在变化形状。一些形状已经锁定,不会逐代变化。有时,一些已经成形的结构会因为一些无序细胞的“入侵”而被破坏。但是形状和秩序经常能从杂乱中产生出来。对于生成的形状和秩序我们称作 pattern。或者在这里,我们也把它称作 creature。“生命游戏”并不是通常意义上的游戏,它没有游戏玩家之间的竞争,也谈不上输赢,甚至可以说游戏的一开始就注定了结果。
    1.2 开发目的和意义本游戏是小组共同开发的课程设计项目,实现了基础的康威生命游戏规则,能够模拟生命繁殖演化的基本过程,实现了必要的图形界面。
    开发生命游戏,让“仿真生物”生存于计算机上,在计算机上生存、死亡,从而模拟生命的演化,通过计算机的模拟,了解生命在一定规则下,开始条件对最终结果的影响,突发事件对最终结果的影响。
    二、需求分析2.1 设计内容和要求制作用户图形界面,使得游戏在运行时,用户能在图形界面上进行操作和直观的看到演化过程与结果。
    按钮,开始、暂停、重置,用来控制繁衍进程。
    用户界面的要求:一个N*N的二维格子界面和对应开始、暂停、重置的按钮,每一个格子代表一个生命,亮为生、暗为死,每一次格子的生与死都显示在屏幕上。
    一个细胞在下一个时刻生死取决于相邻八个方格中活着的或死了的细胞的数量。用代码实现生命游戏中的规则,通过算法控制,计算格子在每一刻的生死状态。
    使用鼠标添加或删去细胞。
    添加游戏说明,方便用户使用。
    2.2 技术上的可行性分析2.2.1 游戏功能在一个二维矩形世界中,每个方格里居住着一个活着的或死了的细胞,每个细胞有两种状态-存活或死亡,每个细胞与以自身为中心的周围八格细胞产生互动。
    一个细胞在下一个时刻生死取决于相邻八个方格中活着的或死了的细胞的数量,模拟生命繁衍。
    可以通过按钮控制繁衍进程,使用鼠标添加或删去细胞。
    2.2.2 游戏规则
    人口过少:当周围低于2个(不包含2个)存活细胞时, 本单元活细胞死亡
    稳定:当周围有2个或3个存活细胞时, 本单元细胞保持原样
    人口过剩:当周围有3个以上的存活细胞时,本单元活细胞死亡
    繁殖:当周围有3个存活细胞时,本单元细胞存活/活化

    2.2.3 游戏界面
    背景世界地图为黑色,画有灰白的网格线,作为各细胞间的分界
    单个活细胞为矩形,红色,死亡细胞为黑色,构成背景
    地图右侧放置按钮,开始、暂停、重置,用来控制繁衍进程
    添加游戏说明,方便用户使用

    经查阅资料并进行分析,利用python及其标准化的库,可以实现我们的设计要求
    2.3 开发环境与工具使用
    操作系统:Windows
    开发工具:PyCharm Community Editon 2016.1.3、Java Pydev
    开发语言:Python
    编码方式:UTF-8
    团队管理工具:leangoo
    版本控制工具:Git
    自动单元测试框架:pyunit
    性能分析:profile
    代码检查:pylint

    三、总体设计3.1 总体结构
    3.2 各功能模块描述
    Button :定义按钮的图像以及具体的位置
    Cell:定义细胞类,包括细胞的大小和颜色,获取细胞位置在画布上绘制细胞
    Data:画布,以及程序相关的具体的数据
    Draw:将画布擦除后,画上按钮,格子以及具体的网格线,然后遍历网格数组中的细胞状态
    next_generation:定义细胞更新的规则:当一个细胞周围有两个或三个细胞时细胞状态为存活,当周围细胞过多或者过少时定义为细胞死亡
    States:将整个游戏世界设定为二维数组,每个网格的状态值分为0,1两种,定义按钮功能,含开始运行、暂停、重置三个方法

    开始运行:获取当前鼠标的状态和位置随时更新画布,并且根据细胞规则随时更新细胞暂停:根据鼠标状态随时更新画布重置:初始化整个画布,数组用0填充
    main:程序的开始入口,设置界面的大小,定义状态机的三种状态:运行状态,暂停状态,以及重置,然后进入游戏的主循环

    3.3 主要模块设计状态机三种状态的设置:开始,暂停,以及重置,主要在States模块中实现:

    States:将整个游戏世界设定为二维数组,每个网格的状态值分为0,1两种,定义按钮功能,含开始运行、暂停、重置三个方法

    开始运行:获取当前鼠标的状态和位置随时更新画布,并且根据细胞规则随时更新细胞
    暂停:根据鼠标状态随时更新画布
    重置:初始化整个画布,数组用0填充


    3.4 核心代码设计next_generation:细胞规则的制定是核心代码的一部分,具体设计。遍历二维数组,更新接下来各个细胞的状态:
    def next_generation(): nbrs_count = sum(np.roll(np.roll(pygame.world, i, 0), j, 1) for i in (-1, 0, 1) for j in (-1, 0, 1) if (i != 0 or j != 0)) pygame.world = (nbrs_count == 3) | ((pygame.world == 1) & (nbrs_count == 2)).astype('int')
    四、测试分析4.1 游戏开始测试测试点击开始按钮游戏界面立即作出响应,并且可以按照细胞规则进行正确的更新。
    4.2 游戏重置测试点击重置按钮,程序立即作出响应,并且画布被擦除。
    4.3 使用工具进行分析测试
    自动单元测试框架:pyunit
    性能分析:profile
    代码检查:pylint

    分析测试细节详情请见对应的工具使用文档。
    五、具体的使用说明
    打开程序,出现游戏界面
    在界面上选择点击相应格子,左键添加细胞,右键擦除细胞
    点击开始,程序自动运行,最终在界面上显示结果,或为一有各个格子组成的特殊图形,或一直杂乱的进行演化
    也可在任意时刻点击暂停按钮,查看到这一时刻生命游戏在一定规则下生成的结果
    玩家可以随时在画布上添加或者擦除细胞
    点击重置按钮可以清空画布,重新来过

    运行截图演示:




    2 评论 91 下载 2018-11-06 09:56:14 下载需要9点积分
  • 基于QT与mplayer的视频播放器

    一、课题的介绍和课题的任务1.1 课题的介绍本次课程设计我选的题目是视频播放器。目前市场上各种应用商店上有各种播放器,而且功能都很强大。一直对里面的具体实现有兴趣,所以这次就尝试着写了个视频播放器。并且加进去了一些很实用的功能,比如截屏和录屏。
    1.2 课题的任务包括视频的播放暂停、音量的加减、播放速度的设置、以及视频文件的添加删除、屏幕的截屏以及录屏。画面不卡顿。播放时进度条能刷新。
    二、设计的要求
    能进行视频的播放
    能暂停正在播放的视频
    能播放正在暂停的视频
    能调节视频播放的视频
    能进行视频播放进度的调节
    能停止正在播放的视频
    能添加新的视频文件到播放列表
    能删除播放列表中选中的视频
    能改变视频播放的速度
    能对正在播放的视频进行截屏
    能录制正在播放的视频

    三、系统的分析和系统中类的设计
    窗口类QMainWidndow
    按钮类QPushButton
    标签类QLabel
    列表类QList
    滑动条类QSilider
    显示类QWidge

    四、系统的实现及调试系统模块框架图

    程序具体实现
    4.1 添加文件进视频播放列表
    代码实现:
    void mplayer_video::on_open_clicked(){ QStringList filenames =QFileDialog::getOpenFileNames(this,tr("选择文件"),"/",tr("视频文件(*mp3 *mp4 *wma *3gp *wav *avi *flv *rmvb *mkv *ts *wmv)")); // *号和前面的要隔开至少一个空格,不能连起来。 if(filenames.count()!=0) ui->list->addItems(filenames);}
    4.2 双击列表选项进行播放
    代码实现:
    void mplayer_video::on_list_itemDoubleClicked(QListWidgetItem *item){ speed=1; ui->lupin_lable->setVisible(false); play(item->text());}void mplayer_video::play(QString fileName){ QStringList arg1; process->kill(); process=new QProcess(this); arg1 << fileName; arg1 << "-slave";//默认情况下,mplayer接受键盘的命令,而"-slave"使其不再接受键盘事件,而是作为后台程序运行, //接受以“\n”结束的命令控制,这样我们可以在进程中给他发送命令,而不需要操作键盘了. arg1 << "-quiet"; //尽可能的不打印播放信息 arg1 << "-zoom"; //视频居中,四周黑条,全屏播放 arg1 << "-wid" << QString::number((unsigned int)(ui->widget->winId())); // "-wid <窗口标识>" 是指让MPlayer依附于那个窗口, //ui->widget->winId() 这个指令就是用来获取widget的标识码 , //这样视频播放的时候,就在这个部件里播放,相当于给他固定起来。 connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(dataRecieve())); process->start(arg,arg1); //开始播放进程 ui->zanting->setText("暂停");}void mplayer_video::dataRecieve(){ process->write("get_time_length\n"); process->write("get_time_pos\n"); process->write("get_percent_pos\n"); while(process->canReadLine()) { QByteArray b=process->readLine(); if(b.startsWith("ANS_TIME_POSITION")) { b.replace(QByteArray("\n"),QByteArray("")); QString s(b); currentStr=s.mid(18); ui->horizontalSlider->setValue(s.mid(18).toFloat()); //更新进度条 } else if((b.startsWith("ANS_LENGTH"))) { b.replace(QByteArray("\n"),QByteArray("")); QString s(b); totalTime=s.mid(11); ui->label_time->setText(currentStr+"秒/"+totalTime+"秒 "); //显示时间进度 ui->horizontalSlider->setRange(0,s.mid(11).toFloat()); } else if((b.startsWith("ANS_PERCENT_POSITION"))) { b.replace(QByteArray("\n"),QByteArray("")); QString s(b); currentPercent=s.mid(21); ui->percentLabel->setText(currentPercent+"%"); } }}
    4.3 播放与暂停的实现
    代码实现:
    void mplayer_video::on_zanting_clicked(){ ui->lupin_lable->setVisible(false); process->write("pause\n"); //ui->list->currentRow()!=-1 判断是否有选中某条数据 //play(ui->list->item(ui->list->currentRow())->text()); 播放选中的某条数据 if(ui->zanting->text()=="播放") { if(ui->list->count()==0) QMessageBox::warning(this,"提示","播放列表为空",QMessageBox::Yes); else { connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(dataRecieve())); process->write("get_time_length\n"); process->write("get_time_pos\n"); process->write("get_percent_pos\n"); ui->zanting->setText("暂停"); } } else { disconnect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(dataRecieve())); ui->zanting->setText("播放"); }}
    4.4 快进与回退代码实现:
    void mplayer_video::on_back_clicked(){ process->write("seek -10\n");}void mplayer_video::on_quick_clicked(){ process->write("seek +10\n");}
    4.5 加速与减速代码实现:
    void mplayer_video::on_back_clicked(){ process->write("seek -10\n");}void mplayer_video::on_quick_clicked(){ process->write("seek +10\n");}
    4.6 停止播放代码实现:
    void mplayer_video::on_stop_clicked(){ process->write("quit\n"); ui->horizontalSlider->setSliderPosition(0); ui->label_time->clear(); ui->percentLabel->clear(); ui->zanting->setText("播放");}
    4.7 从播放列表中删除中选中的视频
    代码实现:
    void mplayer_video::on_del_clicked(){ if(ui->list->currentRow()==-1) QMessageBox::warning(this,"提示","未选中项目或列表为空",QMessageBox::Yes); else { ui->list->takeItem(ui->list->currentRow()); process->close(); ui->horizontalSlider->setSliderPosition(0); //更新进度条 ui->label_time->clear(); ui->percentLabel->clear(); }}
    4.8 加速播放与减速播放
    代码实现:
    定义一个全局静态浮点型变量 speed并初始化为1,每次点击加速,speed的值乘以二,每次点击减速,speed的值除以2
    void mplayer_video::on_jiansu_clicked(){ speed=speed/2; process->write(QString("speed_set "+QString::number(speed)+" 2\n").toUtf8());}void mplayer_video::on_jiasu_clicked(){ speed=speed*2; process->write(QString("speed_set "+QString::number(speed)+" 2\n").toUtf8());}
    4.9 视频播放进度条的刷新这是本程序里最复杂的部分之一。
    主要实现是用connect函数链接进程与DataRecieve函数
    代码实现:
    void mplayer_video::dataRecieve(){ process->write("get_time_length\n"); process->write("get_time_pos\n"); process->write("get_percent_pos\n"); while(process->canReadLine()) { QByteArray b=process->readLine(); if(b.startsWith("ANS_TIME_POSITION")) { b.replace(QByteArray("\n"),QByteArray("")); QString s(b); currentStr=s.mid(18); ui->horizontalSlider->setValue(s.mid(18).toFloat()); //更新进度条 } else if((b.startsWith("ANS_LENGTH"))) { b.replace(QByteArray("\n"),QByteArray("")); QString s(b); totalTime=s.mid(11); ui->label_time->setText(currentStr+"秒/"+totalTime+"秒 "); //显示时间进度 ui->horizontalSlider->setRange(0,s.mid(11).toFloat()); } else if((b.startsWith("ANS_PERCENT_POSITION"))) { b.replace(QByteArray("\n"),QByteArray("")); QString s(b); currentPercent=s.mid(21); ui->percentLabel->setText(currentPercent+"%"); } }}
    4.10 声音滑动条对声音的调节
    代码实现:
    void mplayer_video::on_voice_slider_sliderMoved(int v){ if(ui->zanting->text()=="播放") { process->write(QString("volume "+QString::number(v)+" 2\n").toUtf8()); process->write("pause\n"); } else{ process->write(QString("volume "+QString::number(v)+" 2\n").toUtf8()); }}
    4.11 设置图片按钮
    代码实现:
    QPixmap pixmap; pixmap.load("G:/mplayer_video/voice.jpg"); ui->voice->setFixedSize(pixmap.width(),pixmap.height()); ui->voice->setIcon(pixmap); ui->voice->setIconSize(QSize(pixmap.width(),pixmap.height())); ui->voice->setToolTip("音量"); ui->voice->show();
    4.12 屏幕截图
    代码实现:
    void mplayer_video::on_jietu_clicked(){ cout<<"ok"<<endl; process->write("pause\n"); if(ui->zanting->text()=="播放") { cout<<"1"<<endl; QPixmap snapImage = QPixmap::grabWindow(QApplication::desktop()->winId()); QString filename; QString slcStr; filename = QFileDialog::getSaveFileName(this,tr("保存图片"),"./未命名",tr("PNG(*.png);;JPG(*.jpg);;BMP(*.bmp)"),&slcStr);//弹出保存图片的文件窗口 if(slcStr.left(3)=="JPG") { if(filename.right(3)!="jpg") { filename+=".jpg"; } } if(slcStr.left(3)=="PNG") { if(filename.right(3)!="png") { filename+=".png"; } } if(slcStr.left(3)=="BMP") { if(filename.right(3)!="bmp") { filename+=".bmp"; } } if(filename!=NULL) { snapImage.save(filename); } } else { cout<<"2"<<endl; disconnect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(dataRecieve())); ui->zanting->setText("播放"); QPixmap snapImage = QPixmap::grabWindow(QApplication::desktop()->winId()); QString filename; QString slcStr; filename = QFileDialog::getSaveFileName(this,tr("保存图片"),"./未命名",tr("PNG(*.png);;JPG(*.jpg);;BMP(*.bmp)"),&slcStr);//弹出保存图片的文件窗口 if(slcStr.left(3)=="JPG") { if(filename.right(3)!="jpg") { filename+=".jpg"; } } if(slcStr.left(3)=="PNG") { if(filename.right(3)!="png") { filename+=".png"; } } if(slcStr.left(3)=="BMP") { if(filename.right(3)!="bmp") { filename+=".bmp"; } } if(filename!=NULL) { snapImage.save(filename); } connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(dataRecieve())); process->write("get_time_length\n"); process->write("get_time_pos\n"); process->write("get_percent_pos\n"); ui->zanting->setText("暂停"); }}
    4.13 屏幕录制代码实现:
    void mplayer_video::on_lupin_clicked(){ if(ui->lupin->text()=="录屏") { photoStart(); timer->start(50); ui->lupin->setText("停止"); } else { timer->stop(); ui->lupin->setText("录屏"); }}void mplayer_video::photoStart(){ QDir *d = new QDir(); QString dirName("D:\\video"); if(!d->exists(dirName)) { d->mkdir(dirName); }}void mplayer_video::timerUpdate(){ QPixmap p; QString dirNamee("D:\\video\\"); dirNamee=dirNamee+QString::number(number)+".jpg"; p = QPixmap::grabWindow(QApplication::desktop()->winId()); p.save(dirNamee); number+=1;}
    4.14 屏幕录屏播放代码实现:
    void mplayer_video::on_lupinstart_clicked(){ process->write("quit\n"); QString dirName("D:\\video"); qdir = new QDir(dirName); qdir->setSorting(QDir::Reversed|QDir::Time); list = qdir->entryInfoList(); number2=0; timer2->start(100);}void mplayer_video::on_stop_bofang_clicked(){ timer2->stop(); ui->lupin_lable->setVisible(false);}
    五、系统的使用说明打开程序,点击添加文件进行视频播放列表视频的添加。双击列表中某条记录进行视频的播放,播放按钮自动转换成暂停按钮。点击播放将会播放视频,点击暂停视频会暂停。除了一些视频播放器的基本功能外,本程序还加入了屏幕截图与屏幕录制的功能。具体操作用按钮可以实现。
    11 评论 271 下载 2018-11-15 11:09:18 下载需要10点积分
  • 基于Java实现的飞机大战小游戏

    1.实作项目简介本项目是一款简单的飞机大战小游戏,程序使用Eclipse开发。
    2.项目设计2.1 总体架构设计
    2.2 类设计com.controller包

    com.element包

    com.manager包

    com.show包

    2.3 基本功能
    玩家飞机有四种不同外型的飞机可选择
    通过键盘上下左右键控制飞机的移动
    游戏中敌机在界面上方随机出现,自动发射子弹,并且从上到下垂直方向移动,到达边界自动消失
    Boss飞机在界面上方水平方向随机移动,并且发射子弹的速度大于普通敌机发射子弹的速度
    爆炸效果,敌机与Boss机被玩家击中,玩家被敌机子弹击中,玩家与敌机碰撞均有爆炸效果
    游戏中的道具有血包和护盾两类,血包可为玩家提供一滴血,护盾可为玩家抵挡3颗子弹,并且只持续5秒钟
    玩家的血量上限是10

    3.系统实现3.1 界面GameHomePanel类
    public class GameHomePanel extends JPanel{ private JButton startGameButton = null; private JButton setPalyerButton = null; private ImageIcon backImg = null; public GameHomePanel() { init(); } public void init() { GameLoad.loadImg(); this.startGameButton = new JButton(); this.backImg = GameLoad.imgMap.get("homeimg"); Image img = this.backImg.getImage().getScaledInstance(GameJFrame.GameX, GameJFrame.GameY, Image.SCALE_SMOOTH); this.backImg = new ImageIcon(img); this.startGameButton.setIcon(new ImageIcon("image/startgame.png")); this.startGameButton.setBounds(GameJFrame.GameX / 10 * 3, GameJFrame.GameY / 7 * 5, GameJFrame.GameX / 10 * 4, 80); this.startGameButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // TODO 自动生成的方法存根 GameStart.changePage("game"); } }); this.startGameButton.setBorderPainted(false); this.startGameButton.setBackground(new Color(92, 152, 183)); this.startGameButton.setFocusPainted(false);// this.startGameButton.setContentAreaFilled(false); this.add(this.startGameButton); this.setPalyerButton = new JButton("设置"); this.setPalyerButton.setFont(new Font("Courier", Font.BOLD, 26)); this.setPalyerButton.setForeground(new Color(253, 255, 205)); this.setPalyerButton.setBounds(GameJFrame.GameX / 10 * 3 + 50, GameJFrame.GameY / 7 * 5 + 100, GameJFrame.GameX / 10 * 2, 50); this.setPalyerButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // TODO 自动生成的方法存根 new GameDialog(GameStart.gj, "Set"); } }); this.setPalyerButton.setBorderPainted(false); this.setPalyerButton.setBackground(new Color(92, 152, 183)); this.setPalyerButton.setFocusPainted(false); this.add(this.setPalyerButton); this.setLayout(null); this.setVisible(true);// System.out.println("home"); } @Override public void paint(Graphics g) { // TODO 自动生成的方法存根 super.paint(g); g.drawImage(this.backImg.getImage(), 0, 0, null); g.drawImage(new ImageIcon("image/planemenu.png").getImage(), 90, 0, null); }}
    GameJFrame类
    public class GameJFrame extends JFrame{ public final static int GameX = 600; public final static int GameY = 900; private JPanel jPanel = null; //正在显示的面板 private KeyListener keyListener = null; //键盘监听 private Thread thead = null; //游戏主线程 private JMenuBar menuBar = null; //菜单栏 public GameJFrame() { init(); } public void init() { this.setSize(GameX, GameY); //设置窗体大小 this.setTitle("飞机大战"); this.initJMenuBar(); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLocationRelativeTo(null); //屏幕居中显示 } protected void initJMenuBar() { this.menuBar = new JMenuBar(); this.setJMenuBar(this.menuBar); JMenu menu1 = new JMenu("菜单"); this.menuBar.add(menu1); JMenuItem item1 = new JMenuItem("开始游戏"); menu1.add(item1); menu1.addSeparator(); JMenuItem item2 = new JMenuItem("重新开始"); menu1.add(item2); menu1.addSeparator(); JMenuItem item3 = new JMenuItem("游戏玩法"); menu1.add(item3); item2.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if(GameJFrame.this.jPanel instanceof GameMainJPanel) reStartGame(); } }); item3.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // TODO 自动生成的方法存根 new GameDialog(GameJFrame.this, "HowToPlay"); } }); } public void changePanel(JPanel jpt) { if(this.jPanel != null) this.remove(this.jPanel); this.jPanel = jpt; } /** * @显示启动界面 */ public void showHomePage() { if(this.jPanel != null) this.add(this.jPanel); if(this.jPanel instanceof Runnable) { new Thread((Runnable) this.jPanel).start(); } this.setVisible(true); } /** * 启动方法 */ public void startGame() { GameThread.reSetAllTime(); if(this.jPanel != null) this.add(this.jPanel); if(this.thead == null) this.thead = new GameThread(); this.thead.start(); //启动游戏主线程 if(this.keyListener == null) this.keyListener = new GameListener(); this.addKeyListener(this.keyListener);// this.setVisible(true); if(this.jPanel instanceof Runnable) { new Thread((Runnable)this.jPanel).start(); } System.out.println("startGame: " + Thread.activeCount()); } public void reStartGame() { System.out.println("reStartGame: " + Thread.activeCount()); this.EndGame(); this.jPanel = new GameMainJPanel();// System.out.println("reStart");// System.out.println(((GameThread)this.thead).isInterrupted()); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } this.startGame(); this.reFalsh(); } public void EndGame() { //结束run方法,停止相关线程 ((GameMainJPanel)this.jPanel).panelIsRunning = false; ((GameThread)this.thead).stopGameThread = true; ((GameThread)this.thead).isRunning = false; this.remove(this.jPanel); this.removeKeyListener(this.keyListener); this.jPanel = null; this.keyListener = null; this.thead = null; } public void reFalsh() { this.setVisible(false); this.setVisible(true); } public void addListener() { if(this.keyListener != null) this.addKeyListener(this.keyListener); } public void removeListener() { this.removeKeyListener(this.keyListener); } public void setjPanel(JPanel jPanel) { this.jPanel = jPanel; } public void setKeyListener(KeyListener keyListener) { this.keyListener = keyListener; } public void setThead(Thread thead) { this.thead = thead; }}
    GameMainJPanel类
    /** * @说明 游戏的主要面板 * @功能说明 主要进行元素的显示,同时进行界面的刷新(多线程) * * @多线程刷新 1.本类实现线程接口 */public class GameMainJPanel extends JPanel implements Runnable{// 联动管理器 private ElementManager em; public boolean panelIsRunning = true; public GameMainJPanel() { init(); } public void init() { em = ElementManager.getManager();//得到元素管理器对象 } @Override public void paint(Graphics g) { super.paint(g); Map<GameElement, List<ElementObj>> all = em.getGameElements(); for(GameElement ge : GameElement.values()) { List<ElementObj> list = all.get(ge); for(int i=0; i<list.size(); i++) { ElementObj obj = list.get(i); obj.showElement(g); } } g.setFont(new Font("Times New Roman", Font.BOLD, 24)); int allTime = GameThread.getAllTime()/1000; int munite = allTime / 60; int second = allTime % 60; String m; String s; if(munite < 10) m = "0" + Integer.toString(munite); else m = Integer.toString(munite); if(second<10) s = "0" + Integer.toString(second); else s = Integer.toString(second); g.drawString("Time: "+ m + ":" + s, 0, 50); } @Override public void run() { while(this.panelIsRunning) {// System.out.println("多线程运动"); this.repaint(); try { Thread.sleep(10); //休眠10毫秒 1秒刷新20次 } catch (InterruptedException e) { e.printStackTrace(); } } } }
    3.2 控制GameListener类
    /** * @说明 监听类,用于监听用户的操作 KeyListener */public class GameListener implements KeyListener{ private ElementManager em = ElementManager.getManager(); private Set<Integer> set = new HashSet<Integer>(); @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); List<ElementObj> play = em.getElementsByKey(GameElement.PLAY); for(ElementObj obj : play) { obj.keyClick(true, e.getKeyCode()); } } @Override public void keyReleased(KeyEvent e) { List<ElementObj> play = em.getElementsByKey(GameElement.PLAY); for(ElementObj obj : play) { obj.keyClick(false, e.getKeyCode()); } }}
    GameThread类
    /** * @说明 游戏的主线程,用于控制游戏加载,游戏关卡,游戏运行时自动化 * 游戏判定;游戏地图切换 资源释放和重新读取。 */public class GameThread extends Thread{ private ElementManager em; public boolean stopGameThread = false; public boolean isRunning = true; private static int allTime = 2* 60 * 1000; //2分钟 private static int sleepTime = 10; private int winNumbers = 70; //赢得游戏需击杀的敌人数 public GameThread() { em = ElementManager.getManager(); } @Override public void run() {//游戏的run方法 ,主线程 while(!this.stopGameThread) {// 加载游戏资源(场景资源) gameLoad();// 游戏进行时游戏过程中 gameRun();// 游戏场景结束游戏资源回收(场景资源) gameOver(); try { sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } }// System.out.println("游戏主线程中断"); } /** * 游戏的加载 */ private void gameLoad() { System.out.println("加载中。。。。。");// GameLoad.loadImg(); //加载图片 GameLoad.loadMap(1); //可以变为变量,每一关重新加载 加载地图// 加载主角 GameLoad.loadPlay(GameDialog.getPlayN());//也可以带参数,单机还是2人// 加载敌人NPC等 GameLoad.loadEnemy(3);// 全部加载完成,游戏启动 } /** * @说明 游戏进行时 * @任务说明 游戏过程中需要做的事情:1.自动化玩家的移动,碰撞,死亡 * 2.新元素的增加(NPC死亡后出现道具)等 * */ private void gameRun() { long gameTime = 0L; // System.out.println(this.getName()); System.out.println("加载成功,进入游戏"); while(this.isRunning) { Map<GameElement, List<ElementObj>> all = em.getGameElements(); List<ElementObj> enemys = em.getElementsByKey(GameElement.ENEMY); List<ElementObj> files = em.getElementsByKey(GameElement.PLAYFILE); List<ElementObj> maps = em.getElementsByKey(GameElement.MAPS); List<ElementObj> props = em.getElementsByKey(GameElement.PROP); List<ElementObj> player = em.getElementsByKey(GameElement.PLAY); List<ElementObj> enemyFiles = em.getElementsByKey(GameElement.ENEMYFILE); List<ElementObj> boss = em.getElementsByKey(GameElement.BOSS); List<ElementObj> shield = em.getElementsByKey(GameElement.SHIELD); moveAndUpdate(all,gameTime); //游戏元素自动化方法 ElementPK(files, enemys, 0); ElementPK(player, props, 1); ElementPK(player, enemys, 0); ElementPK(files, boss, 0); ElementPK(player, enemyFiles, 0); ElementPK(files, enemyFiles, 0); ElementPK(shield, enemyFiles, 0); ElementPK(enemyFiles, shield, 0); gameTime++; //唯一的时间控制 if(gameTime % 300 == 0) GameLoad.loadEnemy(3); //设置敌人数量 if(gameTime % 2000 == 0) { //间隔20秒出现boss GameLoad.loadBoss(new Random().nextInt(2) + 1, gameTime); //设置boss数量 }// System.out.println("isRunning"); this.MedJudge(); allTime -= sleepTime; try { sleep(10);//默认理解为 1秒刷新100次 } catch (InterruptedException e) { e.printStackTrace(); } } } private void MedJudge() { if(em.getElementsByKey(GameElement.PLAY).size() <= 0) { GameStart.gj.EndGame(); new GameDialog(GameStart.gj, "LoseGame"); return; } if(allTime <= 0) { int n = ((PaoPao)em.getElementsByKey(GameElement.PLAY).get(0)).getKillEnemy(); if(n < winNumbers) {// System.out.println("失败"); GameStart.gj.EndGame(); new GameDialog(GameStart.gj, "LoseGame"); }else { GameStart.gj.EndGame(); new GameDialog(GameStart.gj, "WinGame"); } } } /** * @说明 碰撞处理 * @param listA 如果是单方面损失碰撞,则这个变量不受损失 * @param listB * @param type 碰撞类型,0表示互损碰撞,1表示单方面损失碰撞 */ public void ElementPK(List<ElementObj> listA, List<ElementObj>listB, int type) { for(int i=0; i<listA.size(); i++) { ElementObj lista = listA.get(i); for(int j=0; j<listB.size(); j++) { ElementObj listb = listB.get(j); if(lista.pk(listb)) { if(type == 0) { lista.setLive(false); listb.setLive(false); if(lista instanceof Enemy || lista instanceof Boss) { if(!lista.isLive() && em.getElementsByKey(GameElement.PLAY).size() > 0) //如果想做双玩家模式,要区别是哪个击杀的 ((PaoPao)em.getElementsByKey(GameElement.PLAY).get(0)).addKillEnemy(1); } if(listb instanceof Enemy || listb instanceof Boss) { if(!listb.isLive() && em.getElementsByKey(GameElement.PLAY).size() > 0) ((PaoPao)em.getElementsByKey(GameElement.PLAY).get(0)).addKillEnemy(1); } } else if(type == 1) { lista.setLive(true); listb.setLive(false); } break; } } } }// 游戏元素自动化方法 public void moveAndUpdate(Map<GameElement, List<ElementObj>> all,long gameTime) { for(GameElement ge:GameElement.values()) { List<ElementObj> list = all.get(ge); for(int i=list.size()-1; i>=0 ;i--){ ElementObj obj=list.get(i); if(!obj.isLive()) { //如果死亡 obj.die(); list.remove(i); continue; } obj.model(gameTime); } } } /**游戏结束*/ private void gameOver() { for(GameElement ge : GameElement.values()) { if(this.em.getElementsByKey(ge).size() > 0) this.em.getElementsByKey(ge).clear(); } System.out.println("gameOver"); } public static void reSetAllTime() { allTime = 2 * 60 * 1000; } public static int getAllTime() { return allTime; }}
    3.3 资源管理ElementManager类
    /** * @说明 本类是元素管理器,专门存储所有的元素,同时,提供方法 * 给予视图和控制获取数据 */public class ElementManager { private Map<GameElement,List<ElementObj>> gameElements; public Map<GameElement, List<ElementObj>> getGameElements() { return gameElements; }// 添加元素(多半由加载器调用) public void addElement(ElementObj obj,GameElement ge) { gameElements.get(ge).add(obj); //添加对象到集合中,按key值就行存储 } public List<ElementObj> getElementsByKey(GameElement ge){ return gameElements.get(ge); } private static ElementManager EM = null; //引用// synchronized线程锁->保证本方法执行中只有一个线程 public static synchronized ElementManager getManager() { if(EM == null) { //控制判定 EM = new ElementManager(); } return EM; } private ElementManager() { //私有化构造方法 init(); //实例化方法 } /** * 本方法是为 将来可能出现的功能扩展,重写init方法准备的。 */ public void init() { //实例化在这里完成 gameElements = new HashMap<GameElement,List<ElementObj>>();// 将每种元素集合都放入到 map中 for(GameElement ge : GameElement.values()) { //通过循环读取枚举类型的方式添加集合 gameElements.put(ge, new ArrayList<ElementObj>()); } }}
    GameLoad类
    /** * 说明 加载器(工具:用户读取配置文件的工具)工具类,大多提供的是 static方法 * @author * */public class GameLoad { private static ElementManager em = ElementManager.getManager(); public static Map<String,ImageIcon> imgMap = new HashMap<>();// 用户读取文件的类 private static Properties pro =new Properties(); /** * @说明 传入地图id有加载方法依据文件规则自动产生地图文件名称,加载文件 * ,如果有地图可调用这个方法 * @param mapId 文件编号,文件id */ public static void MapLoad(int mapId) { String mapName = "com/text/" + mapId + ".map"; ClassLoader classLoader = GameLoad.class.getClassLoader(); InputStream maps = classLoader.getResourceAsStream(mapName); if(maps == null) { System.out.println("配置文件读取异常,请重新安装"); return; } try { pro.clear(); pro.load(maps); Enumeration<?> names = pro.propertyNames(); while(names.hasMoreElements()) { //获取是无序的 String key = names.nextElement().toString(); System.out.println(pro.getProperty(key)); String [] arrs = pro.getProperty(key).split(";"); for(int i=0; i<arrs.length; i++) { ElementObj obj = getObj("map"); ElementObj element = obj.createElement(key+","+arrs[i]); System.out.println(element); em.addElement(element, GameElement.MAPS); } } } catch (IOException e) { e.printStackTrace(); } } /** *@说明 加载图片代码 * */ public static void loadImg() { //可以带参数,因为不同的关也可能需要不一样的图片资源 String texturl = "com/text/GameData.pro"; //文件的命名可以更加有规律 ClassLoader classLoader = GameLoad.class.getClassLoader(); InputStream texts = classLoader.getResourceAsStream(texturl); pro.clear(); try {// System.out.println(texts); pro.load(texts); Set<Object> set = pro.keySet(); for(Object o:set) { String url=pro.getProperty(o.toString());// System.out.println(o.toString() + url); imgMap.put(o.toString(), new ImageIcon(url)); } } catch (IOException e) { e.printStackTrace(); } } /** * 加载玩家 */ public static void loadPlay(int playN) { loadObj(); String playStr = "250,800,player" + String.valueOf(playN); ElementObj obj = getObj("paopao"); ElementObj play = obj.createElement(playStr); em.addElement(play, GameElement.PLAY); } public static void loadEnemy(int enemyNumber) { loadObj();// ElementObj obj = getObj("enemy"); for(int i=0; i<enemyNumber; i++) { ElementObj obj = getObj("enemy"); ElementObj enemy = obj.createElement(null); em.addElement(enemy, GameElement.ENEMY); } } public static void loadBoss(int bossNumber, long gameTime) { loadObj(); for(int i=0; i<bossNumber; i++) { ElementObj obj = getObj("boss"); ElementObj boss = obj.createElement(null); em.addElement(boss, GameElement.BOSS); } } public static void loadMap(int mapsNumber) { loadObj(); for(int i=0; i<mapsNumber; i++) { ElementObj obj = getObj("maps"); ElementObj maps = obj.createElement(null); em.addElement(maps, GameElement.MAPS); } } public static ElementObj getObj(String str) { try { Class<?> class1 = objMap.get(str); Object newInstance = class1.newInstance(); if(newInstance instanceof ElementObj) { return (ElementObj)newInstance; //这个对象就和new Play()等价 } } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } /** * 扩展: 使用配置文件,来实例化对象 通过固定的key(字符串来实例化) * @param args */ private static Map<String,Class<?>> objMap=new HashMap<>(); public static void loadObj() { String texturl = "com/text/obj.pro"; //文件的命名可以更加有规律 ClassLoader classLoader = GameLoad.class.getClassLoader(); InputStream texts = classLoader.getResourceAsStream(texturl); pro.clear(); try { pro.load(texts); Set<Object> set = pro.keySet(); for(Object o:set) { String classUrl=pro.getProperty(o.toString());// 使用反射的方式直接将类进行获取 Class<?> forName = Class.forName(classUrl); objMap.put(o.toString(), forName); } } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }// 用于测试// public static void main(String[] args) {// MapLoad(5);// // }}
    4.游戏界面展示游戏界面1

    游戏界面2

    游戏界面3

    5.不足
    只有一个游戏关卡
    游戏平衡欠缺
    无背景音乐
    0 评论 1 下载 2021-07-29 10:54:32 下载需要11点积分
  • 基于Jsp和MySQL实现的教务信息管理系统

    基于Jsp和MySQL实现的教务信息管理系统# 一、引言
    随着信息技术的革命与发展,计算机已经成为我们学习和工作的得力助手,逐渐改变着信息的管理方式提高了信息管理的安全性和效率,节省了大量的人力和财力。同时 Internet 的普及也促进各个行业的发展,从邮寄信件到 E-mail,从电话会议到网络会议,从传统物流到电子商务,从面对面授课到运程教学等等一系列的变化,人们无不感到 Internet 的强大。信息管理技术的迅速发展正得力于 Internet 的普及和发展。
    目前社会上信息管理系统发展飞快,各个企事业单位都引入了信息管理软件 来管理自己日益增长的各种信息。鉴于目前学校教学规模的日益扩大,教务信息 呈爆炸性增长的前提下,教务信息管理的自动化与准确化的要求日益强烈的背景 下构思出来的,该项目开发的软件就是为学校教务信息管理系统软件,系统完全 独立开发,力求使系统功能简洁明了,但功能齐全且易于操作。该项目设计完成 后可用于一些教育单位(包括学校,学院等等)的教务信息的管理
    二、目的《Asp.Net 应用开发项目设计》课程是软件工程专业学生的一项必修实践性教学环节。通过课程设计,使学生提高理论联系实际解决实际问题的能力;也使学生对基于面向对象的理论进行系统设计过程中的诸多具体问题有感性的认识和深入的理解;进而提高学生的学习兴趣为其将来顺利进入毕业环节作必要的准备。
    三、概述与需求分析学生教务管理系统针对的学校学生情况对学生各科课程有效的管理。能够快 速的查询出学生的各科课程情况,以及所在班级等各种用途。相应的需求如下:

    能够存储一定数量的学生信息,并方便有效地进行相应的数据操作和管理,这主要包括学生信息的录人、删除及修改
    能够对一定数量的读者进行相应的信息存储与管理,这其中包括查询学生信息的登记、删除及修改,学生资料的统计与查询
    能够提供一定的安全机制,提供数据信息授权访问,防止随意删改,同时提供信息备份服务
    使网站更加容易管理和维护,不需对过多人员培训,提高工作效率

    四、系统分析4.1 可行性分析4.1.1 管理可行性信息化的教师教务管理在如今的信息时代是大势所趋,而且随着现代管理理念、方法和途径的提高。教务信息化管理手段日趋成熟,所以从长远利益出发,主管领导对该项目的开发与实施会大力支持。
    4.1.2 技术可行性本系统采用 Windows 作为操作平台。数据库选用 MYSQL,该数据库管理系统在 Windows 环境下可以连接 Java 运行,其体积小、速度快、总体拥有成本低,提高数据的可用性。本系统的应用软件开发平台选用 My Eclipse,java 版本为 JDK1.8,服务器为 tomcat8.5.
    4.1.3 经济可行性采用教师教务管理系统可取代原系统的单据手工传递工作,减少人工开支,节省资金、并且可大大提高信息量的获取,缩短信息处理周期,改进教学质量,能及时反馈学生的平时表现和成绩,反馈教学信息的利用率,使教学质量更上一个台阶。
    4.1.4 社会可行性本系统操作简单,易于理解,只需通过简单熟悉,上手较快,教师学生都可以进行操作,营运环境要求低。
    4.2 业务功能分析教务信息管理系统主要面对 3 个对象(管理员、教师、学生)。下面将详细介绍每个模块的业务功能以及流程图。

    学生模块:根据学生信息,获取其学生基本信息和已经选择的课程

    学生列表显示个人的基本信息选课列表显示所有已经选好的课程,包括上课时间和上课地点,授课老师学生可以在自己的选课管理中精确查询自己所选课程修改个人基本信息级密码
    教师模块:教师登录后,可以获取自己的课程列表,并可以对自己所教课程进行管理,设置上课时间及地点的安排

    学生列表显示所有选择自己课程的学生姓名、班级等基本信息班级列表显示班级的名称及班级的介绍教师列表显示教师本人的基本信息,并且可以进行修改课程列表显示课程安排,各科所选人数和设置上限人数修改密码可以进行修改个人密码
    管理员模块:可对教师信息、学生信息、课程信息进行各种操作。主要功能有

    学生列表显示所有学生姓名、班级等基本信息班级列表显示班级的名称及班级的介绍教师列表显示所有教师姓名、班级、工号等基本信息课程管理列表显示所有课程及对应的任课老师选课列表显示所有显示选择的科目

    4.3 总体功能模块图
    4.4 数据流程图
    五、系统详细设计与实现该系统涉及到的功能比较多,因此在这里只选取部分功能的实现来展开介绍。
    5.1 登录模块教务信息管理系统,如果每一个人进入计算机的人都能够对系统进行操作,就可能有意或无意的破坏数据,对用户产生不良影响,甚至造成无法估量的损失。
    因此,在进入系统之前要设置密码输入功能用户登录关键是判断它的密码和账号是否与数据库中存在的用户信息吻合,若存在则登录成功,若登录不成功,重新输入或者相管理员申请,由管理员分配教师账号,学生账号密码由教师分配。
    <script type="text/javascript"> $(function() { //点击图片切换验证码 $("#vcodeImg").click(function() { this.src = "CpachaServlet?method=loginCapcha&t=" + new Date().getTime(); }); //登录 $("#submitBtn").click(function() { var data = $("#form").serialize(); $.ajax({ type: "post",url: "LoginServlet?method=Login",data: data,dataType: "text", //返回数据类型 success: function(msg) { if ("vcodeError" == msg) { $.messager.alert("消息提醒","验证码错误!","warning"); $("#vcodeImg").click(); //切换验证码 $("input[name='vcode']").val(""); //清空验证码输入框 } else if ("loginError" == msg) { $.messager.alert("消息提醒","用户名或密码错误!","warning"); $("#vcodeImg").click(); //切换验证码 $("input[name='vcode']").val(""); //清空验证码输入框 } else if ("loginSuccess" == msg) { window.location.href = "SystemServlet?method=toAdminView"; } else { alert(msg); } } }); }); //设置复选框 $(".skin-minimal input").iCheck({ radioClass: 'iradio-blue',increaseArea: '25%' }); })</script><title> 登录|教务信息管理系统</title><meta name="keywords" content="教务信息管理系统"></head><body> <div class="header" style="padding: 0;"> <h2 style="color: white; width: 400px; height: 60px; line-height: 60px; margin: 0 0 0 30px; padding: 0;"> 教务信息管理系统 </h2> </div> <div class="loginWraper"> <div id="loginform" class="loginBox"> <form id="form" class="form form-horizontal" method="post"> <div class="row cl"> <label class="form-label col-3"> <i class="Hui-iconfont">  </i> </label> <div class="formControls col-8"> <input id="" name="account" type="text" placeholder="账户" class="input-text size-L"> </div> </div> <div class="row cl"> <label class="form-label col-3"> <i class="Hui-iconfont">  </i> </label> <div class="formControls col-8"> <input id="" name="password" type="password" placeholder="密码" class="input-text size-L"> </div> </div> <div class="row cl"> <div class="formControls col-8 col-offset-3"> <input class="input-text size-L" name="vcode" type="text" placeholder="请输入验证码" style="width: 200px;"> <img title="点击图片切换验证码" id="vcodeImg" src="CpachaServlet?method=loginCapcha"> </div> </div> <div class="mt-20 skin-minimal" style="text-align: center;"> <div class="radio-box"> <input type="radio" id="radio-2" name="type" checked value="2" /> <label for="radio-1"> 学生 </label> </div> <div class="radio-box"> <input type="radio" id="radio-3" name="type" value="3" /> <label for="radio-2"> 老师 </label> </div> <div class="radio-box"> <input type="radio" id="radio-1" name="type" value="1" /> <label for="radio-3"> 管理员 </label> </div> </div> <div class="row"> <div style="text-align: center;" class="formControls col-8 col-offset-3"> <input id="submitBtn" type="button" class="btn btn-success radius size-L" value=" 登    录 "> </div> </div> </form> </div> </div> <div class="footer">   </div></body></html>
    5.2 教师信息管理代码实现教师和管理员可以对信息进行修改:
    <html> <head> <meta charset="UTF-8"> <title> 教师列表 </title> <link rel="stylesheet" type="text/css" href="easyui/themes/default/easyui.css"> <link rel="stylesheet" type="text/css" href="easyui/themes/icon.css"> <link rel="stylesheet" type="text/css" href="easyui/css/demo.css"> <script type="text/javascript" src="easyui/jquery.min.js"> </script> <script type="text/javascript" src="easyui/jquery.easyui.min.js"> </script> <script type="text/javascript" src="easyui/js/validateExtends.js"> </script> <script type="text/javascript"> $(function() { var table; //datagrid初始化 $('#dataList').datagrid({ title: '教师列表',iconCls: 'icon-more', //图标 border: true,collapsible: false, //是否可折叠的 fit: true, //自动大小 method: "post",url: "TeacherServlet?method=TeacherList&t=" + new Date().getTime(),idField: 'id',singleSelect: false, //是否单选 pagination: true, //分页控件 rownumbers: true, //行号 sortName: 'id',sortOrder: 'DESC',remoteSort: false,columns: [[{ field: 'chk',checkbox: true,width: 50 }, { field: 'id',title: 'ID',width: 50,sortable: true }, { field: 'sn',title: '工号',width: 150,sortable: true }, { field: 'name',title: '姓名',width: 150 }, { field: 'sex',title: '性别',width: 100 }, { field: 'mobile',title: '电话',width: 150 }, { field: 'qq',title: 'QQ',width: 150 }, { field: 'clazz_id',title: '班级',width: 150,formatter: function(value,row,index) { if (row.clazzId) { var clazzList = $("#clazzList").combobox("getData"); for (var i = 0; i < clazzList.length; i++) { //console.log(clazzList[i]); if (row.clazzId == clazzList[i].id) return clazzList[i].name; } return row.clazzId; } else { return 'not found'; } } }]],toolbar: "#toolbar",onBeforeLoad: function() { try { $("#clazzList").combobox("getData") } catch(err) { preLoadClazz(); } } }); //设置分页控件 var p = $('#dataList').datagrid('getPager'); $(p).pagination({ pageSize: 10, //每页显示的记录条数,默认为10 pageList: [10,20,30,50,100], //可以设置每页记录条数的列表 beforePageText: '第', //页数文本框前显示的汉字 afterPageText: '页 共 {pages} 页',displayMsg: '当前显示 {from} - {to} 条记录 共 {total} 条记录', }); //设置工具类按钮 $("#add").click(function() { table = $("#addTable"); $("#addDialog").dialog("open"); }); //修改 $("#edit").click(function() { table = $("#editTable"); var selectRows = $("#dataList").datagrid("getSelections"); if (selectRows.length != 1) { $.messager.alert("消息提醒","请选择一条数据进行操作!","warning"); } else { $("#editDialog").dialog("open"); } }); //删除 $("#delete").click(function() { var selectRows = $("#dataList").datagrid("getSelections"); var selectLength = selectRows.length; if (selectLength == 0) { $.messager.alert("消息提醒","请选择数据进行删除!","warning"); } else { var ids = []; $(selectRows).each(function(i,row) { ids[i] = row.id; }); $.messager.confirm("消息提醒","将删除与教师相关的所有数据,确认继续?", function(r) { if (r) { $.ajax({ type: "post",url: "TeacherServlet?method=DeleteTeacher",data: { ids: ids },success: function(msg) { if (msg == "success") { $.messager.alert("消息提醒","删除成功!","info"); //刷新表格 $("#dataList").datagrid("reload"); $("#dataList").datagrid("uncheckAll"); } else { $.messager.alert("消息提醒","删除失败!","warning"); return; } } }); } }); } }); function preLoadClazz() { $("#clazzList").combobox({ width: "150",height: "25",valueField: "id",textField: "name",multiple: false, //可多选 editable: false, //不可编辑 method: "post",url: "ClazzServlet?method=getClazzList&t=" + new Date().getTime() + "&from=combox",onChange: function(newValue,oldValue) { //加载班级下的学生 //$('#dataList').datagrid("options").queryParams = {clazzid: newValue}; //$('#dataList').datagrid("reload"); } }); } //设置添加窗口 $("#addDialog").dialog({ title: "添加教师",width: 850,height: 550,iconCls: "icon-add",modal: true,collapsible: false,minimizable: false,maximizable: false,draggable: true,closed: true,buttons: [{ text: '添加',plain: true,iconCls: 'icon-user_add',handler: function() { var validate = $("#addForm").form("validate"); if (!validate) { $.messager.alert("消息提醒","请检查你输入的数据!","warning"); return; } else { var clazzid = $("#add_clazzList").combobox("getValue"); var name = $("#add_name").textbox("getText"); var sex = $("#add_sex").textbox("getText"); var phone = $("#add_phone").textbox("getText"); var qq = $("#add_qq").textbox("getText"); var password = $("#add_password").textbox("getText"); var data = { clazzid: clazzid,name: name,sex: sex,mobile: phone,qq: qq,password: password }; $.ajax({ type: "post",url: "TeacherServlet?method=AddTeacher",data: data,success: function(msg) { if (msg == "success") { $.messager.alert("消息提醒","添加成功!","info"); //关闭窗口 $("#addDialog").dialog("close"); //清空原表格数据 $("#add_number").textbox('setValue',""); $("#add_name").textbox('setValue',""); $("#add_sex").textbox('setValue',"男"); $("#add_phone").textbox('setValue',""); $("#add_qq").textbox('setValue',""); $(table).find(".chooseTr").remove(); //重新刷新页面数据 $('#dataList').datagrid("reload"); } else { $.messager.alert("消息提醒","添加失败!","warning"); return; } } }); } } }, { text: '重置',plain: true,iconCls: 'icon-reload',handler: function() { $("#add_number").textbox('setValue',""); $("#add_name").textbox('setValue',""); $("#add_phone").textbox('setValue',""); $("#add_qq").textbox('setValue',""); $(table).find(".chooseTr").remove(); } },],onClose: function() { $("#add_number").textbox('setValue',""); $("#add_name").textbox('setValue',""); $("#add_phone").textbox('setValue',""); $("#add_qq").textbox('setValue',""); $(table).find(".chooseTr").remove(); } }); //下拉框通用属性 $("#edit_clazzList, #add_clazzList").combobox({ width: "200",height: "30",valueField: "id",textField: "name",multiple: false, //不可多选 editable: false, //不可编辑 method: "post", }); $("#add_clazzList").combobox({ url: "ClazzServlet?method=getClazzList&t=" + new Date().getTime() + "&from=combox",onLoadSuccess: function() { //默认选择第一条数据 var data = $(this).combobox("getData"); $(this).combobox("setValue",data[0].id); } }); //编辑教师信息班级下拉框 $("#edit_clazzList").combobox({ url: "ClazzServlet?method=getClazzList&t=" + new Date().getTime() + "&from=combox",onLoadSuccess: function() { //默认选择第一条数据 var data = $(this).combobox("getData"); $(this).combobox("setValue",data[0].id); } }); //编辑教师信息 $("#editDialog").dialog({ title: "修改教师信息",width: 850,height: 550,iconCls: "icon-edit",modal: true,collapsible: false,minimizable: false,maximizable: false,draggable: true,closed: true,buttons: [{ text: '提交',plain: true,iconCls: 'icon-user_add',handler: function() { var validate = $("#editForm").form("validate"); if (!validate) { $.messager.alert("消息提醒","请检查你输入的数据!","warning"); return; } else { var clazzid = $("#edit_clazzList").combobox("getValue"); var id = $("#dataList").datagrid("getSelected").id; var name = $("#edit_name").textbox("getText"); var sex = $("#edit_sex").textbox("getText"); var phone = $("#edit_phone").textbox("getText"); var qq = $("#edit_qq").textbox("getText"); var data = { id: id,clazzid: clazzid,name: name,sex: sex,mobile: phone,qq: qq }; $.ajax({ type: "post",url: "TeacherServlet?method=EditTeacher",data: data,success: function(msg) { if (msg == "success") { $.messager.alert("消息提醒","修改成功!","info"); //关闭窗口 $("#editDialog").dialog("close"); //清空原表格数据 $("#edit_name").textbox('setValue',""); $("#edit_sex").textbox('setValue',"男"); $("#edit_phone").textbox('setValue',""); $("#edit_qq").textbox('setValue',""); //重新刷新页面数据 $('#dataList').datagrid("reload"); $('#dataList').datagrid("uncheckAll"); } else { $.messager.alert("消息提醒","修改失败!","warning"); return; } } }); } } }, { text: '重置',plain: true,iconCls: 'icon-reload',handler: function() { $("#edit_name").textbox('setValue',""); $("#edit_phone").textbox('setValue',""); $("#edit_qq").textbox('setValue',""); $(table).find(".chooseTr").remove(); } },],onBeforeOpen: function() { var selectRow = $("#dataList").datagrid("getSelected"); //设置值 $("#edit_name").textbox('setValue',selectRow.name); $("#edit_sex").textbox('setValue',selectRow.sex); $("#edit_phone").textbox('setValue',selectRow.mobile); $("#edit_qq").textbox('setValue',selectRow.qq); $("#edit_photo").attr("src","PhotoServlet?method=getPhoto&type=2&tid=" + selectRow.id); $("#set-photo-id").val(selectRow.id); var clazzid = selectRow.clazzId; setTimeout(function() { $("#edit_clazzList").combobox('setValue',clazzid); },100); },onClose: function() { $("#edit_name").textbox('setValue',""); $("#edit_phone").textbox('setValue',""); $("#edit_qq").textbox('setValue',""); } }); //搜索按钮监听事件 $("#search-btn").click(function() { $('#dataList').datagrid('load', { teacherName: $('#search_student_name').val(),clazzid: $("#clazzList").combobox('getValue') == '' ? 0 : $("#clazzList").combobox('getValue') }); }); }); //上传图片按钮事件 $("#upload-photo-btn").click(function() {}); function uploadPhoto() { var action = $("#uploadForm").attr('action'); var pos = action.indexOf('tid'); if (pos != -1) { action = action.substring(0,pos - 1); } $("#uploadForm").attr('action',action + '&tid=' + $("#set-photo-id").val()); $("#uploadForm").submit(); setTimeout(function() { var message = $(window.frames["photo_target"].document).find("#message").text(); $.messager.alert("消息提醒",message,"info"); $("#edit_photo").attr("src","PhotoServlet?method=getPhoto&tid=" + $("#set-photo-id").val()); },1500) } </script> </head> <body> <!-- 数据列表 --> <table id="dataList" cellspacing="0" cellpadding="0"> </table> <!-- 工具栏 --> <div id="toolbar"> <c:if test="${userType == 1}"> <div style="float: left;"> <a id="add" href="javascript:;" class="easyui-linkbutton" data-options="iconCls:'icon-add',plain:true"> 添加 </a> </div> <div style="float: left;" class="datagrid-btn-separator"> </div> </c:if> <div style="float: left;"> <a id="edit" href="javascript:;" class="easyui-linkbutton" data-options="iconCls:'icon-edit',plain:true"> 修改 </a> </div> <div style="float: left;" class="datagrid-btn-separator"> </div> <c:if test="${userType == 1}"> <div style="float: left;"> <a id="delete" href="javascript:;" class="easyui-linkbutton" data-options="iconCls:'icon-some-delete',plain:true"> 删除 </a> </div> </c:if> <div style="float: left;margin-top:4px;" class="datagrid-btn-separator">     姓名: <input id="search_student_name" class="easyui-textbox" name="search_student_name" /> </div> <div style="margin-left: 10px;margin-top:4px;"> 班级: <input id="clazzList" class="easyui-textbox" name="clazz" /> <a id="search-btn" href="javascript:;" class="easyui-linkbutton" data-options="iconCls:'icon-search',plain:true"> 搜索 </a> </div> </div> <!-- 添加窗口 --> <div id="addDialog" style="padding: 10px;"> <div style=" position: absolute; margin-left: 560px; width: 200px; border: 1px solid #EEF4FF" id="photo"> <img alt="照片" style="max-width: 200px; max-height: 400px;" title="照片" src="PhotoServlet?method=getPhoto" /> </div> <form id="addForm" method="post"> <table id="addTable" border=0 style="width:800px; table-layout:fixed;" cellpadding="6"> <tr> <td style="width:40px"> 班级: </td> <td colspan="3"> <input id="add_clazzList" style="width: 200px; height: 30px;" class="easyui-textbox" name="clazzid" /> </td> <td style="width:80px"> </td> </tr> <tr> <td> 姓名: </td> <td colspan="4"> <input id="add_name" style="width: 200px; height: 30px;" class="easyui-textbox" type="text" name="name" data-options="required:true, missingMessage:'请填写姓名'" /> </td> </tr> <tr> <td> 密码: </td> <td colspan="4"> <input id="add_password" style="width: 200px; height: 30px;" class="easyui-textbox" type="password" name="password" data-options="required:true, missingMessage:'请填写密码'" /> </td> </tr> <tr> <td> 性别: </td> <td colspan="4"> <select id="add_sex" class="easyui-combobox" data-options="editable: false, panelHeight: 50, width: 60, height: 30" name="sex"> <option value="男"> 男 </option> <option value="女"> 女 </option> </select> </td> </tr> <tr> <td> 电话: </td> <td colspan="4"> <input id="add_phone" style="width: 200px; height: 30px;" class="easyui-textbox" type="text" name="phone" validType="mobile" /> </td> </tr> <tr> <td> QQ: </td> <td colspan="4"> <input id="add_qq" style="width: 200px; height: 30px;" class="easyui-textbox" type="text" name="qq" validType="number" /> </td> </tr> </table> </form> </div> <!-- 修改窗口 --> <div id="editDialog" style="padding: 10px"> <div style=" position: absolute; margin-left: 560px; width: 200px; border: 1px solid #EEF4FF"> <img id="edit_photo" alt="照片" style="max-width: 200px; max-height: 400px;" title="照片" src="" /> <form id="uploadForm" method="post" enctype="multipart/form-data" action="PhotoServlet?method=SetPhoto" target="photo_target"> <!-- StudentServlet?method=SetPhoto --> <input type="hidden" name="tid" id="set-photo-id"> <input class="easyui-filebox" name="photo" data-options="prompt:'选择照片'" style="width:200px;"> <input id="upload-photo-btn" onClick="uploadPhoto()" class="easyui-linkbutton" style="width: 50px; height: 24px;" type="button" value="上传" /> </form> </div> <form id="editForm" method="post"> <table id="editTable" border=0 style="width:800px; table-layout:fixed;" cellpadding="6"> <tr> <td style="width:40px"> 班级: </td> <td colspan="3"> <input id="edit_clazzList" style="width: 200px; height: 30px;" class="easyui-textbox" name="clazzid" /> </td> <td style="width:80px"> </td> </tr> <tr> <td> 姓名: </td> <td> <input id="edit_name" style="width: 200px; height: 30px;" class="easyui-textbox" type="text" name="name" data-options="required:true, missingMessage:'请填写姓名'" /> </td> </tr> <tr> <td> 性别: </td> <td> <select id="edit_sex" class="easyui-combobox" data-options="editable: false, panelHeight: 50, width: 60, height: 30" name="sex"> <option value="男"> 男 </option> <option value="女"> 女 </option> </select> </td> </tr> <tr> <td> 电话: </td> <td> <input id="edit_phone" style="width: 200px; height: 30px;" class="easyui-textbox" type="text" name="phone" validType="mobile" /> </td> </tr> <tr> <td> QQ: </td> <td colspan="4"> <input id="edit_qq" style="width: 200px; height: 30px;" class="easyui-textbox" type="text" name="qq" validType="number" /> </td> </tr> </table> </form> </div> <iframe id="photo_target" name="photo_target"> </iframe> </body></html>
    5.3 后台管理代码实现系统管理员可以对后台所有数据进行管理,部分代码如下:
    <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title> 教务信息管理系统 管理员后台 </title> <link rel="shortcut icon" href="favicon.ico" /> <link rel="bookmark" href="favicon.ico" /> <link rel="stylesheet" type="text/css" href="easyui/css/default.css" /> <link rel="stylesheet" type="text/css" href="easyui/themes/default/easyui.css" /> <link rel="stylesheet" type="text/css" href="easyui/themes/icon.css" /> <script type="text/javascript" src="easyui/jquery.min.js"> </script> <script type="text/javascript" src="easyui/jquery.easyui.min.js"> </script> <script type="text/javascript" src='easyui/js/outlook2.js'> </script> <script type="text/javascript"> var _menus = { "menus": [ { "menuid": "2","icon": "","menuname": "学生信息管理","menus": [{ "menuid": "21","menuname": "学生列表","icon": "icon-user-student","url": "StudentServlet?method=toStudentListView" },] }, < c: if test = "${userType == 1 || userType == 3}" > { "menuid": "4","icon": "","menuname": "班级信息管理","menus": [{ "menuid": "42","menuname": "班级列表","icon": "icon-house","url": "ClazzServlet?method=toClazzListView" }] }, < /c:if><c:if test="${userType == 1 || userType == 3}">{ "menuid":"3","icon":"","menuname":"教师信息管理","menus":[ {"menuid":"31","menuname":"教师列表","icon":"icon-user-teacher","url":"TeacherServlet?method=toTeacherListView"}, ] },</c: if > <c: if test = "${userType == 1 || userType == 3}" > { "menuid": "6","icon": "","menuname": "课程信息管理","menus": [{ "menuid": "61","menuname": "课程列表","icon": "icon-book-open","url": "CourseServlet?method=toCourseListView" },] }, < /c:if>{ "menuid":"7","icon":"","menuname":"选课信息管理","menus":[ {"menuid":"71","menuname":"选课列表","icon":"icon-book-open","url":"SelectedCourseServlet?method=toSelectedCourseListView"}, ]},{ "menuid":"5","icon":"","menuname":"系统管理","menus":[ {"menuid":"51","menuname":"修改密码","icon":"icon-set","url":"SystemServlet?method=toPersonalView"}, ]} ] };/ </script> </head> <body class="easyui-layout" style="overflow-y: hidden" scroll="no"> <noscript> <div style=" position:absolute; z-index:100000; height:2046px;top:0px;left:0px; width:100%; background:white; text-align:center;"> <img src="images/noscript.gif" alt='抱歉,请开启脚本支持!' /> </div> </noscript> <div region="north" split="true" border="false" style="overflow: hidden; height: 30px; background: url(images/layout-browser-hd-bg.gif) #7f99be repeat-x center 50%; line-height: 20px; color: #fff; font-family: Verdana, 微软雅黑,黑体"> <span style="float:right; padding-right:20px;" class="head"> <span style="color:red; font-weight:bold;"> $ {user.name}  </span> 您好      <a href="LoginServlet?method=logout" id="loginOut"> 安全退出 </a> </span> <span style="padding-left:10px; font-size: 16px; "> 教务信息管理系统 </span> </div> <div region="south" split="true" style="height: 30px; background: #D2E0F2; "> <div class="footer"> © </div> </div> <div region="west" hide="true" split="true" title="导航菜单" style="width:180px;" id="west"> <div id="nav" class="easyui-accordion" fit="true" border="false"> <!-- 导航内容 --> </div> </div> <div id="mainPanle" region="center" style="background: #eee; overflow-y:hidden"> <div id="tabs" class="easyui-tabs" fit="true" border="false"> <jsp:include page="welcome.jsp" /> </div> </div> <iframe width=0 height=0 src="refresh.jsp"> </iframe> </body></html>
    六、功能测试6.1 登录功能测试
    6.2 学生成功登录功能测试学生成功登录图

    学生修改密码测试图

    6.3 教师成功登录功能测试教师成功登录测试图

    教师查看学生消息测试图

    教师管理课程测试图

    6.4 管理员功能测试管理员成功登录图

    管理员管理所有教师测试图

    管理员对所有课程管理图

    总结在该系统的开发过程中,我参阅了很多相关的书籍,许多网站的帮助解决了我许多难题。系统中所有的页面,我都争取使页面上代码简捷、易懂、易改。
    经过多天的设计与开发,系统终于基本开发完成,各项预期功能都已得到实现。当然,该系统还具有进一步的扩展空间,将会伴随着日后的使用逐步完成,使得界面更加优美,操作更加顺畅。设计和开发过程中遇到的问题也都得到解决,学到了很多的开发经验,受益无穷。
    1 评论 3 下载 2021-07-23 12:23:19 下载需要12点积分
  • 基于JSP和MYSQL数据库实现的在线考试系统

    1 系统概述1.1 功能模块教学部需要考试系统,该考试系统需要完成如下功能:

    考试系统只针对于Java课程,题目全部为单项选择,共10题
    学生注册、登录
    后台管理员功能:题库管理、录入试卷、修改试卷
    试卷生成
    考试
    试卷评分
    分数查看


    1.2 软件环境
    操作系统:WindowsXP、Windows2000 Server,windows server 2003,Linux
    数据库系统:MYSQL5.1及以上版本
    CASE工具: Rational Rose、Visio
    开发工具: Eclipse
    编程语言:Java
    支撑软件:JDK1.5及以上版本、Tomcat,JBoss或其他应用服务器

    1.3 基本设计概念和处理流程
    1.4 系统总体结构
    2 系统功能
    2.1 详细功能2.1.1 注册用户信息



    字段名
    字段类型
    说明




    用户名
    字符串
    用户名,用于登陆,用户唯一标识


    密码
    字符串
    密码要求加密存放


    姓名
    字符串
    用户真实姓名


    性别
    字符串



    电话
    字符串
    可以写多个联系方式


    邮件地址
    字符串



    备注
    字符串



    用户进入首页,如果没有注册,点击注册可以进入注册页面,注册完后,进入登陆页面,并要求自己将注册用户名填入登陆界面的用户名框内。如果已存在用户名,则返回注册界面,提示用户名已存在。

    2.1.2 用户登陆用户进入登陆页面,输入用户密码,点击登陆。登陆成功进入用户首页,登陆失败,返回登陆页面。
    2.1.3 用户密码修改用户在自己界面菜单上点击密码修改,进入密码修改界面,输入原密码,输入新密码和新确认密码,检验成功后进行修改。

    2.1.4. 用户管理
    2.1.4.1 用户查询查询条件:用户名,姓名
    查询结果:显示用户名称、用户名、性别,电话、邮件、备注
    2.1.4.2 用户删除勾选用户后,弹出确认对话框,用户确定后删除,可以进行多条删除,删除用户将删除用户所有考试信息。删除失败将进入失败页面并提示信息。
    2.1.5 题库管理题库全是选择题,选择项数至少两项,至多五项。题库题目名称不能重复。
    题目



    字段名
    字段类型
    说明




    题目名称
    字符串



    答案
    字符
    A,B,C,D,E这样的单字母编号



    选项



    字段名
    字段类型
    说明




    选项编号
    字符
    A,B,C,D这样的编号


    选项名称
    字符串
    选项名


    所属题目ID
    数字
    题目的ID号,在建表时设计



    2.1.5.1 题目添加管理员添加题目到题库。从查询界面点击添加按钮,进入编辑界面,填写题目名称,动态添加选项,至少两项,至多五项,点击添加完成。
    2.1.5.2 题目删除在查询界面中,勾选查询结果,进行删除,删除失败将进入失败界面。不能删除已被试卷引用的题库
    2.1.5.3 题目修改在查询界面,点击要修改的记录,进入编辑界面,修改改相关信息,进行保存。
    2.1.5.4 题目查询查询条件:题目名称
    查询结果:题目列表及选项(展现方式自定)
    2.1.6 试卷管理试卷



    字段名
    字段数据类型
    说明




    试卷名称
    字符型



    考试开始时间
    日期型



    考试结束时间
    日期型



    试卷题目



    字段名
    字段类型
    说明




    题目名称
    字符串



    答案
    字符
    A,B,C,D,E这样的单字母编号


    所属试卷ID
    数字
    试卷的ID号



    试卷选项



    字段名
    字段类型
    说明




    选项编号
    字符
    A,B,C,D这样的编号


    选项名称
    字符串
    选项名


    所属试卷题目ID
    数字
    题目的ID号,在建表时设计



    2.1.6.1 试卷录入从查询界面,点击添加按钮进入添加试卷界面,填写题目信息,从题库的题目列表中选择题目。(此处具体方式可以灵活设计),点击添加完成。
    校验:要求考试结束时间必须大于考试开始时间,考试开始时间必须大于当前(服务器)系统时间30分钟以上。
    2.1.6.2 删除试卷试卷删除时,已考过或正在考的试卷不能删除。(已考过即是在考试结果中能查到该试卷,正在考检查系统服务器时间是否在考试区间内)
    在查询界面,勾选查询结果,点击删除,用户确认删除后,删除所选试卷。删除失败将进入失败界面并提示信息.
    2.1.6.3 修改试卷从查询界面,点击某条记录进入编辑界面。修改相关信息。已考过或正在考的试卷不能再修改。
    2.1.6.4 试卷查询查询条件:试卷名称
    查询结果:试卷名称,考试开始时间,考试结束时间
    2.1.7 考试结果查询


    字段名
    字段类型
    说明




    考试试卷
    字符串



    考生姓名
    字符串



    考试分数
    字符串



    管理员选择考试试卷,点击查询,显示该考试的结果,按分数自动排名,默认查询最近一次已结束的考试排名。
    显示结果:姓名、用户名、分数、排名
    2.1.8 管理员登陆参考用户登陆
    2.1.9 管理员密码修改参考用户密码修改
    2.1.10 考试用户登陆后,在考试列表中,能够查询到当前时间可以考试的试卷。选择试卷进入考试。在时间(取系统服务器时间)未到前,用户如果做完题目可以点击提交按钮提交。在考试时间到之后,系统将自动提交用户试卷。已考过的试卷不会出现在试卷查询列表。考试结束系统计算分数,自动跳转到分数查看界面。

    2.1.11 分数查看在菜单上点击分数查看,显示用户考试科目,日期及分数。
    查询结果:考试科目,日期,分数。
    6 评论 392 下载 2018-11-05 21:01:47 下载需要13点积分
  • 基于JSP和MySQL的网上订餐管理系统的设计与实现

    摘 要随着科学技术与经济的快速发展,网络信息技术也有了显著的提升与进步,当今的社会是一个集数字化,网络化,信息化的,并且是以网络为核心的现代化社会。伴随信息互联网的高速成长,使得互联网应用也走进家家户户的日常生活。网上订餐作为一种新的生活方式,更加新颖。
    毕业设计中,界面的设计主要使用了在jsp插入HTML语言以及JavaScript对系统的页面进行相关的加工处理完善以使得页面实现的效果尽可能的满足美观的要求。而对于后台的设计主要是使用了javaSE基础编程,及javaEE中的Jsp页面的动态编程,servlet处理交互逻辑,并且使用jdbc连接数据库,数据库则选用了更为高效的MySql数据库。
    本论文就此次毕业设计的系统内容,从餐品的管理,餐品的分类以及查询,到订餐车实现,客户对订单的处理,再到系统对订餐和餐品的管理。系统从业务流程的角度上分析,完成了订餐系统的基本功能,可是使得用户通过互联网进行点餐以及交易。相比于以往的订餐方式,网上订餐更加便捷,高效,对于餐厅更加节省人力,有利于管理,对于顾客更加省时省力。
    关键字:网上订餐系统;JSP;系统管理
    AbstractWith the rapid development of science and technology and economy, network information technology has also been improved and significant progress, the society is a set of digital, network, information, and network as the core of the modern society. With the rapid growth of information and Internet, Internet applications have entered daily life in every family. Online ordering as a new way of life, more innovative.
    The graduation design, the interface design of the main use of the HTML language and JavaScript system to insert page processing related to the perfect page to achieve the effect of as much as possible to meet the aesthetic requirements in jsp. For the background of the design is mainly used javaSE based programming, dynamic programming and javaEE Jsp page, servlet interactive logic, and use JDBC to connect to the database, the database is more efficient in MySql database.
    This paper on the graduation design of the system content, from the management of the meal, the classification of food and query, to the order cart, customer order processing, and then to the system of ordering and food management. From the point of view of the business process, the system has completed the basic functions of the ordering system, but it allows users to order and trade via the internet. Compared to the previous way of ordering, online ordering more convenient and efficient, for restaurants to save more manpower, is conducive to management, for customers more time and effort.
    Keywords: online ordering system; JSP; system management
    绪 论随着我国在本世纪科学技术与经济的快速提高,网络信息技术也有了显著的提升与进步。在我们平日生活中有很多生活方式以及习惯随着周围信息化的快速提高也有和以往相比变化越发的翻天覆地。本次毕业设计“基于jsp的网上订餐系统的设计与实现”,相比与之前传统的电话订餐,门店订餐这种靠无线电话,人工传递的方式的信息途径,这些方式解决问题的效率很低,店家(餐厅)不能及时将餐厅对菜品的调整通知顾客,顾客对于用餐需求也不能进行调整,线下的交流并不能形成方便快捷的交互。很多时候对于,餐厅以及顾客都是一种损失。由于上述缺陷,为了适应当前时代信息快速发展,数据大爆炸的趋势,采用先进的发展的网上订餐管理系统使上述的种种缺陷得以得到缓解和解决,精简了餐厅的工作流程,顾客的订餐更加便捷,从而提高了餐厅的营业额。由于网络的的快速发展,所以订餐系统随着网络也要有一定的发展与变化。因此毕业设计“基于jsp的网上订餐系统的设计与实现”是非常有必要的。网上订餐系统对订餐所涉及的两个主要用户:客户与店家(餐厅),在实现网上订餐之前,双方进行订餐工作,双方都需要花费大量不必要的时间精力。而快速发展的网络技术,使得订餐系统中所要使用的管理流程在很大程度上做到了极大的简化了,使得餐厅的管理系统更加快速高效,更加便捷。提高餐厅工作人员的整体工作效率,更加给使用订餐系统的顾客更加便捷的使用享受和良好的用户体验。
    从始至终人们都寻求便捷,舒适的生活方式。网络作为提高生活水平的重要工具,在出现后,人们逐渐对其产生了依赖,在依赖的同时也希望网络能给自己带来更方便的帮助,从而大量的销售网站,娱乐网站等等也就慢慢诞生了,这个网上订餐系统是一种基于B/S架构的一种系统模式,订餐系统网站的上手非常的方便,即使第一次登陆,通过网站的指引也会让您订餐非常顺利便捷,如同多次订餐的老顾客一般。
    此次毕业设计的系统,网上订餐系统的开发与设计,在系统可靠性,以及项目的扩展性上占有极大优势。此外对一些java相关技术进行了部分研究,设计并且实现系统,同时为以后自己的可能还要做的其他项目打下了有效以及坚实的基础。
    1 系统概述与技术介绍网上订餐系统作为一个销售管理系统,首先在页面的结构上一定要相对有自己的独特之处,凸显餐厅的风格,餐品的质量。只有如此才能从一开始吸引顾客的目光,通过美观的页面满足顾客对此类订餐系统的好感依赖以及业务功能的需求。与此同时,系统也要有先对强的实用性,系统的实用性不强,这样的系统会是的顾客产生厌恶心理,不利于一个餐厅的未来发展。当然,作为一个销售管理系统,要对顾客的点餐做数据统计,这样才能方便餐厅对该顾客的用餐习惯分析,更好的对顾客实施更加人性化的服务。
    1.1 课题背景上世纪90年代,互联网逐渐走进人们的视野,在不知不觉中改变着社会的商品交易方式。国内各大企业从认识到互联网的重要性之后,一直坚持不断的探索网上交易的可能。但是由于网络生活具有很大的虚拟性,商家的信誉很难得到保证、有关网上交易的法规未出台、物流的滞后以及其他的一些问题,都成为了网络交易发展的绊脚石。但是,社会的进步是具有持续性的,21世纪以来,各个瓶颈问题包括网上支付、物流速递等一一被攻破,网上交易的黄金时代也随之来临。
    调查显示,由于科技的进步极大地繁荣了物质生产生活,人们对于生活的便利性要求进一步提高,网上交易特别是以食品外卖为代表与大众日常生活休戚相关的网络交易量将在未来几年达到高峰。
    网上交易这一方式给人们的消费模式注入了一股新的活力,极大地冲击了原有的传统购物消费习惯。网上订餐这一方式,在90后人群中拥有大量的支持者,促使他们做出选择的,不仅仅是这一形式的便利性,还包括相关网站对于消费者的引导。
    1.2 B/S结构的介绍此次系统的设计过程主要运用到了我们在学校以及公司经常提及使用的B/S结构。所谓的B/S系统就是浏览器、服务器的系统结构。网上订餐系统使用B/S结构,主要就是需要服务端的计算机安装数据库以及服务器。而在客户端,一个浏览器就足够。服务器在服务端运行,浏览器在客户端运行,
    B/S结构作为目前最先进的软件构造技术,在用户使用的浏览器向服务器提交了一些请求之后,服务器端如果接收到了用户在浏览器端发送的请求之后,服务器端对从浏览器接收而来的请求对其进行相应的业务逻辑处理,随后将其完成处理后的结果返回给浏览器所在的客户端。
    B/S结构也是有很多种的,例如:针对OA系统的开发,这些系统主要包括应用程序的研发(基于C/S结构的开发),以及使用传统的C/S结构的跟网络技术结合的混合应用,以及到目前为止是我们常常用到的网站制作的技术。但是不可否认的是,每中结构以及技术都有自己的优点以及缺点:在此前的C/S结构中,更多的它是一种比较传统的使用较为广泛的软件开发的模式,主要是通过客户端以及数据库两层结构完成系统的实现,在两层之间还可以加入其他层次与结构,C/S作为先前传统的软件开发标准以及开发设计结构,在伴随网络和软件的开发技术快速进步,在各种新兴技术不断出现下,被取代或弥补了其结构的很多缺陷,于是也被其衍生出来的新兴结构技术在系统开发的过程中渐渐的将其取代。
    1.3 JSP技术的介绍此次网上订餐系统中页面主要使用到的技术是java的JSP技术,JSP技术之所以被广泛被使用到各种项目中去,主要也是因为其自身拥有的很多功能,这使得在项目中可以实现满足开发人员,程序员对项目所需要的效果。
    作为JSP技术的基础,servlet技术在此前的开发中一直被开发人员所应用。JSP技术的优点:

    进过一次的开发和编写,可以在多种平台运行:因为JSP/Servlet都是基于Java变成语言的,因此具有其编程语言的一个主要优点——平台无关性,这个就是著名的的“一次编写,随处运行(WORA – Write Once, Run Anywhere)”
    系统的多平台支持性:在目前已知的所有平台JSP技术可以进行任意的环境开发,并且在平台中将项目部署在任意的环境里,相比于其他技术,可以根据自己项目的需求任意的环境中拓展。这些优势相比ASP/PHP的局限性是显而易见的
    强大的可伸缩性:JSP可以运行小到从有一个jar文件,大到多台服务器进行集群和负载均衡,多到多台Application进行transaction,还有消息处理,从一台服务器到无数台服务器,Java程序编程语言显示了其巨大的能量
    功能得多态多样以及获得大多数开发工具的技术支持:这个优势和ASP有点类似,java拥有众多的的开发工具并且极为优秀好用。并且都是免费下载使用的,而且可以成功稳定得在多个平台上顺利运行
    JSP标签可扩充性:JSP对Web网页的动态构建主要是利用脚本技术和标签,JSP技术站在开发者的角度考虑允许开发者拓展JSP标签,定制专属的标签库,xml标签拥有很好的兼容性以及强大的功能,网页制作者可以充分利用,减少对脚本语言的大量依赖,利用自己定制的标签,使网页制作程序员降低了制作网页的难度以及复杂度

    1.4 JavaScript语言介绍此次毕业设计,在其中的前台jsp页面中大量的使用了前端脚本语言JavaScript。 JavaScript编程语言以其独有特性,使得他在目前的大多数项目的前台页面设计以及编程都占有重要的一席之地。由于js设计来的产品会主要运行在用户的浏览器客户端,使得只要用户点击页面的一些按钮或者特殊位置,就可以触发特定的事件进行操作,在页面的JavaScript脚本就会将事件传给客户端(浏览器),在客户端被设计好的事件就会执行进行相应的事件处理完成一系列的操作。
    网上订餐管理系统在前台页面的编写设计中就多次使用到了JavaScript这种流行的前端编程语言,众多的优势,使得很多项目的前台都是它和它发展衍生的众多类库编写的,例如我们熟知的:jQuery,easyUI,Extjs等在众多的丰富的前端js类库。
    网上订餐管理系统在很多地方都用到了JavaScript脚本语言,例如:顾客以及管理员登录页面时候的,检出数据是否有效,包括重复为空等场景。
    1.5 MySQL数据库介绍首先要说的是MySQL是一个开源免费的数据库。这也是为什么作为一个小型关系型数据库管理系统,却获得了大量的使用,当然这并不是它的最大优点。MySQL数据库拥有很多优点,比如说:MySql的适应性很好,运行和反应速度快,使用的可靠性高。与此同时,结构化查询语句是MySql数据库系统主要使用的数据库管理方式,结构化查询语言也是目前在数据库管理语言中最受人们欢迎的,也是最为常用的。因此在很多的项目系统开发中都会被开发人员关注,经常使用。由于数据库开发者的允许,MySql作为开源的软件,在官方网站和很多其他网站都可下载到各种版本的MySql数据库。并且根据个人或者开发团队的项目需要对下载的代码做出合理的修改。由此我们可以看出,作为一个小型的关系型数据库,在一些项目的管理上是一个很好的选择,当然这也是在此项目没有超出MySql的数据处理能力的范围之外。
    1.6 MyEclipse介绍此次毕业设计主要是面向顾客用户在前台页面订餐,后台管理人员对前台页面出来的数据请求进行数据处理,并对客户端页面进行及时调整,完善的管理系统。
    MyEclipse开发软件对系统项目的开发更加方便快捷,开发项目的管理更具有条理性。相比于被广泛使用的Eclipse开发软件,MyEclipse在Eclipse开发软件的基础上进行了详细的优化和功能的完善,并且对Eclipse的开发环境进行了优化,最大的限度进行了拓展。使用Eclipse中很多时候我们自己要寻找安装插件,但是MyEclipse基本会帮开发人员在使用之前就集成好了,这对于开发人员的开发是十分便利的,因此目前正在广泛使用于企业级集成开发中去。而且,MyEclipse开发软件在应用程序的整合方面也显得十分成功,如果开发人员能十分熟悉Eclipse,那么对MyEclipse的使用也一定不会陌生,因为MyEclipse的快捷键与Eclipse基本保持一致。
    1.7 MVC模式介绍此次毕业设计为了能够在设计实现上达到最初的想法及要求。并且使完成的系统可以具有一个优秀系统所拥有的一些优点:安全性高,可移植性好,跨品台性高,拓展性优秀,还能具有分布式结构。因此在项目中用到了前文所介绍的B/S结构体系,我所设计实现的订餐系统正式基于Java编程语言的B/S设计模式的。为了更加完善系统,结合在大学时期学过的计算机软件知识,我还用到了另一个结构模式,MVC三层结构,MVC三层结构主要是指基于模型model,视图view以及控制controller的结构模型,而MVC正是这三者英文的首字母缩写。
    控制器,视图,模型三层软件设计模式是MVC软件设计模式的根本。这三层模式对应到了实际项目系统中的web服务器。目前,在网上订餐管理系统中主要使用的MVC模式,如下图。

    由以上的结构图可以得知,在此次的项目系统中,前台界面页面的主要任务就是使用系统的用户可以正常的使用系统逻辑正确完成所要实现的业务。当我们使用网上订餐管理系统的时候,仅仅需要在用户的本地计算机,移动通讯设备安装一个浏览器,在这里使用的浏览器不会限制其版本,开发团队以及类型。用户就可以通过这个浏览器作为客户端与我们的网上订餐管理系统建立网络连接,用户在使用的浏览器中发送需求信息,交由在系统当中的业务逻辑进行准确的数据处理,这些过程主要是由MVC结构中的对应层次进行处理的。业务逻辑得到准确的执行处理后,将处理好的数据进行数据库的数据交互。在模型层中,数据访问层必不可少,他主要实现了当前的系统(网上订餐管理系统)对数据的增、删、改、查等数据处理操作。
    由上述的阐述,我们可以得出MVC设计模式具有众多的优势,其中主要是有:

    低耦合性,高内聚性
    有利于开发者使用,极高的重用性
    可以简单方便的使用,快速的部署
    具有比较好的可维护性,易于未来的维护
    具有生命周期本身成本较低的优势
    软件过程化的管理方法更有利于开发的进行

    2 系统需求分析2.1 开发环境此次毕业设计“基于JSP的网上订餐管理系统”的开发计算机环境主要是:

    学校配发的戴尔品牌笔记本电脑,型号是惠普242G1
    处理器为英特尔酷睿i5 3代系列
    内存容量为 4GB
    显示屏 14英寸
    显卡芯片品牌NVIDIA
    型号NVIDIA GeForce GT 730M+Intel GMA HD 4000
    硬盘品牌希捷,容量500GB
    使用的系统是Windows7旗舰版 SP1

    在我开发完成的订餐项目系统中,主要使用的数据库是当前非常受欢迎的开源免费的数据库MySQL。进行项目系统开发,发布管理的软件也是MyEclipse工具。使用到的技术,主要是JSP技术,以及前端流行的脚本语言JavaScript,还有JAVA编程语言,HTML标签 等。此次完成的系统项目,订餐管理系统是不需要使用户安装客户端程序就可以使用,用户只需要使用浏览器就可以正常的,完整的使用订餐管理系统的全部所有功能。
    2.2 需求分析参照软件开发的标准规范,参考很多成功的软件开发案例,软件开发很重要的一环就是软件需求分析。软件需求分析当中很重要的一点就是通过这次分析,真正准确了解到用户的真实需求,完整准确地项目设计以及编码开发,这样才能在项目完成之后,交给用户一个满意的系统。不仅如此,同时还能在软件开发之初,对软件项目进行风险评估。最后完成一次完整的软件开发设计。
    软件项目的需求分析这个在软件开发过程中至关重要的一环,无论在什么时候都占有着不可忽视的地位,不能被省略或者敷衍而过。这正是因为它在整个的项目开发当中有着举足轻重的作用。因为软件项目的需求分析,才能在项目的设计开发之前,充分理解用户需要,准确的明确开发的方向。在开发的过程中知道。什么功能是必须实现的,什么工作是必须完成的。对系统进行全面的定义,准确,具体的需求,才能更好的实现在项目开发当中具有极其重要的功能。
    一个完善优秀的项目系统在开发之初,开发的初期就要准备充足的资料,进行项目的需求分析。只有在这个阶段完成一个明细,详尽的需求分析,我们才能在后期的设计,编码中更好的实现系统功能,完成一个用户满意的系统。
    2.3 可行性研究分析在开发的前期,对一个项目系统进行可行性分析,这是软件开发过程中不可或缺的工作。从多个角度,维度进行可行性分析,可以将项目分析的更加透彻具体,从项目的方方面面来深入理解项目系统。
    2.3.1 技术可行性分析在目前大多数的公司使用到的软件开发工具是MyEclipse ,例如我目前实习的公司就是用的是MyEclipse2016,因此我在我此次的项目系统,网上订餐管理系统就是用到了MyEclipse 软件开发工具。ava作为一当下最受欢迎关注的编程语言,历久弥新,而且方便灵活使用,是此次开发系统的不二之选。
    2.2.2 经济的可行性分析此次毕业设计,在整个项目系统设计编码完成之后,用户不需要在自己所在的客户端安装任何的客户端应用程序,只需要正常上网就可以完成对系统的访问和使用,除此之外,只要保证项目系统被正确的部署在服务器上,并且已经正常运行。那么,用户就可在任何连接互联网的浏览器上对系统进行访问。
    2.2.3 法律可行性分析此次毕业设计“基于JSP的网上订餐管理系统的设计与实现”,不仅可以提高餐厅对订餐的管理效率,为顾客对订餐需求上提供便利,提供更加贴心优质的服务,良好的用户使用体验。而且在整个的开发过程中都符合具体的软件开发流程及规范的。在项目的的开发过程中使用到的都是一些开源的免费的数据库以及开发人员主要使用的开发工具,参考以及使用到的一些代码,也都是在开源社区和论坛分享的主要开源代码。因此,此次的网上订餐管理系统是不存在任何问题,在法律上是可行的,满足法律可行性的所有要求。
    为了实现这些要求,我对界面页面的开发做到最大化的简单易懂,将功能实现尽可能的减少不必要的步骤,做到让顾客在最短的事件内可以快速订餐,突出餐厅餐品的特色。做到只要会使用电脑查看网页,就能成功点餐。因此,在操作可行性上也十分可靠。
    3 系统概要设计3.1 系统设计概述系统的设计阶段作为在项目开的发整个过程中,最为复杂的一环,其实也是在项目开发的整个过程中极为重要的的一环,必须经过,必不可缺少。在进行系统项目的设计之前,说明系统项目已经完成了对其自身的分析与设计阶段,这是一个具有发展性的过程,将从分析阶段得出的有些抽象的用户需求进行具体的实现,编码。在对系统项目的设计过程中需要考虑众多因素,例如在系统实现过程中所面对的内在环境和外在因素,对项目进行良好的业务和功能完善以及应该具有的敬业态度。
    作为主要的任务和目标,在系统设计阶段就是为了满足在系统分析阶段提出的用户要求.因此,要从用户的要求出发在不仅可以满足系统分析阶段得出的对系统项目逻辑功能的同时,还要充分考虑到多方因素,包括技术,成本以及时间环境等相关方面。对于不论是在正在进行中的整体的设计结构还是局部的每一个部分,都有相关的技术和针对性的应对方案。在合理的要求和基础上,对项目系统所必要的需求进行满足,并且提出该系统具体到实处的实行方案,使其可以得到完整的实现,完成最初的目标以及要求。
    系统设计的主要方向以及相关要点:

    在系统设计的阶段,主要工作涉及到了绝大多数都是技术以及专业知识
    为了满足用户的需求,在系统项目的设计过程中,可以对之前已经得出的系统项目分析结论作出一些修改,当然,这是基于非原则性上的
    使整个项目系统最终可以获得成功,不仅仅需要完善的分析,严谨的设计,更需要系统项目的设计环境。这个环境不仅仅是技术环境与管理环境,更是两者的有效结合。因此,这是急不可缺的重要一点

    有上述可知系统设计的要点,那么为了更好地设计系统项目就需要了解系统设计的原则:

    易用性原则:对项目做系统设计是为了,开发出的系统项目,可以满足用户提出的需求,达到用户的满意。这种满足需求表现在各个方面,例如:用户的业务需求,用户的逻辑需求,以及使用户处理部分业务时候更加简便,提高用户的用户体验
    开发阶段原则:开发项目系统软件,在系统技术选择阶段主要是站在系统的数据结构的角度进行设计与开发,而实现功能阶段则有不同,这是需要站到用户需求以及开发人员实现的角度考虑的
    业务完整原则:设计实现的项目系统软件,要保证在完成业务的同时保证数据的完整性,减少数据的无处,例如数据库中常常出现的脏读,误读等数据误差
    规范化的业务原则:在最初的设计阶段中,系统主要是完成用户需求要求的业务,但是在实际的操作总。对于系统项目的要求是更高的,它不仅要正确的完成用户的业务要求,也要面对完善的业务流程,以及系统安全性

    3.2 系统功能分析作为网上订餐管理系统主要是为顾客提供便捷,全面的订餐服务,重点要放在面对顾客的页面功能上,其次是管理员对餐品以及餐厅的管理,系统主要模块的设计:

    前台模块

    食品展示模块食品查询模块购物车模块收银台模块用户维护模块订单查询模块公告模块
    后台模块

    食品管理模块用户管理模块管理员维护模块订单管理模块公告管理模块留言管理模块

    如图3-1系统功能层次图所示。
    主要包括这几个方面,其中顾客订餐功能模块是主要重点模块,其次是管理员管理功能模块。当订餐系统管理员使用拥有管理权限的管理员用登录管理员页面的时候。可以看到目前订餐系统中保存的用户信息数据,菜品的数据,员工的数据以及状态,订餐的具体信息,采购原材料的具体情况,以及对顾客页面的管理,例如:留言板,以及营养小贴士等等。通过管理员对餐厅的管理,给予顾客最好的网上订餐服务。
    顾客订餐功能的相对应的模块:主要是顾客进入订餐系统网站之后,可以看到整体的订餐系统网站结构,进行系统的客户端登录,注册,以及对现登陆用户的信息修改,搜索菜品,点餐,订餐,支付,留言的相关功能,通过众多的订餐系统功能。
    管理员系统管理功能相关模块:主要是餐厅管理员从后台管理页面登录管理系统之后,对订餐系统的一些具体业务的调整,可以注册新管理员,以及对现有登录管理员信息的修改,查看分析管理目前注册的顾客的信息,查看修改调整现有菜品的具体情况,新增,删除,完善菜品;对目前餐厅原材料的采购和统计;以及对餐厅员工的管理,新增删除和调整状态;更重要的是可以对目前已知订餐的及时管理,还有就是对顾客订餐页面的一些人性化管理,查看顾客留言,修改给顾客查看的营养小贴士。
    通过这个两个主要的模块,可以完成订餐系统的综合管理,包括了顾客的主要功能,注册,登录,点餐等;以及管理员对餐厅多方面的管理,完成管理员对顾客的服务交互。

    3.3 系统用例图通过管理员用例图,可以清晰的,直观的看到管理员在网上订餐管理系统中对用户订餐以及用户本身的一些主要的操作:

    管理员可以管理餐品信息

    管理员可以添加菜品信息管理员可以删除菜品信息
    管理员可以管理订单信息
    管理员可以管理订餐系统中注册的用户信息

    管理员可以删除用户注册信息管理员可以修改用户信息
    管理员可以对留言进行管理
    管理员可以对用户进行管理

    管理员用例图图,如图3-2所示。

    通过用户(顾客)用例图,可以更加直观的理解在网上订餐管理系统中主要的客户端服务,用户主要使用的功能以及进行的操作,如下:

    游客可以注册会员信息
    游客可以浏览菜品
    游客可以查看公告
    注册会员的用户可以通过注册信息登录
    会员可以在订餐页面浏览菜品信息
    会员可以修改会员信息
    会员可以对正在进行的订餐进行修改
    会员可以对完成的订餐进行查询
    会员可以进行留言

    因此,为了可以更加准确,生动的理解上述所说的用户主要使用的订餐服务功能。绘制用例图就很方便的展示了用户使用主要使用的功能,用户(顾客)用例图,如图3-3所示。

    对于主要功能的业务处理,例如网上订餐管理系统整个业务逻辑处理中最为主要的一部分就是订单处理部分,为了更加直观的理解整个业务逻辑,最对订单的具体的操作如下:

    可以通过用户操作对订单信息,菜品信息进行添加
    可以通过用户操作对订单信息,菜品信息进行处理
    可以通过用户操作对订单信息,菜品信息进行删除

    3.4 系统流程图想对订餐管理系统进行操作,管理员需要登录订餐管理系统的后台管理系统,才能进行一系列的对应管理操作。如果登录时候出现异常,登录失败等状况,系统会要求管理员核对身份密码后重新登录。登录成功之后,就可以通过订餐管理系统的后台模块对整个订餐管理系统进行正确有效的管理。对订单的处理,对菜品的修改,添加,删除。对员工的添加,删除,管理。对原材料的采购登记。订餐管理系统目前的概况,都可以从订餐管理系统的管理员模块进行查看,分析,以及做出及时的相应调整。
    如图,是订餐管理系统的后台管理员模块操作的基本流程图,通过路程图,可以更为直观的看到管理员进行登录操作时的系统业务流程,进行登录,成功进行模块的管理,失败则重新登录等操作,如图3-4管理员流程图所示。

    4 数据库设计与实现4.1 数据库的结构设计一个项目系统软件的设计开发,数据库可以说是必不可少的,没有数据库,用户的数据无法保存,系统的使用人员无法处理数据,那么整个系统可以说是没有意义,以及没有任何使用价值的。在系统项目中,数据库就是用来给用户,管理员等各种使用系统的角色进行数据存储以及取出等交互动作的。不仅如此,根据数据的数据结构的不同,数据库还会对应有不同的存储方式。
    网上订餐管理系统,主要是使用流行的关系数据库MySQL,MySQL是一个开源的免费的关系型数据库,在开发者中极为流行,极为受欢迎。他的众多优点,例如:开源,免费使用,对服务器占用更小,速度更快,是系统更加流畅。这些都使得,系统软件开发的陈本较低,用户体验更佳。
    此次,我们毕业设计“基于JSP的网上订餐管理系统的设计与实现”中主要使用到了MySQL数据库,以下,就对主要的数据表结构进行描述与说明。
    4.1.1 概念结构设计本数据库为满足网上订餐系统的要求,保证使用者信息准确充分的同时,系统的安全性也同样重要。所以,至少要拥有以下功能:

    建立数据表保存使用者注册、登录、验证等功能所需要的数据
    建立两张表,分别保存食品分类信息和食品的详细信息所需要的数据,对食品分类信息分类管理
    使用者确认下单后出现的订单应当记录,包括订单号、地址等详细信息
    订单自动生成滞后,需要记录订单的状态
    除系统管理员外,其他人不能进行系统维护,所以要建立一张表保存管理员的信息
    使用者会对餐品提出意见,那么应该有留言表,留言表内含标题、日期和留言详情

    根据以上信息,网上订餐系统的E-R图如图4-1所示。

    4.1.2 表概要说明网上订餐管理系统主要包括了9张数据表,分别是餐品菜品信息数据表c_book,用户顾客注册数据表表member,管理员数据表admin,餐品菜品类别数据表c_booktype,用户评论数据表comment,订餐车数据表gouwuche,营养小贴士数据表news,订单数据表num,订单详情信息数据表orderbook。其中最为重要的5张数据表,将会在详细描述其表结构。
    4.1.3 数据表的结构餐品菜品信息表c_book
    餐品菜品信息数据表主要是用来保存菜品的基本信息,价格,菜名,描述等,该表的结构如表4-1所示。



    字段名
    数据类型
    长度
    主键否
    描述




    id
    int
    4

    ID


    name
    varchar
    50

    菜名


    author
    varchar
    50

    厨师


    price
    varchar
    50

    价钱


    number
    varchar
    50

    编号


    type
    varchar
    50

    类别


    Sum
    varchar
    50

    数量


    Remark
    varchar
    50

    描述


    tate
    varchar
    50

    原材料


    imgpath
    varchar
    150

    菜品图片



    管理员信息数据表admin
    管理员信息数据表,主要是适用于保存管理员的基本信息。表结构如表4-2所示。



    字段名
    数据类型
    长度
    主键否
    描述




    id
    int
    4

    ID


    name
    varchar
    50

    用户名


    quanxian
    varchar
    10

    权限


    pwd
    varchar
    50

    密码



    菜品类型数据表 c_booktype
    菜品类型数据表,主要保存了当前订餐系统的菜品类型,类型可以根据餐厅的需求,管理员对其进行增加,删除,以及修改等操作管理,如表4-3所示。



    字段名
    数据类型
    长度
    主键否
    描述




    Id
    int
    4

    id


    name
    varchar
    50

    菜品类型名



    用户(顾客)注册信息数据表member
    用户注册信息数据表主要保存了,使用订餐管理系统的用户注册的信息,这张数据表极为重要,表结构如表4-4所示。



    字段名
    数据类型
    长度
    主键否
    描述




    Id
    int
    4

    id


    name
    varchar
    50

    用户名


    pwd
    varchar
    50

    密码


    sex
    varchar
    50

    性别


    realname
    varchar
    50

    真实姓名


    age
    varchar
    50

    年龄


    card
    varchar
    50

    身份证号


    address
    varchar
    150

    地址


    phone
    varchar
    50

    电话(手机)


    email
    varchar
    50

    电子邮件


    code
    varchar
    50

    邮政编码


    type
    varchar
    50

    会员



    订单详情信息数据表orderbook
    订餐详细信息数据表,主要记录了顾客订餐之后,完成的订餐,订餐中主要记录了此时用户完成的订单的详细信息。数据表的结构如表4-5所示。



    字段名
    数据类型
    长度
    主键否
    描述




    id
    int
    4

    id


    userid
    varchar
    50

    用户id编号


    bookid
    varchar
    50

    菜品id标号


    booksum
    varchar
    50

    菜品数量


    times
    varchar
    50

    订餐时间



    5 系统的实现5.1 前台模块首页作为网上订餐管理系统,展现给用户的客户端前台页面是整个项目中最为重要的一环,而首页也是使用户的留下主要印象,重要的得分点之一。一个好的首页能为系统做良好的推广效应,展现系统的主要功能,使得用户可以通过简单快捷的熟悉上手,掌握使用方法,实现自己当前的需求。前台客户端页面首页,运行效果如图5-1。

    如图5-1,我们可以看到,用户使用的首页展示了系统客户端的主要功能,包括,用户的登录,一些管理员希望用户看到的信息,以及目前餐厅主要的菜品,还有就是重要的模块功能导航栏,通过导航栏的点击,用户可以进入相应的功能模块,实现自己目前的需求,包括:详细的点餐,会员中心,订餐车,留言,找回密码等主要用户使用功能。
    首页的部分JSP页面代码:
    <table border="0" width="99%" cellspacing="0" cellpadding="0"height="100%"><tr><td><% ArrayList alNewly = (ArrayList) request.getAttribute("books"); ArrayList alType = (ArrayList) request.getAttribute("type"); int tem = 0; int x = 0; if (alNewly.size() % 3 == 0) { tem = alNewly.size() / 3; } else { tem = alNewly.size() / 3 + 1; }for (int n = 1; n <= tem; n++) { %><table cellspacing="0" cellpadding="3" width="710" border="0"><tr><% for (int i = n * 3 - 3; i < alNewly.size(); i++) { ArrayList alNewlyRow = (ArrayList) alNewly.get(i); %><td align="middle" width="710"> <table border="0" cellspacing="0" cellpadding="0"><tr><td colspan="2" align="center" bgcolor="#FFE3BB"><font color="#ff9900"><% for (int j = 0; j < alType.size(); j++) { ArrayList alTypeRow = (ArrayList) alType.get(j); if (alTypeRow.get(0).equals(alNewlyRow.get(8))) { %><a href="servlet/SearchServlet?types=<%=aTypeRow.get(0)%>"><%=alTypeRow.get(1)%></a><% break;}}%></font>
    5.2 用户注册登录管理用户在使用订餐管理系统客户端页面进行订餐。首先需要登录系统,登录之后才能享受订餐系统带来的便捷快速的订餐服务,如果当前还没有可以登录的账号,首页提供有注册用户的入口。针对已经登录的用户,若果想对自己当前所使用的用户信息进行一些调整,系统也提供了会员中心管理页面,来满足此类用户的需求。如图5-2为用户登录功能的页面:

    用户进行登录之后就可以进行点餐,搜索等相应功能的操作了。用户登录的程序流程图如图5-3所示。

    在用户进行注册成为系统的正式用户之后,就可以进行功能的使用了,但是如果出现对当前用户信息的变更操作,就可以在用户的会员中心,对当前登录的用户信息进行修改,如图5-4为用户会员中心页面效果图:

    5.3 用户订餐管理功能订餐管理系统,作为用户使用的客户端的主要功能就是给用户带来便利的网上点餐服务,此次设计实现的基于JSP的网上订餐管理系统,点餐服务主要通过两个页面来展示菜品使用户进行点餐操作,一是首页点餐,首页会展示目前主要的菜品,以及销售排行和新上菜品,根据这些推荐信息,可以给用户带来更加贴心的用户体验;二是搜索点餐,可以通过首页上方的工具栏,点击进入搜索点餐页面,通过菜品的名称或者菜品所属的类别进行针对性的搜索,然后进行点餐,如图5-5为首页点餐页面效果图。

    如图5-6为搜索点餐页面效果图。

    搜索点餐页面,通过针对性的搜索可以使用户快速的找到自己需要的菜品,进而完成自己的点餐过程。
    进行菜品搜索的servlet部分主要代码是:
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Validate vd = new Validate(); String name = vd.getUnicode(request.getParameter("name")); String types = vd.getUnicode(request.getParameter("types")); String sql = "select * from s "; String[] args = {"id","name","author","publishing","number","price","storage","brief","type","tate","sums","imgpath","price1","sums1"}; if(name != null && !name.equals("")){ sql += "where name like '%"+name+"%'";//构建对菜品名称查询的SQL语句 } if(types != null && !types.equals("")){ sql += "where type='"+types+"'";//构建对菜品类别查询的SQL语句 } SelectBean sb = new SelectBean(); ArrayList al = sb.select(sql, args); request.setAttribute("search", al); RequestDispatcher rd=request.getRequestDispatcher("/qiantai/search.jsp");//跳转到前台菜品搜索页面 rd.forward(request,response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); }
    当用户找到自己心仪的菜品之后,进行点餐操作,所选菜品点餐成功之后,将跳转到订餐车页面,订餐车页面将展示目前为止,用户所选的菜品,如图5-7为订餐车页面效果图。

    在购物车页面中,用户可以清晰的看到目前所点的菜品信息,也可以根据目前自己的需求对已经点的菜品进行操作,例如修改数量,或者删除目前选中的菜品,甚至清空,如果认为还有所需要的菜品,可以点击继续点餐,进入点餐页面,继续点餐操作。当用户认为菜品足够,可以点击收银台,进行订单的提交。
    进行提交之后,将进入收银台页面,点击在线支付,将提供支付宝链接,这样就可以支持网上在线支付,使得用户可以付款进而完成当前的订单。如图5-9为收银台页面效果图。

    5.4 用户其他功能操作页面网上订餐管理系统,不仅能让用户进行注册,登录,修改信息的操作,更重要的是让用户得到良好的订餐功能体验。因此,用户除了可以操作上述的订餐页面之外,也可由有其他更加人性化的功能,例如在此次毕业设计“基于JSP的网上订餐管理系统”中出现的营养小贴士,以及在线留言功能。
    营养小贴士可以用过管理员在后台进行编写,让点餐的用户看到,提供更加贴心的服务,而在线留言功能可以让用户对当前订餐管理系统中存在的问题,以及改进意见进行表达,达到更好的交互体验。如图5-10为用户在线留言页面效果图。

    5.5 后台管理员登录,注册功能作为一个订餐管理系统,仅仅有用户功能的页面是远远不够的,要提供更加全面的服务,为餐厅管理员提供功能管理页面就显得十分重要。通过系统的后台管理管理页面,对餐厅做出实时的管理,了解用户点餐情况以及目前员工的管理,这样才能更好运作系统,使得用户拥有更好的用户订餐体验。
    如图5-11为后台管理员登录页面效果图,5-11为注册管理员,以及修改管理员页面效果图。

    通过登录,管理员可以进入后台管理页面对订餐系统进行管理,可以对当前登录管理员进行修改以及添加新管理员。

    5.6 后台管理员菜品管理管理员通过添加新菜品,以及修改原有菜品,对订餐系统中的菜品进行调整,通过添加菜品的类别可以对菜品进行更加完善的管理。添加菜品时候,通过添加菜名,原材料,价格,图片,以及添加目前拥有的菜品类别等信息,来给用户展示一道菜的方方面面,这样使用户通过网络放心的进行订餐。如图5-13为添加菜品页面效果图。

    5.7 后台员工及会员管理管理员登录后台管理系统之后,不仅能对现有系统注册的会员进行管理,还可以对当前餐厅的员工进行管理,可以添加,删除,修改员工信息,根据目前员工的工作状态也可以在系统中进行标注。添加了员工搜索功能,这样方便了网上订餐管理系统,后台管理模块对员工的综合管理,如图5-14为员工管理页面效果图。

    5.8 后台材料采购管理作为一个订餐管理系统,要将每一天做菜使用的原材料进行统计管理,这样才是一个完善的订餐管理系统。对于原材料采购的记录管理,这样更能方便餐厅管理员,对整个餐厅进行全面的管理,做到对每一天的食材的把控,部分食材采购量的调整,对餐厅运营的成本的管理把控。如图5-15为原材料采购管理页面效果图。

    通过对原材料的统计把控,以及对一段时间的采购单种类及数量的分析,可以知道什么时候需要采购什么材料,采购的数量的参考量,采购的具体方向。对近期,原材料价格走向进行统计分析,得出对餐厅最为合适的采购方案,避免不必要的采购,或采购的数量不准确,导致的餐厅管理成本的提高,这都是需要注意以及及时避免的。
    5.9 销售订餐及统计管理作为网上订餐管理系统,对于当前订餐订单的管理是不可或缺的,因为只有对近期订单进行分析才能知道,用户喜欢的菜品,进而进行针对化的应对,挺高服务质量,对销量高的菜品背后的工作者—厨师,进行奖励管理,提高工作效率,菜品的质量保证。对近期采购单的统计,有效的看出采购方向,和采购数量,为今后采购提供了有力的数据参考保障,避免采购人员出现不必要的事物,餐厅承担不必要的损失。如图5-16为销售订单管理页面效果图。

    如图可以看到,管理页面提供了多样的搜索条件用来搜索符合条件的订餐,例如:用户id,菜品名称,订购数量,这些搜索条件可以快速定位符合条件的订单,然后反馈给管理员来进行订单的管理。
    除此之外,还有统计管理功能,如图5-17为统计管理功能页面效果图:

    如图,统计管理页面可以清晰,完整的看到当日的订餐销售量,销售信息,以及当日对原材料的采购量信息,这方便了管理员对餐厅的管理,也为用户提供快速,优质的使用体验实现了坚实的保障。
    使管理员对当前餐厅的实时状况有了深刻的认识,哪些菜品销量高,需要提前准备,原材料需要大量采购;哪些菜品销量过低,需要减少原材料的采购,甚至下架。近期的用户更喜欢,哪些类别的菜品,是否与天气季节相关,需要对员工厨师进行具体化的调整,提供了有力的数据佐证,与数据分析的资料。这都对今后餐厅的发展十分重要,也是网上订餐管理系统可以被餐厅使用的重要原因之一。
    6 系统测试在大学四年的专业知识学习中,可以得知。作为完整的规范的软件开发流程,在完成系统设计,编码开发之后,进行软件测试是非常重要的一环。是对完成开发,即将投入使用的系统的一次性能以及质量的综合鉴定。在项目正式上线使用之前,进行的必要工作。也是对项目最初的需求分析,系统的总体设计,编码开发的检验,多方面工作的综合最终审核。
    6.1 测试方法在项目进行完整的整合与交互中,对项目系统进行全面的测试,对项目的整体进行问题的查找,在这个过程中耗时相对而言较多。但是也正是因为系统测试的存在,使得系统有了综合质量的保证。
    为了确保网上订餐系统的稳定运行,本节对主要功能模块进行测试。
    6.2 测试流程写好测试的数据以及案例,并对测试数据进行设计逻辑的处理,得出期望结果。
    6.2.1 前台首页测试
    查询模块的测试:首先点击主页正中间的查询栏,在查询栏里中输入要查找的菜品关键字,如果弹出所查找菜品的信息,则说明该模块可行。对该模块进行大量数据的测试,验证其成功无错误
    菜品分类浏览模块的测试:单击页面左边的菜品分类信息,选定某一种类后,系统会弹出属于该类别的所有菜品信息。对给模块进行大量数据的测试,验证其成功无错误,该模块能够完整地实现功能

    6.2.2 购物车模块测试在本模块中首先对修改数量单元进行了测试,如果填写的数量为可行的有效数字如1、2、3,则系统提示修改成功,如果输入的制服非法,系统默认修改数量为1。通过随机数据的测试,验证其成功无错误。假如使用者订购了同一个商品,系统就会对该商品的购买数量进行累加。
    然后对购物车是否能满足使用者的购买数量进行测试,向购物车中添加大量的食品,查看购物车是否会发生崩溃现象。经过测试,购物车完全满足设计要求,达到了预期目标。
    6.2.3 菜品管理模块测试
    添加功能的测试:在菜品添加的功能下,对于已经选定的菜品名、菜品信息、菜品的图片、价格、特价、菜品种类进行添加。通过下拉的选择列表选择菜品的类别,对于菜品图片的添加,需要选择本地的菜品图片,然后上传,当所有必须的食品信息都已经填写完毕的时候,即可上传添加。完成添加以后,随机使用几组不完整的数据对本功能进行测试,均显示失败
    删除功能的测试:以上述添加的这一条记录为例,点击删除按钮,会跳出是否删除的提示信息,点击确定按钮之后,系统返回删除成功的信息。对于菜品分类信息的删除,则需要在本分类之下已经没有菜品信息,否则将不能删除

    6.2.4 会员注册模块测试在会员注册模块中涉及到了三项数据,项目分别为密码和确认密码、使用者真实姓名、住址、性别、E_mail、QQ。测试这个模块准备的数据有:

    979332、979332、王艺博、太原市万柏林区、男、123456@qq.com、123456
    岑志云、12345、1234岑志云、太原市万柏林区、男、bzhi@123.com、6434634

    点击注册按钮,输入第一组数据,单击注册按钮网站会提示表单信息不能为空,因为表单信息要全部填写,而昵称没有填写。接着测试第二组数据,两次所输入的密码并不一样,系统会弹出提示。
    6.3 系统测试结果当本次毕业设计完成完整的项目开发之后,对本次的“基于JSP的网上订餐管理系统设计与实现”,进行了相应的测试,主要的情况如下:
    在项目开发的过程中,每一个进程的每一步都需要被全面的考虑到,从而确保系统在个个时期具备可控性和稳定性。本章注重对前台首页、购物车模块、使用者注册模块和商品管理模块进行了详细的测试说明。对这些模块进行大量数据的测试,验证其成功无错误。
    参考文献[1] 康牧,JSP动态网站开发实用教程,清华大学出版社,2009.
    [2] 戴维尔,JavaScript程序员教程,电子工业出版社,2010.
    [3] 杨学瑜,高立军,软件开发过程与项目管理,电子工业出版社,2008.
    [4].唐友国 湛洪波著.JSP网站开发详解.电子工业出版社2008年10月.
    [5]卫红春等著.信息系统分析与设计[M].北京.清华大学出版社.2009.
    [6] 张文静 林琪著.JSP程序设计.人民邮电出版社.2005.
    [7] 张孝祥、徐明华, JAVA基础与案例开发详解, 清华大学出版社, 2009.
    [8] 张洁才,Java web应用开发教程,科学出版社,2005.
    [9] 戴维尔,JavaScript程序员教程,电子工业出版社,2010.
    [10] James D. McCaffrey等著.NET软件测试自动化之道[M]. 北京.电子工业出版社.2007.
    [11] 黎连业、王华、李淑春,软件测试与测试技术,清华大学出版社,2009.
    [12] 张大方 李玮等著.软件测试技术与管理[M].湖南.湖南大学出版社,2007.
    [13] (美)Elliotte Rusty Harold著.Java Network Programming.东南大学出版社 .2005.
    [14] (美)H.M.Deitel,P.Jdeitel著.Java程序设计教程(第五版). 清华大学出版社.2004.
    [15] (美)David flanagan著.Java技术手册(第五版).东南大学出版社.2006.
    [16] (美)John J.Patrick著.SQL基础(第二版).清华大学出版社.2004.
    12 评论 251 下载 2020-08-04 12:30:59 下载需要13点积分
  • 基于MFC实现的俄罗斯方块游戏

    1.需求分析需要实现的功能:

    使用键盘方向键实现方块的控制和移动
    程序能够对方块的位置进行判断,防止方块移动出界


    当满足消行条件时,能够及时消去满足条件的行数,其他保持不变
    实现加分和等级晋级,以及游戏难度增加等附加功能

    2.设计分析2.1 方块显示可以采用二维数组来对方块进行控制变化和显示。1-代表有方块,0-无方块。如:
    Now[4][4]={ 1,1,1,0 0,1,0,0 0,0,0,0 0,0,0,0};

    2.2 背景数组ArryBK[18][12]={0,0,…,0};
    屏幕绘制采用双缓冲,现在内存绘制,最后一次性送到显存;
    2.3 数据结构设计定义结构体
    struct shape { int ary[4][4]; //方块数组 CPoint pt; //起点(方块左上角),X-所在行,Y-所在列};
    定义类
    class CRussia {public: //构造函数,用来初始化数据成员 CRussia(); virtual ~CRussia(); //重新开始游戏 void GameAgain(); //判断游戏是否结束 bool IsOver(); //将当前形状数组附加到背景数组 void Attch(); //获得当前速度,用开控制游戏难度 int GetSpeed()const; //在内存dc中画出当前图形 void DrawNow(CDC *); //在内存dc中画出右边分数,等级,和下一图形 void DrawScores(CDC *); //在内存dc画出背景 void DrawRussia(CDC *); //消行 void DeleteLines(); //当用户按下方向键上时调用,用来变换矩阵 void InvertShape(); //用来产生随机矩阵图形 void RandShape(); //用来判断方向,当用户按下方向键,左(2),右(3),下(1)时调用 void Judge(int i=1);//默认判断方向为下private: bool m_bOver; //判断是否结束 int m_scores; //玩家得分 int m_speed; //时间间隔,用来设置定时器控制难度 int m_level; //玩家级数 shape Now; //当前矩阵图形 shape Will; //下一矩阵图形 int Russia[18][12]; //背景矩阵 CBitmap m_fangkuai; //方块位图};
    3.设计实现游戏数据初始化
    方块初始起点设置成第0行,第6列。
    CRussia::CRussia(){ m_level=1; m_scores=0; m_speed=600; //600ms间隔 m_bOver=false; m_fangkuai.LoadBitmap(IDB_FANGKUAI); int i,j; for(i=0;i<18;i++) for(j=0;j<12;j++) { Russia[i][j]=0; //背景数组清空 } for (i=0;i<4;i++) for(j=0;j<4;j++) { Now.ary[i][j]=0; //当前矩阵数组清空 Will.ary[i][j]=0; //下一矩阵数组清空 } //当前矩阵图形初始化 Now.ary[0][0]=1; Now.ary[0][1]=1; Now.ary[1][0]=1; Now.ary[2][0]=1; Now.pt.x=0; Now.pt.y=6; //下一矩阵图形初始化 Will.ary[0][0]=1; Will.ary[0][1]=1; Will.ary[1][0]=1; Will.ary[2][0]=1; Will.pt.x=6; Will.pt.y=0;}
    方块,背景及玩家信息屏幕绘制实现
    当前方块图形绘制,由于Now.pt.x表示所在行数,Now.pt.y表示所在列数。正好与默认坐标映射模式相反,所以在BitBlt()函数的前2个参数的X,Y坐标时,调换了行和列的坐标值。
    void CRussia::DrawNow(CDC *pDc){ // 创建内存dc CDC memDc; memDc.CreateCompatibleDC(pDc); int nDC=memDc.SaveDC(); //初始化内存dc memDc.SelectObject(m_fangkuai); for (int i=0;i<4;i++) for(int j=0;j<4;j++) { if (1==Now.ary[i][j]) { //将方块图案绘制到缓冲内存dc中 pDc->BitBlt(30*(j+Now.pt.y),30*(i+Now.pt.x),30,30,&memDc,0,0,SRCCOPY); } } memDc.RestoreDC(nDC); }
    背景数组绘制。
    void CRussia::DrawRussia(CDC *pDc){ CDC memDc; memDc.CreateCompatibleDC(pDc); int nDC=memDc.SaveDC(); memDc.SelectObject(m_fangkuai); for (int i=0;i<18;i++) for(int j=0;j<12;j++) { if (1==Russia[i][j]) { pDc->BitBlt(30*j,30*i,30,30,&memDc,0,0,SRCCOPY); } } memDc.RestoreDC(nDC);}
    游戏附加信息绘制。
    void CRussia::DrawScores(CDC *pDC){ CDC memDc; memDc.CreateCompatibleDC(pDC); int nDC=memDc.SaveDC(); memDc.SelectObject(m_fangkuai); for (int i=0;i<4;i++) for(int j=0;j<4;j++) { if (1==Will.ary[i][j]) { pDC->BitBlt(30*(j+13),30*(i+8),30,30,&memDc,0,0,SRCCOPY); } } memDc.RestoreDC(nDC); int nOldDC=pDC->SaveDC(); CFont font; font.CreatePointFont(300,"华文楷体"); pDC->SelectObject(&font); CString str; pDC->SetTextColor(RGB(20,255,0)); pDC->SetBkColor(RGB(255,255,0)); str.Format("%d",m_level); pDC->TextOut(430,120,str); str.Format("%d",m_scores); pDC->TextOut(430,2,str); pDC->RestoreDC(nOldDC);}
    键盘方向控制实现
    默认方向向下,当方块向下移动时,遍历方块数组依次判断每个值为1的方块的正下方方块是否有方块阻挡,以及判断是否碰到底界,如果遇到阻挡或碰到底,则将当前方块数组附加到背景数组,并返回结束本次移动,否则Now.pt.x++方块起点的X值加1。
    void CRussia::Judge(int i){ //1-下; 2-左 3-右 int j=0,k=0; switch(i) { case 1: for ( j=0;j<4;j++) for( k=0;k<4;k++) { if (1==Now.ary[j][k]) { //判断是否遇阻,以及是否遇到底界 if (1==Russia[Now.pt.x+j+1][Now.pt.y+k]||17==Now.pt.x+j) { if (0==Now.pt.x) { m_bOver=true; MessageBeep(1); } Attch(); return; } } } Now.pt.x++; break; case 2: for (j=0;j<4;j++) for(k=0;k<4;k++) { if (1==Now.ary[j][k]) { //判断是否遇阻,以及是否遇到左边界 if (1==Russia[Now.pt.x+j][Now.pt.y+k-1]||0==Now.pt.y) { MessageBeep(1); return; } } } Now.pt.y--; break; case 3: for (j=0;j<4;j++) for(k=0;k<4;k++) { if (1==Now.ary[j][k]) { //判断是否遇阻,以及是否遇到右边界 if (1==Russia[Now.pt.x+j][Now.pt.y+k+1]||11==Now.pt.y+k) { MessageBeep(1); return; } } } Now.pt.y++; break; default: break; }}
    Attch()函数的实现,遍历当前方块数组,值为1的坐标赋值给背景数组对应的点。并判断是否可以消行。
    void CRussia::Attch(){ for (int i=0;i<4;i++) for(int j=0;j<4;j++) { if (1==Now.ary[i][j]) { Russia[Now.pt.x+i][Now.pt.y+j]=1; } } DeleteLines(); RandShape();}
    DeleteLines()的实现,遍历背景数组,从第一行开始判断。并用nRet记录可消行的行数值。如果nRet不为0,则消行;
    void CRussia::DeleteLines(){ static int nflag=1; int nRet=0; bool bRet=true; for (int i=0;i<18;i++) { for (int j=0;j<12;j++) { if(0==Russia[i][j]) { bRet=false; break; } } //判断是否有一整行全部为1,即达到消行状态 if (bRet) { nRet++; } bRet=true; } //可消行数为1行 if (1==nRet) { m_scores+=1; } //可消行数为2行 if (2==nRet) { m_scores+=3; } //可消行数为3行 if (3==nRet) { m_scores+=5; } //可消行数为4行 if (4==nRet) { m_scores+=10; } if (m_scores>50*nflag) //加分,晋级,及难度控制 { m_level+=1; m_speed-=50; nflag++; } if (nRet!=0) { bool bFlag=true; for (int i=0;i<18;i++) { for (int j=0;j<12;j++) { if(0==Russia[i][j]) { bFlag=false; break; } } //为了记录所在行数值i,采用一行一行消去 if (bFlag) { //可消行,i值记录了可消的行所在的行数 for(int m=0;m<i;m++) for (int k=0;k<12;k++) { //第i行以上整体下移一行 Russia[i-m][k]=Russia[i-m-1][k]; } } bFlag=true; } }}
    方向上键控制,用来转换方块矩阵图形InvertShape()。
    void CRussia::InvertShape(){ int i=0,j=0,MaxV=0; for ( i=0;i<4;i++) for( j=0;j<4;j++) { Now.ary[i][j]=0; //清空 } static int k=2; switch(k) { case 0: Now.ary[0][0]=1; Now.ary[0][1]=1; Now.ary[1][0]=1; Now.ary[1][1]=1; break; case 1: Now.ary[0][0]=1; Now.ary[0][1]=1; Now.ary[1][0]=1; Now.ary[2][0]=1; break; case 2: Now.ary[0][0]=1; Now.ary[0][1]=1; Now.ary[1][1]=1; Now.ary[2][1]=1; break; case 3: Now.ary[0][0]=1; Now.ary[1][0]=1; Now.ary[1][1]=1; Now.ary[1][2]=1; break; case 4: Now.ary[0][2]=1; Now.ary[1][0]=1; Now.ary[1][1]=1; Now.ary[1][2]=1; break; case 5: Now.ary[0][0]=1; Now.ary[0][1]=1; Now.ary[0][2]=1; Now.ary[1][0]=1; break; case 6: Now.ary[0][0]=1; Now.ary[0][1]=1; Now.ary[0][2]=1; Now.ary[1][2]=1; break; case 7: Now.ary[0][1]=1; Now.ary[1][0]=1; Now.ary[1][1]=1; Now.ary[2][0]=1; break; case 8: Now.ary[0][1]=1; Now.ary[0][2]=1; Now.ary[1][0]=1; Now.ary[1][1]=1; break; case 9: Now.ary[0][1]=1; Now.ary[1][0]=1; Now.ary[1][1]=1; Now.ary[1][2]=1; break; case 10: Now.ary[0][0]=1; Now.ary[0][1]=1; Now.ary[0][2]=1; Now.ary[1][1]=1; break; case 11: Now.ary[0][0]=1; Now.ary[1][0]=1; Now.ary[2][0]=1; Now.ary[3][0]=1; break; case 12: Now.ary[0][0]=1; Now.ary[0][1]=1; Now.ary[0][2]=1; Now.ary[0][3]=1; break; } k=++k%13; //判断是否出右边界,出界则向左移动方块起点 for ( i=0;i<4;i++) for( j=0;j<4;j++) { if (1==Now.ary[i][j]) { if (12==Now.pt.y+j) Now.pt.y-=1; if (13==Now.pt.y+j) Now.pt.y-=2; if (14==Now.pt.y+j) Now.pt.y-=3; } }}
    4.游戏测试经多次测试,游戏可以按照设计文档的功能需求运行;

    5 评论 88 下载 2019-06-06 11:04:40 下载需要11点积分
  • 基于Python的PyGame实现的超级马里奥游戏

    一、选题在《实践:数据结构与算法实践》中选择了“超级马里奥第一关”为最后作业的题目。
    超级马里奥是红白机上的横版过关类游戏。
    功能特性在于在实现人物移动的同时,要使背景的地图也要进行移动,还有砖块、怪物等其他要素也要进行移动,因为只有让两者一起进行移动,才能让人物和地图和其他的要素保持相对的位置。后期又加入了音效和美化了一下界面。
    二、方案该选题难题主要分为以下几点实现。

    实现了人物的动态移动效果。主要是使用了MyLibrary.py里精灵类来实现的,该类在继承pygame自带的基础类上,加入符合本游戏需要运作的相关代码。在主文件main.py中我使用了四个精灵去实现人物的移动:向左走、向右走、向左跳、向右跳。然后通过一些变量继承来让马里奥实现了在图上只有一个存在且能完成四个动作。但也因为我这样设计导致了后面难以使用Pygame的碰撞检测函数,改用了点坐标去判断,有点累赘。
    由于马里奥掉下坑和其他一些需要根据位图来判断地方和屏幕上直接绘图的数据时不同的。所以要实现人物移动的同时,要让地图、问号砖块、砖块、旗画在当前的屏幕上,以此必须要这些要素也实现相对的移动。当马里奥运行到屏幕中间时,屏幕会向左运动,而马里奥横坐标会固定在屏幕中间,以此形成一种马里奥在移动的错觉,其他的要素(问号砖块、怪物)也是在此条件下发现地图在进行相对移动时,这些要素也会进行向左移动,以此保证一种没有动的错觉。
    关于水管和其他三角形障碍物的判定,由于马里奥精灵是使用了四个精灵来实现的,所以使用pygame自带的碰撞检测的话也不是很好用,我就直接采用了点坐标判断的方式,为了能更直观的去写代码。
    在最后阶段,加碰砖块的特效、金币闪烁的特效,蘑菇出现的特效、所有的特效。这里也使用了精灵去实现特效。
    由于时间有限,最后并没有实现马里奥吃蘑菇变大和吃花变无敌的特效,很遗憾。

    三、关键技术关键技术分为以下几点:

    马里奥动态实现。马里奥动态实现时调用了四种不同的精灵去实现,根据键盘的不同反应会调用不同的精灵,以此实现了马里奥向左走、向右走、向左跳、向右跳的动态画面。这样写的好处是我可以实现空中变向和空中控制降落地点的原作没有的功能。
    碰撞检测。由于马里奥动态实现不是单个精灵的问题,这里是采用了点坐标判断的方式,也就是meetobstacle.py实现的代码相当多,数据也是很复杂。
    马里奥撞击问号砖块的判定问题和特效问题。也是有一个碰撞检测的函数去进行了判断,然后加载动画效果,再最后在原地方画上另外一种砖块。
    怪兽的移动、死亡、杀死马里奥。首先要实现怪物和马里奥之间相对距离随地图的改变而变化的问题,是地图移动时,怪物还是以一种原来的速度去移动。然后追加怪兽被踩时死亡效果和杀死马里奥的判定。

    四、结果和效果人物移动和跳跃的效果可能有点违和,没有实现原作的吃蘑菇升级功能和吃花无敌功能,额外实现了空中变向和可以玩家在跳跃时选择落地点的功能。






    五、总结和不足前两周的时候,我本来是打算实现超级马里奥,但发现运用c语言去实现的话问题会有很多,于是后来就选择了中国象棋。在稍微接触了一点Python和pygame的一些相关知识后,就决定用python去实现了这个之前有点遗憾的游戏。从结果上也可以看出,Python由于拥有功能更加完善和多样的库,所以使用Python去实现像超级马里奥之类的动作较多、场景较多的游戏是比C语言要更完善的。Python的库真的很多、很方便,利用好这些库的话,可以轻松实现C语言很难实现的功能。
    不足之处是没有考虑到将判定的坐标进行变量化,而是直接用数据去进行了判定,如果在一开始考虑到这点的话,可以很轻松实现马里奥吃蘑菇变大的功能,但由于写到结尾才发现这个问题,所以就没有实现这个功能,是我一个很大的遗憾。
    11 评论 381 下载 2019-02-22 18:04:00 下载需要12点积分
  • 基于JSP和MYSQL的酒店房间管理系统

    摘 要随着社会服务行业的不断发展,使用计算机系统软件来管理整个酒店业务的 要求也逐年提高,我国一些酒店都采用了相关的酒店管理系统来管理酒店业务, 以解决酒店全凭原始的手工记录管理效率低、易出错的缺陷;另外酒店行业对自 身提供服务的质量和能力也有了更高的要求,因此,酒店管理系统正因此而越来 越受到管理者的重视。
    本课题结合酒店管理系统的开发过程,详细介绍如何针对酒店的需求,将先 进的软件应用技术融入现代酒店管理系统当中,开发出功能更完善的酒店管理系 统。本酒店管理系统采用 JSP 技术、MYSQL 数据库,基于 B/S 结构开发实现,系 统主要包括两大功能模块,即用户功能模块和管理员功能模块。本系统采用当前 流行的 B/S 结构,将酒店管理各方面信息集中存储于数据库,实现了信息的实时 共享,适合酒店向集团化发展的需要。系统具有运行稳定、数据结构严谨、稳定 性强等特点。
    关键词 :酒店管理系统; MYSQL 数据库; JSP 技术; B/S 结构
    1 概述1.1 研究背景网络的快速发展从根本上更改了世界的企业的管理方式,自二十世纪九十年 代开始,我国的很多企业就设想可以通过互联网来进行管理企业相关信息。因为 当时存在很多的原因,比如企业的声誉非常不好进行认证、互联网的相关法律法 规也不够完善、开发技术也不够成熟等,阻碍了互联网在各大企业中的发展速度。 进入二十一世纪以后,我国经济有了快速的发展,限制企业管理的各个难题逐一 被解决,国内各大企业都加入到了电子信息化的管理模式中来。
    由于我国经济发展水平正在飞速发展,酒店这个行业作为服务行业中的重要 组成部分,己经越来越显示出其强劲的发展势头。随着我国酒店的不断增多,酒 店这一行业竞争也越来越激烈,因此需要开辟一个新的管理方式。我国酒店业利 用计算机管理系统来加强管理、提高服务水平,虽然至今已有多年的历史,但由 于我国起步发展较晚,只是一些浅层次应用,大多数还停留于七拼八凑的 MIS 系 统水平,甚至还仅限于简单的电算化和信息发布阶段,与国际酒店业先进信息化 应用的差距非常明显。信息化程度不高导致企业决策失误、市场反应速度缓慢等, 己经成为制约我国酒店业进一步发展的重要瓶颈。
    鉴于目前酒店管理的现状,结合信息管理系统的发展,该 JSP 酒店管理系统 充分运用 MIS 的总体思想,综合应用了 MYSQL、JSP 等技术开发,具有很好的管 理功能,真正完好地达到服务于用户的计划。
    1.2 研究现状根据最新调查得知,在此之前对酒店信息的管理通常是基于文本,表格等纸 介的手工处理,酒店客户信息情况的统计和核实等通常采用人工检查与核实,以 及对客房信息的管理等通过人工计算或手抄等方式进行,信息量大,但在数据处 理方面存在工作量大且易出错,其次还存在数据繁多与数据丢失等现象出现,而 且还不方便查找,在总体上存在缺乏系统与规范的信息管理系统现象,为了提高 工作效率我们急需开发出这套 JSP 酒店管理系统。
    随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信 息的重要场所,二十一世纪是信息的时代,所以信息的交换和信息流通显得特别重要。因此,使用计算机来管理酒店信息成为必然。开发合适的酒店管理系统, 可以方便酒店管理者对客房、预订以及会员等信息的管理,提高酒店管理的工作 效率及查询效率,有利于更好的了解客户、管理客户。
    1.3 研究意义JSP 酒店管理系统是酒店业务流程的重组整合用户信息资源,以更有效的方 法来管理酒店业务,从而降低运营成本,为客户提供更经济、快捷、周到的服务, 保持和吸引更多的客户,以求最终达到酒店利润最大化的目的。
    JSP 酒店管理系统与传统方式管理方式比较有很多的优点如:

    查询比较方便:JSP 酒店管理系统提供了非常多的查询途径,可以通过各种途径进行查询, 快速又准确
    信息量大:与过去的管理方式比较,JSP 酒店管理系统能够提供方便的酒店信息
    成本比较低,风险小,不受地点的限制:JSP 酒店管理系统最突出的优势是,管理员通过本系统可快速进行酒店相关 信息的管理,这样就使管理者直观的了解酒店相关信息,大大节省了手工翻阅的 时间。同时为用户提供了一个便利的查询预订的途径,更好的为客户服务

    2 系统相关技术介绍2.1 开发工具本系统的设计主要运用了 MyEclipse 和 Tomcat 后台服务器技术,设计时中 采用了 JSP 技术完成了页面设计过程,接下来我们主要对 MyEclipse 和 Tomcat 进行说明。
    2.1.1 MyEclipseMyEclipse,通常用来设计 Java, J2EE 的 Eclipse 插件集合,利用它可以 完成对数据库和 J2EE 的开发。通过对应用程序服务器进行整合,可以大大的增 强运算速度。MyEclipse 的功能十分强大,几乎涵盖了各种设计功能。
    2.1.2 TomcatTomcat 是一种是一个免费的开放源代码的 Web 应用服务器。在访问客户比 较少的情况下被经常采纳,在设计 JSP 程序时成为最好的选择。换句话说,将 Tomcat 服务器安装到一台电脑上时,可通过它对 HTML 页面的访问请求进行配合。 事实上,Tomcat 可以看成 Apache 服务器基础上的延伸,但它工作时相对比较独 立,因此当 tomcat 工作时,事实上它是看成一个与 Apache 服务器相对独立的 进程运行的。
    2.2 JSP 技术JSP 程序使用了 Java 编程语言,JSP 技术可以对动态网页进行封装。通过 tags 和 script,网页还能访问存在于服务端的资源的应用逻辑。JSP 可以分离网页逻 辑与网页设计和显示,对可重用的基于组件的开发进行支撑,更容易的对基于 Web 的应用程序进行设计。
    当 Web 服务器接收到访问 JSP 网页的请求时,首先运行的程序段,接下来将 JSP 文件中的 HTML 代码和运行效果一并返还给用户。通过 Java 文件的插入能够 对数据库、网页多重定向等运行,从而满足构建动态网页所需要的程序。JSP 和 Servle 相同,都可以通过服务器端运行。由于能够将一个 HTML 文本返回给用户 端,所以用户端具备浏览器就可以进行浏览。HTML 程序和穿插在内部的 Java 程 序可以构建 JSP 网页。在服务器被用户端访问时,能够处理相应的 Java 代码, 然后将产生的 HTML 页面再返回给用户端的浏览器。JSP 的设计关键是 Servlet, 通常大型的 Web 应用程序的设计成果也通过 Java Servlet 和 JSP 的协作。JSP既拥有了方便快捷的 Java 程序,又统统的面向用户,既实现了平台的无关性危 险还比较小,可以具备互联网的全部优势。
    JSP 技术的优点:

    一次编写,到处运行。除了系统之外,代码无需做任何改动
    系统的多平台支持。通常情况下,能够在任何情况下的全部平台上进 行设计,能够安排在任何情况中,也能够在任何情况下进行发展。相比 ASP/.net 来说,优点是显而易见的
    强大的可塑性。通过一个不大的 Jar 程序能够对 Servlet/JSP 进行运 行,也能够通过很多服务器进行集群和负载平衡,甚至能够通过多台 Application 解决问题。单台服务器到多台服务器,Java 展现了一个强大的功能
    具有强大和多样化的开发工具支持。Java 已经有了很多的设计方法, 何况大部分工具都是没有花费的,这中间有很多都在多种平台之下顺畅的进展
    支持服务器端组件。只有很有力的服务器端组件才能支撑 web 运行,因 此开发者可以在调用 web 页面时通过另外的开发工具来达成纷乱效用的组件,来 加强系统的可操作性。JSP 可以通过完善的 JAVA BEANS 组件来达成纷乱的商务功能

    内部对象表现出:request 用户端请求,此请求会涵盖来自 GET/POST 请求 的参数; response 网页传回用户端的反应;管理 pageContext 网页的属性; session 与请求相关的会话;application servlet 正在进行的内容;out 用来 输送响应的输出流; config 代码片段配置对象;page JSP 网页本身。
    2.3 B/S 结构在三层体系结构的 B/S(Browser/Server,浏览器/服务器结构)系统中, 用户可以通过浏览器向分布在网络上的众多服务器发出请求。B/S 系统极大地简 化了客户机的工作量,客户机上只需要安装、配置少量的客户端运行软件即可, 服务器将担负大量的工作,对数据库的访问以及应用程序的执行都将由服务器来 完成。
    B/S 架构的不断成熟,主要使用 WWW 浏览器技术,结合多种浏览器脚本语言, 用通用浏览器需要实现原本复杂的专有软件来实现的强大功能,并节约了开发成 本,是一种新的软件架构。B/S 系统包括:表示逻辑层,控制逻辑层,数据展现 层,三层是相对独立又相互关联。
    2.4 MYSQL 数据库在软件项目中,通过使用数据库来操作数据,可以保证数据的独立性、一致 性和安全性,为系统提供有效地访问数据的方式,同时为程序员减少了应用程序 的开发时间。
    常见的数据库无非分为两类,一类是关系型数据库(Oracle,DB2,MySQL, SQL Server )和非关系型数据库(NoSql、MongeDB)。不同的数据库有各自的优缺 点,此处不做具体介绍。
    MySQL 支持多线程的特点,可以方便的利用系统资源,有效提高速度,而 且提供了 TCP/IP、ODBC 和 JDBC 等多种方式途径来连接数据库;虽说其功能 不够强大、规模也相对较小,但是对于本系统来说足够了,同时也可以进行二次 开发的数据库表结构空间的扩展。
    使用 MySQL 建立系统数据库,不仅有利于前期对数据的整合处理操作,同 时利于后期的二次开发的数据扩展操作,对于有限级的数据处理,MySQL 可以 很好的胜任。
    3 系统分析3.1 可行性分析对所有的系统来说,都有可能会受到时间和空间上的制约。所以,我们在设 计每一个项目的时候,必须对该系统实行可行性分析,这样不但能够降低项目的 危害,还能改降低人力、物力和财力的损耗。下面对技术、经济、操作和法律四 个方面进行介绍。
    3.1.1 技术可行性JSP 酒店管理系统的开发基于 B/S 模式,主要包括前端应用程序的开发以及 后台数据库的建立和维护两个方面。对于应用程序的开发要求具备功能要完备、 使用应简单等特点,而对于数据库的建立和维护则要求建立一个数据完整性强、 数据安全性好、数据稳定性高的库。
    在过去很长一段时间,网络软件的开发都采用客户端(Client)/服务器(Server)模式,即所谓的 C/S 模式。比如在 Java 中,可以通过 Socket 实现一 个客户端/服务器的架构。在这种模式下,主要业务逻辑都集中与客户端的程序, 因此,必然导致以下问题:

    系统的安装、运行、调试、维护和升级的困难
    在 JSP 酒店管理系统中,客户端分布在信息逻辑和用户界面之间,必然增 加了系统的安全隐患

    正是由于 C/S 架构的这些问题,人们逐渐接受了基于浏览器/服务器(Server) 结构的系统,即 B/S 模式。在 B/S 这个模式中,用通用的浏览器来取代之前的客 户端系统程序就是主要的核心。
    B/S 模式对 C/S 模式虽然只作了少许改动,但却带来了很大的优势:因为客 户端统称为浏览器,所以,应用程序在下载、升级、维护时,仅需要在服务器端 进行配置就可以了。所有的配置工作均集中在服务器端,大大的解决了了系统的 安全隐患。
    虽然 B/S 模式拥有很多优势,但是因为在客户端能够利用编程对象仅仅是浏 览器,因此,之前在 C/S 模式下很简单就能实现的一些客户端功能,在 B/S 模式 下,却变的很难实现甚至无法实现。
    虽然如此,B/S 模式仍然是当前许多应用系统的首要选择模式。
    对于计算机专业毕业的学生,对数据库比较熟悉,该系统运行 MYSQL 数据库, 掌握了 Java 编程语言,建立这样一个系统应该在能力范围之内。
    因此从技术方面讲开发此系统是可行的。
    3.1.2 经济可行性本系统采用的软件都是开源的,这样能够削减很多的精力和资源,降低开发 成本。同时也能够提升设计的作用,JSP 酒店管理系统对计算机配置的条件要求 很低,即使是网吧淘汰下来的计算机也能够满足需要,因此,本系统在经济上是 完全具有可行性的。
    3.1.3 操作可行性JSP 酒店管理系统是基于 B/S 模式,通过电脑进行访问和操作,且界面简单 易操作,用户只要平时使用过电脑都能进行访问和操作。本系统具有易操作、易 管理、交互性好的特点,在操作上是非常简单的。因此本系统可以进行开发。
    3.1.4 法律可行性此 JSP 酒店管理系统是自己设计的管理系统,具有很大的实际意义。开发环 境软件和使用的数据库都是开源代码,因此对这个系统进行开发与普通的系统软 件设计存在很大不同,没有侵权等问题,在法律上完全具有可行性。
    总而言之,设计一个 JSP 酒店管理系统具有效率高,操作简便,降低成本等 优点,所以,建立一个 JSP 酒店管理系统是非常必要的。
    3.2 用户需求分析JSP 酒店管理系统主要满足 2 种类型用户的需求,这 2 种类型用户分别为管理员和用户。用户间的静态结构图如图 3-1 所示:

    3.3 性能需求分析为了保证JSP酒店管理系统能够长期、稳定、高效的运行,必须要保证系统 开发的性能。在JSP酒店管理系统的开发过程中,必须用充分的方法确保系统的 安全性和有效性。我们要充分考虑以下几点:

    安全性:在信息化的时代,信息就是宝贵的财富,保证信息的安全,特别是 个人信息更要求可靠的安全性
    先进性:结合当前流行趋势,开发要符合用户的需求,能够快速准确的实现 酒店信息管理相关功能
    可扩展性:JSP酒店管理系统给酒店信息管理带来了极大的便利,提高了管 理效率,备受管理人员的关注,因此在开发JSP酒店管理系统的过程中,我们要 考虑到系统的可扩展性,便于将来系统的升级、更新
    有效性:有效性主要包括功能有效性,设计JSP酒店管理系统的功能一定要 最大限度地满足用户的需求

    3.4 系统流程分析3.4.1 操作流程为了保证系统的安全性,要使用本系统必须先登陆到系统中,管理员和用户 通过不同的账号和密码,登录到不同的管理界面。其登录流程图如图3-2所示。

    3.4.2 注册流程用户在注册账号的时候,首先进入注册界面,填写用户信息进行注册。用户 注册流程图如图3-3所示。

    3.5 系统用例分析3.5.1 管理员用例系统中的核心用户是系统管理员,管理员登录后主要功能有系统用户管理, 注册用户管理,酒店楼层管理,酒店类型管理,酒店客房管理,客房信息管理, 酒店活动管理,留言管理和系统管理。管理员用户的用例如图3-4所示。

    3.5.2 用户用例用户可以查看网站信息,包括首页,酒店活动,地理位置,客房信息,在线 留言,注册登录,登录后进入个人中心,包括个人资料管理,我的预订管理,入 住记录管理和退房记录管理,用户用例图如图3-5所示。

    4 系统设计4.1 系统结构设计JSP 酒店管理系统的设计与实现主要分为用户和管理员 2 个用户角色,系统 结构图 4-1 所示:

    4.2 系统功能模块设计4.2.1 功能概述JSP酒店管理系统分为三个用户角色,分别是管理员,员工和用户,其具体 功能如下:

    管理员功能模块: 管理员登录后主要功能有系统用户管理,注册用户管理,酒店楼层管理,酒店类型管理,酒店客房管理,客房信息管理,酒店活动管理留言管理和系统管理
    用户功能模块: 用户可以查看网站信息,包括首页,酒店活动,地理位置,客房信息,在线留言,注册登录,登录后进入个人中心,包括个人资料管理,我的预订管理,入 住记录管理和退房记录管理

    4.2.2 系统功能结构通过上述分析,得出本JSP酒店管理系统功能模块图如图4-2所示:

    4.3 系统顺序图顺序图表示交互、是指为得到一个期望的结果而在多个分类器角色之间进行的交互序列。
    4.3.1 登录模块顺序图
    4.3.2 添加信息模块顺序图
    4.4 数据库设计4.4.1 数据库设计原则在概念设计中,通常用四种方法: 自顶向下、自底向上、逐步扩张、混合策略,以它为骨架集成由自底向上策略中设计的各局部概念结构 在物理结构设计阶段首先分两步走:确定数据库的物理结构,在关系数据库中主要是指存取方法和存储结构。对 物理结构的评价是时间和空间效率。选取正确的关系模式存取方法,常用的有:存取索引方法、聚簇存取、HASH 存取方法等。
    4.4.2 数据库实体在此阶段,用户可以参与和评价数据库系统的设计,从而有利于保证数据库 系统的设计与用户的需求相吻合。在概念模式的设计中,E-R模型法是最常见的 设计方法。
    通过上述分析对数据库的需求,与系统概念模型的特点及开发方法相结合, 我们可以建立E-R模型图,本系统的E-R图如下图所示:
    管理员信息实体E-R图如图4-5所示:

    酒店客房信息实体E-R图如图4-6所示:

    客房预订信息实体E-R图如图4-7所示:

    留言板信息实体E-R图如图4-8所示:

    入住登记信息实体属性图如图4-9所示:

    退房信息实体属性图如图4-10所示:

    4.4.3 数据库表设计本酒店管理系统需要后台数据库,本系统采用MYSQL数据库进行数据的存储, 下面介绍数据库中的各个表的详细信息。
    allusers 管理员信息表



    列名
    数据类型
    长度
    是否主键
    注释




    ID
    int
    1,1

    编号


    username
    varchar
    50

    用户名


    pwd
    varchar
    50

    密码


    cx
    varchar
    50

    权限


    addtime
    datetime


    添加时间



    jiudiankefang 酒店客房信息表



    列名
    数据类型
    长度
    是否主键
    注释




    id
    int
    1,1

    编号


    fanghao
    varchar
    50
    用户名
    房号


    louceng
    varchar
    50

    楼层


    leixing
    varchar
    50

    类型


    jiage
    varchar
    50

    价格


    yajin
    varchar
    50

    押金


    zhuangtai
    varchar
    50

    状态


    tupian
    varchar
    50

    图片


    beizhu
    varchar
    500

    备注


    addtime
    datetime


    添加时间



    kefangyuding 客房预订信息表



    列名
    数据类型
    长度
    是否主键
    注释




    id
    int
    1,1

    编号


    fanghao
    varchar
    50

    房号


    louceng
    varchar
    50

    楼层


    leixing
    varchar
    50

    类型


    jiage
    varchar
    50

    价格


    yajin
    varchar
    50

    押金


    yudingriqi
    varchar
    50

    预定日期


    yudingshiduan
    varchar
    50

    预定时段


    tianshu
    varchar
    50

    天数


    yudingren
    varchar
    50

    预订人


    xingming
    varchar
    50

    姓名


    shenfenzheng
    varchar
    50

    身份证


    beizhu
    varchar
    500

    备注


    issh
    varchar
    2

    是否审核


    addtime
    datetime


    添加时间



    liuyanban 留言板信息表



    列名
    数据类型
    长度
    是否主键
    注释




    Id
    int
    1,1

    编号


    cheng
    varchar
    50

    昵称


    xingbie
    varchar
    2

    性别


    QQ
    varchar
    50

    QQ


    youxiang
    varchar
    50

    邮箱


    dianhua
    varchar
    50

    电话


    neirong
    varchar
    500

    留言内容


    addtime
    datetime


    留言时间


    huifuneirong
    varchar
    500

    回复内容



    ruzhudengji 入住登记信息表



    列名
    数据类型
    长度
    是否主键
    注释




    id
    int
    1,1

    编号


    fanghao
    varchar
    50

    房号


    louceng
    varchar
    50

    楼层


    leixing
    varchar
    50

    类型


    jiage
    varchar
    50

    价格


    yajin
    varchar
    50

    押金


    xingming
    varchar
    50

    姓名


    shenfenzheng
    varchar
    300

    身份证


    ruzhuriqi
    varchar
    50

    入住日期


    lidianriqi
    varchar
    50

    离店日期



    tuifang 退房信息表



    列名
    数据类型
    长度
    是否主键
    注释




    id
    int
    1,1

    编号


    fanghao
    varchar
    50

    房号


    yajin
    varchar
    50

    押金


    xingming
    varchar
    50

    姓名


    shenfenzheng
    varchar
    50

    身份证


    jine
    varchar
    50

    金额


    feiyongjiesuan
    varchar
    50

    费用结算


    tuifangriqi
    varchar
    50

    退房日期


    tuifangren
    varchar
    50

    退房人


    beizhu
    varchar
    200

    备注


    issh
    varchar
    2

    是否审核


    addtime
    datetime


    添加时间



    5 系统的实现5.1 用户功能模块的实现5.1.1 系统主界面用户进入本系统可查看酒店活动、地理位置以及客房信息等,系统主界面如 下图5-1所示。

    5.1.2 用户登录界面用户要想实现酒店客房预订操作必须登录系统,用户登录界面展示如图5-2 所示。

    5.1.3 酒店客房信息界面用户可就如酒店客房信息界面查看客房详情信息,登录后并可进行预订和评 论操作,酒店客房信息界面展示如图5-3所示。

    5.1.4 客房预订界面用户在客房预订界面可输入预定日期、离店时间以及身份证等,客房预定界 面展示如图5-4所示。

    5.1.5 用户注册界面未有账号的用户可进入注册界面进行注册操作,用户注册界面展示如图5-5 所示。

    5.1.6 在线留言界面用户在在线留言界面可输入留言内容,进行留言操作,在线留言界面展示如 图5-6所示。

    5.1.7 我的预订管理界面用户登录后可进入我的预定管理界面查看个人预定信息,并可对其进行删除 操作,我的预定管理界面展示如图5-7所示。

    5.2 管理员功能模块的实现5.2.1 管理员登录界面管理员要想进入系统后台进行管理操作,必须登录系统,管理员登录界面展 示如图5-8所示。

    5.2.2 注册用户管理界面管理员登录后可查看注册用户信息,并可对其进行审核、修改和删除操作, 注册用户管理界面展示如图5-9所示。

    5.2.3 酒店楼层管理界面管理员可添加、修改和删除酒店楼层信息,酒店楼层管理界面展示如图5-10 所示。

    5.2.3 酒店客房管理界面管理员可添加、修改和删除酒店客房信息,酒店客房管理界面展示如图5-11 所示。

    5.2.5 预订信息查询界面管理员可查看用户客房预订信息,并可对其进行审核和添加预订入住操作, 预订信息查询界面展示如图5-12所示。添加预订入住界面展示如图5-13所示。
    预订信息查询界面

    添加预订入住信息界面

    6 系统测试6.1 系统测试目的与意义系统测试是开发一个管理信息周期中非常重要而且漫长的的阶段。其重要性 体现在他是保证系统质量与可靠性的重要关口,是对整个系统开发过程的最终审 查。
    系统测试的主要任务是尽可能的检查出程序中的错误,提高系统的可靠性, 主要的目的是位列检验系统“做得如何”。其中这一阶段又可以分为三个步骤: 模块测试;组装测试;确认测试;通过测试整个管理系统来确定能不能够满足用 户的需求。通过测试发现问题以后,我们要经过不断的调试找出错误具体原因和 位置,然后对其进行修改。
    6.2 测试方法在我们设计软件的过程中,测试系统常用的测试方法主要有两种:功能测试 和结构测试。
    功能测试也被叫做黑盒测试和数据驱动测试,是在已经知道系统应该具有的 具体功能的情况下,通过黑盒测试来测试系统功能是不是能够正常运行。在测试 时,将系统当做不能打开的盒子,在不管系统内部结构与特性的状况下进行测试, 它只检查系统功能是不是根据系统说明书的规定正常运行的,同时检测系统是否 能正确接收的输入信息和输出信息的正确对应,并保持系统的完整性的外部信息 需求。
    白盒测试与黑盒测试相反,它了解系统内部工作的各项具体程序,能够通过 测试来检查系统内部的运行是不是按照系统说明书的规定进行正常运作的,因 此,白盒测试又被叫做结构测试和逻辑驱动测试。根据测试程序的结构在每个道 路试验,当系统运行时不是能按预定要求正确运行,无论其功能如,白盒测试试 验,道路试验是一个逻辑驱动器,这种测试主要用来软件测验。
    软件测试工作必须要通过制定测试计划、设计测试、实施测试、执行测试、 评估测试五个阶段完成。设计测试的目的是确定、描述和生成测试过程和测试用 例。实施测试的目的是实施设计测试中定义的测试过程。测试的目的是实施和测 试过程定义的设计实现。测试的目的是确保由运行意图建立系统的实现。
    6.3 其他错误在程序设计实现的过程中不可避免的会产生各种难以预料的错误,如书写错 误、传值类型不一致、参数传递问题等等。这些都需要通过细心的检测与不断的 调试才能够排除。比如在servlet路径配置时因粗心错误导致运行导致所报错误, 如图6-1所示:

    6.4 测试结果经过对上述的测试结果分析,本酒店管理系统满足用户的要求和需求。所有 基本功能齐全,操作简单,系统运行性能良好,是一个值得推广的酒店管理系统。
    7 系统评价7.1 系统的特点和优点本系统设计时借鉴了国内外优秀网站的优点,从界面到系统设计都保证了管 理员、员工以及用户能够方便操作。系统的主要特点和优点归纳如下:

    本系统用的移置性和针对性都比较高,因为针对性高可以提供更好的 服务而移置性可以在多个系统上运行,更给客户带来了极大的方便
    该酒店管理系统内容全面,管理方便可以及时的全面的处理各种错误, 异常,这样避免了很多因客户的马虎操作而出现的失误,其操作方便,用户界面 友好,能够上网的人都可以很好的进行操作

    7.2 系统存在的不足和改进方案本系统应为时间仓促造成了很多的不足,下面我来一一的进行陈述并在日后 得到更好的改进方案:
    首先界面并不够美观,不能更好的吸引用户,所以在今后的日子里我会对其 视觉上的不足作出修改,其次系统的代码和数据库出现了非常多的冗余现象,都 是因为对编程技术的应用不够熟练,在日后我会加强自己的自身学习和能力,减 少这样的冗余现象。
    6 评论 122 下载 2020-08-26 10:31:16 下载需要10点积分
  • 基于WPF实现的简单绘图工具

    1、系统功能设计
    开发、测试环境

    开发环境: Visual Studio 2012 Premium运行框架:.net framework 4.5测试环境:Windows 8.1、Windows 7
    开发语言

    C#XAML

    1.1 前言当初选择这么一个软件来编写纯粹是出于对玩弄文字游戏的xx管理系统的不喜,但我们没有料想到,经实践表明,涉及实时跟踪鼠标键盘事件和实时绘图的软件编写难度远大于主要通过文字实现信息交互的xx管理系统。仅仅实现一个屏幕上图形的框选功能就让我改了六七遍代码,我的队友更是间断地找出了五个bug。当终于能够把整体功能流畅地实现时,我们对软件开发者的了解与敬意又加深了一层。
    1.2 总体功能描述当今图像处理越发普及,人们对于图像处理的需求也各不相同。而一些绘图软件存在过于复杂(如PS)或是只具备基础功能(如windows自带画图)的问题,因此我们开发一个基于Windows Presentation Foundation(WPF)的简单绘图工具。
    以下为程序的工作界面

    1.3 功能点说明


    功能类型
    功能点名称
    按键
    实现方式
    功能点描述




    基本功能
    主流类型图片载入
    Ctrl+O
    自己编写C#代码
    支持.png.jpg.gif.bmp.eps等主流图片类型的读入和加载。使用C#标准OpenFileDialog对象获得文件路径并且使用Uri读入之后转为BitmapImage,用Image控件显示


    基本功能
    图片保存
    Ctrl+S
    自己编写C#代码
    支持bmp(位图)和eps(矢量图)两种格式。使用SaveFileDialog对象获得文件路径之后用filestream输出。


    基本功能
    鼠标手绘图形
    鼠标拖框
    自己编写C#代码
    包括矩形、圆角矩形、圆、椭圆、直线、贝塞尔曲线等


    基本功能
    单击选择图形
    鼠标单击
    自己编写C#代码
    调用类接口SelectPoint来实现


    复杂功能
    框选图形
    鼠标拖框
    自己编写C#代码
    递归调用类接口SelectRect来实现


    复杂功能
    全选图形
    Ctrl+A
    自己编写C#代码
    调用类接口SelectAll来实现


    复杂功能
    多次选中图形
    Shift+鼠标拖框
    自己编写C#代码
    调用类接口MergeComposite来实现


    复杂功能
    被选择图形的闪烁

    自己编写C#代码
    通过来回设置选择的CompositeGraphic的isVisible属性来达到闪烁的目的。


    复杂功能
    删除图形
    Delete
    自己编写C#代码
    调用类接口Clear来实现


    复杂功能
    图形状态变更

    自己编写C#代码
    设置类属性DrawMode来实现。可以设置图形的边框粗细、颜色,以及内部颜色


    复杂功能
    调色板

    使用第三方库
    支持通过ARGB属性或是在图形中直接选色的方式给图形的边框和填充分别选色


    复杂功能
    拖动图形
    鼠标按住拖动
    自己编写C#代码
    调用类接口Move来实现


    复杂功能
    键盘移动
    Up,Down, Left,Right
    自己编写C#代码
    通过长按可快速移动


    复杂功能
    剪切选中图形
    Ctrl+X
    自己编写C#代码
    将选中的图形加入一个List,并从画布上删除选中的图形


    复杂功能
    复制选中图形
    Ctrl+C
    自己编写C#代码
    将选中的图形加入一个List,但不从画布上删除选中的图形


    复杂功能
    粘贴图形
    Ctrl+V
    自己编写C#代码
    对上述List中的所有成员递归调用接口 ICloneable.Clone。长按Ctrl+V可以连续粘贴


    统计功能
    图形个数统计

    自己编写C#代码
    递归调用类属性Count并将它和Label绑定


    用户体验优化
    打开和新建图片、关闭程序时的友情提醒。

    自己编写C#代码
    防止误删未完成画布中的内容。


    用户体验优化
    显示系统时间

    自己编写C#代码
    使用DateTime.Now.ToString方法


    错误处理
    载入图像时对不支持图像及无法处理的图像的抛出。

    自己编写C#代码
    若捕获异常,会弹出对话框



    2、系统总体结构2.1 概要设计按照“面向接口编程,而不是面向实现编程”的面向对象基本原则,在建立解决方案的时候我就将解决方案分成了Ccao-big-homework(UI,WPF工程项目,由我的队友邵键准同学实现,调用者)和Ccao-big-homework-core(实现,C#类库,由我实现,被调用者)。双方互不干涉,独立调试,在整个大作业过程中不曾因为接口耦合问题出现bug。
    由于采用了多种科学合理的设计模式(见下文各模块介绍),本类库在维持良好的可复用性的同时,不曾进行过任何强制类型转换,不曾进行过任何运行时类型判定,所有的多态都靠重载函数来实现,充分体现了面向对象的思想。
    3、具体实现3.1 GUI的设计GUI的设计采用了较为简洁的风格,设计完成后曾请求周边同学进行体验并对细节进行改进,力求用户体验较好。主体采用XAML语言,实现设计和功能的分离,并配之以C#的事件处理函数。程序取消了不怎么美观的窗口边框,并采取点住程序窗口任何一个位置均可拖动的方法。
    3.1.1 程序启动和关闭动画设计程序的主要窗口在开始和结束时都是通过淡入和淡出来呈现和销毁窗口,实现此效果使用了一个计时器,并让窗口的透明度随计时器而改变。下图为启动过程截图,可看见窗体还是半透明状态(请无视背景的代码)。
    3.1.2 程序启动界面的设计界面包括版本号与开发人员,“新建绘图”按钮在鼠标移上后会有高亮,点击进入绘图页面,点击“离开”按钮则直接调用Application.Current.Shutdown()函数销毁窗口。
    3.1.3 程序主体绘图界面设计主体绘图界面如下。

    上部为菜单栏,具体按钮功能见使用手册,实现了鼠标移到某个按键上时该按钮闪烁一次并且放大,同时调整整个工作框的布局。效果如下。

    左部为绘图框,选择后可使用鼠标绘制不同的图形,包括直线、圆、椭圆、正方形、长方形、贝塞尔曲线。其中贝塞尔曲线限于WPF提供的贝塞尔曲线构造函数的局限性,其必定从画布的左上角开始绘制。
    左下角为一个图标,无实际作用。
    3.1.4 程序图标的添加我们的程序可是有图标的哦!

    下面是调色板的图标。

    3.2 逻辑层主要实现解决方案Ccao-big-homework。
    3.2.1 工作窗口WorkWindow部分3.2.1.1 概述主要实现人与程序的交互,包括鼠标事件和键盘事件等。由于绘图软件基本是在一个窗口进行操作,一般使用组合而非继承的方式,因此类的结构比较扁平。类图如下。


    由于没有继承,全部实现在一个窗口里代码显得非常臃肿,因此我根据功能的不同将同一个窗口类分成了如下几个文件。

    下面逐步介绍各个文件实现的方法。
    3.2.1.2 BtnEvent实现菜单栏所有按钮功能,包括新建、打开、保存、退出、全选、复制、剪切、粘贴、样式选择按钮。实现方法是调用其他文件里的私有函数。
    3.2.1.3 FileEvent实现图片读写的相关方法。我们的程序支持使用文件夹视图来把文件保存到计算机的任意位置或是从计算机任意位置载入图片。同时还在现有图片未保存时弹出对话框提示用户要保存,防止了图片的误删,优化用户体验。

    实现画布的新建与刷新,并实现程序的退出功能。
    3.2.1.4 FishEyePanel实现上部菜单栏中当鼠标移到某个按键上时该按钮闪烁一次并且放大,同时调整整个工作框的布局。此处采用了组合的形式,FishEyePanel是一个新的类,在WorkWindow类中创建该类的对象,并布局到主窗口上。
    3.2.1.5 GraphicsOperation实现图像整体操作,包括:

    全选:调用队友提供的SelectRect接口,并把范围设置成整个画布大小的矩形,从而得到一个类型为List<CompositeGraphic>的对象,添加到selectedGraphics里
    复制:调用队友提供的Clone()函数,往clonedGraphics这个对象里添加对象
    剪切:复制的同时清空selectedGraphics
    粘贴:将clonedGraphics里的所有成员添加到总画布compositeGraphic的Children()成员中,从而实现绘制,并向右下角移动(10,10),从而和复制的原图区分开,然后清空clonedGraphics(),并再次调用复制函数(),从而实现粘贴的连续性,即复制一次可连续粘贴。下图为按下Ctrl+C后连续按下Ctrl+V的效果


    3.2.1.6 KeyBoard实现键盘的按键监控,包括:

    Ctrl+A:全选图像
    Ctrl+C:复制选中图像
    Ctrl+V:粘贴选中图像
    Ctrl+X:剪切选中图像
    Ctrl+W:关闭程序
    Ctrl+O:打开图片
    Ctrl+N:新建画布
    Ctrl+S:保存图片
    Delete:删除选中图像
    Key Up、Key Down、Key Left、Key Right:选中图像的上下左右移动
    Shift:按住时可多次增加选择已选中的图形

    3.2.1.7 MouseEvent我的工作中最难的部分,而且肩负调试队友代码的使命。

    Window_MouseLeftButtonDown事件:实现鼠标不在画布上时窗口根据鼠标的移动而拖动
    OnMouseLeftButtonDown事件:鼠标左键按下处理事件。主要记录鼠标开始移动的点startPoint,让画布捕捉到鼠标,并标记左侧的ToolBar是否选中rbSelect选择按钮
    OnMouseMove事件:鼠标移动时的处理事件。当鼠标移动且画布捕捉到鼠标的时候,若是发现rbSelect选择按钮被选中且当前有图形被选中且Shift键未被按下,那么说明这个鼠标事件需要的是移动图形,因而用虚直线实时绘制鼠标指示的移动路径;若是其他绘图按钮被选中,则说明要绘制图形,则用虚长方形或是虚直线实时绘制图形
    OnMouseLeftButtonUp事件:鼠标左键抬起的处理事件。首先判断鼠标抬起时和按下时位置是否相同。若是相同,则说明用户只是按了一下,那么不管左侧ToolBar是选中的什么,说明用户都是想选中一个图像,因此将左侧的工具条调整到rbSelect按钮,并且调用总画布compositrGraphic的SelectPoint方法,得到这个点选中的图像,将其加入selectGraphics,在这个List里面的对象,每隔0.5秒更改一次可见性,从外观看来,选中的图形会闪烁。若是鼠标移动了,且选项选中的是图形选项卡,则绘制对应的图形,并且刷新画布,并把之前实时跟踪鼠标的虚线图形删去。接下来判断选项卡是否为贝塞尔曲线选项,若是则把该点增加到贝塞尔曲线的List里,当List里的成员个数增加到4时,绘制一条贝塞尔曲线并清空该List。最后是最为复杂的rbSelect按钮,如果当时选中的图形为0,即selectGraphics为空,则说明用户想要选中他框选的图形,则调用SelectRect得到选中的所有图形,并把其加入selectGraphics中使其闪烁。若selectGraphics不为空,则说明用户想要移动选中的图形,则调用move方法移动选中的图形,并把selectGraphics清空。同时,如果整个过程中Shift键被按下且rbSelect被选中,说明用户想要增加选择图形,于是将选中的图形增加到selectGraphics里面。

    以上方法还各自特判了贝塞尔曲线绘制时的点四个点的情况。
    3.2.1.8 Paint各种图形的绘制,包括:

    直线
    长方形
    正方形

    椭圆
    圆角矩形
    贝塞尔曲线

    其中(1)~(6)的绘制方式基本相同,都是新建一个该图形的对象,然后根据传来的两个点确定图形的长宽和位置,将这个对象添加至总画布compositeGraphic,然后刷新画布。
    对于(7),绘制方式是在画布上点四个点,则出现贝塞尔曲线。
    3.2.1.9 其他零碎功能主要包括一些动画效果。启动时工具条的移入运用了ThicknessAnimation控件。为了美观我特意写了一个函数隐藏了工具条尾部的小箭头。选中图形闪烁的功能则使用了一个DispatcherTimer计时器,每过500ms就把selectGraphics的成员的可见性改变一次。图形个数统计调用总画布compositeGraphic的count属性,每隔0.5秒刷新一次。系统时间标签则使用DateTime.Now.ToString方法获取。
    3.2.2 启动窗口MainWindow部分这个窗口很简单,只实现了弹出WorkWindow和关闭窗口退出的功能。并贴了一张图,写了版本号。
    3.2.3 颜色拾取窗口StyleSettingWindow部分颜色拾取窗口我并没有花太多时间自己写,本来以为WPF自带调色板控件,结果发现没有,于是在网上找了一个扩展控件,并组合到WorkWindow类中,在按下上部菜单栏中的“样式选择”按钮时弹出。

    3.3 类库Ccao-big-homework-core-wpf的实现3.3.1概述。本类库(Ccao-big-homework-core-wpf.csproj)基于WPF,文件统一注释为”Du 2015.9”。

    由于本类库被设计作为实现图形操作的类的类库,所以各类之间比起“is-implemented-in-term-of-a“或者”has-a“来说更符合”is-a”关系,所以本类库大量使用了继承、多态、递归调用这些OO的方法,和UI相比更好的体现了这次大作业的教育目的。

    3.3.2 MyGraphic类基本的图像类。之所以声明为类而不是接口是因为有几个函数要有默认实现。
    下图是Mygraphic类的全部类图。各函数基本都是函数名自解释的,如果一眼看不出来有什么用可以参见源代码的注释。

    乍看上去,Ienumerator和Ienumerable两个接口(包括count,getenumerator,current,add,clear,dispose,reset等,可以使得这个类被像list一样用foreach遍历)看上去都不应该是MyGraphic类作为一个基本的图像类应该有的方法或者属性。事实上这里采用了Composite设计模式。为了使得单个对象和组合对象的使用具有一致性,其他库函数(以及用户)能够统一的使用组合结构中的所有对象(具体来说,使得我们不用在override各种函数的时候来写出诸如MyGraphic g as CompositeGraphic这种效率很低的运行时类型判定代码来),所以在MyGraphic类中定义了Composite类的各种接口,并且给以了默认实现(当然了由于MyGraphic不是CompositeGraphic,默认实现理应是空实现)。
    另外,MyGraphic类还实现了接口ICloneable,这个接口允许MyGraphic被深复制,因而实现了UI的复制-粘贴功能。
    IsVisible指示本图像是否会被画到画布上。
    Father指示MyGraphic类的父图像。Father类的set方法被重写来调用父图像的DisposeChildren方法来删除父图像维护列表中自己的存在。这样就能保证整个MyGraphic类是一棵树(树的顶点是由UI保存的一个Composite,事实上充当了画布的功能),为递归遍历创造了条件。所以同时,当Father被置null的时候,本图形就会因为失去一切引用而被C#的GC机制自动回收,相当于是被Dispose了。因此本程序的效率大大提高,本人的电脑在有1500个图形的时候还能够正常工作。
    SelectError指示点击一个点的时候允许多大的误差以选中一个图形。
    还有不少函数在MyGraphic类中被声明仅仅是为了作为接口被递归调用,例如SelectRect、Count属性等就是这样,当然整个程序中最重要的Draw也不例外。
    3.3.3 SingleModeGraphic类顾名思义,是整个图形有同一个drawmode的类,也是所有基本图形(basic_graphics)的基类。显然composite类由于可以add进各种drawmode的图形所以不可能能维持有同一个drawmode。

    drawmode指示一个给定border的geometry的图形如何被绘制,将调用drawmode的draw方法(见3.3.6)。
    重载了基类的SelectRect方法,当选中时返回包括自己的一个CompositeGraphic,反之返回null。
    getGeometry方法返回这个对象的border的geometry。
    3.3.4 CompositeGraphic类可以包含其他graphic的graphic的实现,或者说用windows画图打比方的话,就是那个选框功能。重载了IEnumerable和IEnumerator接口。

    首先,作为Composite设计模式的一部分,override了MyGraphic中的Composite相关的函数(isComposite, Clear, Add, MoveNext, Reset, Current),进行了事实上的操作。
    CompositeGraphic类维护一个私有的辅助list,用来保存每个成员相对于本体的左上角的相对位置。当CompositeGraphic类要执行某个操作的时候(例如Draw或者SelectRect),它就递归调用每个成员的相应操作,好像这个类不曾存在过一样(如果设置了isCombined = false,当这个标记被置true的时候整个CompositeGraphic将被视为是一个整体,类似于PPT或者Flash提供的“组合”功能)
    另外CompositeGraphic也像SingleModeGraphic一样有drawmode类型的属性backgroundmode,这是为了画出它的边界和背景色。边界总是一个矩形。
    当调用SelectRect的时候,由于递归调用的过程会产生大量很多层的CompositeGraphic(因为selectRect的原理是将所有被选中的图形改为连接到同一个Composite中,然后将这个Composite的父图形设为this),所以设计了MergeComposite,将一个Composite中的全部内容合并到另一个中,减少了递归的层次(在这种设计之下,递归最多两层),有效提高了运行效率。
    3.3.5 基本的图像类(basic_graphics)这些类都继承自SingleModeGraphic并且是Sealed类。有几个属性来记录自己的形状,并且override了getGeometry接口来确定自己的外形。如类图所显示的那样,新建一个基本的图像类是非常简单的,只需要实现getGeometry方法和Clone方法两个方法,并且定义几个足够确定图形位置和形状的属性,就能够被立刻应用到类库之中,像其他图形一样被选择、被移动、被更改颜色、被剪切、被复制、被粘贴,这充分体现了本类库良好的可扩充性。

    对于Ellipse、Line、Rectangle,WPF都提供了相应的Geometry对象来绘画,然而对于Bezier,WPF并没有提供相应的Geometry,而是提供了一个PathSegment——BezierSegment。BezierSegment只有三个参数(也就是说默认从原点开始画),第四个点需要通过设置PathFigure的起始点来确定。
    3.3.6 DrawMode类
    抽象类。指示如何绘制一个Geometry形状的Mygraphic为drawing。这个类其实做成接口也没什么问题。如果深究起来的话把绘图方式单独封装起来似乎也是一种设计模式,学名叫做Strategy模式。Strategy模式的好处也是显而易见的——如果直接将各种绘图方式以硬编码的方式写在SingleModeGraphic中,虽然可以少几个类,但是这意味着你可以在完全不破坏类库的情况下添加新的DrawMode,使得它易于切换、易于理解、易于扩展,进一步体现了作为一个类库的重要理念——可扩充性。(嘛,不过这毕竟只是大作业,虽说类库要可扩充性良好,但是也就我自己扩充我自己的类库玩罢了…但是当我发现WPF的drawing系列图像的构架思想竟然和我一开始手画的类图一模一样的时候,我心中别提有多得意了)
    3.3.7 DrawMode类的派生类
    这些类都继承自Drawmode类并且是Sealed类。有几个属性来记录自己的绘图方式,且override了draw来绘制。
    3.3.8 defaultConstant类
    储存一些常量。在GDI+中有System.Drawing.Color枚举,然而在WPF中似乎没有对应字段,为了方便类库的设计所以作为static readonly变量定义在这里,效果类似于C++的全局const。另外准备了defaultbrush(透明色)和defaultpen(黑色,宽2.0f)来作为GeometryMode的默认构造值。
    由于是常量,所以被作为partial类分散定义在drawmode的各个派生类中。
    3.3.9 DrawingUIElement类
    本来作为一个普适的类库有上面的类就已经能够绘图了;但是我所写的这个类库毕竟是个wpf类库,然而wpf的基本控件Canvas的Children只接受某种System.Windows.UIElement作为它的子成员。所以为了避免推倒重来,此处采用了Adapter(或者叫做Wrapper)设计模式,将本类库的接口类型(System.Windows.Media.Drawing)转换为我的调用方,邵键准同学的UI能够接受的参数UIElement。
    重写了OnRender方法,只要对它调用UIElement所固有的InvalidateVisual方法就能迫使控件重画,从而将drawing指示的画面显示在wpf界面上。
    3.4 类库Ccao-big-homework-core-winform的实现本类库(Ccao-big-homework-core-winform.csproj,并没有被本次大作业引用)是一开始我的队友尚未开始施工的时候编写而成的(文件注释为”Du 2015.8”),当时前期调研做的不够好,没有意识到wpf和winform不兼容,所以手贱就先写了一个winform版。Winform版实现比wpf版要早,Class Diagram也和wpf版类似,几乎所有的类名都一样,只是winform版基于GDI+,命名空间为System.Drawing,而wpf版基于WPF,命名空间为System.Windows。在此对于两个类库之间雷同的部分不再赘述。
    在本大作业中并没有用到winform类库(因为winform的界面远没有wpf美观),但是winform类库在我们往届的测试中证明是可以使用的(见github上9.6晚上的commit,hash为87ce7da,当时有一个基于VB的样例test基于winform测试了这个类库的可行性)。如果有兴趣做winform开发,可以尝试使用这个类库。
    本类库和wpf版的唯一区别在于draw的实现。在wpf版中,draw函数是一个普通的返回System.Windows.Media.Drawing的函数。然而在winform中我们采取的并不是Adapter模式,而是另一种著名设计模式Bridge模式:我们有一个接口IWindow实现drawpath和fillpath两个接口,然后draw函数接受参数IWindow,并在函数体内调用这两个接口进行绘图,没有返回值。这样做的好处在于可以将抽象部分与它的实现分离,使得双方都可以有独立的变化。无论类库将要面对怎样的UI(即便这是个WPF UI甚至是个VB项目,例如我的测试用项目),只要这个UI实现了接口IWindow,类库就可以不作任何修改的应用到这个UI上。
    以下是项目文件列表,除了IWindow外的所有类都和wpf版一样。

    4、项目总结4.1 亮点首先,由于采用了Composite模式,所以几乎所有的Composite接口都是通过递归调用来完成的,简洁明了,体现了合理设计模式的优越性。假使不采用Composite模式,那么(任举一例),SelectRect方法将不得不返回一个list<MyGraphic>,且不说这样子将使得这个类库丧失组合/打散的固有功能,而且返回list将使得对于这个list的每个操作都必须由客户端通过类似foreach MyGraphic g…这样子的调用方式手动对每个list的成员执行。现在只需要调用Composite的对应函数,就能通过递归调用在对客户隐藏的情况下执行了,体现了良好的封装。
    其次,本类库的可扩充性堪称良好。向本类库中加入新的几何图形只需要继承SingleModeGraphic并且重写getGraphic和Clone;向本类库中加入新的绘图方式只需要继承DrawMode并且重写Draw。
    4.2 OOP模式的优越性接口和实现的分离极大提高了我们的开发效率。只需要知道给接口提供什么参数,能得到什么结果就可以了,不需要知道它是如何被实现的,这样的黑箱极大地提高了我们的开发效率。
    4.3 版本控制的重要性版本控制不仅让我们能够清晰地了解自己的开发进度,而且在开发出现重大bug的时候,能够迅速地回滚到以前的版本。这样不会出现自己写了什么挂了都不知道的,结果只好全部删除重来的情况。况且,每一次在Git上的Commit都意味着我实现了新的功能,内心总能感到满足。
    4.4 自主解决困难的能力为了写大作业我估计百度了不下300次,基本开发的状态就是:想实现某功能—>发现自己不会—>百度google大法好—>会了—>实现该功能—>又想实现某功能。
    开发过程中我遇到过很多困难,举个例子:关闭窗口时我写了个淡出动画,结果发现动画刚开始运行就程序就被退出,表现为动画无法播放。百度了一个小时,终于找到解决办法:在给程序的OnClosing事件中,把close命令取消,然后坐等0.6秒动画放完后再退出程序。
    真正到开发程序才发现以前学的都是纸上谈兵,经过一份大作业的洗礼我收获了极大提升的编程技能。
    16 评论 121 下载 2019-04-02 10:31:39 下载需要11点积分
  • 基于SSM和mysql的个人博客系统

    摘 要随着互联网的发展,博客在自由和共享的精神的影响下应运而生。博客的出现让我们有更多机会在日常生活中向他人展示自己的观点和信息。博客就是开放的私人空间。在互联网中,你可以尽情的发表自己的思想和言论。可以在网络上结交各式各样的人。
    互联网在大家的方方面面都提供了极大的帮助。所以很明显的趋势就是网站的出现。个人博客系统为树立个人在网络上的形象提供了一个良好的平台。
    JAVA作为目前最盛行的技术之一,J2EE(JAVA企业版本)十分适合于Web应用程序的设计和实现。此外,目前基于J2EE的开源框架在市场上久经考验,java社区也是十分活跃。本文的目的就是利用J2EE技术设计和实现个人博客系统。
    关键词:个人博客系统;B/S结构;SpringMVC;Spring ;MyBatis
    第一章 绪论个人博客是人们在网络上展现自己个性的一种方式。自从互联网走进千家万户,大受人们喜爱。大家都喜欢通过网络来获取各种各样的信息。而在网络上,你也可以畅所欲言,而个人博客也是其中一种。在个人博客上,你可以发表自己的心路旅程,发表自己的工作经验,发表技术博客等等。
    首先介绍一下什么是博客,它也被称为网络日志。博客其实就是一个网页,它是由各种各样的帖子组成。这些帖子可以是你某一天观看电影的感慨,也可以是阅读到某篇书籍的读后感,更可以是你在自己技术领域的心得。它就是一个网页,但是大家可以在上面用文字或者图片分享自己的心情等,它提供的内容可以用来进行交流。
    博客最开始的时候是论坛下的一个子系统。最早参与博客的都是一些信息技术的一些专家和学者,讨论的都是专业技能。直到发现了博客的商业价值,一些开放了自发式的博客,大家也都发现了博客分享和讨论的趣味。越来越多的人参与进来,博客也越来越风靡盛行。
    博客与论坛有许多的相似之处,许多朋友都分不清他们两的区别。首先,论坛和博客都可以进行交友和交流等。而其中论坛注重的是集体讨论,博客注重的是个人分享。它们两者的核心点就有着很大的区别。论坛的创建的用户是基于为众人服务,而博客是为了博主服务。它们的不同点还有在形式上的不同。博客是独立存在的。而论坛并不是。总结起来,论坛是多人一起交流的地方,互动性强,社交性强。博客是发表个人文章的地方,虽然也可以交流,但更多的还是自娱自乐。
    第二章 相关技术介绍2.1 B/S 简介软件系统体系结构分为两种,是客户机/服务器结构和浏览器/服务器结构。其中的浏览器/服务器结构就是B/S结构。

    C/S模式:是客户端/服务器(Client/Server)模式,主要指的是传统的桌面级的应用程序。比如我们经常用的信息管理系统
    B/S模式:是浏览器/服务器(Browser/Server)模式,主要指的是web应用程序,就像电子商务网站,如淘宝,阿里巴巴等。相对于C/S模式的应用程序来说,B/S模式最大的优势在于客户端只要有浏览器就可以运行。而C/S模式的应用程序需要在客户端进行安装,而且升级也不太方便。而B/S模式的应用程序对于客户端来说,永远都是最新版本的

    2.2 JAVA 简介Java的前身是Oak,sun公司在1995年申请注册商标的时候,发现已经Oak已经被注册了,最终才另外取了一个名字叫JAVA(其中还有一个趣味故事,有兴趣的可以去查找看看),要使用Java首先要到官网甲骨文官网上下载Java的软件开发工具包,其中分为windows版本和Linux版本,我使用的是Windows的。而在Windows上要使用Java,要设置JAVA的环境变量。设置环境变量的步骤如下:第一步,点击计算机属性中的高级系统设置,点击系统属性高级的环境变量。第二步,设置一个系统变量为JAVA_HOME,其中的值是你的Java安装目录。它的作用还在于一些使用Java的工具时候需要用到这个变量,否则打不开,例如eclipse.第三步,设置一个classpath系统变量,它的作用是在你写Java源文件导包的时候去查找的类路径。第三步,在Windows自有的系统变量path中加入Java安装目录下的bin路径。既可以写成%JAVA_HOME%/bin;这就将Java的运行环境搭配好了。
    介绍一下Java的文件目录。首先最重要的bin目录下面包含的是一些JDK包含的一些开发工具执行文件,例如像编译器javac.exe.运行Java的java.exe等等都在这个目录下面。其中Java启动的虚拟机在Java目录的jre目录中。
    2.3 JSP 简介Jsp是服务端技术,与微软的ASP一样,是一种动态网页的技术,不过jsp是使用Java语言技术开发的技术,jsp使用的时候会被jsp引擎解析成Servlet代码,而jsp虽然可以写Java代码,但是jsp主要的作用是为了展示视图,所以jsp+javabean 可以很好的解决代码混淆问题,然后将视图与逻辑分离。
    2.4 SpringMVC简介SpringMVC是一种现今十分流行的WEB框架,它的作用是使用了MVC思想设计模式对web层进行解耦。是用来接受请求和处理请求的。
    SpringMVC处理请求的流程是如下:首先用户从浏览器中发送请求;之后它SpringMVC的核心组件DispacherServlet 前端控制器根据请求信息也即是url的信息来选择一个页面控制器进行处理;页面控制器接受得到委托之后,它首先会收集和绑定参数到某个对象中,然后调用业务对象进行业务逻辑代码处理,处理结束后返回ModelAndView。前端控制器根据视图的名字渲染相应的视图然后将响应传到前台去。
    第三章 可行性分析3.1 技术可行性分析本系统管理项目使用的是maven,数据库连接使用的是mybatis,数据库使用的是mysql,接受浏览器请求并处理的是使用springmvc,他们都是经过市场检验的,都已经十分成熟了,在安全性、可用性、可靠性等方面都是可以值得肯定的。
    3.2 经济可行性分析本系统使用的技术框架都是开源框架,比如spring,springmvc,mybatis.而使用的数据库也是开源免费的mysql,使用的开发软件eclipse也是免费的,人员就本人一个也是免费的。所以在经济上消费很低,在经济可行性分析中是可以确定可行的。
    3.3 操作可行性个人博客系统开发结合个人需求而开发,能解决用户可以通过互联网来展现自己等诸多问题,因此该项目符合开发条件,具有成熟的基础,并且,从前面的分析来看,技术上的操作是十分成熟并且开源免费广为人们使用,从系统的操作上是可行的。
    第四章 系统设计4.1 系统总流程
    本个人博客系统分为两个角色,分别是博主和游客。只有博主才能登录后台管理系统,进行博客发表。

    首先要通过用户名和密码登录后台管理系统,才能发布博客
    博主和游客都可以阅读博客
    博主和游客都可以发表评论
    经过博主的评论审核,评论才可以发布
    此时博主和游客才可以观看到评论

    4.2 博主用例

    登入功能:登入后台管理系统:首先进入登录页面,需要输入账号和密码。它会使用Shiro进行安全管理,对前台输入的密码进行加密运算,然后与数据库中的进行比较。成功后才能登入后台系统
    博客管理功能:博客管理功能分为写博客和博客信息管理。写博客是博主用来发表编写博客的,需要博客标题,然后选择博客类型,最后将博客内容填入百度的富文本编辑器中,点击发布博客按钮即可发布博客
    博客类别管理系统:博主类别管理系统可以添加,修改和删除博客类型名称和排序序号。将会显示到首页的按日志类别区域。游客可以从这里查找相关的感兴趣的博客内容
    评论管理功能:评论管理功能分为评论审核和评论信息管理两部分。评论审核是当有游客或自己发表了评论之后,博主需要在后台管理系统中审核评论。若想将此评论显示在页面上则点击审核通过,否则点击审核不通过
    个人信息管理功能:在这里可以修改博主的个人信息,可以修改昵称,个性签名,可以添加个人头像,修改个人简介
    系统管理功能:这里的功能有友情链接管理,修改密码,刷新系统缓存和安全退出
    友情链接管理:添加,修改,删除友情链接网址

    4.3 游客用例


    4.4 系统类
    本系统主要功能和模块的JavaBean主要集中博客、博客类型、评论、友情链接这四个类。
    4.4.1 博客类功能:用于存储博主发表的博客的一些信息。
    属性
    id; // 编号 title; // 博客标题 summary; // 摘要 leaseDate; // 发布日期 clickHit; // 查看次数 replyHit; // 回复次数 content; // 博客内容 contentNoTag; // 博客内容 无网页标签 Lucene分词用 blogType; // 博客类型 blogCount; // 博客数量 非博客实际属性,主要是 根据发布日期归档查询博客数量用releaseDateStr; // 发布日期字符串 只取年和月 keyWord; // 关键字
    方法:都是属性对应的setter,getter方法。
    4.4.2 博客类型类功能:对博客进行分类,将博客分为几大类型。
    属性
    id; // 编号 userName; // 用户名 password; // 密码 nickName; // 昵称 sign; // 个性签名 proFile; // 个人简介 imageName; // 博主头像
    方法:对应的setter,getter方法。
    4.4.3 评论类功能:对博客评论数据保存。
    属性
    id; // 编号 userIp; // 用户IP content; // 评论内容 blog; // 被评论的博客 commentDate; // 评论日期 state; // 审核状态 0 待审核 1 审核通过 2 审核未通过
    方法:对应的setter,getter方法。
    4.4.4 友情链接类功能:可以保存页面上的友情链接网址。
    属性
    id; // 编号 linkName; // 链接名称 linkUrl; // 链接地址 orderNo; // 排序序号 从小到大排序
    方法:对应的setter,getter方法。
    4.5 E-R图博客类的关系模式

    博主类的关系模式

    博客类型类的关系模式

    评论类的关系模式

    友情链接类的关系模式

    4.6 系统表设计系统总共有五张表,分别是博客表,博主表,博客类型表,评论表,友情链接表。如下所示:


    第五章 系统实现5.1 登录模块5.1.1 博主登录登入系统后台管理登录页面,博主首先输入用户名和密码,它回去调用Controller层代码,然后进入业务层调用数据库的一些操作确认是否用户名密码正确,然后返回到前台就会登进去。
    登录首页模块主要代码:
    使用form表单提交到后台进行数据验证
    <form action="${pageContext.request.contextPath}/blogger/login.do" method="post" onsubmit="return checkForm()"> <DIV style="width: 165px; height: 96px; position: absolute;"> <DIV class="tou"> </DIV> <DIV class="initial_left_hand" id="left_hand"> </DIV> <DIV class="initial_right_hand" id="right_hand"> </DIV> </DIV> <P style="padding: 30px 0px 10px; position: relative;"> <SPAN class="u_logo"></SPAN> <INPUT id="userName" name="userName" class="ipt" type="text" placeholder="请输入用户名" value="${blogger.userName }"> </P> <P style="position: relative;"> <SPAN class="p_logo"></SPAN> <INPUT id="password" name="password" class="ipt" type="password" placeholder="请输入密码" value="${blogger.password }"> </P> <DIV style="height: 50px; line-height: 50px; margin-top: 30px; border-top-color: rgb(231, 231, 231); border-top-width: 1px; border-top-style: solid;"> <P style="margin: 0px 35px 20px 45px;"> <SPAN style="float: left;"><a href="${pageContext.request.contextPath}/index.html">Java个人博客系统</a></SPAN> <span><font color="red" id="error">${errorInfo }</font></span> <SPAN style="float: right;"> <input type="submit" value="登录"/> </SPAN> </P> </DIV> </DIV></form>
    使用javascrip对输入的博主用户名和密码进行校验,若用户名或密码为空,提示错误信息来提醒用户, 用户再去查找错误。
    function checkForm(){ var userName=$("#userName").val(); var password=$("#password").val(); if(userName==null||userName==""){ $("#error").html("用户名不能为空!"); return false; } if(password==null||password==""){ $("#error").html("密码不能为空!"); return false; } return true;}
    使用MVC框架,对后台数据和前台form表单提交的数据进行交互
    @Controller@RequestMapping("/blogger")public class BloggerController { @Resource private BloggerService bloggerService; /** * 用户登录 * @param blogger * @param request * @return */ @RequestMapping("/login") public String login(Blogger blogger,HttpServletRequest request){ Subject subject=SecurityUtils.getSubject(); UsernamePasswordToken token=new UsernamePasswordToken(blogger.getUserName(), CryptographyUtil.md5(blogger.getPassword(), "java1234")); try{ subject.login(token); // 登录验证 return "redirect:/admin/main.jsp"; }catch(Exception e){ e.printStackTrace(); request.setAttribute("blogger", blogger); request.setAttribute("errorInfo", "用户名或密码错误!"); return "login"; }
    5.2 博客管理模块博客管理管理模块为个人博客系统的用户(即博主)提供写博客和博客信息管理功能。在个人博客系统的首页上的博客就是从这里进行发布的。博客管理包含。

    新建:対博客的新建,博客可以含有图片,视频,音频附件。新建博客必须要有博客标题,博客类别自己选择所需要的博客类别,然后填入博客内容,最后发表文章
    搜索:在博客信息管理中,可以输入自己想要搜索的博客信息,系统会自动筛选出适合的博客展现给用户
    修改: 点击你想要修改的博客,系统会弹出修改博客页面,之后博客的标题,所属的博客类型,博客内容等都可以修改
    删除: 该系统支持单个删除和批量删除

    5.2.1 博客查询

    按条件查询博客,调用控制层的list方法,在其中调用服务层list方法,返回 blog集合:List<Blog> list。获得集合后使用方法把查询到符要求的数据传到前台,在前台对数据进行处理。中心代码如下:
    @RequestMapping("/list") public String list(@RequestParam(value="page",required=false)String page,@RequestParam(value="rows",required=false)String rows,Blog s_blog,HttpServletResponse response)throws Exception{ PageBean pageBean=new PageBean(Integer.parseInt(page),Integer.parseInt(rows)); Map<String,Object> map=new HashMap<String,Object>(); map.put("title", StringUtil.formatLike(s_blog.getTitle())); map.put("start", pageBean.getStart()); map.put("size", pageBean.getPageSize()); List<Blog> blogList=blogService.list(map); Long total=blogService.getTotal(map); JSONObject result=new JSONObject(); JsonConfig jsonConfig=new JsonConfig(); jsonConfig.registerJsonValueProcessor(java.util.Date.class, new DateJsonValueProcessor("yyyy-MM-dd")); JSONArray jsonArray=JSONArray.fromObject(blogList,jsonConfig); result.put("rows", jsonArray); result.put("total", total); ResponseUtil.write(response, result); return null; }
    5.2.2 博客新建

    点击写博客进入博客发布界面,填写博客内容信息,点击发布博客,提交到控制层的save方法,传入参数:Blog,该参数包含了该博客所有信息内容,在提交的时候使用javascript对博客的内容进行校验。校验成功后便会调用控制层的方法,在控制层的save()方法中调用服务层的add()方法,对该博客进行保存,持久到数据库中。部分代码如下:
    @RequestMapping("/save") public String save(Blog blog,HttpServletResponse response)throws Exception{ int resultTotal=0; // 操作的记录条数 if(blog.getId()==null){ resultTotal=blogService.add(blog); blogIndex.addIndex(blog); // 添加博客索引 }else{ resultTotal=blogService.update(blog); blogIndex.updateIndex(blog); // 更新博客索引 } JSONObject result=new JSONObject(); if(resultTotal>0){ result.put("success", true); }else{ result.put("success", false); } ResponseUtil.write(response, result); return null;}
    5.2.3 博客修改

    进入博客修改页面,修改博客内容信息,点击发布博客,提交到控制层的save方法,传入参数:Blog,该参数包含了修改后的博客所有信息内容,在提交的时候使用javascript对博客的内容进行校验。校验成功后便会调用控制层的方法,在控制层的save()方法中调用服务层的update()方法,对该博客进行保存,持久到数据库中。部分代码如下:
    @RequestMapping("/save") public String save(Blog blog,HttpServletResponse response)throws Exception{ int resultTotal=0; // 操作的记录条数 if(blog.getId()==null){ resultTotal=blogService.add(blog); blogIndex.addIndex(blog); // 添加博客索引 }else{ resultTotal=blogService.update(blog); blogIndex.updateIndex(blog); // 更新博客索引 } JSONObject result=new JSONObject(); if(resultTotal>0){ result.put("success", true); }else{ result.put("success", false); } ResponseUtil.write(response, result); return null;}
    5.2.4 博客删除

    在博客管理页面选择需要删除的博客,点击删除按钮,提交到控制层的delete方法,传入参数:需要删除博客的id,调用控制层的方法,在控制层的delete()方法中调用服务层的delete()方法,对该博客或多个博客进行删除,持久到数据库中。部分代码如下:
    @RequestMapping("/delete") public String delete(@RequestParam(value="ids")String ids,HttpServletResponse response)throws Exception{ String []idsStr=ids.split(","); for(int i=0;i<idsStr.length;i++){ blogService.delete(Integer.parseInt(idsStr[i])); blogIndex.deleteIndex(idsStr[i]); // 删除对应博客的索引 } JSONObject result=new JSONObject(); result.put("success", true); ResponseUtil.write(response, result); return null; }
    5.3 博客类别管理模块5.3.1 添加博客类别

    在博客类别管理页面打开添加博客类别弹窗,填写博客类别名称和排序,点击保存按钮,提交到控制层的save方法,传入参数:需要添加的博客类型blogType,调用控制层的方法,在控制层的save()方法中调用服务层的add()方法,添加博客类别的相关信息,持久到数据库中。部分代码如下:
    @RequestMapping("/save") public String save(BlogType blogType,HttpServletResponse response)throws Exception{ int resultTotal=0; // 操作的记录条数 if(blogType.getId()==null){ resultTotal=blogTypeService.add(blogType); }else{ resultTotal=blogTypeService.update(blogType); } JSONObject result=new JSONObject(); if(resultTotal>0){ result.put("success", true); }else{ result.put("success", false); } ResponseUtil.write(response, result); return null; }
    5.3.2 修改博客类别

    在博客类别管理页面先选择要修改的数据,点击修改按钮,打开修改博客类别弹窗,填写修改后博客类别名称和排序,点击保存按钮,提交到控制层的save方法,传入参数:需要添加的博客类型blogType,调用控制层的方法,在控制层的save()方法中调用服务层的update()方法,修改博客类别的相关信息,持久到数据库中。部分代码如下:
    @RequestMapping("/save") public String save(BlogType blogType,HttpServletResponse response)throws Exception{ int resultTotal=0; // 操作的记录条数 if(blogType.getId()==null){ resultTotal=blogTypeService.add(blogType); }else{ resultTotal=blogTypeService.update(blogType); } JSONObject result=new JSONObject(); if(resultTotal>0){ result.put("success", true); }else{ result.put("success", false); } ResponseUtil.write(response, result); return null; }
    5.3.3 删除博客类别

    在博客类别管理页面先勾选上要删除的数据,点击删除按钮,提交到控制层的delete方法,传入参数:需要删除的博客类型的id(可以是多个),调用控制层的方法,在控制层的delete()方法中调用服务层的delete()方法,删除博客类别的相关信息,持久到数据库中。部分代码如下:
    /** * 删除博客类别信息 * @param ids * @param response * @return * @throws Exception */ @RequestMapping("/delete") public String delete(@RequestParam(value="ids")String ids,HttpServletResponse response)throws Exception{ String []idsStr=ids.split(","); JSONObject result=new JSONObject(); for(int i=0;i<idsStr.length;i++){ if(blogService.getBlogByTypeId(Integer.parseInt(idsStr[i]))>0){ result.put("exist", "博客类别下有博客,不能删除!"); }else{ blogTypeService.delete(Integer.parseInt(idsStr[i])); } } result.put("success", true); ResponseUtil.write(response, result); return null; }
    5.3.4 显示博客类别

    在打开博客类别管理页面时,调用控制层的list方法,传入参数:当前页数和每页数量,调用控制层的方法,在控制层的list()方法中调用服务层的list()方法,从数据库中查询到博客类别信息,然后将博客类别的相关数据渲染页面上。部分代码如下:
    @RequestMapping("/list") public String list(@RequestParam(value="page",required=false)String page,@RequestParam(value="rows",required=false)String rows,HttpServletResponse response)throws Exception{ PageBean pageBean=new PageBean(Integer.parseInt(page),Integer.parseInt(rows)); Map<String,Object> map=new HashMap<String,Object>(); map.put("start", pageBean.getStart()); map.put("size", pageBean.getPageSize()); List<BlogType> blogTypeList=blogTypeService.list(map); Long total=blogTypeService.getTotal(map); JSONObject result=new JSONObject(); JSONArray jsonArray=JSONArray.fromObject(blogTypeList); result.put("rows", jsonArray); result.put("total", total); ResponseUtil.write(response, result); return null; }
    5.4 评论管理模块5.4.1 审核评论
    博主在后台页面打开评论管理页面,选择需要审核的评论,点击审核通过按钮,调用controller层的review方法,controller层调用service层的update方法,将评论的状态字段改为对应的代表通过审核的1,如果点击不通过那就是2.然后调用dao层的update方法持久化到数据库中,相关的代码如下:
    /** * 评论审核 * @param comment * @param response * @return * @throws Exception */ @RequestMapping("/review") public String review(@RequestParam(value="ids")String ids,@RequestParam(value="state")Integer state,HttpServletResponse response)throws Exception{ String []idsStr=ids.split(","); for(int i=0;i<idsStr.length;i++){ Comment comment=new Comment(); comment.setState(state); comment.setId(Integer.parseInt(idsStr[i])); commentService.update(comment); } JSONObject result=new JSONObject(); result.put("success", true); ResponseUtil.write(response, result); return null; }
    5.4.2 删除评论
    博主在后台打开评论管理页面,选择需要删除的评论,点击删除按钮。调用controller层的delete方法,在其中的方法中调用业务逻辑层的实现方法,然后调用dao层的方法,最后持久化到数据库中,相关的代码如下:
    /** * 删除评论信息 * @param ids * @param response * @return * @throws Exception */ @RequestMapping("/delete") public String delete(@RequestParam(value="ids")String ids,HttpServletResponse response)throws Exception{ String []idsStr=ids.split(","); for(int i=0;i<idsStr.length;i++){ commentService.delete(Integer.parseInt(idsStr[i])); } JSONObject result=new JSONObject(); result.put("success", true); ResponseUtil.write(response, result); return null; }
    第六章 系统测试6.1 前台模块测试浏览器的网址输入框中输入正确的地址既可以看到系统前台页面:

    6.2 后台模块测试在前台首页可以点击登录后台按钮可以登录到后台管理页面,在后台管理页面可以进行博客管理,博客类别管理,评论审核和个人信息管理还有系统管理。但是首先要获取用户名和密码,拥有博主权限才可以进入到后台管理页面,首先输入用户名:admin,然后输入密码: 123。结果有两种,一种是密码正确成功登录,另外一种是不成功,登录失败,若是失败,则会在页面上打出红色字体:用户名或密码错误。

    登录成功后,可以进入到后台管理页面,在这个页面,博主可以管理博客,可以新增博客,可以删除修改博客,也可以管理评论等等。


    点击发布博客按钮,发布成功。
    第七章 总结经过了几个月的辛苦,个人博客系统基本完成。从最开始的束手无策,经过了老师和同学们的帮助下慢慢进入状态。历经了很多辛苦和难点,都一一针对性的去解决,一步一步脚踏实地慢慢对待,现在完成了毕业设计,我在这个过程中学习到了很多,发现了自己在技术上的不足和缺点。我在毕业设计中留下许多美好的回忆和感动。
    首先,在选题上我的导师给予很大的帮助。还有在遇到难点的时候我的同学给予了我很多帮助。而在完成了毕业设计后,我还感觉到了许多的不足之处。例如我的博客系统还可以添加许多功能,可以添加多用户之类的。所以在接下来的日子里,我需要更加努力的学习。
    参考文献[1] 李洋. SSM框架在Web应用开发中的设计与实现[J]. 计算机技术与发展,2016,(12):190-194.
    [2] 蒋启明,彭小宁,张文. “轻量级Java EE”课程的Spring框架教学改革探讨[J]. 科教文汇(中旬刊),2016,(11):57-58.
    [3] 马杰川. 基于JSP的企业Blog系统的设计与实现[D].电子科技大学,2013.
    [4] 韦耿,钟亮. 基于JSP的个人博客系统[J]. 电脑知识与技术,2013,(21):4865-4869+4876.
    [5] 杨嘉群. 基于JSP的博客系统[J]. 电子制作,2013,(09):68-69+32.
    [6] 祁新安,李凯. 基于JSP的多媒体博客系统的研究[J]. 电脑开发与应用,2013,(04):33-35.
    [7]尚云龙. 关于网络博客系统的设计与实现[D].电子科技大学,2013.
    [8] 邬心云. 日志式个人博客的自我呈现心理研究[D].华中科技大学,2012.
    [9] 何发胜. 基于SSH模式架构的博客系统的设计与实现[D].湖南大学,2012.
    [10] 崔程,张钦. 一种基于JSP技术的博客系统设计[J]. 安阳师范学院学报,2011,(05):93-95.
    [11] 郭向阳,李红娟. 基于JSP技术的都市博客系统的设计与实现[J]. 软件导刊,2010,(10):151-152.
    4 评论 168 下载 2020-07-18 14:51:08 下载需要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 分类管理点击我的群组界面,可以查看群组并且显示群组。在里面可以对群组进行增删改查操作。
    112 评论 412 下载 2019-01-30 17:27:39 下载需要13点积分
  • 基于Java的飞机大战游戏的设计与实现

    摘 要现如今,随着智能手机的兴起与普及,加上4G(the 4th Generation mobile communication ,第四代移动通信技术)网络的深入,越来越多的IT行业开始向手机行业转移重心。而手机行业中游戏方面的利润所占比重较大,并且手机游戏大多数则是由Java语言开发研制的。所以我想顺应时代发展,用学到的Java知识对游戏进行一次深入的了解与创作。
    Java语言在我们大学学习中占了很大的比重,其优点甚多:面向对象,可靠,安全,多平台可移植,高性能,多线程等。面向对象是相对于c语言的面向过程来说的,在面向对象编程中,我们用Java去新建一个对象,调用其方法就能实现我们的目标,并不需要了解这个对象的方法的具体实现过程;Java的可靠安全特点体现Java不支持指针,禁止第三方访问,杜绝了外部风险。所以使用Java开发游戏,是一个正确的选择。
    大学学习即将结束,在毕业之际,我想用我4年里学习的知识为自己编写一个属于自己的游戏——飞机大战游戏,为我的大学生活画上圆满的句号。
    关键词:Java游戏;面向对象;可靠安全;多线程
    AbstractNowadays, with the emergence and popularization of smart phones, plus 4 g (the 4 th Generation mobile communication, the fourth Generation mobile communication technology) the development of the Internet, more and more in the IT industry began to shift to the mobile phone industry center of gravity. Aspect of the game of the mobile phone industry profits account for a large proportion, and most mobile game is developed by Java language. So I want to keep up with the development of The Times, use Java knowledge for an in-depth understanding of the game and creation.
    Java language learning in our universities accounted for a large proportion of its many advantages: Object-oriented, reliable, secure, multi-platform portable, high-performance, multi-threading. Object-oriented process-oriented with respect to the terms of the c language, object-oriented programming, specifically we use Java to create a new object, call its methods will be able to achieve our goal, we do not need to know the object’s method of implementation ; reliable safety features reflect Java Java does not support pointers to prohibit third-party access, to eliminate the external risk. Therefore, the use of Java development aircraft war game, is the right choice.
    University coming to an end, on the occasion of the graduation, I want to use my four years studying knowledge and made themselves a game of their own - Aircraft war game for my college life painting satisfactory conclusion.
    Keywords: Java game; object oriented; reliable and secure; multi thread
    1 引言1.1 项目背景90后的我们,童年最开始接触电子游戏是在游戏厅,那时候的飞机大战游戏机前,往往人山人海,绚丽多彩的画面,带感操作让人沉醉不能自拔。再后来,珍珠港(Pearl Harbor),虎虎虎(Tora! Tora! Tora!)等空战电影中激烈的空战和飞机在天空中的英姿让我彻底爱上了空战,所以毕业设计我选择了与飞机战斗有关——基于Java的飞机大战游戏的设计与实现的毕业设计。
    而选基于Java的飞机大战游戏的设计与实现为题,是对大学期间学到知识的一次实践运用,也是对自己大学四年学习成果的一次检验。
    柏拉图:“游戏是一切幼子生活和能力跳跃需要而产生的有意识的模拟活动。”亚里士多德给游戏的定义是:“游戏是劳作后的休息和消遣,本身并带有任何目的性的一种行为活动。”可以说,游戏是一种一直存在的社会现象,有了人类就有了游戏,人类与游戏息息相关。游戏也随着人类的进步有了新的发展。
    PC机刚开始普及的时候,游戏并不能被广泛接受。最主要的原因就是不能充分发挥PC机的性能,即游戏程序不能最大化使用PC机的硬件资源,导致PC机的早起游戏画面差,操作感僵硬,可玩度不高,所以不被人们所接受。但是随着切硅的技术的提升导致CPU性能的飞跃及Java语言的开发,游戏程序对硬件资源的利用率的提高,现在游戏的各个方面都有了质的飞跃。比如20世纪末,暴雪公司下的《星际争霸1》掀起全球星际流,其操作感和画面打击感及游戏可玩性都有很大的提升。当然,除了游戏本身的优秀质量以外,可以较广的支持不同的硬件设备的功能也不容忽视,高中低端PC机都有不错的流畅度。
    而飞机大战类游戏中起步较早的还要数由日本公司Cyber Front研制并发行的雷电系列,该系列操作简单,节奏明快,因此,可以说成是飞机大战游戏类的经典之作。该系列下的《雷电3》在2016年中旬从PS2平台移植到PC机平台上后,更成为当时风靡一时的游戏。
    《雷电3》一共有8个关卡,分别是病变的森林,玄武岩城市。岩石港湾,金色的沙漠,原子核工厂,小行星带,大型宇宙舰和地方总部。雷电3的关卡不多,而且流程比较短,所以主要还是以刷新分数上限,挑战操作极限的目的为主,考验玩家的手速和反应能力,是一款极为经典的游戏,即使过去了十几年,《雷电3》仍然广受欢迎,各大应用商店的点击下载量还是很高,衍生出来的游戏更是数不胜数。
    1.2 国内外研究现状Java语言经过多年的发展,已经十分成熟。Java语言称霸企业级应用这门多年的事实证明了这门语言适合开发各种项目。当Java语言的运行效率随着发展再次提升了一大截后,Java语言的一系列优势就更加明显的体现出来了,比如:语言严谨,高抽象,可读性强等。
    对于游戏开发,由于涉及到各种复杂的问题情况,经常遇到新的问题,所以在开发过程中,需要进行对代码进行不断的修改添加,这就需要可以随时随地的修改代码。而Java具有虚拟机特性,Java游戏本身也可以用Java来写,例如,目前的BeanShell,Groovy和其他脚本语言可以很容易地,无缝地与Java语言的互动,我们可以通过脚本随时对游戏进行添加与删除,不必要重新开发某个模块。这是大大方便了Java游戏编程。
    在游戏的发展中涉及到了大量的Java技术,某些技术现在已经淘汰,但是也有些技术一直在使用。如Sun公司较早推出了3D技术— Java3D,是一个高度封装的API,OpenGL和Direct 3D都是基于Java3D的,可以说是最有名的3D Java技术;Jogl函数则是opengl接口对Java的实现;lwjgl函数(light weight Java game library)是将游戏图形(opengl)、音效(openal)、控制输入集合为一,以成为Java界的directx(不是direct3d)而努力;joal函数则是Java对openal的一个绑定,是Java音效的一个解决方案;jinput函数是Java对非标准输入设备(游戏手柄,操纵杆)的解决方案; Project Wonderland是Sun开发的一个3d虚拟世界构建工具等。
    由于VR(Virtual Reality)虚拟现实的发展,对游戏的发展影响巨大。科幻电影小说中的科幻游戏玩法有可能成为现实,未来游戏也许不需要鼠标键盘,只需要一个类似VRBox的头盔设备即可完成指令的输入与输出。
    1.3 项目主要工作本次项目的题目——基于Java的飞机大战游戏的设计与实现,主要目的是实现飞机大战这个游戏。期望结果:游戏无BUG(现在人们将在电脑系统或程序中,隐藏着的一些未被发现的缺陷或问题统称为BUG——漏洞),简单易上手,老少皆宜,让玩家“玩不释手”。
    从游戏的玩法来说,主要就是我方飞机(Hero airplane)和敌方飞机(Enemy airplane)的对决,首先是游戏的开始界面与结束界面,然后就是我方飞机(Hero airplane)的移动方式(鼠标移动或者键盘移动,我打算选择鼠标移动,因为鼠标移动可以转移到手机上,现在大多数手机都没有键盘,基本靠手指滑动操作),接下来就是我方飞机(Hero airplane)子弹的生成,然后是敌方飞机(Enemy airplane)的出现坐标的选择,然后飞机与子弹防碰撞,飞机与飞机的防碰撞,最后是我方飞机(Hero airplane)与敌方飞机(Enemy airplane)的对战结果。
    该游戏要满足以下功能性需求:

    游戏状态控制功能:游戏的状态控制包括运行、暂停、恢复及结束游戏,首先是游戏的开始页面,在游戏正在进行时,如果你有其他的事情又不想结束游戏你可以将鼠标移出游戏界面或者鼠标在游戏界面单击即可暂停游戏,当你的其他事情解决后你还可以选择恢复游戏,继续玩下去,当游戏结束时会显示游戏结束界面
    游戏难度的调整:玩家随着玩游戏的时间的增加,敌方飞机的数量会增加,出现的频率会有所提高,移动速度也会提高
    游戏界面绘画功能:在右上角显示游戏时间(游戏难度于时间成正比,即游戏时间越长难度越高),玩家游戏得分,与我方飞机生命值,游戏主屏用来显示玩家对我方飞机(Hero airplane)的控制与敌方飞机(Enemy airplane)的出现及移动的显示
    玩家游戏控制功能:玩家可以通过控制移动鼠标或者键盘来控制友机的移动

    1.4 本文组织结构本文的组织结构如下:

    第一部分介绍了本文的国内外背景
    第二部分介绍了开发游戏项目涉及到的软件平台与开发语言
    第三部分介绍了项目的需求分析
    第四部分介绍了项目各个模块的实现
    第五部分介绍了对软件测试的过程及结果,找到项目的优缺点

    2 开发平台与开发技术本章主要介绍软件开发平台如何选择。本软件涉及到的开发平台是IntelliJ IDEA,开发技术是Java技术。下面将会介绍一下选择IntelliJ IDEA的理由。
    2.1 IntelliJ IDEA简介IntelliJ IDEA是一个Java的 集成开发环境(IDE),用于开发各种项目的计算机软件。它是由JetBrains公司(原名的IntelliJ)开发的,个人版被Apache 2授权许可,商业版则是作为专业版,可以用来进行大型的商业开发。
    IntelliJ IDEA的第一个版本发布于2001年1月,并且是第一个具有先进的代码导航和一个代码重构的综合能力的Java IDE。
    IntelliJ IDEA对于系统的要求:微软的Windows 10/8/7 / Vista/ 2003 / XP(incl.64位),最少1 GB内存,2 GB RAM(推荐),300 MB硬盘空间+至少1 GB的高速缓存,1024×768的最小屏幕分辨率。
    IntelliJ IDEA特点:

    编码提示:IDE可以进行代码提示,比如:结合上下文对当前代码进行补充;代码导航,可以快速定义到某个声明过的类;代码错误提示,对于代码错误的地方进行提示并且提供有效的解决方案
    内置工具和整合:IDE提供了构建与打包工具,如grunt , bower , gradle , 和 SBT 。它支持各个版本的控制系统,如 GIT , Mercurial , Perforce , and SVN 。可以直接从IDE对SQL Server,ORACLE,PostgreSQL和MySQL数据库进行访问
    各种各样的插件系统:IntelliJ IDEA支持插件,通过插件可以对IDE添加额外的功能。无论是从IntelliJ IDEA的插件库网站或通过IDE的内置插件,都可以进行搜索插件和插件的安装。目前的IntelliJ IDEA个人版则拥有1495个可用的插件,其中IDE的旗舰版则拥有1626个可用的内置插件

    2.2 IntelliJ IDEA与Eclipse 的比较我们大学学习中,对于Java的开发工具一般都是选择 Eclipse,MyEclipse开发工具。Eclipse是Sun公司自己开发的Java开发工具,优点在于简洁没有插件,用户可以根据自己的需求自己寻找安装合适的插件,同时这也是它的缺点,没有提供插件,某些开发就会让人感觉不方便,并且插件都是个人开发,并不是适合所有人。MyEclipse则需要收费(虽然网上有破解版,但是并不提倡,支持正版从你我做起),它实际上是将eclipse和其他常用插件集成在一起的一个庞大开发工具,优势就是常用插件齐全,不用自行下载安装,当然支持自己扩展,劣势就是插件太多导致软件繁重,运行时占用系统太多资源,当然他是收费的(对于学生来说这个是致命的)。
    IntelliJ IDEA更为优秀的原因是:IntelliJ IDEA更为智能,更贴合用户。以下进行详细说明。

    调试:作为调试过程的一部分,我们通常希望选中一些表达式来查看它的值。在Eclipse中,你需要选择这种表达,并且准确选择整个表达式是很重要的,否则在Eclipse中无法评估它。在IntelliJ IDEA中,你只需按下有关快捷键,即可看到表达式的值
    自动完成:自动完成功能的好坏是区分任何IDE的标杆。在这方面的感觉的背景下,IntelliJ IDEA则有一个定性的优势。IntelliJ IDEA不等待任何按键,比如,当你输入一个方法函数是,它立刻会明白方法函数希望将某个定义过的类作为第二个参数,这时会有一个静态变量在类名处呈现可见状态。对于用户来说,提供建议和想法是一个的确不错的做法。但是Eclipse做不到,Eclipse只能理解你当前输入的字符,并不能与前边的联系起来
    重构:专业编程人员如果利用IntelliJ IDEA的IDE提供的重构将会事半功倍。所有IDE提供了一个用处非常大的重构。但话又说回来,IDEA的重构是非常智能的。它知道你想要什么,并提供了大多数情况下适用的不同的建议选项

    如果我们选择一个Java IDE作为开发工具,那么IntelliJ IDEA肯定比Eclipse的更好。这不只是一个个人品味的问题。客观来说IDEA的确是第一选择,它可以让你快速,方便地编写和修改代码,建议适当的函数,提供适当的方法。它不要求你准确选择表达式,但会猜测你想要做什么。
    2.3 JavaJava是一个通用计算机编程语言,是并发的,类型,面向对象的。它的目的是让应用程序开发者“一次编写,到处运行”,也就是说Java可以在任何设备上开发,也可以在任何装有Java虚拟机(JVM)设备上运行,而无需再次编译。
    Java应用程序通常被编译成字节码可以在任何装有Java虚拟机上(JVM)的计算机体系结构上运行。截至2016年,Java是最流行的编程语言之一,特别是对于客户端,服务器的Web应用程序,有报道称有900万开发者在使用Java语言进行开发。Java是由詹姆斯•高斯林在Sun Microsystems(这已经被甲骨文公司收购)创造的,并于1995年发布,作为Sun Microsystems的Java平台的核心组件开发,Java语言多从C和C ++中语法派生出来的。
    最初有Sun公司对参考实现Java的编译器,虚拟机和类库下发专用许可证。截至2007年5月,按照Java社区进程的规章制度,SunRelicensed GNU下大部分的Java技术都在通用公共许可证下。其他人也开发了Java软件替代和实现了Sun公司下的一些技术,如GNU Java编译器(字节码编译),GNU Classpath(标准库)和IcedTea项目的Web(浏览器插件小程序)。
    目前(2016年6月)Java的最新版本是第8个版本,这是目前Oracle支持免费的唯一版本,单早期版本都是由甲骨文等公司在商业基础上的支持的。
    詹姆斯•高斯林,迈克•谢里登和帕特里克•诺顿启动Java语言项目是在在1991年6月,Java最初设计则是用于交互式电视,但它相对于在当时的有线数字电视产业过于超前。后来该项目又由名称Green并最终改名的Java,从Java咖啡(来自爪哇的一种咖啡)得名。高斯林设计的Java与C / C ++ 语法风格相似,系统和应用程序的程序员会发现二者有很大程度的相似点。
    Sun Microsystems公司在1995年发布了第一个公开的实行版本Java 1.0,它承诺“一次编写,到处运行”(WORA)。其相当安全,并设有配置的安全标准,它对网络和文件实行访问限制。主流浏览器很快将Java程序的能力纳入到网页中运行,导致Java迅速走红,然而大多数是外面的浏览器,但是这并不是原来的计划,所以在2016年1月,甲骨文宣布,基于JDK 9 Java运行时环境将不再支持浏览器插件。Java 1.0编译器由亚瑟•范•霍夫重新用Java编写,严格遵守Java 1.0语言的规范。Java 2,新的版本可以在不同类型的平台搭建不同的配置。 J2EE包括面向企业级应用的技术和通常在服务器环境中运行的API,而J2ME对API功能的移动应用进行了优化,桌面版改名为J2SE。在2006年,出于营销目的,将新版本J2分别命名为Java EE,Java ME,和Java SE。
    1997年,Sun Microsystems加入ISO/ IEC JTC 1标准组织,后来的ECMA国际组织要求Java正式化,但它很快就从组织中退出了。但Java仍然是一个事实上的标准,控制Java社区的标准。2006年11月13日,Sun在GNU通用公共许可证(GPL)条款支持下将其Java虚拟机(JVM)公布于众。2007年5月8日,Sun完成了开源的所有过程,在自由软件/开源分发条款下放出了它所有的JVM的核心代码,除了从Sun未持有版权的小部分代码。2010年4月2日,詹姆斯•高斯林(Java的主要创始人)从甲骨文公司辞职。
    3 可行性研究可行性研究顾名思义,研究其的可行性。可行性研究是项目开发之前的重要阶段。在软件开发实践中,软件开发人员或者用户对市场的了解不充分,对技术的掌握不好,对进行开发的各项风险评估不足等因素,有些问题不能再预期下得到解决,造成不可预估的损失,为了避免盲目的软件开发和不必要的损失,相关人员需要对开发特定软件项目的可行性进行研究,结合资金、时间和环境等各方面的制约条件,对该软件产品是否能够解决存在的问题,是否能够带来预期的效果和价值做出评估。
    3.1 技术可行性现在开发游戏的语言一般都是Java语言,为了保证开发出来的游戏可以在手机、Web浏览器、PC客户端等平台使用,所以就要求开发语言可以在多平台移植,而Java语言刚好符合这个特性。开发工具IntelliJ IDEA可以下载并且可以免费使用,Java的编译工具JDK也可以在Sun官网上直接下载安装,其过程十分简单。
    3.2 经济可行性配置较低的电脑也能进行Java游戏的开发,一台电脑就行,开发成本低。由于Java具有跨平台以及一次编译,到处运行的特点,开发出来的游戏可以放到各大游戏平台上发售,玩家可以在电脑,浏览器,手机等各种平台运行。而且软件维护简单,实用性强,一次开发使用,即可长久使用,当软件满足不了用户需求时,只需对用户的需求进行添加即可。
    3.3 操作可行性本游戏操作简单,在电脑和浏览器上可以用鼠标键盘操作,在手机上可以用手触摸屏幕运行。
    3.4用户使用可行性本软件操作简单,对用户的要求,不需要多强技术能力。
    3.5 法律可行性信息产业部已将游戏通用引擎研究及示范产品纳入国家“863计划”,这是中国首次将游戏技术纳入国家科技计划当中。
    4 需求分析需求分析是对即将开发的系统确定一个完整的,准确的要求。需求分析的结果是否完美解决了用户的问题,将直接影响到后面的进程,并影响到设计结果是否能让用户接受。软件需求分析对软件系统提出了清楚、准确、全面而具体的要求,是对软件使用者意图不断进行揭示与准确判断的过程,它并不考虑系统的具体实现,而是严密地、完整地描述了软件系统应该做些什么的一种过程。
    4.1 系统需求概述飞机大战主要需要我方飞机和敌方飞机,还有子弹,特殊nPC,开始背景,结束背景,以及背景音乐。我方飞机可以随意移动,敌方飞机无规律出现。游戏玩家通过鼠标移动控制飞机移动,我方飞机在游戏开始时就一直能发射子弹,当我方子弹碰到敌方飞机时,敌方飞机消失。当玩家飞机碰到敌方子弹时,生命值减一,直到玩家飞机生命值为一时,游戏结束。
    基于Java的飞机大战游戏的设计与实现有以下几个模块:

    游戏状态控制功能模块
    游戏难度的调整模块
    游戏界面绘画功能模块
    玩家游戏控制功能模块

    4.2 功能模块设计4.2.1 游戏状态控制功能模块游戏的状态控制包括运行及结束游戏,首先进入游戏的开始页面,在游戏进行时,玩家必须躲避或者击落敌方飞机,玩家飞机的生命值降低为0的时候游戏就会结束,弹出游戏结束界面。
    4.2.2 游戏难度的调整模块玩家玩的时间越长游戏的难度越高,敌方飞机的数量越多、敌方飞机出现的频率越高,玩家保证飞机的存活的难度越高,操作难度相应也高。
    4.2.3 游戏界面绘画功能模块左上角会显示玩家飞机当前生命值,游戏时间,当前分数,其他地方用来输出玩家对我方飞机的控制与敌方飞机的动作显示。
    4.2.4 玩家游戏控制功能模块玩家可以通过控制鼠标或者键盘来控制方飞机(Hero airplane)的移动。
    4.3 游戏难点分析4.3.1 绘图美化清新靓丽的游戏界面将给用户带来愉悦的美感。因此,在这个游戏中,主要参考原始的游戏画面,敌我飞机的形象也应该是美丽的。
    4.3.2 多线程技术的实现应用程序线程机制的基石,实现了游戏,游戏的刷架的控制,装上各种角色的资源和背景(如飞机,机友)的要求,以实现整个游戏实现自动控制线程 控制。
    4.3.3 防碰撞问题的解决例如,敌方飞机与玩家飞机防碰撞,敌方飞机与玩家飞机防碰撞,等等。防碰撞检测技术实现在不同情况下,有不同的防碰撞检测方法。
    4.3.4 动画的实现用图片的阵列,动画切片变换形成。图像阵列,千变万化的图像画在画布标,使动画,这是一个图像的形成阵列。使用切片来实现动画,所有的帧都放置在相同的图像中,以达到爆炸的效果。
    5 飞机大战功能实现5.1 模型图
    5. 2 软件功能模块
    5.3 游戏首页的实现5.3.1 界面实现飞机大战的界面如图1-3所示。

    5.3.2 流程图游戏开始的流程图如图1-4所示。

    5.3.3 核心代码游戏初始化代码
    \** 写于3月20日,主要目的:完成游戏的初始化过程*\public final void paint(Graphics g) { g.setColor(this.bgColor); g.fillRect(x, y, width, height); g.setColor(this.fgColor); g.drawRect(x, y, width, height); this.paintBoxContents(g);}private void paintBlock(int x, int y, int blockType, Graphics g) { int blockX = this.boardX + (this.blockSize * x); IntblockY=this.boardY+(this.blockSize*(y-TetrisConstants.TOP_VISIBLE_ROW)); if(TetrisConstants.BLOCK_EMPTY != blockType) { g.setColor(TetrisConstants.COLOR_BLACK); g.fillRect(blockX + 1, blockY + 1, this.blockSize - 1, this.blockSize - 1); this.setColor(blockType, g); g.fillRect(blockX, blockY, this.blockSize - 1, this.blockSize - 1); } else { g.setColor(TetrisConstants.COLOR_WHITE); g.fillRect(blockX, blockY, this.blockSize, this.blockSize); }}
    5.4 游戏开始模块的实现5.4.1 界面实现飞机大战的开始界面如图1-5所示。

    5.4.2 流程图流程图如图1-6所示。

    5.4.3 核心代码游戏开始模块的功能代码
    \** 写于3月27日,主要目的:完成游戏的开始界面*\private int clearCompletedRows(TetrisPiece piece) { TetrisBoard board = this.getBoard(); for(int i = 0; i < TetrisConstants.FOUR_BLOCKS; i++) { int rowY = piece.getBlockY(i); if(board.checkRowCompleted(rowY)) { this.markRowCompleted(rowY, true); } } int numClearedRows = 0; for(int y = TetrisConstants.HEIGHT - 1; y >= 0; y--) { if(numClearedRows > 0) { board.dropRow(y, numClearedRows); } if(this.isRowCompleted(y)) { numClearedRows++; this.markRowCompleted(y, false); } } for(int i = 0; i < numClearedRows; i++) { board.clearRow(i); } return numClearedRows;}
    5.5 发射子弹模块的实现5.5.1 界面实现发射子弹界面实现如图1-7所示。

    5.5.2 流程图流程图如图1-8所示。

    5.5.3 核心代码发射子弹实现代码
    \** 写于4月5日,主要目的:完成游戏的子弹的自动发射*\public void rotate(int pivotX, int pivotY, boolean rotateDirection) { if(TetrisConstants.ROTATION_TYPE_TOGGLE == this.rotationType) { // 如果翻转类型为TOGGLE rotateDirection = this.rotationToggle; //判断翻转方向 this.rotationToggle = !this.rotationToggle; // 如果与canRotate匹配,中心点方块将被使用 } // 重构四个小块,每个都转动 for(int i = 0; i < TetrisConstants.FOUR_BLOCKS; i++) { int blockX = this.getBlockX(i); int blockY = this.getBlockY(i); // 左旋转:交换x和y坐标,x坐标取反 // 右旋转:交换x和以坐标,y坐标取反 int dx = blockY - pivotY; int dy = blockX - pivotX; if(rotateDirection) { // 如向左旋转 dx *= -1; } else { // 如向右旋转 dy *= -1; } int rotateX = pivotX + dx; int rotateY = pivotY + dy; this.setBlockCoords(i, rotateX, rotateY);//得到翻转后的新坐标 }}
    选中敌机目标后,开始发射子弹。在TetrisBoard.Java中的checkRowCompleted()方法实现了此功能,其代码如下:
    public boolean checkRowCompleted(int rowY) { for(int x = 0; x < TetrisConstants.WIDTH; x++) { if(TetrisConstants.BLOCK_EMPTY == this.getBlockType(x, rowY)) { // 选中目标,发射子弹 return false; } } return true;}
    当击中敌机后,积分就会有所变化,计算并显示出用户当前的分数。同时等待玩家键入数字,选择游戏难度开始新的游戏。其实现由init()方法控制,其代码如下:
    \** 写于4月12日,主要目的:完成游戏的难度选择*\private void init() { this.board = new TetrisBoard(); this.gameCanvas = new TetrisCanvas(this); this.activePiece = new TetrisPiece(); this.completedRows = new boolean[TetrisConstants.HEIGHT]; //初始化数组 this.hiScore = this.openAndReadHiScore(); this.nextPieceType = TetrisConstants.UNINITIALIZED; this.rand = new Random(); // 设置exit/pause/resume命令 this.setuPCommands(); this.gameCanvas.addCommand(this.exitCommand); // 显示title屏 this.setGameState(TetrisConstants.TITLE_STATE);}
    5.6 积分模块的实现5.6.1 界面的实现飞机大战积分模块界面如图1-8所示。

    5.6.2 核心代码积分板实现代码如下:
    \** 写于4月16日,主要目的:完成游戏的积分模块*\public void drawCount(Graphics g){ g.setColor(Color.white); Font font = new Font("宋体", 1, 20); g.setFont(font); g.drawString("积分:" + this.score, 0, 470); }
    实现积分的增长
    if (burst != null) burst.draw(g_off);for (int i = 0; i < list.size(); i++) { Role chara1 = (Role) list.get(i); if (chara1.isDead()) { if (chara1 instanceof Enemy) { chara1.drawBurst(g_off); this.battle.score++; } list.remove(i); }}
    全屏爆炸时,计算炸死几个敌人增长分数
    if(GamePanel.skillCount>0){ for (int i = 0; i < GamePanel.list.size(); i++) { Role chara1 = (Role) GamePanel.list.get(i); if(!(chara1 instanceof Battle) && chara1.x>0 && chara1.y>0 && !(chara1 instanceof BossA) && !(chara1 instanceof BossB) && !(chara1 instanceof BossC)){ GamePanel.list.remove(i); if(chara1 instanceof Enemy){ this.score++; }
    实现积分的输出
    private void gameOver() { GamePanel.skillCount = 10; if (Key.enter) { gameMode = 12; stage = 1; } else { g_off.setColor(Color.white); Font font = new Font("黑体", 1, 28); g_off.setFont(font); FontMetrics fontMetrics = getFontMetrics(font); g_off.drawString("Game Over", (450 - fontMetrics.stringWidth("Game Over")) / 2, (500 + fontMetrics.getHeight()) / 2 - 50); String score = "Score: " + this.battle.score; g_off.drawString(score, (450 - fontMetrics.stringWidth(score)) / 2, (500 + fontMetrics.getHeight()) / 2 - 20); if (15 <= current % 50) g_off.drawString("请按 回车", (450 - fontMetrics.stringWidth("请按 回车")) / 2,(500 + fontMetrics.getHeight()) / 2 + 100); } }
    5.7 防碰撞逻辑判断飞机是否中弹的逻辑非常简单就是在绘制飞机与子弹的时候判断两个图片是否存在重合的部分,如果存在则玩家生命值减一,之后将中弹飞机从飞机队列中删除,子弹同样的处理。
    5.7.1 核心代码防碰撞逻辑核心代码
    \** 写于4月24日,主要目的:完成游戏的防碰撞模块*\public boolean checkHit(Role chara) { if ((chara instanceof EnemyA) || (chara instanceof EnemyB)|| (chara instanceof EnemyC) || (chara instanceof EnemyShot)) { if ((x + WIDTH) - 14F > chara.x && x + 14F < chara.x + chara.WIDTH && (y + HEIGHT) - 12F > chara.y && y + 12F < chara.y + chara.HEIGHT) { //如果碰到敌人,敌人死亡 chara.dead(); //如果碰到子弹血量减少 if (chara instanceof EnemyBeam){ power--; } power -= 50; if (power <= 0) { dead(); //绘制爆炸图片 GamePanel.burst = new Burst(x, y); } return true; }
    5.8 游戏操作的实现本游戏操作采用鼠标/键盘的移动来实现玩家飞机的移动。
    5.8.1 核心代码游戏操作实现代码
    \** 写于4月23日,主要目的:完成游戏的游戏操作*\public void move() { oldx = x; oldy = y; if (Key.left) { if (Key.xkey) x -= (double) speed / 4D; else x -= speed; if (x <= 0.0F) x = 0.0F; } if (Key.right) { if (Key.xkey) x += (double) speed / 4D; else x += speed; if (x + WIDTH >= (float) app.getWidth()) x = (float) app.getWidth() - WIDTH;} if (Key.down) { if (Key.xkey) y += (double) speed / 4D; else y += speed; if (y + HEIGHT >= (float) app.getHeight()) y = (float) app.getHeight() - HEIGHT; } if (Key.up) { if (Key.xkey) y -= (double) speed / 4D; else y -= speed; if (y <= 0.0F) y = 0.0F; }
    5.9 特殊NPC蜜蜂\** 写于4月30日,主要目的:完成游戏的特殊NPC的添加*\package com.tarena.fly;import Java.util.Random;/**蜜蜂*/public class Bee extends FlyingObject implements Award{ private int xSpeed=1;//x坐标移动速度 private int ySpeed=2;//y坐标移动速度 private int awardType;//奖励类型 /**初始化数据*/ public Bee(){ this.image=ShootGame.bee; width=image.getWidth(); height=image.getHeight(); y=-height; Random rand=new Random(); x=rand.nextInt(ShootGame.WIDTH-width); awardType=rand.nextInt(2);//初始化时给奖励 } /**获得奖励类型*/ public int getType(){ return awardType; } /**越界处理*/ @Override public boolean outOfBounds(){ return y>ShootGame.HEIGHT; } /**移动,可斜着飞*/ @Override public void step(){ x+=xSpeed; y+=ySpeed; if(x>ShootGame.WIDTH-width){ xSpeed=-1; } if(x<0){ xSpeed=1; } }}
    6 系统测试测试是处在开发阶段的最后部分,是保证软件质量的重要手段。软件测试是一个软件应用程序或一个所谓的条件处理和评估在控制条件(包括正常条件和非正常条件)下操作并评价其结果的过程。软件测试过程中应当故意诱导程序发生错误,正常情况下它虽然不应该存在,但是不确定它有可能在任何时候出现。从本质上说,软件测试是“探测”发现“探针”的问题。
    6.1 测试的定义及其重要性6.1.1 测试的定义软件测试是一项为了给利益相关方提供有关产品质量或者是正在测试的服务的信息而进行调查的过程。软件测试也可以提供一个客观,独立的视角来看待软件,以便让企业知晓并理解软件实现过程中可能存在的风险。软件测试技术是一种带着为了发现软件或者程序的BUG(错误或者其他的缺陷)的态度来运行一个程序或者应用的过程。
    软件测试涉及一个软件组件或系统组件的执行,以评估所关注的对象的一个或多个属性。在一般情况下,这些属性表明该组件或系统被测试的程度:

    满足其设计和发展的需要
    对各种输入进行正确的相应
    在用户可容忍的时间内实现其功能
    所有功能都能满足使用
    可以在预定的环境中完美安装并运行
    可以实现如其利益相关者所期望的正常结果

    由于即使对简单的软件组件所进行的测试数量都是数量巨大的,所有的软件测试都运用一些策略去挑选那些无论在时间是对资源都是合适的测试用例。其造成的结果是,软件测试通常(但也不排除其他情况)尝试着带着为了发现软件BUG(错误或者其他的缺陷)的态度来运行一个程序或者应用。当BUG不被解决时,需要反复进行软件测试的工作。它可能解决其他更深层次的BUG,但也可能会使得程序出现新的BUG。
    软件测试可以为用户和赞助商提供有关软件质量和可能存在的风险等级的信息。当然,这种信息是相对客观,独立的。
    软件测试可以为用户和赞助商提供有关软件质量和可能存在的风险等级的信息。当然,这种信息是相对客观,独立的。例如,例如,在软件开发的不同阶段,大部分的测试工作总是在系统需求已经被明确定义时才开始的,然后在测试过程中实现。与此相反,Agile(敏捷开发,是一种对于经常被用于在线应用程序的开发模型的涵盖性术语)方法下,需求,分析,编程和测试经常同时进行。
    6.1.2 测试的重要性尽管测试可以在某些特定假设的前提下,确定了软件的正确性,但是测试还是不能找出软件中所有的缺陷。相反,有些人也许可能会注意到这些问题,它对产品的申明和行为进行评论或与其他产品对照比较,看是否违反了Oracle公司的原则。这些Oracle的原则可能包括(但不限于)规范,合同,类似的产品,过去同一版本的产品,预期的计划或预期的目的,用户或客户的期望,相关标准,适用法律或其他标准。
    测试的主要目的是检测软件故障,使得缺陷被发现并且纠正。测试不能证明在所有条件下,软件或者程序都能正常的运行,它只能检测到在某种特定情况下,软件或者程序不能正常工作。软件测试的范围通常包括代码的检查以及在各种环境和条件的代码的执行情况以及检查的代码功能:什么是它应该做的,如何让它做需要它做的。在软件开发的当前环境中,检测团队可以独立于开发团队之外。从软件测试得出的信息可被用来校正开发软件的过程,防止出现无法挽回的错误。
    每个软件产品都有一些特定的用户。例如,用户对视频游戏软件和银行软件有完全不同的看法。因此,当一个组织开发或以其他方式投资一个软件产品时,软件测试可以评估它的最终用户,购买者或者其它利益相关者是否会接受该软件产品。软件测试是试图评估这一信息的过程。
    并非所有的软件缺陷是由编码错误引起的。往往因为一些错误会付出巨额的代价,这些错误常见的原因之一就是出现在需求方面,例如,程序员没有完全理解需求,从而导程序设计开发时与用户出现分歧。需求的差距往往来自非功能性需求,如可测试性,可扩展性,可维护性,可用性,性能和安全性。
    软件故障,在下述情况是发生:程序员犯了一个错误(失误),这将导致在本软件的源代码中出现一个缺陷(故障,错误),如果执行这种有缺陷的代码,在某些情况下,系统会产生提示出现错误,从而引起了故障。当然并非所有缺陷都将导致故障的发生。例如,死代码缺陷永远不会导致故障。当环境变化时的缺陷可以成为一个失败的关键。这些在环境变化的例子中包括软件在新的计算机硬件平台运行,源代码的改变,或用不同软件进行交互,一个简单的缺陷可能导致一个软件的失败。
    软件测试的基本问题是:即使一个简单的产品,用所有的输入组合和先决条件(初始状态)进行测试是不可行的。这意味着一个软件产品的缺陷数量可以是非常巨大的,而且很多缺陷是难以在测试中发现的。更重要的是,非功能性的属性(它应该做什么与它如何做)如 可用性,可扩展性,性能,兼容性,可靠性是高度主观的; 一个人可能接受其中一个属性的价值却不能认同另外一个。
    软件开发人员无法测试所有的东西(所有的输入组合和先决条件),但他们可以使用组合测试设计,来确定他们想要覆盖测试所需的最小数量。组合测试设计,使用户用很少的测试用例能够获得很大的测试覆盖率。他们可以使用组合测试设计的方法来构建他们的测试用例,是他们的测试速度与测试深度有很大的提升。
    6.2 测试方法软件测试可用许多方法。回归,演练,或校对被称为静态测试,而实际执行程序代码与给定的测试案例被称为动态测试。静态测试往往是隐含的,如校对,再加上编程工具/文本编辑器查看源代码结构或编译器(预编译器)检查语法和数据流的静态程序分析。当程序在运行时动态测试发生。动态测试可以在程序100%完成前开始测试,以便测试特定的代码,也可以应用于分散的功能或者模块中。这个典型的技术使用驱动程序或在调试环境下执行。
    程序测试的主要方法分为两大类:白盒测试和黑盒测试。
    白盒测试(也称为清晰盒测试,玻璃盒测试,透明盒测试和结构测试)可以观察源代码,测试内部结构或程序的运作,而不是暴露终端用户的功能。白盒测试系统,用于设计测试用例,以及透视内部编程的技巧。测试器通过选择路径输入代码来确定相应的输出。这类似于在测试一个电路节点,例如:电路测试(ICT)。
    而白盒测试可以应用于单元测试,集成测试和系统测试的软件流程,但是它通常在单元级别进行的。它可以在集成单元和子系统之间的测试路径上进行系统级别的测试。虽然这种方法测试设计可以发现许多错误或问题,但是它可能无法规范检测到或遗漏需求分析未实现的部分。
    在白盒测试中使用的技术包括:

    API测试 -通过公共和私人的应用测试的API(应用程序编程接口)
    代码覆盖率 -创建测试,以满足代码覆盖率的一些标准(如:测试设计人员可以创建测试,以使程序中所有的语句至少执行一次)
    故障注入方法-有意引入故障来衡量测试策略的效果
    突变检测方法
    静态测试方法

    代码覆盖工具可以评估任何方法,包括创建了一个完整的测试套件的黑盒测试方法。这允许软件团队可以很少对测试进行检查,只确保对最重要的一个系统的部分功能点进行检验即可。代码覆盖率常作为衡量测试好坏的指标,甚至用代码覆盖率来考核测试任务完成情况:

    功能覆盖,函数是否执行
    语句覆盖,语句是否执行
    判定覆盖,对程序中每个判定条件的真分支和假分支至少进行一次判定

    100%的语句覆盖,确保所有的代码路径或分支(在以下方面控制流程)至少执行一次。这对于确保功能的正确有很大的帮助,但是对于相同代码有可能因为输入的不同而有不同的结果。
    黑盒测试把软件作为一个“黑盒子”,具有审查的功能,而有关内部实现的任何细节都不清楚,也看不到其源代码。该测试人员只了解该软件的功能与作用,而不清楚它是如何具体实现的。黑盒测试方法包括:等价类划分,边界值分析,全局测试,状态表转移,决策表测试,模糊测试,基于模型的测试,用例测试,探索性测试和基于规范的测试。
    基于规范型的测试旨在去测试软件关于适应性要求方面的功能。这种级别的测试通常需要测试人员提供全面的测试用例,然后只需验证其中一个给定的输入值,输出值(或行为),不管在测试用例中与期望结果是否相同。测试用例的选取是建立在规范和要求下的,也就是说,应用程序应该做什么。它使用的软件的外部描述,包括规格,要求,和设计以获取测试用例。这些测试虽然有时有用,有时无效,但是通常是有用的。
    基于规范的测试可能只能检测其功能的有效性和正确性,但它不足以应对复杂或高风险的情况。
    黑盒测试技术的一个优点是不需要专业的编程知识。即使编写程序的编程人员与测试人员有鸿沟一般的编程差距,但是测试人员总能从不同的方面给出相应的建设性意见。在另一方面,黑盒测试的过程可以被说成是“摸着石头过河。” 因为不需要检查程序的源代码,所以在某种情况下,测试人员需要写很多测试用例来检查程序,但是该程序只能被一种测试用例来测试或者只能测试程序的部分功能。
    测试的这种方法可以应用到软件测试的各个方面,例如:单元测试,集成测试,系统测试和验收测试。它虽然不能包括测试过程中的所有流程,但是在单元测试中却保持着绝对的优势。
    6.3 测试结果软件评价是指软件在正式运行了一段时间之后,对它在功能上、技术上和经济上所进行的审核评价。针对本软件的评价如下:

    软件功能评价:根据这套软件开发前的目标,试运行完成后软件后,软件达到了预定的发展目标,在实际使用功能可满足用户的需求
    技术评价:该软件设计合理,功能达到预期目标,软件后运行稳定,可靠,安全,实用
    经济评价:在规定时间内,该软件完成后,软件分析,以确定软件的发展目标,符合设计要求,投入使用,为用户节省了大量的人力,物力和财力,提高科学管理水平

    参考文献[1] 杨大生, 陈忠. 基于Symbian平台飞机大战游戏设计[J]. 福建电脑, 2010(07):140-140
    [2] 谢海军. 基于Java的手机游戏引擎的研究及实现[D]. 西南交通大学, 2007.
    [3] 马鹏强. 基于J2ME的手机五子棋游戏设计与实现[D]. 电子科技大学, 2012.
    [4] 周凤英, 文惺. Java游戏开发起步[J]. 电脑爱好者, 2003(14):116-116.,
    [5] 陈立伟. 精通Java手机游戏与应用程序设计[M]. 中国青年出版社, 2005.
    [6] 丁知平, 罗光华, 陈传起,等. 基于项目驱动的Java手机游戏开发教学方法的探讨[J]. 科技信息:科学教研, 2008(7):208-208.
    [7] 陈小玉. 基才J2ME的Java手机游戏开发实例[J]. 电脑编程技巧与维护, 2005.
    [8] Ross J M. Guiding students through programming puzzles: value and examples of Java game assignments.[J]. Acm Sigcse Bulletin, 2002, 34(4):94-98.
    [9] Wang Y H, Wu I C, Jiang J Y. A portable AWT/Swing architecture for Java game development[J]. Software Practice & Experience, 2007, 37(7):727–745.
    [10] Zhu Y. Design and implementation of a Java game applet[J]. Computer Science & Software Engineering, 2002.
    2 评论 56 下载 2020-07-25 15:58:31 下载需要15点积分
  • 基于MFC实现的AES加密解密程序

    1 算法背景及介绍1.1 背景高级加密标准(Advanced Encryption Standard,AES)作为传统对称加密算法标准DES的替代者,由美国国家标准与技术研究所(NIST)于1997年提出征集该算法的公告。1999年3月22日,NIST从15个候选算法中公布了5个候选算法进入第二轮选择:MARS,RC6,Rijindael,SERPENT和Twofish。
    2000年10月2日,以安全性(稳定的数学基础,没有算法弱点,算法抗密码分析的强度,算法输出的随机性)、性能(必须能在多种平台上以较快的速度实现)、大小(不能占用大量的存储空间和内存)、实现特性(灵活行、硬件和软件实行性、算法的简单性等)为标准而最终选定了两个比利时研究者Vincent Rijinmen和Joan Daemen发明的Rijndael算法,并于2001年正式发布了AES标准。
    1.2 AES加密算法AES算法本质上是一种对称分组密码体制,采用代替/置换网络。AES算法主要包括三个方面:轮变化、圈数和密钥扩展。
    1.2.1 圈变化AES每一个圈变换由以下三个层组成:

    非线性层——进行Subbyte变换,非线性层由16个S盒并置起到混淆的作用
    线行混合层——进行ShiftRow和MixColumn运算,线性混合层确保多轮之上的高度扩散
    密钥加层——进行AddRoundKey运算,密钥加密层将子密钥异或到中间状态

    Subbyte变换是作用在状态中每个字节上的一种非线性字节转换,可以通过计算出来的S盒进行映射。
    ShiftRow是一个字节换位。它将状态中的行按照不同的偏移量进行循环移位。
    在MixColumn变换中,把状态中的每一列看作GF(28)上的多项式a(x)与固定多项式c(x)相乘的结果。b(x)=c(x)*a(x)的系数这样计算:*运算不是普通的乘法运算,而是特殊的运算,即 b(x)=c(x) • a(x)(mod x4+1) 算法如下图:

    对于逆变化,其矩阵C要改变成相应的D,即b(x)=d(x)\*a(x)。
    密钥加层运算(addround)是将圈密钥状态中的对应字节按位“异或”。
    根据线性变化的性质,解密运算是加密变化的逆变化。
    1.2.2 轮变化对不同的分组长度,其对应的轮变化次数是不同的,这里要介绍的密钥长度为128位的轮变化数为10轮;密钥长度为192位的轮变化数为12轮;密钥长度为256位的轮变化数为14轮。
    1.2.3 密钥扩展AES算法利用外部输入密钥K(密钥串的字数为Nk),通过密钥的扩展程序得到共计4(Nr+1)字的扩展密钥。它涉及如下三个模块:

    位置变换(rotword)——把一个4字节的序列[A,B,C,D]变化成[B,C,D,A];
    S盒变换(subword)——对一个4字节进行S盒代替;
    变换Rcon——Rcon表示32位比特字[xi-1,00,00,00]。这里的x是(02),如 Rcon[1]=[01000000];Rcon[2]=[02000000];Rcon[3]=[04000000]……

    扩展密钥的生成:扩展密钥的前Nk个字就是外部密钥K;以后的字W[]等于它前一个字W[i-1]与前第Nk个字W[i-Nk]的“异或”,即W[]=W[i-1]⊕W[i- Nk]。但是若i为Nk的倍数,则W=W[i-Nk]⊕Subword(Rotword(W[i-1]))⊕Rcon[i/Nk]。
    2 系统设计2.1 系统主要目标基本要求部分:

    在深入理解AES加密/解密算法理论的基础上,设计了一个AES加密/解密软件系统
    完成一个明文分组的加解密,明文和密钥是十六进制,长度都为128比特(32个16进制数),按照标准输入明文和密钥,输出密文,进行加密后,能够进行正确的解密
    程序运行时,输出每一轮使用的密钥,以及每一轮中字节替代、行移位、列混合,密钥加等每一步操作之后的16进制表示的值

    较高要求部分:

    如果明文不止一个分组,程序能完成分组,然后加密;最后一个分组长度不足时填充0;密钥长度不足时填充0,过长则自动截取前面部分
    密钥可以采用16进制ASCII码或英文字符输入,明文输入信息可以是16进制数值或英文,任意字符(不包括汉字),或者是文本文档,进行加密后,能够进行正确的解密
    程序代码有比较好的结构,模块划分合理,通过调用类的成员函数实现加密解密功能,函数的参数及返回值设置合理。
    界面友好

    2.2 主要软件需求(运行环境)
    本软件适用VC语言编写,编译成功后的EXE文件可以在装有Windows系统的任何计算机上使用
    测试平台:Windows XP Professional
    使用软件:Visual C++ 6.0

    2.3 功能模块与系统结构加密/解密的大致结构图:


    加密/解密主要流程图:

    3 系统功能程序设计本程序中用到2张表格:Sbox[256],iSbox[256]和Rcon[32];均采用一维数组存放;明文分组plaintext[16]和初始密钥key[16]也均为一维数组;但在处理过程中仍把Sbox[256]和iSbox[256]看做16行16列的矩阵;把Rcon[32]看做8行4列的矩阵;把plaintext[16]和key[16]看做4行4列的矩阵,则第i行j列的数在一维数组中的位置为4i+j。扩展密钥采用二维数组w[44][4]存放。由于明文和密钥装入数组为顺序装入,即相当于AES算法中按列装入的矩阵的转置,所以进行对应的行变换即应该进行相应的列变换。
    3.1 基本要求部分3.1.1 字节替换Sbox[256],plaintext[16]均采用一维数组存放,plaintext中存放的为转化为16进制的操作数,进行字节替换时是取plaintext存放的数据的二进制值的高4位做行坐标i,低四位做列坐标j来取Sbox中对应位置的数据替换,而plaintext的值恰好为16i+j,所以plaintext的值即为对应的替换值在Sbox中的位置。
    void CAESDlg::SubByte(){ int i; for(i=0;i<16;i++) plaintext[i]=Sbox[plaintext[i]];}
    3.1.2 行移位Plaintext[16]采用一维数组存放操作数,把它看做每行4列的矩阵,所以第k行i列即为plaintext[4*k+i ]。由于AES采用列存放数据,而这里plaintext采用顺序存放,相当于行存放,即为列存放的转置矩阵,所以进行行移位时即应该进行相应的列移位:
    列变换(行移位)情况如下图所示:

    void CAESDlg::ShiftUp(int i){ int j,k,temp; for(j=0;j<i;j++) { temp=plaintext[i]; for(k=0;k<3;k++) plaintext[4*k+i]=plaintext[4*(k+1)+i]; plaintext[i+12]=temp; }}void CAESDlg::ShiftRows(){ int i; for(i=1;i<4;i++) ShiftUp(i);}
    3.1.3 列混合把一维数组plaintext[16]看做4行4列,则i行j列即为4*i+j , 列混合即为两个矩阵相乘,由于AES采用列存放数据,而这里plaintext采用顺序存放,相当于行存放,即为列存放的转置矩阵,所以另一个矩阵也转置,相乘后仍然是AES列混合后的转置矩阵:
    相当于下面两个矩阵相乘:

    int CAESDlg::gfmultby02(int b){ if (b<0x80) //(0x80=OB10000000) return (b<<1); else return (((b<<1)-256)^(0x1b)); //(0X1b=OB00011011)}int CAESDlg::gfmultby03(int b){ return (gfmultby02(b)^b);}void CAESDlg::MixColumns() { int i,temp[16]; memcpy(temp,plaintext,64); for(i=0;i<4;i++) { plaintext[4*i]=gfmultby02(temp[4*i+0]) ^ gfmultby03(temp[4*i+1]) ^ temp[4*i+2] ^ temp[4*i+3]; plaintext[4*i+1]=temp[4*i+0] ^ gfmultby02(temp[4*i+1]) ^ gfmultby03(temp[4*i+2]) ^ temp[4*i+3]; plaintext[4*i+2]=temp[4*i+0] ^ temp[4*i+1] ^ gfmultby02(temp[4*i+2]) ^ gfmultby03(temp[4*i+3]) ; plaintext[4*i+3]=gfmultby03(temp[4*i+0]) ^ temp[4*i+1] ^ temp[4*i+2] ^ gfmultby02(temp[4*i+3]); }}
    3.1.4 密钥加密钥w[44][4]依次存的为初始密钥和扩展后的10轮轮变换的密钥,round为加密的轮数,w[4*round+r][c]即为第round轮的密钥第r行c列。把一维数组plaintext看做4行4列,则r行c列即为4*r+c,分别行取值异或,即为密钥加:
    void CAESDlg::AddRoundKey(int round){ int r,c; for(r=0;r<4;++r) for(c=0;c<4;++c) plaintext[4*r+c]=(plaintext[4*r+c]^w[4*round+r][c]);}
    3.1.5 密钥扩展rowtem%flag==0时即为每轮密钥开始的行数,它的前一行移位RotWord后查表Sbox再和前4行密钥异或,第一列再和Rcon异或;当不为轮开始的第一行密钥时,直接取前一行和前四行异或:
    void CAESDlg::InitKey(){ int inkey[16]; int temp[4],flag=4; memcpy(inkey,key,64); //内存COPY函数,(目的,源,大小) for(int row=0;row<4;row++) { w[row][0] = inkey[4*row]; w[row][1] = inkey[4*row+1]; w[row][2] = inkey[4*row+2]; w[row][3] = inkey[4*row+3]; } for(int rowtem=flag;rowtem<44;rowtem++) { temp[0] = w[rowtem-1][0]; temp[1] = w[rowtem-1][1]; temp[2] = w[rowtem-1][2]; temp[3] = w[rowtem-1][3]; if (rowtem%flag==0) { RotWord(temp); SubWord(temp); temp[0] = (temp[0]^Rcon[rowtem/flag]); } // w[row] = w[row-Nk] xor temp w[rowtem][0] = ( w[rowtem-flag][0] ^ temp[0] ); w[rowtem][1] = ( w[rowtem-flag][1] ^ temp[1] ); w[rowtem][2] = ( w[rowtem-flag][2] ^ temp[2] ); w[rowtem][3] = ( w[rowtem-flag][3] ^ temp[3] ); }//loop}void CAESDlg::RotWord(int *word ){ int temp; temp=word[0]; word[0] = word[1]; word[1] = word[2]; word[2] = word[3]; word[3] = temp;}void CAESDlg::SubWord(int* word ){ word[0] = Sbox[ (word[0] >> 4)*16+(word[0] & 0x0f)]; word[1] = Sbox[ (word[1] >> 4)*16+(word[1] & 0x0f)]; word[2] = Sbox[ (word[2] >> 4)*16+(word[2] & 0x0f)]; word[3] = Sbox[ (word[3] >> 4)*16+(word[3] & 0x0f)];}
    3.1.6 逆字节替换与字节替代类似,iSbox[256],plaintext[16]均采用一维数组存放,plaintext中存放的为转化为16进制的操作数,进行字节替换时是取plaintext存放的数据的二进制值的高4位做行坐标i,低四位做列坐标j来取iSbox中对应位置的数据替换,而plaintext的值恰好为16i+j,所以plaintext的值即为对应的逆替换值在iSbox中的位置。
    void CAESDlg::InvSubBytes(){ int i; for(i=0;i<16;i++) plaintext[i]=iSbox[plaintext[i]];}
    3.1.7 逆行移位与行移位类似,Plaintext[16]采用一维数组存放操作数,把它看做每行4列的矩阵,所以第k行i列即为plaintext[4*k+i ]。由于AES采用列存放数据,而这里plaintext采用顺序存放,相当于行存放,即为列存放的转置矩阵,所以进行逆行移位时即应该进行相应的逆列移位:
    逆列变换(逆行移位)情况如下图所示:

    void CAESDlg::ShiftDown(int i){ int j,k,temp; for(j=0;j<i;j++) { temp=plaintext[12+i]; for(k=2;k>=0;k--) plaintext[4*(k+1)+i]=plaintext[4*k+i]; plaintext[i]=temp; }}void CAESDlg::InvShiftRows(){ int i; for(i=1;i<4;i++) ShiftDown(i);}
    3.1.8 逆列混合与列混合类似,把一维数组plaintext[16]看做4行4列,则i行j列即为4*i+j , 逆列混合即为两个矩阵相乘,由于AES采用列存放数据,而这里plaintext采用顺序存放,相当于行存放,即为列存放的转置矩阵,所以另一个矩阵也转置,相乘后仍然是AES列混合后的转置矩阵:
    相当于下面两个矩阵相乘:

    int CAESDlg::gfmultby09(int b){ return (gfmultby02(gfmultby02(gfmultby02(b)))^b );}int CAESDlg::gfmultby0b(int b){ return (gfmultby02(gfmultby02(gfmultby02(b)))^gfmultby02(b)^b);}int CAESDlg::gfmultby0d(int b){ return (gfmultby02(gfmultby02(gfmultby02(b)))^gfmultby02(gfmultby02(b))^(b));}int CAESDlg::gfmultby0e(int b){ return (gfmultby02(gfmultby02(gfmultby02(b)))^gfmultby02(gfmultby02(b))^gfmultby02(b) );}void CAESDlg::InvMixColumns() { int i,temp[16]; memcpy(temp,plaintext,64); for(i=0;i<4;i++) { plaintext[4*i]=gfmultby0e(temp[4*i+0]) ^ gfmultby0b(temp[4*i+1]) ^ gfmultby0d(temp[4*i+2]) ^ gfmultby09(temp[4*i+3]); plaintext[4*i+1]=gfmultby09(temp[4*i+0]) ^ gfmultby0e(temp[4*i+1]) ^ gfmultby0b(temp[4*i+2]) ^ gfmultby0d(temp[4*i+3]); plaintext[4*i+2]=gfmultby0d(temp[4*i+0]) ^ gfmultby09(temp[4*i+1]) ^ gfmultby0e(temp[4*i+2]) ^ gfmultby0b(temp[4*i+3]) ; plaintext[4*i+3]=gfmultby0b(temp[4*i+0]) ^ gfmultby0d(temp[4*i+1]) ^ gfmultby09(temp[4*i+2]) ^ gfmultby0e(temp[4*i+3]); }}
    3.1.9 加密先一轮密钥加AddRoundKey(0),再进入主循环,依次进行字节替换SubByte()、行移位ShiftRows()、列混合MixColumns()、密钥加AddRoundKey(round)运算,循环9次,再做一次字节替代SubByte()、行移位ShiftRows()、密钥加AddRoundKey(Nr)运算,完成加密:
    void CAESDlg::Cipher(){ …… AddRoundKey(0); for (int round = 1; round < Nr; ++round) // main round loop { SubByte(); ShiftRows(); MixColumns(); AddRoundKey(round); } // main round loop SubByte(); ShiftRows(); AddRoundKey(Nr);}
    3.1.10 解密先一轮密钥加AddRoundKey(Nr),再进入主循环,依次进行逆行移位InvShiftRows()、逆字节替换InvSubBytes()、密钥加AddRoundKey(round)、逆列混合InvMixColumns()运算,循环9次,再做一次逆行移位InvShiftRows()、逆字节替代InvSubBytes()、密钥加AddRoundKey(0)运算,完成解密:
    void CAESDlg::InvCipher(){ AddRoundKey(Nr); for (int round=Nr-1;round>=1;round--) // main round loop { InvShiftRows(); InvSubBytes(); AddRoundKey(round); InvMixColumns(); } // main round loop InvShiftRows(); InvSubBytes(); AddRoundKey(0);}
    3.2 较高要求部分3.2.1 明文分组实现输入的明文存在m_text中,length为输入的明文的总长度,每次循环Cipher()只处理128位,长于128位的暂不处理,留作下一轮处理,不足128位的在Cipher()处理的过程中已做了填充处理;每轮k加1,tag*k就指向m_text中没处理的明文的第一个字符,经过变换后,temp中的存放的就为没处理的明文,再将temp中的前128位取出处理,依次循环直到最后处理完明文为止。
    void CAESDlg::OnBUTTONCipher() {…………….. do{ temp=""; Cipher(); Show(); k++; if(length>tag*k) { for(int i=0;i<tag&&i<length-tag*k;i++) { test.Format("%c",m_text[tag*k+i]); temp+=test; } if(m_RadioInputTextHex==0) InputHex(temp,plaintext,Nb); else CharToHex(temp,plaintext,Nb); } }while(length>tag*k);…………………}
    3.2.2 明文最后分组的填充明文首先是以字符串形式读入的,每次处理一个分组,处理时再根据相应的输入模式调用相应的函数在字符串中取值存到plaintext[16]数组中进行处理。
    当为字符输入模式时,调用CharToHex()函数,每次处理取字符串的前16个字符换成ASCII码作为一个分组进行处理,直到最后一个分组,若不足16个字符,不足部分填充0;当为16进制输入模式时,调用InputHex ()函数,每次处理取字符串的前32个字符换成相应的16进制代码进行处理,直到最后一个分组,若不足32个字符时,不足部分填充0;
    void CAESDlg::CharToHex(CString str,int *array,int n){ int i; for(i=0;i<str.GetLength()&&i<n;i++) array[i]=str[i]; if(str.GetLength()<Nb) for(i=str.GetLength();i<n;i++) array[i]=0;}void CAESDlg::InputHex(CString strCS,int *array,int n){ int i,high[16],low[16]; string str; str=strCS; for(i=0;i<n;i++) { if(str[2*i]>=47 && str[2*i]<=57) high[i]=(int)str[2*i]-48; else if(str[2*i]>=65 && str[2*i]<=70) high[i]=(int)str[2*i]-55; else if(str[2*i]>=97 && str[2*i]<=102) high[i]=(int)str[2*i]-87; else high[i]=0; if(str[2*i+1]>=47 && str[2*i+1]<=57) low[i]=(int)str[2*i+1]-48; else if(str[2*i+1]>=65 && str[2*i+1]<=70) //大写字母A--F low[i]=(int)str[2*i+1]-55; else if(str[2*i+1]>=97 && str[2*i+1]<=102) //小写字母a---f low[i]=(int)str[2*i+1]-87; else low[i]=0; } for(i=0;i<n;i++) array[i]=high[i]*16+low[i];}
    3.2.3 密钥的填充与截取密钥的填充与明文的填充类似,不同的是密钥只处理一个分组。
    当为字符输入模式时,调用CharToHex()函数处理,若密钥长度不足16个字符时,在把密钥换成16进制ASCII码存入key[16]数组中后,不足部分填充0,填满后作为一个密钥再进行相应的处理,实现密钥的填充;若密钥长度大于16,则只取前16个字符换成16进制ASCII码存入key[16]数组中作为一个密钥,忽略后面的字符,实现密钥的截取;
    当为16进制输入模式时,调用InputHex ()函数处理,若密钥长度不足32个字符时,在把密钥换成16进制代码存入key[16]数组中后,不足部分填充0,填满后作为一个密钥再进行相应的处理,实现密钥的填充;若密钥长度大于32,则只取取前32个字符换成16进制代码存入key[16]数组中作为一个密钥,忽略后面的字符,实现密钥的截取;
    3.2.4 文本文件加密文本文件加密与字符加密大致相同。从文本文件中读入字符串,相当于字符加密的字符输入模式,然后再调用相应的加密函数对字符串进行分组加密,加密结果输出为16进制值,加密结束后再把加密结果写入一个新的文本文件(加密文件Hex.txt)中,完成文本文件的加密。
    void CAESDlg::OnBUTTONFileCipher() { ……………………………….. FileInitialize(); CharToHex(m_FileData,plaintext,Nb); InitKey(); m_progress.SetPos(50); tag=Nb; strFileHex=""; do{ temp=""; CipherFile(); for(i=0;i<Nb;i++) { test.Format("%02x",plaintext[i]); strFileHex+=test; } k++; if(length>tag*k) { for(int i=0;i<tag&&i<length-tag*k;i++) { test.Format("%c",m_FileData[tag*k+i]); temp+=test; } CharToHex(temp,plaintext,Nb); } }while(length>tag*k); ……………………….}
    3.2.5 文本文件解密文本文件解密与字符解密大致相同。从文本文件中读入字符串,相当于字符解密的16进制输入模式,然后再调用相应的解密函数对字符串进行相应的分组解密,解密结果输出为字符型,解密结束后再把解密结果写入一个新的文本文件(解密文件Char.txt)中,完成文本文件的解密。
    void CAESDlg::OnBUTTONFileInvCipher() { ………………………. FileInitialize(); InputHex(m_FileData,plaintext,Nb); InitKey(); m_progress.SetPos(50); tag=Nb*2; strFileChar=""; do{ temp=""; InvCipherFile(); for(i=0;i<Nb;i++) { test.Format("%c",plaintext[i]); strFileChar+=test; } k++; if(length>tag*k) { for(int i=0;i<tag&&i<length-tag*k;i++) { test.Format("%c",m_FileData[tag*k+i]); temp+=test; } InputHex(temp,plaintext,Nb); } }while(length>tag*k); ………………………….}
    3.3 程序界面预览为方便测试,设置明文和密钥的默认值为标准值。
    待处理的文本框输入明文或密文进行加密或解密;可以选择为16进制输入或字符输入;密钥输入框输入加密或解密密钥,可以选择为16进制输入或字符输入。若选择为16进制模式输入,若不为有效的16进制代码,则当做0处理;若选择为字符模式输入,可以输入任意英文字符。
    输入待处理明文/密文后,点击加密按钮或解密按钮进行加密或解密处理。
    处理后的结果有两种显示方法,即16进制显示(显示处理后的16进制值)和字符显示(显示处理后的16进制值对应的字符);
    两个换序按钮能方便的分别将处理后的两个结果框中对应的字符换到待处理的文本框中,进行验证加密/解密的正确性,或再进行多次加密处理。
    右边中间输出结果框显示了每一轮使用的密钥,以及每一轮中字节替代、行移位、列混合,密钥加等每一步操作之后的16进制表示的值。
    进度条显示加密的进度。
    初始化按钮能回到最初的默认状态。方便测试。
    文本加密,点击浏览按钮来选择文本路径。
    文件加密密钥输入同字符加密的密钥输入一样,可以选择为16进制输入或字符输入,输入密钥对文本文档进行处理。
    选择了文本文档路径,输入了文件加密/解密密钥后,点击对应的加密或解密按钮,进行文本文件加密或解密处理。

    4 测试报告4.1 字符加密/解密检测:
    明文:00112233445566778899aabbccddeeff (16进制输入模式)
    密钥:000102030405060708090a0b0c0d0e0f (16进制输入模式)
    加密结果:69c4e0d86a7b0430d8cdb78070b4c55a (16进制表示)

    对照标准,输入明文和密钥,经过加密后运行结果与标准相同,中间每步的处理结果也与标准相同,按下16进制显示框对应的换序按钮,再进行相应的解密能得到正确的明文。
    将Text输入方式和key输入方式换成字符输入模式,在明文输入框和密钥输入框中均输入超过1个分组长度的英文字符(包括英文特殊字符)进行加密:
    明文

    密钥

    加密结果

    点击16进制显示框对应的换序按钮,把加密结果的16进制值换到待处理文本输入框中进行解密:
    密文

    密钥

    解密结果

    将明文和密钥的输入方式换成字符输入模式,在明文输入框和密钥输入框中均输入超过1个分组长度的英文字符(包括英文特殊字符)进行加密,用加密得到的16进制值(在16进制显示框中)进行解密,能得到正确的字符(在字符显示框中显示)。
    4.2 文本文档加密/解密检测test.txt文件内容

    文件加密

    加密结果

    解密

    解密结果

    经过检测:

    本软件能对字符和文本文档进行正确的加密和解密,加密和解密结果没有错误
    对于不足128bit的明文分组,最后填充0补满128bit
    对于不足128bit的密钥,填充0补满128bit;对于超过128bit的密钥,只截取前128bit
    没有发现导致致命错误的操作方法

    5 结论通过这次的课程设计,对AES的算法有了更深入的了解:字节代换的仿射变换可用S盒表示;对于不同的分组行移位也是不同的;列混合中的计算则要用到GF(28)上的多项式,再与一个固定的多项式C(x)进行模X4+1的乘法,而C(x)是固定的,而且最后一轮没用列混合。虽然此软件能顺利完成对英文字符和文本文档的加密,但也还存在很多不足,如:不能对汉字进行处理,不能处理其他格式的文件、文件夹等,只支持128bit的密钥,没有实现192bit,256bit密钥长度的加密,还需要进一步完善。
    参考文献[1] 谭浩强. C程序设计(第二版). 清华大学出版社. 1999
    [2] 张海藩. 软件工程导论(第四版). 清华大学出版社. 2003
    [3] 杨波. 现代密码学. 清华大学出版社. 2003
    [4] 黄维通. Visual C++面向对象与可视化程序设计. 清华大学出版社. 2000
    [5] 张福泰. 密码学教程(第一版). 武汉大学出版社. 2006
    5 评论 127 下载 2018-12-02 17:14:35 下载需要10点积分
  • 基于HTML和CSS实现的TC读书网页面设计

    一、项目总体设计1.1 需求分析1.1.1 阐述这个网页设计我是以“TC 读书网”为主题展开,选择这个题目,是因为自己本身就很喜欢看书,喜欢看各种各样的书籍。像很多读书爱好者一样,喜欢在安静的地方静静的看书,比如自己的房间里、图书馆、书店。喜欢把自己生活中的点点滴滴都装扮带有书香的气息。自己在家里的房间里,就装有书架,并摆满了各类书。每次回家我就很喜欢待在房间里,坐在书桌前看书。在这种环境下,能让自己的身心愉悦,心情美美的。自己也养成了坚持看书的习惯,在学校一旦有时间就会去图书馆或自习室看书。在书中不但能学习到很多东西,而且还会让一个人的精神面貌有所不同。在此之前我也浏览了很多读书网页,觉得很有意思。现在学了网页设计,当然也要根据自己的想法来设计自己的网页,同时想通过自己设计的网页,来满足更多读书爱好者的需求,让更多的爱好者在我设计的网页里找到更有意思的东西。
    1.1.2 功能此网页能够满足喜欢看书的书友,随时随地的打开网页就可以阅读各种各样的书籍,无论是国内还是国外的书籍都可以看,网页的设计还进行了书籍的分类,有在线阅读的书籍、近段时间书籍阅读量的排行榜、本网页出版的图书等等。网页的设计根据自己个人爱好来设计,比较简易,颜色不是浓艳,这样正是符合了读书的一个环境。本网页还设计了登录页面,可以让更多的读书爱好者加入进来。读书爱好者能及时、准确、完整阅读到自己喜欢的书籍,管理员可以在后台对书籍的更新点信息进行准确校对、修改和删除。
    1.1.3 技术
    HTML 语言
    CSS 样式表

    1.2 网站结构分析该网站主要由首页、栏目页、内容页组成,每个页面都由头部(logo、TC 读书网)、导航栏、主体部分及尾部版权栏构成。
    导航栏
    首页、国学/古籍、出版图书、电子书、网络小说、排行榜、读书导航七个目录组成。
    主体部分
    图片展示栏、文字说明
    1.3 网站风格分析网站主要以简约风格为主,简洁的表现形式来满足读书爱好者对此网页的了解。

    总体印象:以展示本网页优点等,主题突出,内容精干,形式简洁
    版式布局:栏目集中,分栏目检索明确,导航标志清晰
    色彩运用:总体呈浅灰色简洁风格
    图片运用:配合文字,以极简的图片效果吸引用户
    语言:中文
    结构:浏览路线方便快捷、清晰明确


    1.4 网站结构图
    二、项目详细设计2.1 登录页面设计


    登陆界面主要由顶部的滚动文字、用户输入账号登录、用户注册、忘记密码组成。在登录框中加入了超链接,只要点击登录就可以进入首页。
    所遇难点:通过输入账号登录(未实现)
    2.2 主页页面设计


    整个主页布局主要是用了盒子嵌套和排版,内容有寻找框,右上角有注册/登录键,导航栏,图书分类。导航栏通过加入超链接点击进入对应的页面。在页面最底部还加入了网页的相关信息。
    所遇难点:未实现中间图片为滚动的。
    2.3 在线读书页面设计


    在线读书页面的设计很合理,设计了图书的分类、实现不同兴趣爱好的读书者的需求,图书也设计了读书推荐,读书推荐是根据广大读书者的评价做出的推荐,最大的板块是最新发行的图书,每本书都用一句话做出简介。整个页面的设计也非常简洁美观。
    三、项目总结在设计过程中也出现了很多的问题,如忘记使用浮动导致盒子位置错乱、class 和 id 的使用有什么区别,还有文字滚动的属性,但通过看书,上网查询,请教同学等方式,不断地学习、思考、实践、提高,最终顺利的完成了作品。但是还是有一些自己想要设计进去的东西没有办法加进去,因为技术还不够,自己时间的安排不合理没有学习到那方面的知识。例如:使用 JavaScript 脚本技术让图片滚动,输入正确的账号才可以登录。
    1 评论 1 下载 2021-07-22 10:14:16 下载需要11点积分
显示 0 到 15 ,共 15 条
eject