分类

课内:
不限
类型:
不限 毕业设计 课程设计 小学期 大作业
汇编语言 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和SQL SERVER数据库实现的实验信息综合管理系统

    1 需求分析1.1 需求来源本系统是对于实验综合信息进行管理的系统。
    1.1.1 功能需求
    学生用户:修改系统登陆密码、查询选择的课程、查询选择课程对应的实验课表、导出查询到的课程数据、实验课表数据
    教师用户:修改系统登陆密码、修改个人联系方式、查询教授的课程、查询实验安排、增加课程信息、增加实验信息、按学号查询出勤率、按班级查询出勤率、导出查询到的数据记录
    管理员用户:增加学生信息、修改学生信息、增加教师信息、修改教师信息、增加课程信息、修改课程信息,增加实验信息、修改实验信息,增加实验室信息、修改实验室信息,更新实验打卡信息

    1.1.2 数据需求系统涉及的数据表为8个表,管理员信息表(ADMINB)、教师表(JSB)、教师课程表(JSKCB)、课程表(KCB)、实验打卡表(SYDKB)、实验室表(SYSB)、实验信息表(SYXXB)、学生表(XSB)。
    其中管理员信息表包含的基本属性为管理员用户名、登陆密码。教师表包含的几本书新为教师姓名、联系方式、登陆密码。教师课程表包含的基本属性为教师姓名、课程代码。课程表包含的基本属性为课程代码、课程名称、开课学院。实验打卡表包含的基本属性为实验编号、学生学号、打卡状态。实验室表包含的基本属性为实验中心、实验分室、上课地点。实验信息表包含的基本属性为实验编号、课程代码、实验项目、上课老师、辅助教师、上课日期、星期几、上课地点。学生表包含的基本属性为学号、姓名、班级、登陆密码。
    1.1.3 性能需求
    要求系统在本地访问时数据具有可靠性、运行速度快,简单快捷
    要求系统能在多系统(Windows、Linux)、多终端(PC、手机)

    1.2 设计目的利用服务器和大容量存储等最新的硬件设备,以及数据库和网络技术所开发出的实验信息管理系统使用户能对大量的实验综合信息进行高效的管理。通过实验信息管理系统,信息录入、查询等原先繁复枯燥的工作的效率得到了显著的提升;更重要的是数据的准确性和安全性也同时得到了保证。
    1.3 设计要求不同类型的用户能够通过本系统使用不同的功能,对实验综合信息进行管理。
    1.4 开发工具及相关技术通过采用Microsoft SQL Server等大型关系型数据库,实验的各项数据的存储更为规范和完整。数据库技术也使得实验数据的备份和恢复变得简单便捷。而在硬件方面,采取RAID5等存储解决方案组成的磁盘阵列,以极低的存储成本极大的提高了数据的安全性。通过采用python平台开发,采用了基于B/S的三层开发结构(UI、BLL、DAL)。同时运用tkinter等GUI的最新技术,提供美观实用的系统界面和顺畅的用户体验。
    2 总体设计2.1 总体结构设计为了满足实验综合信息管理系统各方面信息的管理功能,需要明确用户的各个功能。数据库中应该有教师、学生以及管理员的基本信息,这些来自于本系统。教师、学生只能在客户端进行操作。管理员可以使用管理端操作,修改、删除、增加教师、学生的信息。此类权限不对教师、学生用户开放。除此之外,还要通过登录名和密码严格限定登陆者的身份并且控制相应的操作权限,只有管理员有权限修改账户以及密码,防止其他密码泄露造成的其他问题。
    2.1.1 模块设计系统模块设计:

    2.2.2 模块功能描述“管理员用户”子系统针对管理员用户的日常工作流程,分为“学生管理”,“教师管理”,“课程管理”,“实验管理”,“实验室管理”等子模块。其模块具体功能描述如下:

    “学生管理”模块:该模块对学生信息进行维护,如对增加新入学学生的信息,为转专业学生更改班级信息,为改名学生更改姓名信息,删除退学、毕业学生信息,为忘记登陆密码的学生用户重新设置用户密码等
    “教师管理”模块:该模块对教师信息进行维护,如对增加新入职老师的信息,删除离职老师的信息,为忘记登陆密码的教师用户重新设置登陆密码等
    “课程管理”模块:该模块对课程信息进行维护,如对课程名称、开课学院等信息系的修改,增加新开设课程的信息
    “实验管理”模块:该模块对实验信息进行维护,如对实验下属各种信息的修改调整、增加新的实验信息、更新实验打卡信息等
    “实验室管理”模块:该模块对实验室信息进行维护,如对实验中心、实验分室、实验教师信息的修改、增加等

    “教师用户”子系统针对教师用户的日常使用流程,分为“学生管理”模块,“课程管理”模块,“实验管理”模块、“个人管理”模块。其模块具体功能描述如下:

    “学生管理”模块:该模块对学生信息进行查询,如对班级整体实验打卡记录的查询,对指定具体学号的学生实验打卡记录的查询,对查询到的信息进行导出等
    “课程管理”模块:该模块对课程信息进行查询与维护,如将新教授的课程信息录入系统,查询正在教授的课程信息等
    “实验管理”模块:该模块对实验信息进行查询与维护,如查询已安排为授课教师的实验信息,添加新的实验信息等
    “个人管理”模块:该模块对教师个人信息进行维护,如修改自己的登陆密码、修改个人的联系方式等

    “学生用户”子系统针对学生用户的日常使用流程,分为“个人管理”模块,“课程管理”模块,“实验管理”模块等。其模块具体功能描述如下:

    “个人管理”模块:该模块对学生用户个人信息进行维护,如修改自己的登陆密码等
    “课程管理”模块:该模块对课程信息进行查询,如查询自己选择的课程信息等
    “实验管理”模块:该模块对实验信息进行查询,如查询自己选择的课程所安排的实验信息等

    2.2 数据库设计2.2.1 概念结构设计
    管理员信息表(ADMINB)主要用于在系统中储存管理员信息,包含了管理员的登陆ID、密码,其中登陆ID是主键
    教师表(JSB)主要用于在系统中储存教师信息,包含了教师用户的姓名、密码、联系方式,其中姓名是主键。管理员用户可对该表进行维护
    教师课程表(JSKCB)主要用于在系统中储存教师授课信息,包含了教师姓名、课程代码。管理员用户、教师用户可对该表进行维护
    课程表(KCB)主要用于储存课程信息,包含了课程代码、开课学院、课程名称,其中课程代码是主键。管理员用户可对该表进行维护
    实验打卡表(SYDKB)主要用于储存学生打卡信息,包含了实验编号,学生学号、打卡状态。管理员用户可对该表进行维护,教师用户可对该表进行查询
    实验室表(SYSB)主要用于储存实验室信息,包含了实验中心、实验分室、实验教室,其中实验教室是主键。管理员用户可对该表进行维护
    实验信息表(SYXXB)主要用于储存实验信息,包含了实验编号、课程代码、实验项目、上课老师、辅助教师、上课日期、星期几、上课地点,其中实验编号是主键。管理员用户、教师用户可对该表进行维护
    学生表(XSB)主要用于储存学生信息,包含了学号、姓名、班级、登陆密码,其中学号是主键。管理员用户可对该表进行维护

    系统E-R图

    2.2.2 逻辑结构设计根据E-R模型转换关系结构:

    教师实体集(JSB)可以转换化为关系:
    教师用户(姓名,联系方式,登陆密码)

    管理员实体集(ADMINB)可以转化为关系:
    管理员用户(登陆ID,密码)

    课程实体集(KCB)可以转化为关系:
    课程(课程代码,开课学院,课程名称)

    实验室实体集(SYSB)可以转化为关系:
    实验室(实验分室、实验中心、实验教室)

    实验信息实体集(SYXXB)可以转化为关系:
    实验信息(实验编号、课程代码、实验项目、上课老师、辅助教师、上课日期、星期几)

    学生实体集(XSB)可以转换为关系:
    学生(姓名、学号、班级)

    教师与课程之间是n:m的联系,可以转化为一个关系:
    教师课程(JSKCB)(教师姓名、课程编号)

    学生与实验打卡信息之间是1:m的联系,可以对学生关系进行拓展,但由于打卡信息较多,进行扩展会导致数据库冗余信息较多,故单独转化为一个关系:
    学生打卡(XSDKB)(学号、实验编号、打卡信息)

    实验室与实验信息之间是n:m的联系,可以对实验信息进行拓展,不必单独转为一个关系:
    实验信息(实验编号、课程代码、实验项目、上课老师、辅助教师、上课日期、星期几、实验教室)
    2.2.3 物理结构设计教师表(JSB)



    字段名称
    数据类型
    字段长度
    是否为空
    备注




    姓名
    varchar
    20
    No
    主码


    联系电话
    varchar
    20
    Yes



    登陆密码
    varchar
    255
    Yes



    教师课程表(JSKCB)



    字段名称
    数据类型
    字段长度
    是否为空
    备注




    课程代码
    varchar
    20
    No



    上课教师
    varchar
    20
    No



    课程表(KCB)



    字段名称
    数据类型
    字段长度
    是否为空
    备注




    课程代码
    varchar
    20
    No
    主码


    开课学院
    varchar
    20
    No



    课程名称
    varchar
    255
    No



    **实验打卡表(SYDKB)



    字段名称
    数据类型
    字段长度
    是否为空
    备注




    实验编号
    varchar
    20
    No



    学号
    varchar
    20
    No



    实际上课时间
    varchar
    255
    No



    状态
    varchar
    255
    No



    实验室表(SYDKB)



    字段名称
    数据类型
    字段长度
    是否为空
    备注




    实验中心
    varchar
    255
    No



    实验分室
    varchar
    255
    No



    实验教室
    varchar
    255
    No
    主码



    实验信息表(SYXXB)



    字段名称
    数据类型
    字段长度
    是否为空
    备注




    实验编号
    varchar
    255
    No
    主码


    课程代码
    varchar
    255
    No



    实验项目
    varchar
    255
    No



    上课老师
    varchar
    255
    No



    辅助教师
    varchar
    255
    Yes



    上课日期
    varchar
    255
    No



    星期几
    varchar
    255
    No



    实验教室
    varchar
    255
    No



    学生表(XSB)



    字段名称
    数据类型
    字段长度
    是否为空
    备注




    姓名
    varchar
    20
    No



    学号
    char
    11
    No
    主码


    班级
    varchar
    255
    No



    登陆密码
    varchar
    255
    Yes



    管理员表(XSB)



    字段名称
    数据类型
    字段长度
    是否为空
    备注




    登陆ID
    varchar
    20
    No
    主码


    登陆密码
    varchar
    255
    No



    3 详细设计3.1 数据库的创建create database SYDK
    3.2 表的创建import pyodbccnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=127.0.0.1;DATABASE=SYDK;UID=sa;PWD=test')cursor = cnxn.cursor()cursor.execute(""" Create Table XSB ( 班级 varchar(20), 学号 char(11), 姓名 varchar(20), 登陆密码 varchar(255) ) """)#学生表cursor.execute(""" Create Table KCB ( 课程代码 varchar(20), 课程名称 varchar(255), 开课学院 varchar(20) ) """)#课程表cursor.execute(""" Create Table JSB ( 姓名 varchar(20), 联系电话 varchar(20), 登陆密码 varchar(255) ) """)#教师表cursor.execute(""" Create Table SYXXB ( 实验编号 varchar(20), 课程代码 varchar(20), 实验项目 varchar(20), 上课老师 varchar(20), 辅助教师 varchar(20), 上课日期 varchar(255), 星期几 varchar(20), 实验中心 varchar(255), 实验分室 varchar(255), 上课地点 varchar(255) ) """)#实验信息表cursor.execute(""" Create Table SYDKB ( 实验编号 varchar(20), 学号 varchar(20), 实际上课时间 varchar(255), 状态 varchar(255) ) """)#实验打卡表cursor.execute(""" Create Table SYSB ( 实验中心 varchar(255), 实验分室 varchar(255), 上课地点 varchar(255) ) """)#实验室表cursor.execute(""" Create Table JSKCB ( 课程代码 varchar(20), 上课老师 varchar(20) ) """)#教师课程表cursor.execute(""" Create Table ADMINB ( id varchar(20), password varchar(20) ) """)#管理员表cursor.commit()cursor.close()
    3.3 数据设定本系统对接南京信息工程大学实践教学综合管理平台,通过访问平台接口,以正则表达式的方法,获取得到教师信息、学生信息、实验信息,从其内含的依赖关系衍生出实验打卡表,实验室表,课程表,教室课程表。同时,管理员用户通过本系统,也可调用该程式对数据库中信息进行维护工作。核心代码如下:
    cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=127.0.0.1;DATABASE=SYDK;UID=sa;PWD=test') cursor = cnxn.cursor() cursor.execute("SELECT * FROM SYXXB WHERE 实验编号="+str(i)) row = cursor.fetchall() print(i) if (len(row)!=0): cursor.close() continue url="http://sjjx.nuist.edu.cn/syjx/admin/experiment/looksyzx.aspx?type=kb&id="+str(i) try: req=urllib.request.Request(url) resp=urllib.request.urlopen(req) except: print("oppops") continue data=resp.read().decode('GBK') w1='<td width=\'610\' height=\'25\' style=\'padding-left:5px;\'>' w2='</td></tr>' pat=re.compile(w1+'(.*?)'+w2,re.S) sybz=pat.findall(data) if(len(sybz)==0): continue del(sybz[9]) w1='<td height=\'25\' style=\'padding-left:5px; width: 82px;\'>' w2='</td>' pat2=re.compile(w1+'(.*?)'+w2,re.S) syb=pat2.findall(data) del(syb[9]) for j in range(0,len(syb)): print (syb[j]+':'+sybz[j]) if(sybz[4].find("(")!=-1): tmp=sybz[4] tmp=tmp[0:tmp.find("(")] sybz[4]=tmp print(sybz[4]) print(sybz[5]) w1='<td align=\'center\'>' w2='</td>' pat3=re.compile(w1+'(.*?)'+w2,re.S) xsbz=pat3.findall(data) cursor.execute("SELECT * FROM JSB WHERE 姓名=\'"+sybz[4]+"\'") row = cursor.fetchall() if (len(row)==0): cursor.execute("insert into JSB values ("+"\'"+sybz[4]+"\'"+",\'"+sybz[5]+"\'"+",\'\')") cursor.execute("SELECT * FROM KCB WHERE 课程代码="+sybz[0])cursor.commit();cursor.close();
    3.4 模块设定3.4.1 登陆模块本模块供不同类型的用户登陆使用,通过单选框的选择,可以选择登陆的用户类型,输入账号密码后,登陆本系统。系统访问数据库判断密码情况,若密码错误则无法成功登陆,访问请求被系统拒绝,若密码正确则进入对应的综合管理模块。

    其核心代码如下:
    from tkinter import *from CoCenter import *import tkinter.messageboxclass LoginFrame (Frame): def __init__(self,master): def ButtonClick(self): s1 = self.ent1.get() s2 = self.ent2.get() if(self.v.get() == 0): self.login(s1,s2,"XSB","学号") elif(self.v.get() == 1): self.login(s1,s2,"JSB","姓名") elif(self.v.get() == 2): self.login(s1,s2,"admin") else: showinfo(title = '错误', message = '未选择登陆方式!') def login(self,name,pwd,tbname="XSB",ab="学号"): if(tbname=="admin"): import pyodbc cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=127.0.0.1;DATABASE=SYDK;UID=sa;PWD=test') cursor = cnxn.cursor() cursor.execute("SELECT password FROM ADMINB WHERE id =\'" +name+"\'") row = cursor.fetchall() cursor.close() if(len(row)==0): tkinter.messagebox.showinfo(title = '错误', message = '用户名不存在') else: if(getVal(str(row[0]))==pwd): tkinter.messagebox.showinfo(title = '成功', message = '登陆成功')
    3.4.2 综合管理模块学生用户管理模块
    学生用户登陆成功后,则可以进入学生用户管理模块,通过点击学生用户管理模块上的按钮,可以调用相应的信息维护模块。

    其核心代码如下:
    self.button=tk.Button(frame,text = "更改登陆密码",pady=10,command = self.XSinfoUpdate)self.button.grid(row = 0,column = 0,padx=10)self.button1=tk.Button(frame,text = "查询个人选课",pady=10,command = self.XSCrouseQry)self.button1.grid(row = 0,column = 1,padx=10,pady=15)self.button2=tk.Button(frame,text = "查询实验课表",pady=10,command = self.XSCrouseQry2)self.button2.grid(row = 0,column = 2,padx=10)self.geometry('310x80')
    教师用户管理模块
    教师用户登陆成功后,则可以进入教师用户管理模块,通过点击教师用户管理模块上的按钮,可以调用相应的信息维护模块。

    其核心代码如下:
    self.button=tk.Button(frame, text = "更改个人信息",pady=10,command = self.JSinfoUpdate)self.button.grid(row = 0,column = 0,padx=10,pady=10)self.button1=tk.Button(frame,text = "更改登陆密码",pady=10,command = self.JSPwdUpdate)self.button1.grid(row = 0,column = 1)self.button2=tk.Button(frame,text = "查询所教课程",pady=10,command = self.JSCrouseQry)self.button2.grid(row = 1,column = 0,padx=10,pady=10)self.button3=tk.Button(frame,text = "查询实验信息",pady=10,command = self.JSExpQry)self.button3.grid(row = 1,column = 1)
    管理员用户管理模块
    管理员用户登陆成功后,则可以进入管理员用户管理模块,通过点击管理员用户管理模块上的按钮,可以调用相应的信息维护模块。

    其核心代码如下:
    self.button=tk.Button(frame,text = "添加学生信息",pady=10,command = self.AdStuAdd)self.button.grid(row = 0,column = 0,padx=10,pady=10)self.button1=tk.Button(frame,text = "修改学生信息",pady=10,command = self.AdStuUpdate)self.button1.grid(row = 0,column = 1,padx=10,pady=10)self.button2=tk.Button(frame,text = "添加教师信息",pady=10,command = self.AdJSAdd)self.button2.grid(row = 1,column = 0,padx=10,pady=10)self.button3=tk.Button(frame,text = "修改教师信息",pady=10,command = self.AdJSUpdate)self.button3.grid(row = 1,column = 1,padx=10,pady=10)self.button4=tk.Button(frame,text = "添加课程信息",pady=10,command = self.AdKCAdd)self.button4.grid(row = 2,column = 0,padx=10,pady=10)self.button5=tk.Button(frame,text = "修改课程信息",pady=10,command = self.AdKCUpdate)self.button5.grid(row = 2,column = 1,padx=10,pady=10)self.button6=tk.Button(frame,text = "添加实验信息",pady=10,command = self.AdExpAdd)self.button6.grid(row = 3,column = 0,padx=10,pady=10)self.button6=tk.Button(frame,text = "修改实验信息",pady=10,command = self.AdExpUpdate)self.button6.grid(row = 3,column = 1,padx=10,pady=10)self.button6=tk.Button(frame,text = "添加实验室信息",pady=10,command = self.AdExpPlaceAdd)self.button6.grid(row = 4,column = 0,padx=10,pady=10)
    3.4.3 信息维护模块用户信息维护模块
    根据不同用户,调用不同的信息维护模块,具体描述如下:
    学生用户调用本模块对登陆密码进行维护

    其核心代码如下:
    Sql("EXEC XS_INFO_UPDATE \'"+self.name+"\',\'"+str(self.newp.get())+"\'",2)tk.messagebox.showinfo('提示','修改成功')
    教师用户调用本模块对登陆密码、联系方式进行维护。

    其核心代码如下:
    Sql("EXEC JS_PWD_UPDATE \'"+self.name+"\',\'"+str(self.newp.get())+"\'",2)tk.messagebox.showinfo('提示','修改成功')
    管理员用户调用本模块对学生的所有属性、教师用户的所有属性进行维护。

    其核心代码如下:
    if(self.element=="STUDENT"): if(self.flag=="ADD"): Sql("INSERT INTO XSB VALUES (\'"+str(self.clsname.get())+"\',\'"+str(self.id.get())+"\',\'"+str(self.name.get())+"\',\'"+str(self.pwd.get())+"\')",2) else: Sql("UPDATE XSB SET 班级=\'"+str(self.clsname.get())+"\',姓名=\'"+str(self.name.get())+ "\',登陆密码=\'"+str(self.pwd.get())+"\' \n WHERE 学号=\'"+str(self.id.get())+"\'",2)if(self.element=="TEACHER"): if(self.flag=="ADD"): Sql("INSERT INTO JSB VALUES (\'"+str(self.id.get())+"\',\'"+str(self.tel.get())+"\',\'"+str(self.pwd.get())+"\')",2) else: Sql("UPDATE JSB SET 联系电话=\'"+str(self.tel.get())+ "\',登陆密码=\'"+str(self.pwd.get())+"\' \n WHERE 姓名=\'"+str(self.id.get())+"\'",2)
    课程信息维护模块
    不同用户对于课程信息维护模块具有不同的权限,具体如下:
    学生用户具有对课程信息的查询权限,对于查询到的课程信息,学生用户可以选择是否导出为excel表格形式:

    其核心代码如下:
    row=Sql("EXEC XS_Course_Qry1 \'"+ self.stuid+"\'",1)table=PrettyTable(["课程代码","课程名称","开课学院"])row1=getVal(row)for i in range(0,int(len(row1)/3)):table.add_row([row1[i*3],row1[i*3+1],row1[i*3+2]])tk.messagebox.showinfo(title = '课程', message = table)a=tk.messagebox.askokcancel('提示', '是否导出选课表')
    教师用户具有对课程信息的查询、创建权限,对于查询到的课程信息,教师用户可以选择是否导出为excel表格形式:

    核心代码如下:
    row=Sql("EXEC JS_Course_Qry \'"+ self.stuid+"\'",1)table=PrettyTable(["课程代码","课程名称","开课学院"])row1=getVal(row)for i in range(0,int(len(row1)/3)):table.add_row([row1[i*3],row1[i*3+1],row1[i*3+2]])tk.messagebox.showinfo(title = '课程', message = table)
    管理用户具有对课程信息的所有权限:

    其核心代码如下:
    if(self.element=="CROUSE"): if(self.flag=="ADD"): Sql("INSERT INTO KCB VALUES (\'"+str(self.id.get())+"\',\'"+str(self.name.get())+"\',\'"+str(self.inst.get())+"\')",2) elif(self.flag=="UPDATE"): Sql("UPDATE KCB SET 开课学院=\'"+str(self.inst.get())+ "\',课程名称=\'"+str(self.name.get())+"\' \n WHERE 课程代码=\'"+str(self.id.get())+"\'",2) else: Sql("INSERT INTO KCB VALUES (\'"+str(self.id.get())+"\',\'"+str(self.name.get())+"\',\'"+str(self.inst.get())+"\')",2) tmp=str(self.flag).split("2") Sql("INSERT INTO JSKCB VALUES (\'"+str(self.id.get())+"\',\'"+str(tmp[1])+"\')",2)
    实验信息维护模块
    根据不同用户,调用不同的信息维护模块,具体描述如下:
    学生用户对于实验信息具有查询权限,对于查询到的实验信息,可以选择是否导出为EXCEL表格

    其核心代码如下:
    row =Sql("EXEC XS_Course_Qry2 \'"+ self.stuid+"\'",1) table=PrettyTable(["实验编号","课程代码","实验项目", "上课老师","辅助教师","上课日期","星期几", "实验中心","实验分室","上课地点"]) row1=getVal(row) for i in range(0,int(len(row1)/10)): table.add_row([row1[i*10],row1[i*10+1],row1[i*10+2], row1[i*10+3],row1[i*10+4],row1[i*10+5], row1[i*10+6],row1[i*10+7],row1[i*10+8],row1[i*10+9]]) tk.messagebox.showinfo(title = '课表', message = table) a=tk.messagebox.askokcancel('提示', '是否导出课表')
    教师用户对于实验信息具有查询、修改权限,对于查询到的实验信息,可以导出为EXCEL表格

    其核心代码如下:
    if(self.element=="EXP"): if(self.flag=="ADD"): Sql("INSERT INTO SYXXB VALUES (\'"+str(self.id.get())+"\',\'"+str(self.kcdm.get())+"\',\'"+str(self.syxm.get())+"\',\'"+str(self.skls.get())+"\',\'" +str(self.fzjs.get())+"\',\'"+str(self.skrq.get())+"\',\'"+str(self.xqj.get())+"\',\'"+str(self.syzx.get())+"\',\'"+str(self.syfs.get())+"\',\'"+str(self.skdd.get())+"\')",2) tk.messagebox.showinfo('提示','更新成功!')
    同时,教师用户对于实验打卡信息具有查询权限,可以通过学生学号查询打卡信息,也可以通过所教班级查询打卡信息,并将打卡信息导出到EXCEL表格。

    其核心代码如下:
    for i in range(0,len(row1)): if(len(row1[i])==11): row=Sql("EXEC JS_STU_QRY5 \'"+self.name+"\',\'"+row1[i]+"\'",1) if(len(row)==0): continue else: row=Sql(""" declare @f1 float declare @f2 float EXEC JS_STU_Qry2 \'"""+str(row1[i])+"\',\'"+self.name+"""\',@f1 output,@f2 output SELECT @f1,@f2""",1) row2=getVal(row) table.add_row([str(row1[i]),str(row2[0]),str(row2[1])]) tk.messagebox.showinfo(title = '查询结果', message =table)
    管理员用户对于实验信息具有全部权限

    核心代码如下:
    Sql("UPDATE SYXXB SET 课程代码=\'"+str(self.kcdm.get())+"\',实验项目=\'" +str(self.syxm.get())+"\',上课老师=\'" +str(self.skls.get())+"\',辅助教师=\'" +str(self.fzjs.get())+"\',上课日期=\'" +str(self.skrq.get())+"\',星期几=\'" +str(self.xqj.get())+"\',实验中心=\'" +str(self.syzx.get())+"\',实验分室=\'" +str(self.syfs.get())+"\',上课地点=\'" +str(self.skdd.get()) +"\' \n WHERE 实验编号=\'"+str(self.id.get())+"\'",2)
    实验室信息维护模块
    管理员用户对实验室信息具有全部权限

    其核心代码如下:
    if(self.element=="EXPPLACE"): if(self.flag=="ADD"): Sql("INSERT INTO SYSB VALUES (\'"+str(self.syzx.get())+"\',\'"+str(self.syfs.get())+"\',\'"+str(self.skdd.get())+"\')",2) else: Sql("UPDATE SYSB SET 实验中心=\'"+str(self.syzx.get())+ "\',实验分室=\'"+str(self.syfs.get())+"\' \n WHERE 上课地点=\'"+str(self.skdd.get())+"\'",2)
    4 总结整个系统的设计过程对于我来说算是个学习、探索的过程,通过实践和对比别人开发程序的过程。在整个设计过程中,出现过很多的问题,很多繁琐的东西都需要反复的修改,主要是前期工作不彻底,对系统的需求分析的要求认识不够清楚,使得在后边的工作中不得不经常反复去修改。使我体会到设置中每一步的重要性。所以在分析一个问题时,我们需要站在一个有远见的高度。
    虽然时间紧迫但我学会了很多,也感到自身知识的贫乏,希望在日后的努力中能做出更完善的系统。
    5 评论 281 下载 2018-10-24 21:35:32 下载需要11点积分
  • 基于MFC的图书管理系统

    1、系统介绍1.1 系统设计目标本次课程设计选择的题目是做一个简易的图书管理系统,应用MFC编程,更加理解了MFC基于对话框的使用完成应用软件的各项功能以及连接数据库的应用,及各个类之间数据传递的关系。主要综合运用所学知识,熟练掌握VC++程序设计的编码与MFC框架结构。
    1.2 系统功能介绍图书馆需要对大量的图书信息进行处理,利用C++文件存储的应用来实现对图书,作者信息,图书借阅信息的添加、修改、删除、查询等常用功能。
    1.3 环境
    开发软件:Visual Studio 2010
    运行平台:Windows系统

    2、系统详细设计思路两大步骤:

    数据存储分析
    代码编写以及功能实现

    首先分析图书,读者,借阅所需要存储的信息,设计合适的存储结构。利用C++面向对象的特性,可以定义图书,读者,借阅三个类来分别存储以上三类信息。
    在界面设计上,将功能分为三大模块,图书管理,读者管理,借阅管理。用选项卡来进行不同模块之间的切换。
    每个模块里,数据展示的方式主要通过CListCtrl控件,该控件可以展示多条同一格式的数据,同时也方便管理者对数据的增删查改操作
    3、各种图3.1 系统流程图、类关系图
    3.2 主要运行界面图、运行结果图图书管理主界面

    添加图书界面

    读者管理主界面

    添加或编辑读者信息

    借阅信息管理界面

    添加借阅信息

    查看借阅信息

    查看借阅信息(如果逾期未归还计算罚款金额)

    4、系统开发过程中遇到的问题对于自己设计的这个小型图书管理系统,考虑平时学校的图书馆管理系统,再结合自身学习的知识来完成这个小型的图书管理系统。
    其中比较大的问题是如何在不同控件之间实现数据的传递,例如借阅信息模块中,添加借阅信息中的借阅人,借阅图书信息必须是来自于已有的读者信息,图书信息。因此我把它做成了不可编辑只可选择的下拉框,因此需要面对如何获得读者信息,图书信息的数据的问题。最后的解决办法是将图书信息,读者信息存储在一个全局的链表中(CList),就可以被不同控件公用。
    5、心得体会经过这段时间的努力基本完成了图书管理系统。对于这个图书管理系统,刚开始对于系统的基本功能是这样设计的:管理员对图书信息的管理以及系统管理员对读者信息的管理、读者的借书、还书。对于一个大型的程序,在实现的过程中,考虑到实际,对于具体的功能 进行了增加、删除。
    同时通过这几天的程序及报告编写,把学过的C++知识运用到了实践。同时,通过和其它同学的交流,对于MFC窗体程序和有了进一步的理解。我也发现了自己的很多不足,自己知识的很多漏洞,看到了自己的实践经验还是比较缺乏,理论联系实际的能力还是比较脆弱。尤其是编写大型的程序所要拥有的知识和技能比较缺乏。程序编好了,还要经过调试和修改,这步也很关键,好的程序是经过了无数次的修改和调试才产生的。我们的程序基本上能够满足要求,但还有一些地方需要改进,在今后我们应该在多看书的同时还要加强实践的练习。才能进一步提高自己的编程能力。
    13 评论 736 下载 2019-03-31 21:35:57 下载需要13点积分
  • 基于JSP实现的美食餐饮管理系统

    摘 要越来越多的人接受了电子商务这种便捷、快速的交易形式,网上订餐的推出也很快受到了大家的欢迎。首先,简要地介绍了国内网络技术和信息产业的发展情况以及研究课题的现状,阐述了网上订餐系统解决方案以及实施的重要意义。然后是建设网上订餐系统,具体分析如何实现系统功能,规划系统流程,设计系统数据库的逻辑结构,介绍在开发系统过程中所使用的重要开发语言、开发工具、配套插件以及开发平台。最后设计和实现了一个B/S结构的网上订餐系统,着重论述了系统的功能与实现、数据流程及存储。包括用户管理、彩票信息介绍、网上订餐以及后台数据库管理等,使用图文并茂(功能代码及截图)的方式,对整个网上订餐系统功能模块的实现方法进行阐述和分析。
    一、开发背景高新科技和计算机的飞速发展,给人们带来了更多的便利,电脑普及时代即将到来,网络技术也在逐渐完善,人们的生活已经开始发生重要的变革,效率已经成为各个企业生存的首要条件,更好更快的使用和了解相关的信息,以及处理更多更繁琐的事物便是我们设计网上购物系统的初衷。
    由于互联网发展已深入家庭,网上订餐这个课题已经提出,为了方便人民生活,提高人民的生活效率,本系统根据现实订餐的方式虚拟于网络之,使人们通过网络就可以完成生活中必要的事情(饮食)。系统的完成不仅可以基本实现客户预定菜的功能,还能在此基础上提供更多的,更贴心的服务。信息技术的发展将更快的推动互联网的发展,订餐系统的重要性也将越显其强大的作用。
    随着越来越多的人接受了电子商务这种便捷、快速的交易形式,网上订餐的顺势而出很快受到了大家的欢迎。
    互联网的应用以普及千家万户,这位网络订餐提供了良好的发展空间。同时网上订餐服务的直观、有效、便捷等优点是传统的电话订餐业务无法比拟的。调查数据显示,现在白领更乐于选择网上订餐服务,网上订餐将是白领一族捕获餐店信息、进行订餐的发展趋势。
    网络订餐随着互联网的成长会逐渐被人们所喜爱,正如几年前手机移动的短信一样,为企业带来的几百个亿的业务收入。在互联网世界里面,谁早一步在应用上创新,谁就掌握了未来的方向,品牌更是一炮打红,网络订餐,看到希望的是希望,看到泡沫的是泡沫。
    二、需求分析2.1 用户基本需求描述根据用户基本的需求分析,系统实现以下功能:

    美食管理:管理员可以对美食进行管理
    用户管理:管理员可以对已注册的用户进行管理
    订单管理:管理员可以对已下单的订单进行管理

    2.2 数据流图分析
    2.3 数据字典


    三、详细设计3.1 概念模型设计
    3.2 关系模型设计
    用户(用户名,密码,性别,籍贯)
    订单(订单ID,总价格,创建时间,支付状态)
    订单详情(ID,菜名,价格,订单ID)
    美食(菜名,图片,菜系,商家名称,价格)

    3.3 物理模型设计用户表(tb_user)



    字段名称
    数据类型
    主键
    是否空
    说明




    name
    varchar(50)
    Y
    N
    用户名


    password
    varchar(50)
    N
    N
    密码


    sex
    varchar(50)
    N
    N
    性别


    address
    varchar(50)
    N
    N
    籍贯



    订单表(tb_order)



    字段名称
    数据类型
    主键
    是否空
    说明




    orderId
    varchar(50)
    Y
    N
    订单ID


    createTime
    varchar(50)
    N
    N
    创建时间


    price
    Decimal(11,2)
    N
    N
    价格


    datetime
    datetime
    N
    N
    修改时间


    status
    int
    Y
    N
    支付状态


    userid
    varchar(128)
    Y
    N
    用户ID



    订单详情表(tb_orderitem)



    字段名称
    数据类型
    主键
    是否空
    说明




    id
    int
    Y
    N
    ID


    name
    varchar(50)
    N
    N
    菜名


    count
    int
    N
    N
    数量


    price
    decimal(11,2)
    N
    N
    价格


    totalprice
    decimal(11,2)
    Y
    N
    总价格


    orderId
    varchar(50)
    Y
    N
    订单ID



    美食表(tb_food)



    字段名称
    数据类型
    主键
    是否空
    说明




    name
    varchar(50)
    Y
    N
    菜名


    photo
    varchar(50)
    N
    N
    图片


    sort
    varchar(50)
    N
    N
    菜系


    restaurant
    varchar(50)
    N
    N
    商家名称


    privce
    double
    Y
    N
    价格


    stock
    int
    Y
    N
    销量



    3.4 SQL命令用户表
    CREATE TABLE `user` (`name` varchar(255) NOT NULL,`password` varchar(255) NOT NULL,`sex` varchar(255) DEFAULT NULL,`address` varchar(255) DEFAULT NULL,PRIMARY KEY (`name`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    美食表
    CREATE TABLE `food` ( `name` varchar(255) NOT NULL, `photo` varchar(255) DEFAULT NULL, `sort` varchar(255) DEFAULT NULL, `restaurant` varchar(255) DEFAULT NULL, `privce` double DEFAULT NULL, `stock` int(11) DEFAULT NULL, PRIMARY KEY (`name`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    订单表
    CREATE TABLE `order` ( `orderId` varchar(50) NOT NULL, `createTime` varchar(19) DEFAULT NULL, `price` decimal(11,2) DEFAULT NULL, `datetime` datetime DEFAULT NULL, `status` int(11) DEFAULT NULL, `userid` varchar(255) DEFAULT NULL, PRIMARY KEY (`orderId`), KEY `userid` (`userid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    订单详细表
    CREATE TABLE `orderitem` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(100) DEFAULT NULL, `count` int(11) DEFAULT NULL, `price` decimal(11,2) DEFAULT NULL, `totalprice` decimal(11,2) DEFAULT NULL, `orderId` varchar(50) DEFAULT NULL, PRIMARY KEY (`id`), KEY `orderId` (`orderId`), CONSTRAINT `orderitem_ibfk_1` FOREIGN KEY (`orderId`) REFERENCES `order` (`orderId`)) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
    四、系统功能模块说明4.1 用户登录模块
    功能描述:此模块的主要功能是实现用户注册。系统的用户必须在注册获得合法身份之后才能登录系统进行对应的操作
    输入:用户名、密码、性别、籍贯
    输出:系统合法用户

    4.2 美食管理模块
    功能描述:此模块的功能主要是实现对美食的管理。管理员可以进行增删改查美食信息
    输入:无
    输出:美食信息

    4.3 用户管理模块
    功能描述:此模块的功能主要是实现对用户的管理。管理员可以进行增删改查用户信息
    输入:无
    输出:用户信息

    4.4 订单管理模块
    功能描述:此模块的功能主要是实现对订单的管理。管理员可以进行增删改查订单信息
    输入:无
    输出:订单信息

    五、系统实现源代码架构图

    5.1 用户登录界面
    5.2 首页界面
    5.3 订单管理界面
    5.4 用户管理界面
    总结在本系统的开发过程中,由于我是初次开发软件,在知识、经验方面都存在着不足,但是我克服种种困难,成功开发出美食餐饮管理系统。另外,在整个开发的过程中,时间也比较仓促。因此,该系统必然会存在一些缺陷和不足。因为对学生管理的整个流程不够熟悉,在需求分析时未能做到完全满足用户的需求。虽然网络在学生管理系统中的应用不是很多,但是未来的发展方向,在本次开发过程由于硬件的限制,未能实现网络功能,因此在以后的系统更新过程中可能会造成一些不必要的数据损失。
    尽管本管理系统存在着很多不足,但其功能全面、易于日后程序更新、数据库管理容易、界面友好、操作方便、效率高、安全性好等优点是本管理系统所必需的。相信本学生管理系统是一套学校在日常管理中必不可少的管理软件,通过开发这个系统,我掌握了的项目过程,了解了的基本知识巩固了我对(开发软件)的学习,但在这次课程设计中的最大收获并不是掌握这几门开发工具的应用,而是学会了设计系统的思维方法。 

    参考文献[1] 陈益全.基于创新型人才培养模式的《Java Web开发》教学设计[J].湖北开放职业学院学报,2020,33(04):5-7.
    [2] 汪永松.JavaWeb开发技巧之项目模板[J].电脑编程技巧与维护,2020(02):3-8+16.
    [3] 季昆,孟丽丽,薛迁,孙晓伟,王才华.基于JavaWeb的产品质量检测预警系统的设计与实现[J].数字技术与应用,2019,37(10):176-177.
    [4] 孙超,孟庆民,王力,姚吉进,宗宝良,郭永新,焦青.基于Java Web的DSA信息管理与图像分析系统的研制[J].中国医疗器械杂志,2019,43(05):348-351.
    [5] 陈青云.HTML5与CSS3技术在网页制作中的应用及发展前景[J].信息与电脑(理论版),2018(16):1-2.
    [6] 熊慧.HTML5和CSS3.0在网页设计中的新特性分析探讨[J].信息记录材料,2018,19(06):106-107.
    [7] 辛红.基于HTML5+CSS3交互式网页布局的研究[J].考试周刊,2017(A3):195.
    [8] 葛蓝.基于HTML5+CSS3的网页布局[J].数字技术与应用,2017(10):92-93.
    [9] 刘京华等.Java Web整合开发王者归来+Java Web整合开发实战.北京:清华大学出版社,2017.1
    [10] 罗永权.HTML语言的网页制作技巧与方法研究[J].计算机产品与流通,2019(10):151
    9 评论 37 下载 2020-09-30 14:59:08 下载需要11点积分
  • 基于C++实现的运动会统分系统

    一、需求分析本系统主要是运动会分数统计方案设计。运动会分数统计方案适合采用结构体数组,为了实现系统功能,主要应实现以下几部分:比赛成绩输入、比赛成绩输出、查询比赛成绩和调用统计结果,进入菜单界面后,需要输入学校编号,项目编号,取得的名次个数,以及哪些名次,并且应该提供键盘式选择菜单实现功能选择。由于运动会分数统计需要处理大量的数据,所以在运行期间,为了避免在运行大量数据时出错,并且系统能够在很短的时间内将运行结果稳定准确输出,就需要系统达到安全性能好,可靠性高,稳定性强,处理数据迅速等特点。
    程序执行命令包括:

    设置运动会相关参数
    输入比赛项目名称和学校名称
    输入各学校比赛成绩以及学校成绩的查询操作

    测试数据:

    二、概要设计按照课题要求,在设计时将本系统分为输入项目成绩、查看学校成绩、查看项目成绩、输入学校和项目名称、设置几个功能模块,并且将对录入的分数按照各项成绩得分以及团体总分排序。系统定义数据时使用结构体和结构体数组来存储信息数据,输入基本信息后由系统统计总分的内容并全部存入文件file中,在排序输出中使用归并排序进行不同关键字的排序,查询函数采用顺序表的查找来完成。
    2.1 学校的抽象数据类型ADT School{ 数据对象:D={ai|ai(-SchoolSet,i=1,2,3,…,n,0<n<=20} 数据关系:R1={<ai-1,ai>|ai-1,ai(-D,i=2,3,…n} 基本操作: firstUsed(&S) 操作结果:将学校结构体中的数据置空,清零。 saveToFile (&S) 操作结果:将学校结构体中的数据存储到文件中。 readFromFile(&S) 操作结果:将文件中的学校结构体数据读取到内存中。 merge_sort($S,option) 操作结果:将学校结构体数组按照条件排序。 schoolInput(&S) 操作结果:将学校信息输入到学校结构体中。 showSchool(&S) 操作结果:将学校结构体中的数据输出。}ADT School
    2.2 比赛项目的抽象数据类型ADT Sport{数据对象:D={ai|ai(-SportsSet,i=1,2,3,…,n,0<n<=20} 数据关系:R1={<ai-1,ai>|ai-1,ai(-D,i=2,3,…n} 基本操作: firstUsed(&S) 操作结果:将比赛项目结构体中的数据置空,清零。 saveToFile (&S) 操作结果:将比赛项目结构体中的数据存储到文件中。 readFromFile(&S) 操作结果:将文件中的比赛项目结构体数据读取到内存中。 inputScores (&S) 操作结果:将比赛项目信息输入到学校结构体中。 showSports (&S) 操作结果:将比赛项目结构体中的数据输出。}ADT Sport
    由于本程序中的学校和比赛项目数据类型呈平行关系且他们在程序运行期间反复使用,故设计为全局变量,减少传参导致系统性能的降低;又由于二则的操作几近相同,故把二者的操作放在一起,同时执行,因此,抽象数据类型的设计与代码优化后的结果略有差异。
    2.3 本程序包含六个模块2.3.1 主程序模块Void main(){ 初始化; While(1){ 接收命令; 处理命令; If(退出)break;}
    2.3.2 输入项目成绩模块实现对运动会比赛成绩的输入操作。
    2.3.3 查看学校成绩模块实现对学校的比赛成绩的排名查看。
    2.3.4 查看项目成绩模块实现对项目的成绩查看。
    2.3.5 输入学校和项目名称模块实现对学校和比赛项目的名称输入。
    2.3.6 输入学校和项目名称模块实现对学校和比赛项目的名称输入。
    2.4 模块调用图
    三、具体设计3.1 头文件声明和全局变量定义#include <stdio.h>#include<windows.h>#include<stdlib.h>#include<conio.h>#include<string.h>#define default_num 3 ///默认获奖名次数目,取3或5int n=20; ///最大学校数目int m=10; ///最大男子项目数目int w=10; ///最大女子项目数目School schools[25]; ///学校结构体数组School temp[25]; ///用来缓存排序列表学校数据School temp1[25]; ///排序缓存数组Sport sports[50]; ///比赛项目结构体数组int three[3]={5,3,2}; ///获得前三名的学校积分int five[5]={7,5,3,2,1}; ///获得前五名的学校积分
    3.2 函数声明///从数据文件读取存有的运动会成绩信息void readFromFile(); ///将输入到内存中的数据存到文件中void saveToFile(); ///程序文件数据清零void firstUsed(); ///初始化操作,在此文件操作,进行打开程序的读取初始化操作void initialization(); ///按照不同的参数对学校数组进行排序,采用归并排序void merge_sort(School temp[],int st,int en,int option,School temp1[]); ///输入学校成绩并统计void schoolInput(int schoolnum,int award_num,int i,int pos); ///输入项目成绩菜单void inputScores(); ///输出学校菜单void showSchool(); ///输出查找项目菜单void showSports(); ///输入学校和项目名称菜单void InputName(); ///设置菜单void setting(); ///主菜单的操作void menu();
    3.3 数据结构定义3.3.1 运动项目数据表运动会系统先制定本次运动会所需的参赛项目。本数据表根据要求设计存储每个项目的编号、项目名称、要取的名次、各个名次获奖学校。用于对以后项目情况的统计已及查询。其中项目编号直接用运动项目数组下标+1表示,name和win_school由输入信息输入,award_num由设置选项输入。
    typedef struct Sport{ char name[20]; ///项目名称 int win_school[5]; ///获奖前三或前五学校的编号 int award_num; ///这个运动项目取名次的数目,取3或5} Sport; ///存放项目信息Sport sports[50]; ///定义运动项目数组
    3.3.2 学校数据表本数据表根据要求储存了各个参赛学校的总体情况,包括学校的编号、学校名称、各个项目得分、学校总分、男子团体总分、女子团体总分。其中学校编号由学校数组下标+1表示,学校名称,各项目得分由输入信息输入,学校总分,男子团体总分,女子团体总分由系统自动统计。
    注:学校总分,男子团体总分,女子团体总分存储在一个长度为3 的数组当中,作此设计是为了实现对学校的按照特定参数排序操作中,用传入一个下标参数的形式实现对排序条件的控制。
    typedef struct School{ int total_score[3];///下标0表示学校总分,1表示男子总分,2表示女子总分,方便之后的排序输出而存在数组中 char name[20]; ///学校名称 int scores[50]; ///各个项目得分} School;School schools[25]; ///定义学校数组
    四、运行结果4.1 主菜单界面
    4.2 设置运动会相关参数
    4.3 输入学校和项目名称
    4.4 输入运动会比赛成绩
    4.5 查看学校运动会成绩
    4.6 查看项目比赛成绩
    五、调试分析
    学校数组和比赛项目数组的数据一开始出现不同步的现象,两个数组之间的数据没有对应关系,这是导致一开始程序运行结果与预期结果不一致的主要问题
    对于数据文件的储存,刚开始没有考虑程序执行一半退出系统前要先把数据保存再退出,导致操作数据丢失。对于文件操作,文件的内容及时保存是避免这个错误的可靠方法
    本程序的模块跳转之间的文件保存、跳转之间的数据传递、模块跳转的合理性也是一开始设计上不足所在,这些问题经过调试也得到解决,因此,在以后的设计中,应该要把细节方面考虑清楚,减少对问题的考虑疏忽导致程序产生难以找到的错误
    关于中英文的字符串长度和对齐问题:经过调试得知中文一个字符的长度是2,这在学校成绩输出表格的对齐问题上有重要作用
    程序代码的时空分析:由于本程序中的学校数组和比赛项目数组长度都是常数阶,故本程序的时间复杂度为O(1),空间复杂度也为O(1)

    六、程序数据的文件存储形式本程序将程序数据分为三个txt文件保存,分别是schools.txt, sports.txt, setting.txt。分别保存学校数组,运动项目数组和设置参数的数据。其中学校数组和运动项目数组按照结构体的成块储存,每块保存着单个结构体的所有参数数据,而设置参数则按照设置菜单的顺序直接存储各个参数。该储存结构可通过附件查看得到。
    七、关于非法数据的输入在本程序中,不论整体非法数据还是局部非法数据,在数据的输入过程中对数据直接进行检测,只要遇到一个非法数据,即提醒用户重新输入,知道输入的数据合法为止,例如以下情况:

    八、用户使用说明本程序的运行环境为Code::Blocks13.12,执行文件为SportsMeeting.exe,在进入该程序软件打开文档,然后对本程序进行调试,调试完毕,用户可根据需求从主菜单选择相应的功能,调用功能函数对用户需求进行单独运算。
    本程序通过对实际操作的考虑,设计成在程序执行前先进行对运动会相关参数的设定,再输入学校、项目名称,最后再输入成绩进行分数统计,其中,参数设定必须先执行,之后的操作可由用户喜好决定。
    3 评论 89 下载 2018-10-31 11:14:43 下载需要9点积分
  • Java飞机大战游戏设计与实现

    1 概述1.1 项目简介本次Java课程设计是做一个飞机大战的游戏,应用Swing编程,完成一个界面简洁流畅、游戏方式简单,玩起来易于上手的桌面游戏。该飞机大战项目运用的主要技术即是Swing编程中的一些窗口类库、事件监听以及贴图技术。
    1.2 实训功能说明1.2.1 基本功能
    通过键盘,方向键和ASWD键可控制战机的位置,空格键和鼠标左键发射子弹
    界面中敌机出现的位置,以及敌机和Boss炸弹的发射均为随机的,敌机与敌机炸弹、Boss炸弹均具有一定的速度,且随着关卡难度的增大,数量和速度均随着关卡数增加而增加
    对于随机产生的敌机和敌机炸弹,若超过矩形区域,则释放该对象
    添加碰撞效果,包括战机子弹打中敌机爆炸、敌机炸弹打中战机爆炸、战机与敌机相撞爆炸、战机子弹与敌机炸弹相撞爆炸、战机子弹打中Boss、战机与Boss碰撞以及战机吃到血包七种碰撞效果。且碰撞发生后子弹、炸弹、血包均消失,战机生命值减一,敌机和Boss生命值减少当前战机炮弹威力的生命值,若敌机或Boss生命值归零,则删除敌机或Boss
    血包:随着关卡游戏进程的进行,会出现一定量的血包供战机补给生命值,血包会在客户区矩形框内运动,10秒后消失;若战机在10秒内吃到血包,则会增加5点生命值知道生命值上限
    每关中战机有三条命,每条命10点生命值,生命使用完后,会进入GameOver界面显示得分数,并提供重新开始游戏和退出功能
    游戏提供10个关卡,每个关卡需要打死相应关卡的敌机数量才能进入Boss模式,打败Boss之后将会进入下一关。10关通关后,显示通关界面,并提供重新开始游戏和退出游戏的功能选项
    暂停功能:游戏进行过程中按下Z键可进入暂停模式,再按Z则返回游戏
    无敌模式:游戏进行过程中按下Y键可进入无敌模式,再按Y则返回正常游戏。该模式下战机生命值不会减少,可供测试使用
    魔法值:游戏进行过程中,战机魔法值会随着时间递增到上限10,魔法值供战机道具功能的使用,过一个关卡魔法值不清零
    战机大招:当战机魔法值为10满状态时,按下X键消耗所有魔法值可发动大招,对屏幕中的敌机进行清屏,Boss扣50点血量
    防护罩:当魔法值不为0时,按下C键可打开防护罩道具,该状态下战机处于无敌状态,不会损失生命值,但魔法值会随着防护罩开启慢慢降低
    战机升级功能:战机子弹单个威力为1,在魔法值不为0时,按下V键开启升级战机模式,战机图标变为动画,子弹威力变成两倍。(若同时开启防护罩和战机升级,则魔法值递减速度翻倍)

    1.2.2 附加功能
    为游戏界面每个关卡添加了滚动背景图片和背景音乐,并在敌机发送炮弹、战机发射子弹、战机击中敌机、敌机击中战机、战机敌机相撞、敌机战机子弹相撞、战机吃到血包、战机大招、战机升级、战机防护罩、游戏结束时均添加了音效
    为美化游戏界面,采用了一部分全民飞机大战图标,并添加了爆炸动画和升级战机动画特效,背景音乐采用微信飞机大战背景音乐和相关特效音效
    为游戏设置了不同的关卡,每个关卡难度不同,敌机与敌机炸弹的速度随着关卡增大而加快,进入第五关以后敌机从上下方均会随机出现,且随机发射炸弹
    前五关卡敌机从上方飞出,速度一定,战机每打掉一架敌机则增加一分,当战机得分超过该关卡所需分数(和关卡数相关)则可进入Boss模式,打败Boss进入下一关;进入第六关以后,敌机分别从上下两方飞出。随着关卡数增加,敌机数量增加,速度增快,敌机炮弹数量和速度也相应增加,进入Boss所需分数增加,Boss生命值和火力也随着关卡数的增加而增加,游戏难度陡然直升
    游戏界面中显示当前状态下的关卡数、当前命数、当前得分、战机血条、战机魔法条、无敌模式提醒和战机道具提醒,Boss模式下还有Boss血条
    增加了鼠标控制战机位置这一效果,战绩的位置随着鼠标的移动而移动,并且点击鼠标左键可使得战机发射子弹
    进入游戏先进入欢迎界面,欢迎界面中显示游戏使用说明,点击鼠标左键和空格键开始游戏。游戏过程中战机命数使用完、通关均有相应界面进行提醒,用户可选择重新开始游戏或退出游戏

    2 相关技术2.1 Timer定时器技术本次项目采用了Java的Timer定时器和TimerTask任务,Timer周期性地在每经过一个指定的时间间隔后就通知TimerTask一次,让TimerTask按照Timer设定的周期循环地执行任务。本程序中使用多个定时器,分别控制不同的功能,分别是屏幕刷新Timer,敌机产生Timer,魔法值变化Timer,血包生命周期Timer。
    2.2 透明贴图实现技术绘制透明位图的关键就是创建一个“掩码”位图(mask bitmap),这个“掩码”位图是一个单色位图,它是位图中图像的一个单色剪影。
    整个绘制过程需要使用到ImageUtil类的createImageByMaskColorEx静态方法,把传入的原图BufferedImage中的指定颜色的背景去掉,返回去掉背景的BufferedImage对象,传送到窗口进行展示。
    2.3 游戏对象列表Java类库中提供了丰富的List接口的实现方法,本项目采用ArrayList存放游戏运行过程中的游戏对象。
    滚动背景模块
    // 欢迎界面图像列表private static BufferedImage titleImage;// 游戏背景对象public static Scene scene;
    各游戏对象
    public static MyPlane myplane = null;Enemy enemy = null;public static Boss boss = null;Bomb bomb = null;Ball ball = null;Explosion explosion = null;Blood blood = null;
    存储游戏对象的对象列表
    public static List<Enemy> enemyList = new ArrayList<Enemy>();public static List<MyPlane> meList = new ArrayList<MyPlane>();public static List<Bomb> bombList = new ArrayList<Bomb>();public static List<Ball> ballList = new ArrayList<Ball>();public static List<Explosion> explosionList = new ArrayList<Explosion>();public static List<Blood> bloodList = new ArrayList<Blood>();
    游戏运行相关参数
    int speed; // 战机的速度,方向键控制public static int myLife; // 为战机设置生命值public static int lifeNum; // 战机命条数public static int myScore; // 战机的得分public static int passScore; // 当前关卡得分数public static int lifeCount; // 血包产生控制参数public static boolean bloodExist; // 标记屏幕中是否存在血包public static int magicCount; // 魔法值,控制能否发大招public static int bossBlood; // Boss血量public static int passNum; // 记录当前关卡
    游戏运行相关标志位
    public static boolean isPass; // 是否通关的标志public static boolean isPause; // 是否暂停public static boolean isBoss; // 标记是否进入Bosspublic static boolean bossLoaded; // 标记Boss出场完成public static boolean isProtect; // 标记是否开启防护罩public static boolean isUpdate; // 标记战机是否升级public static boolean test; // 无敌模式参数public static int isStop; // 标记游戏停止public static boolean isStarted; // 标记欢迎界面是否加载完成
    2.4获取矩形区域使用 Rectangle的intersects方法来判断两个源矩形是否有重合的部分。如果有重合,返回true,没有从何返回false。
    2.5 List<BufferedImage>处理爆炸效果爆炸效果是连续的显示一系列的图片。如果把每一张图片都在要显示的时候进行加载,占用的时间是非常多的,必然后导致程序的可行性下降。List<BufferedImage>是一个“图象列表”是相同大小图象的集合,每个图象都可由其基于零的索引来参考。可以用来存放爆炸效果的一组图片,通过Timer消息连续循环绘制出List<BufferedImage>中的多张图片做成的爆炸效果。
    3 总体设计与详细设计3.1 系统模块划分该飞机大战游戏程序分为游戏滚动背景绘制模块、各游戏对象绘制模块、游戏对象之间的碰撞模块、爆炸效果产生模块、游戏界面输出玩家得分关卡信息模块、战机道具技能维护模块、消息处理模块、视图生命周期维护模块。
    其中在游戏对象绘制模块中,战机是唯一对象,在游戏开始时产生该对象,赋予其固定的生命值,当其与敌机对象、敌机炸弹碰撞时使其生命值减一,直至生命值为零,便删除战机对象。敌机对象与敌机炸弹对象的绘制中采用定时器技术,定时产生。爆炸对象初始化为空,当游戏过程中即时发生碰撞时,在碰撞位置产生爆炸对象,添加到爆炸链表中,并根据爆炸素材图像分八帧进行输出,达到动画特效。
    3.2 主要功能模块3.2.1 系统对象类图
    GameObject是各个游戏对象的抽象父类,继承自Object类,其他的类:战机类、敌机类、爆炸类、子弹类、炸弹类、血包类、文字类都继承了此类,Boss类继承敌机类。每个游戏对象类中既继承了来自父类GameObject的属性,又有自己的特有属性和方法。
    GameObject类介绍:
    // 该游戏对象在窗口中的坐标位置protected Point point;// 在窗口中绘制该游戏对象图标public boolean draw(Graphics g, JPanel panel, boolean pause);// 获取该游戏对象图标在窗口中的矩形框,进行碰撞检测时使用public Rectangle getRect();// 加载该游戏对象对应的图像到内存,方便之后的显示调用public static boolean loadImage(BufferedImage image, String source);
    继承GameObject的其他游戏对象类也都重载了相关方法,以便于各个游戏对象在程序的调用过程中调用方式的一致性。
    3.2.2 项目包和类层次结构图

    MyPanel:JPanel的继承类,是飞机大战窗口的总显示面板,其中包含了游戏运行过程中的大量全局参数和全局标记位
    SpaceWar:程序的入口,窗口对象启动的位置,并在此对相关事件进行了监听
    Ball:敌机炮弹类,继承GameObject,有加载图片,获取矩形框,获取对象位置,绘制回想等游戏对象通用操作方法
    Blood:血包类,继承GameObject,有加载图片,获取矩形框,获取对象位置,绘制回想等游戏对象通用操作方法
    Bomb:战机炮弹类,继承GameObject,有加载图片,获取矩形框,获取对象位置,绘制回想等游戏对象通用操作方法
    Boss:Boss类,继承GameObject,有加载图片,获取矩形框,获取对象位置,绘制回想等游戏对象通用操作方法
    Enemy:敌机类,继承GameObject,有加载图片,获取矩形框,获取对象位置,绘制回想等游戏对象通用操作方法
    Explosion:爆炸效果类,继承GameObject,有加载图片,获取矩形框,获取对象位置,绘制图片等游戏对象通用操作方法
    GameObject:游戏对象基类,有加载图片,获取矩形框,获取对象位置,绘制图片的游戏对象统一的方法,统一游戏对象的操作方式
    MyPlane:战机类,继承GameObject,有加载图片,获取矩形框,获取对象位置,绘制图片等游戏对象通用操作方法
    Scene:场景类,实现了背景滚动,并根据关卡显示不同的背景图片
    EnemyTask:实现了TimerTask接口,随着Timer计时器的调用而随时间产生敌机对象和敌机炮弹对象,实现自动产生敌机的效果
    MagicTask:实现了TimerTask接口,随着Timer计时器的调用而随时间改变魔法值
    RefreshTask:实现了TimerTask接口,随着Timer计时器的调用而随时间刷新窗口界面
    AudioUtil:音频操作工具类,提供播放背景音乐和操作音效
    ImageUtil:图片加工工具类,实现了透明贴图方法和背景图片拼接

    3.2.3 系统主程序活动图
    3.2.4 系统部分流程图飞机大战游戏执行流程图

    定时器产生敌机和炸弹流程图

    血包执行流程图

    4 编码实现4.1 滚动背景在滚动背景的初始化方法和释放方法添加背景音乐播放和释放
    //场景类public class Scene { private int beginY;// 背景的Y坐标 private List<BufferedImage> images; public Scene() { this.images = new ArrayList<BufferedImage>(); } // 初始化场景 public boolean initScene() { // 加载开始图片 BufferedImage buffer; try { buffer = ImageUtil.copyImage(ImageIO.read(new File( "images/start.bmp"))); this.images.add(buffer); // 如果加载失败, 返回false for (int i = 1; i <= 6; i++) { buffer = ImageUtil.copyImage(ImageIO.read(new File( "images/background" + i + ".bmp"))); this.images.add(buffer); } } catch (IOException e) { e.printStackTrace(); return false; } // 背景起始坐标为0 this.beginY = 0; // 播放背景音乐 AudioUtil.playBackground(); return true; } // 绘制场景 public void stickScene(Graphics graphics, int index, ImageObserver observer) { if (index == -1) index = 0; else index = index % 6 + 1; BufferedImage image = images.get(index); // 窗口滑在图片中间 if (beginY >= 0 && beginY + SpaceWar.WINDOWS_HEIGHT <= image.getHeight()) { BufferedImage buffer = image.getSubimage(0, beginY, image.getWidth(), SpaceWar.WINDOWS_HEIGHT); graphics.drawImage(buffer, 0, 0, SpaceWar.WINDOWS_WIDTH, SpaceWar.WINDOWS_HEIGHT, observer); } else if (beginY < 0) { // 超出图片上界 BufferedImage imageUp = image.getSubimage(0, image.getHeight() + beginY, image.getWidth(), -beginY); graphics.drawImage(imageUp, 0, 0, SpaceWar.WINDOWS_WIDTH, -beginY, observer); graphics.drawImage(image, 0, -beginY, SpaceWar.WINDOWS_WIDTH, SpaceWar.WINDOWS_HEIGHT, observer); if (-beginY > SpaceWar.WINDOWS_HEIGHT) { beginY = image.getHeight() + beginY; } } } // 移动背景 public void moveBg() { // 移动背景 beginY -= 1; } // 释放内存资源 public void releaseScene() { for (int i = 0; i < 7; i++) if (images.get(i) != null) images.get(i).flush(); // 关闭背景音乐 AudioUtil.stopBackground(); } public int getBeginY() { return beginY; } public void setBeginY(int beginY) { this.beginY = beginY; }}//在MyPanel中刷新滚动// 滚动背景scene.stickScene(g, -1, this);scene.moveBg();
    4.2 显示战机if (myplane != null) { myplane.draw(g, this, isPause, isProtect);}
    4.3 随机产生敌机和敌机炮弹、Boss炮弹 //随机添加敌机,敌机随机发射炸弹,此时敌机速度与数量和关卡有关 // 根据关卡数产生敌机 if (MyPanel.passNum <= 5) { // 前五关只有一个方向的敌机 Enemy enemy = new Enemy(Enemy.ENEMY_SPEED, 1);// 设置敌机的方向,从上方飞出 enemyList.add(enemy);// 随机产生敌机 if (new Random().nextInt(2) == 0) {// 控制敌机炮弹发出频率 Ball ball = new Ball( enemy.getPoint().x + Enemy.ENEMY_WIDTH / 2, enemy.getPoint().y + Enemy.ENEMY_HEIGHT, enemy.getDirection()); ball.setBallSpeed(enemy.getSpeed()+2); MyPanel.ballList.add(ball); // 音效 AudioUtil.play(AudioUtil.AUDIO_BALL); } } else if (MyPanel.passNum > 5) {// 第五关之后,两个方向的敌机 Enemy enemy1 = new Enemy(Enemy.ENEMY_SPEED, 1);// 设置敌机的方向,从上方飞出 enemy1.setSpeed(Enemy.ENEMY_SPEED + (new Random().nextInt(2) + MyPanel.passNum - 1)); enemyList.add(enemy1); Enemy enemy2 = new Enemy(Enemy.ENEMY_SPEED, -1);// 设置敌机的方向,从下方飞出 enemy2.setSpeed(Enemy.ENEMY_SPEED + (new Random().nextInt(2) + MyPanel.passNum - 1)); enemyList.add(enemy2); int rand = new Random().nextInt(3); if (rand == 0) {// 控制敌机炮弹发出频率 Ball ball = new Ball(enemy1.getPoint().x + Enemy.ENEMY_WIDTH / 2, enemy1.getPoint().y + Enemy.ENEMY_HEIGHT, enemy1.getDirection()); ball.setBallSpeed(enemy1.getSpeed()+2); MyPanel.ballList.add(ball); // 音效 AudioUtil.play(AudioUtil.AUDIO_BALL); } if (rand == 1) {// 控制敌机炮弹发出频率 Ball ball = new Ball(enemy2.getPoint().x + Enemy.ENEMY_WIDTH / 2, enemy2.getPoint().y, enemy2.getDirection()); ball.setBallSpeed(enemy2.getSpeed()+2); MyPanel.ballList.add(ball); // 音效 AudioUtil.play(AudioUtil.AUDIO_BALL); } } if (MyPanel.isBoss) { // Boss发射子弹 // 敌机炸弹产生定时器触发 // 设置定时器产生敌机炸弹 Ball ball1 = new Ball(MyPanel.boss.getPoint().x + Boss.BOSS_WIDTH / 2, MyPanel.boss.getPoint().y + Boss.BOSS_HEIGHT, 1); ball1.setBallSpeed(Ball.BALL_SPEED + (MyPanel.passNum - 1) * 2); MyPanel.ballList.add(ball1); Ball ball2 = new Ball(MyPanel.boss.getPoint().x + 5, MyPanel.boss.getPoint().y + Boss.BOSS_HEIGHT, 1); ball2.setBallSpeed(Ball.BALL_SPEED + (MyPanel.passNum - 1) * 2); MyPanel.ballList.add(ball2); Ball ball3 = new Ball(MyPanel.boss.getPoint().x + Boss.BOSS_WIDTH - 5, MyPanel.boss.getPoint().y + Boss.BOSS_HEIGHT, 1); ball3.setBallSpeed(Ball.BALL_SPEED + (MyPanel.passNum - 1) * 2); MyPanel.ballList.add(ball3); Ball ball4 = new Ball(MyPanel.boss.getPoint().x + Boss.BOSS_WIDTH / 2 + 85, MyPanel.boss.getPoint().y + Boss.BOSS_HEIGHT, 1); ball4.setBallSpeed(Ball.BALL_SPEED + (MyPanel.passNum - 1) * 2); MyPanel.ballList.add(ball4); Ball ball5 = new Ball(MyPanel.boss.getPoint().x + Boss.BOSS_WIDTH / 2 - 85, MyPanel.boss.getPoint().y + Boss.BOSS_HEIGHT, 1); ball5.setBallSpeed(Ball.BALL_SPEED + (MyPanel.passNum - 1) * 2); MyPanel.ballList.add(ball5); // 音效 AudioUtil.play(AudioUtil.AUDIO_BALL); }
    4.4 显示战机发射子弹for (int i = 0; i < bombList.size(); i++) { bomb = bombList.get(i); if (bomb == null) continue; bomb.setCurrentIndex(i); bomb.isUpdate = isUpdate; if (!bomb.draw(g, this, isPause)) i--; }
    4.5 碰撞检测,以战机子弹集中敌机为例if (MyPanel.myplane != null && !MyPanel.isPause) { // 子弹打中敌机 boolean flag = false; for (int i = 0; i < MyPanel.bombList.size(); i++) { Bomb bomb = MyPanel.bombList.get(i); if (bomb == null) continue; Rectangle bombRectangle = bomb.getRect(); for (int j = 0; j < MyPanel.enemyList.size(); j++) { Enemy enemy = MyPanel.enemyList.get(j); if (enemy == null) continue; Rectangle enemyRectangle = enemy.getRect(); if (enemyRectangle.intersects(bombRectangle)) { Explosion explosion = new Explosion( (bomb.getPoint().x + Bomb.BOMB_WIDTH / 2 - Explosion.EXPLOSION_WIDTH / 2), (bomb.getPoint().y + Bomb.BOMB_HEIGHT / 2 - Explosion.EXPLOSION_WIDTH / 2)); MyPanel.explosionList.add(explosion); // 音效 AudioUtil.play(AudioUtil.AUDIO_EXPLOSION); // 爆炸后删除子弹 MyPanel.bombList.remove(i); i--; // 敌机生命值减少 enemy.life -= MyPanel.isUpdate ? 2 : 1; if (enemy.life <= 0) { // 增加得分 MyPanel.passScore++; // 删除敌机 MyPanel.enemyList.remove(j); j--; } // 炮弹已删除,直接跳出本循环 flag = true; break; } } if (flag) continue; if (MyPanel.isBoss && bomb != null) { // 获得战机子弹的矩形区域 Rectangle bombRect = bomb.getRect(); // 获得Boss的矩形区域 Rectangle bossRect = MyPanel.boss.getRect(); // 判断两个矩形区域是否有交接 if (bombRect.intersects(bossRect)) { // 将爆炸对象添加到爆炸链表中 Explosion explosion = new Explosion( (bomb.getPoint().x + Bomb.BOMB_WIDTH / 2 - Explosion.EXPLOSION_WIDTH / 2), (bomb.getPoint().y + Bomb.BOMB_HEIGHT / 2 - Explosion.EXPLOSION_WIDTH / 2)); MyPanel.explosionList.add(explosion); // 音效 AudioUtil.play(AudioUtil.AUDIO_EXPLOSION); // 爆炸后删除子弹 MyPanel.bombList.remove(i); i--; bomb = null; // 是Boss,不删除敌机,只扣血 MyPanel.bossBlood -= MyPanel.isUpdate ? 2 : 1; if (MyPanel.bossBlood <= 0) { Explosion explosion1 = new Explosion( MyPanel.boss.getPoint().x, MyPanel.boss.getPoint().y); MyPanel.explosionList.add(explosion1); Explosion explosion2 = new Explosion( (MyPanel.boss.getPoint().x + Boss.BOSS_WIDTH), (MyPanel.boss.getPoint().y + Boss.BOSS_HEIGHT)); MyPanel.explosionList.add(explosion2); Explosion explosion3 = new Explosion( (MyPanel.boss.getPoint().x + Boss.BOSS_WIDTH), (MyPanel.boss.getPoint().y)); MyPanel.explosionList.add(explosion3); Explosion explosion4 = new Explosion( (MyPanel.boss.getPoint().x), (MyPanel.boss.getPoint().y + Boss.BOSS_HEIGHT)); MyPanel.explosionList.add(explosion4); Explosion explosion5 = new Explosion( (MyPanel.boss.getPoint().x + Boss.BOSS_WIDTH / 2 - Explosion.EXPLOSION_WIDTH / 2), (MyPanel.boss.getPoint().y + Boss.BOSS_HEIGHT / 2 - Explosion.EXPLOSION_WIDTH / 2)); explosion5.setBossDie(true);// 标记最后一个炸弹,炸完之后跳入下一关 MyPanel.explosionList.add(explosion5); MyPanel.boss = null; // 过关的标志变量 // isPause = TRUE; // CMyPlane* temp = myplane; // myplane = new CMyPlane(FALSE); MyPanel.myplane = null; MyPanel.isPass = true; MyPanel.isBoss = false; } } } } }
    4.6 显示爆炸效果for (int i = 0; i < explosionList.size(); i++) { explosion = explosionList.get(i); if (explosion == null) continue; boolean b = explosion.draw(g, this, isPause); if (!b) { explosionList.remove(i); i--; } }
    4.7 血包功能游戏三分之一和三分之二进程时刻出现血包
    //开启血包 if (MyPanel.myplane != null && MyPanel.myLife > 0 && !MyPanel.isPause) { // 关卡打了三分之一三分之二处出现血包 if (MyPanel.passScore > (MyPanel.PASS_SCORE + MyPanel.passNum * 5) * MyPanel.lifeCount / 3) { // 若屏幕中有未吃掉的血包,这次不产生血包 if (!MyPanel.bloodExist) { MyPanel.lifeCount++; // 产生血包 Blood blood = new Blood(); MyPanel.bloodList.add(blood); MyPanel.bloodExist = true; bloodTimer = new Timer(); bloodTimer.schedule(new TimerTask() { @Override public void run() { bloodTimer.cancel(); bloodTimer = null; MyPanel.bloodExist = false; // 声明血包位置 for (int i = 0; i < MyPanel.bloodList.size(); i++) { MyPanel.bloodList.remove(i); i--; } } }, 10000); } else MyPanel.lifeCount++; } } //血包定时器,10秒后血包消失 bloodTimer = new Timer(); bloodTimer.schedule(new TimerTask() { @Override public void run() { bloodTimer.cancel(); bloodTimer = null; MyPanel.bloodExist = false; // 声明血包位置 for (int i = 0; i < MyPanel.bloodList.size(); i++) { MyPanel.bloodList.remove(i); i--; } } }, 10000); //显示血包 if (myplane != null && !isPause) { // 检索血包链表,非空时在所在位置显示 int i = 0; while (i < bloodList.size()) { blood = bloodList.get(i); if (blood == null) continue; blood.draw(g, this, false); i++; }// while }//血包碰撞检测 if (MyPanel.myplane != null && !MyPanel.isPause) { // 吃到血包 // 声明血包位置 for (int i = 0; i < MyPanel.bloodList.size(); i++) { Blood blood = MyPanel.bloodList.get(i); // 获得血包矩形 Rectangle bloodbRect = blood.getRect(); // 获得战机矩形 Rectangle planeRect = MyPanel.myplane.getRect(); // 判断两个矩形区域是否有交接 if (bloodbRect.intersects(planeRect)) {// 音效 AudioUtil.play(AudioUtil.AUDIO_BLOOD); // 加血效果 MyPanel.myLife += 5; if (MyPanel.myLife > MyPanel.DEFAULT_LIFE) MyPanel.myLife = MyPanel.DEFAULT_LIFE; // TODO 声音 // 加血后血包删除 MyPanel.bloodList.remove(i); i--; break; }// if }// for }
    4.8 通关和死亡消息页面if (isStop == FLAG_RESTART) { Font textFont = new Font("宋体", Font.BOLD, 20); g.setFont(textFont); // 设置透明背景 // cdc.SetBkMode(TRANSPARENT); g.setColor(Color.red); g.drawString("哇,恭喜你已通关!", SpaceWar.WINDOWS_WIDTH / 2 - 100, SpaceWar.WINDOWS_HEIGHT / 2 - 30); g.drawString("您的得分为:" + myScore, SpaceWar.WINDOWS_WIDTH / 2 - 100, SpaceWar.WINDOWS_HEIGHT / 2 - 10); g.drawString("COME ON !重新开始?Y/N", SpaceWar.WINDOWS_WIDTH / 2 - 100, SpaceWar.WINDOWS_HEIGHT / 2 + 10); return; } else if (isStop == FLAG_STOP) { Font textFont = new Font("宋体", Font.BOLD, 20); g.setFont(textFont); // 设置透明背景 // cdc.SetBkMode(TRANSPARENT); g.setColor(Color.red); // 显示最后结果 g.drawString("GAME OVER!", SpaceWar.WINDOWS_WIDTH / 2 - 100, SpaceWar.WINDOWS_HEIGHT / 2 - 30); g.drawString("您的得分为:" + myScore, SpaceWar.WINDOWS_WIDTH / 2 - 100, SpaceWar.WINDOWS_HEIGHT / 2 - 10); g.drawString("COME ON !重新开始?Y/N", SpaceWar.WINDOWS_WIDTH / 2 - 100, SpaceWar.WINDOWS_HEIGHT / 2 + 10); return; }
    4.9 魔法值控制维护public class MagicTask extends TimerTask { @Override public void run() { if (MyPanel.myplane != null && !MyPanel.isPause && MyPanel.isStarted) { // 防护罩和战机升级没打开,魔法值递增 if (!MyPanel.isProtect && !MyPanel.isUpdate) { MyPanel.magicCount++; if (MyPanel.magicCount > 10) MyPanel.magicCount = 10; } // 判断是否打开防护罩 if (MyPanel.isProtect) { // 开启防护罩魔法值递减 MyPanel.magicCount--; if (MyPanel.magicCount <= 0) { MyPanel.magicCount = 0; MyPanel.isProtect = false; } } // 判断是否升级战机 if (MyPanel.isUpdate) { // 战机升级,魔法值递减 MyPanel.magicCount--; if (MyPanel.magicCount <= 0) { MyPanel.magicCount = 0; MyPanel.isUpdate = false; MyPanel.myplane.isUpdate = MyPanel.isUpdate; } } } }}
    4.10 得分到达关卡需求,进入Boss // 进入Boss int pScore = MyPanel.PASS_SCORE + MyPanel.passNum * 5; // TODO调试条件 // if (MyPanel.myplane != null && MyPanel.passScore >= 3 && // !MyPanel.isPause&&!MyPanel.isBoss) if (MyPanel.myplane != null && MyPanel.passScore >= pScore && !MyPanel.isPause && !MyPanel.isBoss) { // 进入Boss MyPanel.isBoss = true; MyPanel.boss = new Boss(1); MyPanel.boss.setSpeed(Boss.BOSS_SPEED + MyPanel.passNum - 1); MyPanel.boss.life = Boss.BOSS_LIFE + MyPanel.passNum * 50;// Boss总血量 MyPanel.bossBlood = Boss.BOSS_LIFE + MyPanel.passNum * 50;// 当前Boss血量 // Boss出场,暂停游戏 MyPanel.bossLoaded = false; // 重新设置Boss的子弹产生频率,增强Boss子弹发射频率 MyPanel.enemyTimer.cancel(); MyPanel.enemyTimer = null; MyPanel.enemyTimer = new Timer(); MyPanel.enemyTimer.schedule(new EnemyTask(MyPanel.enemyList), 0, 2000 - MyPanel.passNum * 120); }//显示Boss if (myplane != null && boss != null && !isPause && isBoss) { boolean status = boss.draw(g, this, passNum, isPause); if (status) bossLoaded = true; }
    4.11 检测标记位isPass,判断打赢Boss,进入下一关if (MyPanel.isPass) { MyPanel.isPass = false; if (MyPanel.passNum == 10)// 10关 { // 重新初始化数据 MyPanel.killTimer(); MyPanel.myplane = new MyPlane(false); MyPanel.isPause = true; MyPanel.isStop = MyPanel.FLAG_RESTART; // 清屏 }// if else { MyPanel.killTimer(); MyPanel.isPause = true; // 保存所需数据 int tScore = MyPanel.myScore + MyPanel.passScore; int tPassNum = MyPanel.passNum + 1; boolean tTest = MyPanel.test; int magic = MyPanel.magicCount; // 重新开始游戏 MyPanel.Restart(); MyPanel.myplane = new MyPlane(false); MyPanel.myScore = tScore; MyPanel.passNum = tPassNum; MyPanel.magicCount = magic; MyPanel.test = tTest; }// else }// if
    4.12 消息监听4.12.1 按键监听 // 按键监听 frame.addKeyListener(new KeyListener() { @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub } @Override public void keyReleased(KeyEvent e) { // TODO Auto-generated method stub } @Override public void keyPressed(KeyEvent event) { if (MyPanel.myplane != null && !MyPanel.isPause) { switch (event.getKeyCode()) { case KeyEvent.VK_LEFT: int x = MyPanel.myplane.getPoint().x - MyPanel.DEFAULT_SPEED; if (x < 0) x = 0; MyPanel.myplane.setPoint(new Point(x, MyPanel.myplane .getPoint().y)); break; case KeyEvent.VK_RIGHT: int x1 = MyPanel.myplane.getPoint().x + MyPanel.DEFAULT_SPEED; if (x1 > SpaceWar.WINDOWS_WIDTH - Bomb.BOMB_WIDTH) x1 = SpaceWar.WINDOWS_WIDTH - Bomb.BOMB_WIDTH; MyPanel.myplane.setPoint(new Point(x1, MyPanel.myplane .getPoint().y)); break; case KeyEvent.VK_UP: int y = MyPanel.myplane.getPoint().y - MyPanel.DEFAULT_SPEED; if (y < 0) y = 0; MyPanel.myplane.setPoint(new Point(MyPanel.myplane .getPoint().x, y)); break; case KeyEvent.VK_DOWN: int y1 = MyPanel.myplane.getPoint().y + MyPanel.DEFAULT_SPEED; if (y1 > SpaceWar.WINDOWS_HEIGHT) y1 = SpaceWar.WINDOWS_HEIGHT; MyPanel.myplane.setPoint(new Point(MyPanel.myplane .getPoint().x, y1)); break; case KeyEvent.VK_SPACE: Bomb bomb1 = new Bomb( MyPanel.myplane.getPoint().x + 10, MyPanel.myplane.getPoint().y, 1, MyPanel.isUpdate); MyPanel.bombList.add(bomb1); Bomb bomb2 = new Bomb(MyPanel.myplane.getPoint().x + MyPlane.PLANE_WIDTH - 40, MyPanel.myplane .getPoint().y, 1, MyPanel.isUpdate); MyPanel.bombList.add(bomb2); // 音效 AudioUtil.play(AudioUtil.AUDIO_BOMB); break; case KeyEvent.VK_C: // 开启防护罩 MyPanel.isProtect = true; // 音效 AudioUtil.play(AudioUtil.AUDIO_PROTECT); break; case KeyEvent.VK_V: // 战机升级 MyPanel.isUpdate = true; MyPanel.myplane.isUpdate = true; // 音效 AudioUtil.play(AudioUtil.AUDIO_UPDATE); break; case KeyEvent.VK_Y: if (MyPanel.isStop == 0) { // 无敌模式开关 if (MyPanel.test == false) MyPanel.test = true; else MyPanel.test = false; } break; case KeyEvent.VK_X:// 大招 if (MyPanel.bossLoaded) { // 战机发大招 if (MyPanel.magicCount >= 10) { MyPanel.magicCount -= 10; // 清空敌机 for (int i = 0; i < MyPanel.enemyList.size(); i++) { Enemy enemy = MyPanel.enemyList.get(i); // 将爆炸对象添加到爆炸链表中 Explosion explosion = new Explosion( (enemy.getPoint().x + Enemy.ENEMY_WIDTH / 2), (enemy.getPoint().y + Enemy.ENEMY_HEIGHT / 2)); MyPanel.explosionList.add(explosion); // 删除敌机 MyPanel.enemyList.remove(i); // 增加得分 MyPanel.passScore++; }// for if (MyPanel.isBoss) { // 将爆炸对象添加到爆炸链表中 Explosion explosion = new Explosion( MyPanel.boss.getPoint().x + Boss.BOSS_WIDTH / 2, MyPanel.boss.getPoint().y + Boss.BOSS_HEIGHT / 2); MyPanel.explosionList.add(explosion); MyPanel.bossBlood -= 50; if (MyPanel.bossBlood <= 0) { // boss死,过关 // 过关的标志变量 MyPanel.boss = null; // 过关的标志变量 MyPanel.isPause = true; MyPanel.myplane = new MyPlane(false); MyPanel.isPass = true; MyPanel.isBoss = false; } } // 清空敌机炮弹 for (int i = 0; i < MyPanel.ballList.size(); i++) { MyPanel.ballList.remove(i); } // 音效 AudioUtil.play(AudioUtil.AUDIO_DAZHAO); } } break; default: break; } } // 暂停 if (event.getKeyCode() == KeyEvent.VK_Z) { if (MyPanel.isPause) MyPanel.isPause = false; else MyPanel.isPause = true; } // 取消键N else if (event.getKeyCode() == KeyEvent.VK_N) { if (MyPanel.isStop != 0) { JDialog dialog = new JDialog(frame); dialog.setTitle("关于"); dialog.setSize(400, 200); dialog.setLocation(450, 200); JButton button = new JButton(); button.setText("确定"); button.setSize(100, 50); button.setLocation(200, 120); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.exit(0); } }); dialog.add(button); dialog.setVisible(true); } } // 确认键Y if (MyPanel.isStop != 0 && event.getKeyCode() == KeyEvent.VK_Y) { MyPanel.isStop = 0; MyPanel.Restart(); } // 按空格进入游戏 if (!MyPanel.isStarted && event.getKeyCode() == KeyEvent.VK_SPACE) { MyPanel.isStarted = true; MyPanel.scene.setBeginY(0); } } });
    4.12.2 鼠标移动监听frame.addMouseMotionListener(new MouseMotionListener() { @Override public void mouseMoved(MouseEvent arg0) { if (MyPanel.myplane != null && !MyPanel.isPause) MyPanel.myplane.setPoint(arg0.getPoint()); } @Override public void mouseDragged(MouseEvent arg0) { } });
    4.12.3 鼠标左键发射子弹和开始界面进入游戏frame.addMouseListener(new MouseListener() { @Override public void mouseReleased(MouseEvent arg0) { } @Override public void mousePressed(MouseEvent event) { if (MyPanel.myplane != null && !MyPanel.isPause) { if (event.getButton() == MouseEvent.BUTTON1) { // 左键 if (MyPanel.myplane != null && !MyPanel.isPause) { Bomb bomb1 = new Bomb( MyPanel.myplane.getPoint().x + 10, MyPanel.myplane.getPoint().y, 1, MyPanel.isUpdate); MyPanel.bombList.add(bomb1); Bomb bomb2 = new Bomb(MyPanel.myplane.getPoint().x + MyPlane.PLANE_WIDTH - 40, MyPanel.myplane .getPoint().y, 1, MyPanel.isUpdate); MyPanel.bombList.add(bomb2); // 音效 AudioUtil.play(AudioUtil.AUDIO_BOMB); } if (!MyPanel.isStarted) { MyPanel.isStarted = true; MyPanel.scene.setBeginY(0); } } } } @Override public void mouseExited(MouseEvent arg0) { } @Override public void mouseEntered(MouseEvent arg0) { } @Override public void mouseClicked(MouseEvent arg0) { } });
    4.13 生命周期4.13.1游戏重新开始public static void Restart() { // TODO: 在此处添加游戏重新开始初始化参数 // 战机重新加载 MyPanel.myplane = new MyPlane(false); scene.setBeginY(0); // 清空敌机链表 if (MyPanel.enemyList.size() > 0) MyPanel.enemyList.removeAll(MyPanel.enemyList); // 清空战机链表 if (MyPanel.meList.size() > 0) MyPanel.meList.removeAll(MyPanel.meList); // 清空战机子弹链表 if (MyPanel.bombList.size() > 0) MyPanel.bombList.removeAll(MyPanel.bombList); // 清空敌机炸弹链表 if (MyPanel.ballList.size() > 0) MyPanel.ballList.removeAll(MyPanel.ballList); // 清空爆炸链表 if (MyPanel.explosionList.size() > 0) MyPanel.explosionList.removeAll(MyPanel.explosionList); // 清空血包列表 if (MyPanel.bloodList.size() > 0) MyPanel.bloodList.removeAll(MyPanel.bloodList); // 参数重新初始化 MyPanel.myLife = DEFAULT_LIFE; MyPanel.lifeNum = DEFAULT_LIFE_COUNT; MyPanel.myScore = 0; MyPanel.passScore = 0; MyPanel.passNum = DEFAULT_PASS; MyPanel.isPass = false; MyPanel.isPause = false; MyPanel.lifeCount = 1; MyPanel.magicCount = 0; MyPanel.bloodExist = false; MyPanel.bossBlood = Boss.BOSS_LIFE; MyPanel.isBoss = false; MyPanel.bossLoaded = true; MyPanel.isProtect = false; MyPanel.isUpdate = false; MyPanel.test = false; MyPanel.boss = null; // isStarted = FALSE; initTimer(); }
    4.13.2 生命值归零,游戏结束public static void gameOver() { // 结束游戏界面 // 释放计时器 killTimer(); // 计算最后得分 myScore += passScore; // 播放游戏结束音乐 // 清屏 // 音效 AudioUtil.play(AudioUtil.AUDIO_GAMEOVER); isStop = FLAG_STOP; // TODO System.out.println("-----------gameOver"); }
    5 课程设计中遇到的主要问题及解决方法5.1 滚动背景实现问题要实现滚动背景,需要在背景图上取出客户区矩形大小的区域,并按照Timer进行递进,并且要在背景图边界处衔接好返回背景图开头位置,实现一张背景图的循环反复,达到滚动背景图的目的,刚开始由于不懂得如何实现开头结尾处的衔接问题,导致滚动背景图实现难度大,后来经由网上查阅的资料得知要把背景图加载两份,第二份背景图开头衔接在第一份结尾处,让客户区矩形在该两份背景图上进行滑动,当滑动到第二份背景图时,再把第一份接到第二份结尾处,从而实现循环反复滚动背景。其中实现的难点在于控制好客户区矩形坐标和背景图上要显示的图片块位于图片上的坐标的对应关系。
    5.2 背景音乐循环播放和游戏音效同时输出问题由于平时接触Swing太少,对Swing操作多媒体文件颇为陌生,对于Java的音频播放也是颇为陌生,通过网上查找了很多相关资料,才把AudioClip对音频的播放功能实现,而且刚开始使用,没注意到音频文件播放完的释放问题,导致程序运行一阶段之后出现了内存溢出而崩溃的情况。
    5.3 多帧位图素材的动画特效实现问题飞机大战中的爆炸显示是通过一张带有八个帧的位图进行连续输出实现爆炸特效,刚开始只是简单的在一个while循环中循环八次,结果不尽如人意,后来联想到帧和时间的对应关系,在每一次TimerTask调用时输出一帧,并在爆炸对象中用progress标记位记录播放位置,等到八个帧播放结束时,返回播放结束标记位,在TimerTask中检测并删除播放完成的该爆炸对象。
    5.4 游戏结束和游戏重新开始的游戏资源维护问题该游戏由于实现了多个额外功能,且都是带有全局意义的,因此放置了较多标记位来标记每个状态,通过这些标记位来控制游戏进程中的各个状态,因此在游戏结束和重新开始游戏时,各个标记位的正确重置将会决定重新开始游戏之后的游戏状态。还由于这些操作可能会在TimerTask类调用过程中进行中断,因此程序运行中途的中断时的游戏参数的维护对程序的正确执行至关重要。
    6 课程设计体会由于对Swing接触不多,因此在开发过程中走了很多弯路,但是也是这次的实训,让我了解了Swing的事件处理机制,了解了如何在屏幕中绘制需要向用户展示的图形信息,学会了使用基本的操作对屏幕中绘制的图形进行控制,也了解了Java的Timer定时器的机制,学习了Sun封装好的Swing类库,学会遇到问题到JDK文档中查询Api,并对Eclipse的使用和编程也进行了提高。
    在开发过程中遇到了大量的异常,通过此次开发,也学会了遇到错误如何慢慢通过IDE的错误信息进行错误查找和代码排错更正,通过添加断点调试程序一步步监视程序运行的具体过程,从而找到程序运行出错的原因。
    本次的课程设计的飞机大战代码是基于前一次的MFC飞机大战进行移植的,因此,在模块的分布和设计方面大多维持原来C++的布局,因此,本次项目开发的源码层次接口没有严格的按照Java的规范,这是这个项目的不足之处,如果时间允许,应该着手对其中的代码布局进行相应的修改,以符合Java的风格,增强代码的可读性。
    7 游戏演示游戏画面1

    游戏画面2
    14 评论 890 下载 2018-11-04 23:00:52 下载需要11点积分
  • 基于深度学习的图像识别

    介 绍随着计算机理论、技术和应用的快速发展,视频图像处理和计算能力得到了极大的提高,使得计算机视觉成为了计算机领域与人工智能领域中最热门的研究课题之一。计算机视觉(CV),通俗地说,是一门研究如何使机器“看”的科学,更进一步的说,是指用摄影机和电脑代替人眼对目标进行识别、跟踪和测量等机器视觉,并进一步做图形处理,使电脑处理成为更适合人眼观察或传送给仪器检测的图像。
    本小组研究的课题是基于深度学习的图像识别,最终实现的是对海量图片数据的学习和准确的识别,不仅如此,我们测试了几种不同的分类模型,并比较预测结果,计算预测准确率,对预测方法进行优化,希望得到一种最高效的预测方法,从而实现真正的机器智能化识别。
    本小组课设主要基于python开发环境下的scikit-learn标准库以及PIL图像处理库,并采用matplotlib实现最终结果的比对,PIL库用于图像的特征值批量读取,scikit-learn标准库用于分类模型的构建,matplotlib则用于显示最终结果。
    这是这两个基本库的homepage以及参考网页:

    PIL

    http://www.pythonware.com/products/pil/http://blog.csdn.net/u013467442/article/details/41827085http://blog.csdn.net/passball/article/details/5204132
    scikit-learn

    http://scikit-learn.org/stable/index.html

    下面是本小组的方案流程以及说明:

    1 图像特征向量的提取特征提取是计算机视觉和图像处理中的一个概念。它指的是使用计算机提取图像信息,决定每个图像的点是否属于一个图像特征。特征提取的结果是把图像上的点分为不同的子集,这些子集往往属于孤立的点、连续的曲线或者连续的区域。
    特征的精确定义往往由问题或者应用类型决定。特征是一个数字图像中“有趣”的部分,它是许多计算机图像分析算法的起点。因此一个算法是否成功往往由它使用和定义的特征决定。因此特征提取最重要的一个特性是“可重复性”:同一场景的不同图像所提取的特征应该是相同的。
    常用的特征提取方法有方向梯度直方图(Histogram of Oriented Gradient, HOG)特征,主要思想是在一副图像中,局部目标的表象和形状(appearance and shape)能够被梯度或边缘的方向密度分布很好地描述;LBP(Local Binary Pattern,局部二值模式)特征,一种用来描述图像局部纹理特征的算子;Haar-like特征,最早由Papageorgiou等应用于人脸表示。
    我们采用HOG方法进行图像特征的提取,特别的,HOG+SVM方法进行图像识别已经被广泛用于图像识别领域中。
    通过调用PIL库中的Image模块可以实现上述功能。

    img = Image.open(j)

    j为图片所在路径,采用open方法描述图片。进行灰度化:

    Gray = (R^2.2 0.2973 + G^2.2 0.6274 + B^2.2 * 0.0753)^(1/2.2)

    通过相关算法对图片的特征进行处理,最终可得到想要的特征向量。此外,需要保存每张图像对应的目标值以及图像的三原色信息。(详细的容器说明见代码)
    2 训练集、测试集的分离调用sklearn中的train_test_split方法:

    self.x_train0, self.x_test0, self.y_train0, self.y_test0 = train_test_split(self.pic_data_gray, self.target, test_size=0.25, random_state=42)

    3 图像主成分的析取及灰度化通过第一步图片的特征向量提取,我们得到一组特征向量的列表集,但由于特征向量的维度过高,一来提高了计算的复杂度,占用内存资源,不利于大规模开发,二来特征描述过分详细,相关性不大的维度会对分类器的分类造成负面影响,所以接下来对图片的特征向量进行降维处理。
    这里采用PCA(Principal Component Analysis)降维方法,PCA又称主成分分析法,是一种常用的数据分析方法。PCA通过线性变换将原始数据变换为一组各维度线性无关的表示,可用于提取数据的主要特征分量,常用于高维数据的降维。
    对于一个k维的特征来说,相当于它的每一维特征与其他维都是正交的(相当于在多维坐标系中,坐标轴都是垂直的),那么我们可以变化这些维的坐标系,从而使这个特征在某些维上方差大,而在某些维上方差很小。例如,一个45度倾斜的椭圆,在第一坐标系,如果按照x,y坐标来投影,这些点的x和y的属性很难用于区分他们,因为他们在x,y轴上坐标变化的方差都差不多,我们无法根据这个点的某个x属性来判断这个点是哪个,而如果将坐标轴旋转,以椭圆长轴为x轴,则椭圆在长轴上的分布比较长,方差大,而在短轴上的分布短,方差小,所以可以考虑只保留这些点的长轴属性,来区分椭圆上的点,这样,区分性比x,y轴的方法要好!
    所以我们的做法就是求得一个k维特征的投影矩阵,这个投影矩阵可以将特征从高维降到低维。投影矩阵也可以叫做变换矩阵。新的低维特征必须每个维都正交,特征向量都是正交的。通过求样本矩阵的协方差矩阵,然后求出协方差矩阵的特征向量,这些特征向量就可以构成这个投影矩阵了。特征向量的选择取决于协方差矩阵的特征值的大小。
    举一个例子:
    对于一个训练集,100个对象模板,特征是10维,那么它可以建立一个100*10的矩阵,作为样本。求这个样本的协方差矩阵,得到一个10*10的协方差矩阵,然后求出这个协方差矩阵的特征值和特征向量,应该有10个特征值和特征向量,我们根据特征值的大小,取前四个特征值所对应的特征向量,构成一个10*4的矩阵,这个矩阵就是我们要求的特征矩阵,100*10的样本矩阵乘以这个10*4的特征矩阵,就得到了一个100*4的新的降维之后的样本矩阵,每个特征的维数下降了。
    总结一下PCA的算法步骤:
    设有m条n维数据。

    将原始数据按列组成n行m列矩阵X
    将X的每一行(代表一个属性字段)进行零均值化,即减去这一行的均值
    求出协方差矩阵
    求出协方差矩阵的特征值及对应的特征向量
    将特征向量按对应特征值大小从上到下按行排列成矩阵,取前k行组成矩阵P
    即为降维到k维后的数据

    具体的原理:

    http://blog.csdn.net/xiaojidan2011/article/details/11595869
    http://www.cnblogs.com/549294286/archive/2013/11/11/3417702.html

    算法实现为:

    pca = PCA(n_components = n_components, svd_solver=’auto’,whiten=True).fit(self.x_train0)x_train_pca = pca.transform(self.x_train0)

    4 分类器的构造与训练学习这是整个课设的核心部分,即构造建模合理的分类器。我们采用支持向量机(Support Vector Machine)进行分类。

    SVM是Cortes和Vapnik于1995年首先提出的,它在解决小样本、非线性及高维模式识别中表现出许多特有的优势,并能够推广应用到函数拟合等其他机器学习问题中。
    机器学习本质上就是一种对问题真实模型的逼近(我们选择一个我们认为比较好的近似模型,这个近似模型就叫做一个假设),但毫无疑问,真实模型一定是不知道的(如果知道了,我们干吗还要机器学习?直接用真实模型解决问题不就可以了?对吧,哈哈)既然真实模型不知道,那么我们选择的假设与问题真实解之间究竟有多大差距,我们就没法得知。比如说我们认为宇宙诞生于150亿年前的一场大爆炸,这个假设能够描述很多我们观察到的现象,但它与真实的宇宙模型之间还相差多少?谁也说不清,因为我们压根就不知道真实的宇宙模型到底是什么。
    这个与问题真实解之间的误差,就叫做风险(更严格的说,误差的累积叫做风险)。我们选择了一个假设之后(更直观点说,我们得到了一个分类器以后),真实误差无从得知,但我们可以用某些可以掌握的量来逼近它。最直观的想法就是使用分类器在样本数据上的分类的结果与真实结果(因为样本是已经标注过的数据,是准确的数据)之间的差值来表示。这个差值叫做经验风险Remp(w)。以前的机器学习方法都把经验风险最小化作为努力的目标,但后来发现很多分类函数能够在样本集上轻易达到100%的正确率,在真实分类时却一塌糊涂(即所谓的推广能力差,或泛化能力差)。此时的情况便是选择了一个足够复杂的分类函数(它的VC维很高),能够精确的记住每一个样本,但对样本之外的数据一律分类错误。回头看看经验风险最小化原则我们就会发现,此原则适用的大前提是经验风险要确实能够逼近真实风险才行(行话叫一致),但实际上能逼近么?答案是不能,因为样本数相对于现实世界要分类的文本数来说简直九牛一毛,经验风险最小化原则只在这占很小比例的样本上做到没有误差,当然不能保证在更大比例的真实文本上也没有误差。
    统计学习因此而引入了泛化误差界的概念,就是指真实风险应该由两部分内容刻画,一是经验风险,代表了分类器在给定样本上的误差;二是置信风险,代表了我们在多大程度上可以信任分类器在未知文本上分类的结果。很显然,第二部分是没有办法精确计算的,因此只能给出一个估计的区间,也使得整个误差只能计算上界,而无法计算准确的值(所以叫做泛化误差界,而不叫泛化误差)。
    置信风险与两个量有关,一是样本数量,显然给定的样本数量越大,我们的学习结果越有可能正确,此时置信风险越小;二是分类函数的VC维,显然VC维越大,推广能力越差,置信风险会变大。泛化误差界的公式为:

    R(w)≤Remp(w)+Ф(n/h)

    公式中R(w)就是真实风险,Remp(w)就是经验风险,Ф(n/h)就是置信风险。统计学习的目标从经验风险最小化变为了寻求经验风险与置信风险的和最小,即结构风险最小。
    SVM正是这样一种努力最小化结构风险的算法。
    下面举例简述基本原理:
    首先是线性SVM向量机,如图所示二维平面有两类点,我们要做的便是找到一条分类线将整个平面分为两部分,一部分属于蓝色五角星,一部分属于红色点,如过新加入的点落在五角星一侧便判定他为五角星类。

    这些分类线可能有很多,现需要找到最优的分类线。

    通俗地理解,只需要使得如图所示的Gap达到最大即可。同样的方法适用于多维多类的问题,此时分类线即分类超平面。

    设w为这个超平面的法向量,中间具体的数学推导过程不再详述,总之我们要实现的优化是:

    yI为正确的分类结果,xi为特征向量。一个更简单的例子,要对苹果和香蕉进行分类:


    SVM支持向量机则引入了非线性的神经网络,从而更好地解决非线性问题:
    我们将使用一种叫做核函数(kernel)的工具,将数据从一个空间转换到另一个空间,使其变成易于分类器理解的形式。但要确保核函数可以很快速的进行计算,否则影响效率。
    常用的核函数有:

    多项式核函数(Polynomial Kernel),其形式如下:
    Kernel(X,X′)=(ξ+γXTX′)Q
    径向基函数(Radial Basis Function,RBF),其形式如下:
    Kernel(X,X′)=e(−||X−X′||22σ2)上述高斯核函数将数据从特征空间映射到更高维的空间,具体来说这里是映射到一个无穷维的空间。
    将核函数(kernel)引入到 SVM 中也就是替换 SVM 中的 XTY 为 Kernel(X,Y),也就是将第3部份第2步的二次规划规划问题中的 XTX 为 Kernel(X,X),例如二次项核函数的 (1+XT∗X)2,将
    b=ys−wTxs=ys−(∑Nn=1αnynxn)xs替换为:
    b=ys−∑Nn=1αnynKernel(xn,xs)其中 s 表示某个支持向量。
    最后,将:
    gsvm(x)=sign(wTx+b)=sign((∑Nn=1αnynxn)x+b)替换为:
    gsvm(x)=sign(∑Nn=1αnynKernel(xn,x)+b)之后进行神经网络的建模,其中K(x1,x)为上述核函数:

    详见:

    http://blog.csdn.net/passball/article/details/7661887/
    http://blog.csdn.net/macyang/article/details/38782399/
    https://www.zhihu.com/question/21094489

    5 预测测试图片集,分析结果首先,对预测结果,采用matplotlib简单地绘制了预测结果和真实图片的比较:

    这里比较了12组预测结果,其中只有第7组预测有误,其他均预测正确!下面是程序在沙盒下的运行结果:

    Python 3.5.3 (v3.5.3:1880cb95a742, Jan 16 2017, 16:02:32) [MSC v.1900 64 bit (AMD64)] on win32Type “copyright”, “credits” or “license()” for more information.


    ====== RESTART: C:\Users\76947\Desktop\machine learning\plot_gallary.py ======正在采集图像数据…图片信息采集完毕!花费了9.126秒总数据库的规模如下:样本数: 1110特征数: 80000分类数: 5正在进行降维处理…完成!花费了 28.129秒数据分类降维完毕!正在进行训练…完成,共计 8.308秒最优分类向量机找到:SVC(C=1000.0, cache_size=200, class_weight=’balanced’, coef0=0.0, decision_function_shape=None, degree=3, gamma=0.1, kernel=’rbf’, max_iter=-1, probability=False, random_state=None, shrinking=True, tol=0.001, verbose=False)正在预测图片…完成预测,共计 0.016秒预测结果如下:precision recall f1-score supportairplanes 0.93 0.99 0.95 213brain 0.77 0.81 0.79 21chair 0.18 0.20 0.19 10dolphin 0.80 0.42 0.55 19sunflower 0.75 0.40 0.52 15avg / total 0.87 0.87 0.86 278[[210 1 1 1 0] [ 2 17 2 0 0] [ 7 0 2 0 1] [ 4 1 5 8 1] [ 4 3 1 1 6]]预测的准确率为: 0.8741007194244604{‘target:’: ‘brain’, ‘predict:’: ‘brain’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘dolphin’, ‘predict:’: ‘brain’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘brain’, ‘predict:’: ‘brain’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘dolphin’, ‘predict:’: ‘chair’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘sunflower’, ‘predict:’: ‘brain’}{‘target:’: ‘dolphin’, ‘predict:’: ‘airplanes’}{‘target:’: ‘dolphin’, ‘predict:’: ‘sunflower’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘dolphin’, ‘predict:’: ‘airplanes’}{‘target:’: ‘brain’, ‘predict:’: ‘brain’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘brain’, ‘predict:’: ‘brain’}{‘target:’: ‘brain’, ‘predict:’: ‘brain’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘brain’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘sunflower’, ‘predict:’: ‘sunflower’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘sunflower’, ‘predict:’: ‘sunflower’}{‘target:’: ‘dolphin’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘chair’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘dolphin’, ‘predict:’: ‘dolphin’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘sunflower’, ‘predict:’: ‘sunflower’}{‘target:’: ‘airplanes’, ‘predict:’: ‘chair’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘brain’, ‘predict:’: ‘brain’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘brain’, ‘predict:’: ‘brain’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘dolphin’, ‘predict:’: ‘dolphin’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘chair’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘chair’, ‘predict:’: ‘sunflower’}{‘target:’: ‘dolphin’, ‘predict:’: ‘chair’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘sunflower’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘airplanes’, ‘predict:’: ‘airplanes’}{‘target:’: ‘brain’, ‘predict:’: ‘brain’}



    预测准确率有可观的0.8741007194244604,对飞机的预测更是达到了0.93的准确率,这里的预测准确度和学习的样本数有关,如果样本数足够多,相信我们会得到更可观的结果。下面是采用不同核函数的预测准确率比较:

    可以看到采用rbf径向基函数可达到很高的预测准确度。
    4 评论 85 下载 2019-03-04 10:48:16 下载需要15点积分
  • 基于JSP和Sql Server实现的飞机票售票管理系统

    1.系统背景随着现代生活水平提高,人类逐渐对精神文化享受重视,追求不同的生活,而其中旅游成为大众的喜爱,于是到年到节的时候需要一种交通 工具来达到目的地,这也成为这系统开发的动力,系统的进步也是应客户的需求而生,为了能够在更早的出售机票,不影响客户的行程,机票售票系统也做出相应的决策,那就是通过无人管理机票预定,然后在快到期的那天,管理员可以通过订单管理来处理客户订单。所以管理员的模块也极其重要,本系统通过后台界面为管理员和数据库与服务器进行交互提供环境。客户只要通过浏览器来进行订票,订票的数据存储在数据里面,然后管理员通过打开后台浏览器来进行信息汇总,然后下单确定发票,整一个信息传递过程是订票信息→订票查询→核实机票。
    2.功能简介
    顾客上网通过浏览器来登入系统首页,系统提供客户注册、机票查询和机票预定功能,当然也包括已预定机票取消
    用户通过窗口选取机票,订单信息保存在数据库上,等待管理员审核
    管理员处理用户信息,确定用户购买
    用户可以根据己购买的字眼可以到代理取票,也可以再登机那天取票
    管理员随时更新航班信息
    客户可以随时登入系统获取航班信息

    3.系统分析系统通过数据库的连接,通过接受客户数据来响应WEB服务器处理,来进行数据管理。整个分为两大部分,第一部分就是客户模块,第二部分就是管理员模块。客户模块包括客户注册、查询、购票、换票、取消机票。管理员模块包括自动处理客户订单、管理员处理订单、机票班次更新、管理系统用户。通过计算机网络来贯穿两大模块,从而实现客户和服务器的交互。
    3.1 功能需求在客户端系统的功能实现上,可以分为以下几个部分:

    用户通过支持web容器的浏览器来进行信息的输入,客户端根据用户输入将数据流输入和数据流的统计。这部分的要求是一个人性化的界面,让用户通过浏览器来进行页面访问。所谓人性化界面包括,浏览功能,预定功能,多种进行人机交互按钮,比如html页面信息和提交、重置等
    把用户信息存储到客户端系统中,经过系统自动审核后存储到数据库当中,已备以后登录查询
    服务器通过数据库出来从客户端传输的信息加以确定,然后返回给客户端,客户端通过信息来提醒用户,用户可以根据信息到柜台拿票

    在服务器端系统的功能实现上,可以分为以下几个部分:

    服务器通过网络接受用户从客户端输入所需要的信息,然后根据用户所需要的信息来判断是否通过WEB容器进行管理,如果纯粹是看票的话,直接调用数据库已经存储好的机票信息通过静态服务反馈用户,如果有购票需要数据通过WEB服务器来进行管理
    在服务器段提供了航班输入功能,管理员根据现实情况来对航班进行管理
    把航班信息通过网络来传递到客户端来与用户进行交互

    3.2 数据流图根据数据流图的特点可以从大到小逐渐深入系统处理过程,图3-1是飞机票售票管理系统的最顶层的数据流图。

    从顶层数据流图,可以得到整个数据流图过程,如图3-2,图3-3。
    系统数据流图

    订票数据流图

    3.3 业务流图飞机票售票管理系统的业务流图如图3-4。

    3.4 数据库表说明在一个B/S系统中数据无疑是非常重要的,数据的安全性、稳定性、可恢复性对使用者起着极其重要的作用。选择一个健全稳定的数据库无疑也是系统实现的首要步骤,本系统选用的是SQL 2005,它能提供大型系统所需的数据库服务。下面将介绍系统的数据库结构。本系统的最主要的功能在与数据库的分配,对不同的用户采用不同的数据库,和不同的查询方式。
    用户表common_user
    CREATE TABLE IF NOT EXISTS `common_user` ( `user_name` varchar(16) NOT NULL, `user_pwd` varchar(32) NOT NULL, `avatar_img` varchar(50) DEFAULT NULL, PRIMARY KEY (`user_name`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='用户表' AUTO_INCREMENT=1 ;
    管理员用户表admin_user
    CREATE TABLE IF NOT EXISTS `admin_user` ( `user` varchar(16) NOT NULL COMMENT '管理员用户名', `pwd` varchar(32) NOT NULL COMMENT '管理员密码', PRIMARY KEY (`user`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='管理员用户表' AUTO_INCREMENT=1 ;
    航班信息表flight
    CREATE TABLE IF NOT EXISTS `flight` ( `f_n` varchar(6) NOT NULL COMMENT '航班号', `f_s_p` varchar(4) NOT NULL COMMENT '航班起点', `f_e_p` varchar(4) NOT NULL COMMENT '航班终点', `f_s_a` varchar(12) NOT NULL COMMENT '航班起飞机场', `f_a_a` varchar(12) NOT NULL COMMENT '航班到达机场', `f_d_t` varchar(5) NOT NULL COMMENT '起飞(departure)时间', `f_a_t` varchar(5) NOT NULL COMMENT '到达时间', `f_f_c_p` int(11) NOT NULL COMMENT '头等舱价格First class price', `f_s_c_p` int(11) NOT NULL COMMENT '商务舱价格', `f_t_c_p` int(11) NOT NULL COMMENT '经济舱价格', PRIMARY KEY (`f_n`), UNIQUE KEY `f_n` (`f_n`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='航班信息' AUTO_INCREMENT=1 ;
    航班订单信息表t_order
    CREATE TABLE IF NOT EXISTS `t_order` ( `id` int(12) NOT NULL AUTO_INCREMENT, `order_user` varchar(16) NOT NULL COMMENT '下单用户', `f_n` varchar(6) NOT NULL COMMENT '航班号', `p_name` varchar(6) NOT NULL COMMENT '乘客姓名', `date` varchar(12) NOT NULL COMMENT '订单日期', `grade` varchar(3) NOT NULL COMMENT '舱别', `p_id` varchar(18) NOT NULL COMMENT '乘客身份证号', `contact` varchar(6) NOT NULL COMMENT '联系人', `c_p` varchar(11) NOT NULL COMMENT '联系人电话', PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci AUTO_INCREMENT=8 ;
    用户留言信息表user_message
    CREATE TABLE IF NOT EXISTS `user_message` ( `id` int(11) NOT NULL AUTO_INCREMENT, `time` varchar(10) NOT NULL, `user_name` varchar(32) NOT NULL, `message_content` text NOT NULL, PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=30 ;
    4.程序结构功能结构4.1 用户注册系统对于用户来说只能查询,不能诺命购票,因为不提供真实身份,无法判断用户,购票也极为麻烦,所以只能依靠登录来进行用户识别和购票。
    用户注册的关键代码,主要利用request这个接口的getParameter0方法来接受用户所输入的数据,通过getRemoteAddr()方法来获取用户的ID,每一个以用户都只有唯一—个ID标识,然后通过flag来判断输入是否符合,为真的话就通过request的setAtribute方法来保存信息。
    1. public void doPost(HttpServletRequest req, HttpServletResponse resp) 2. throws ServletException, IOException { 3. String log_name = req.getParameter("log_name"); 4. String log_pwd = req.getParameter("log_pwd"); 5. String reg_name = req.getParameter("reg_name"); 6. String reg_pwd1 = req.getParameter("reg_pwd1"); 7. String reg_pwd2 = req.getParameter("reg_pwd2"); 8. 9. if(log_name!=null&&log_pwd!=null&®_name==null&®_pwd1==null&®_pwd2==null) { 10. //调用登录方法处理登录 11. go_login(log_name, log_pwd, req, resp); 12. 13. } 14. else if(log_name==null&&log_pwd==null&®_name!=null&®_pwd1!=null&®_pwd2!=null&®_pwd1.equals(reg_pwd2)) { 15. //调用注册方法处理注册 16. go_reg(reg_name, reg_pwd1, req, resp); 17. 18. }//为什么不再写一个判断注册时reg_pwd1和reg_pwd2是否相等的语句呢?因为,前端页面中已经用js去做判断了, 19. //如果用户两次输入的密码不一致根本不可能提交数据到此servlet,除非用户限制js或者修改了js,也就是做了非法操作 20. //因此,直接输出提示非法操作的提示信息即可 21. else { 22. 23. resp.setContentType("text/html;charset=utf-8"); 24. PrintWriter out = resp.getWriter(); 25. out.println("请不要尝试非法操作"); 26. /*****测试数据 27. out.println("登录账号:"+log_name+"\n登录密码:"+log_pwd+"\n注册账号:" 28. +reg_name+"\n注册密码1:"+reg_pwd1+"\n注册密码2:"+reg_pwd2); 29. out.print("---log_name==null:"+(log_name==null)); 30. out.print("---log_pwd==null:"+(log_pwd==null)); 31. out.print("---reg_name==null:"+(reg_name==null)); 32. out.print("---reg_pwd1==null:"+(reg_pwd1==null)); 33. out.print("---reg_pwd2==null:"+(reg_pwd2==null)); 34. */ 35. 36. resp.setHeader("refresh", "2;url=index/login_reg.jsp"); 37. //除了登录和注册操作,提交其它数据均为非法操作,不做处理,仅给出提示非法信息 38. } 39. }
    4.2 机票查询在该系统当中,因为运行外面的旅客访问系统并查询系统,以供是否注册为本系统用户,所以两者都可以查询机票航班,旅客通过session来访问,但访问数据随着页面刷新而消除。
    这部的关键步骤也是调用request这个接口的获取信息方法,同样也是调用geParameter()方法就可以把信息获取出来。同时用SQL语言来查询表的信息,附值给定义的属性,可以通过方法来调用数据库。
    1. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 2. req.setCharacterEncoding("utf-8"); 3. //HttpSession session = req.getSession(); 4. String url=null; 5. /* 6. * if(session.getAttribute("url")!=null) { 7. * url=session.getAttribute("url").toString(); }else { 8. */ 9. url="default/index.jsp"; 10. 11. String departure=null; 12. String destination=null; 13. departure=req.getParameter("departure"); 14. destination=req.getParameter("destination"); 15. String sql=null; 16. if(departure==""&&destination=="") { 17. //如果始发地和目的地都为空则跳转回原页面 18. resp.sendRedirect(url); 19. }else if (departure!=""&&destination=="") { 20. sql="select * from flight where f_s_p='"+departure+"'"; 21. }else if (departure==""&&destination!="") { 22. sql="select * from flight where f_e_p='"+destination+"'"; 23. }else if (departure!=""&&destination!="") { 24. sql="select * from flight where f_s_p='"+departure+"' and f_e_p='"+destination+"'"; 25. } 26. if(departure==""&&destination=="") { 27. //如果都为空,执行不到这一步,所以就不用做处理了,否则,执行else 28. }else { 29. db_conn conn=new db_conn(); 30. //System.out.println(sql); 31. ArrayList<flight> flightlist = new ArrayList<flight>(); 32. flight flight_info=new flight(); 33. 34. ResultSet res=conn.executeQuery(sql); 35. try { 36. while (res.next()) { 37. flight_info.setF_n(res.getString(1)); 38. flight_info.setF_s_a(res.getString(4)); 39. flight_info.setF_a_a(res.getString(5)); 40. flight_info.setF_d_t(res.getString(6)); 41. flight_info.setF_a_t(res.getString(7)); 42. flight_info.setF_f_c_p(res.getString(8)); 43. flight_info.setF_s_c_p(res.getString(9)); 44. flight_info.setF_t_c_p(res.getString(10)); 45. flightlist.add(flight_info); 46. } 47. req.setAttribute("flightlist", flightlist); 48. } catch (SQLException e) { 49. System.out.println("错误信息:"+e); 50. }finally { 51. conn.closeDB(); 52. } 53. //resp.sendRedirect("default/search.jsp"); 54. req.getRequestDispatcher("default/search.jsp").forward(req, resp); 55. } 56. }
    4.3 机票预定为了整个流程更为简单,易用,该系统就只设定只用验证的用户才可以购买飞机票,同时用户可以通过登录查询自己的航班。
    下面代码是预定机票的代码,通过判断机票剩余数和预定机票的关系,确定用户购买成功,成功的话,设置成功信息,失败的设只失败提示信息。
    1. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 2. //开始获取各种参数 3. req.setCharacterEncoding("utf-8"); 4. String flight_id=req.getParameter("flight_id"); 5. String start_place=req.getParameter("start_place"); 6. String end_place=req.getParameter("end_place"); 7. String start_airport=req.getParameter("start_airport"); 8. String end_airport=req.getParameter("end_airport"); 9. String take_off_time=req.getParameter("take_off_time"); 10. String landing_time=req.getParameter("landing_time"); 11. String first_class_price_str=req.getParameter("first_class_price"); 12. Integer first_class_price=Integer.parseInt(first_class_price_str); 13. String business_class_price_str=req.getParameter("business_class_price"); 14. Integer business_class_price=Integer.parseInt(business_class_price_str); 15. String economy_class_price_str=req.getParameter("economy_class_price"); 16. Integer economy_class_price=Integer.parseInt(economy_class_price_str); 17. //参数获取结束 18. db_conn conn=new db_conn(); 19. String sql="select * from flight where f_n='"+flight_id+"'"; 20. ResultSet res=conn.executeQuery(sql); 21. try { 22. if(res.next()) { 23. resp.setContentType("text/html;charset=utf-8"); 24. PrintWriter out=resp.getWriter(); 25. out.println("您输入的航班号重复了,请选择其他航班号添加,5s后返回"); 26. resp.setHeader("refresh", "5;url=admin/flight_add.jsp"); 27. }else { 28. sql="insert into flight values('"+flight_id+"','"+start_place+"','"+end_place+"','"+start_airport+"','"+end_airport+"','"+take_off_time+"','"+landing_time+"','"+first_class_price+"','"+business_class_price+"','"+economy_class_price+"')"; 29. //Integer res= 30. conn.executeInsert(sql); 31. //System.out.println(res); 32. //System.out.println(sql); 33. resp.sendRedirect("admin/flight_list.jsp"); 34. } 35. } catch (SQLException e) { 36. // TODO Auto-generated catch block 37. e.printStackTrace(); 38. } 39. }
    4.4 订单管理订单管理模块主要是对用户订票进行管理,管理员通过登录进行访问系统后台页面,然后选取订单管理模块,对客户进行处理。通过数据库对用户订单信息组进行管理,通过定义ArrayList()数据组来获得订票所以信息。
    1. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 2. req.setCharacterEncoding("utf-8"); 3. HttpSession session = req.getSession(); 4. if(session.getAttribute("user_id")!=null) { 5. String user_id=session.getAttribute("user_id").toString(); 6. String f_i=req.getParameter("flight_id"); 7. String passenger_name=req.getParameter("passenger_name"); 8. String date=req.getParameter("date"); 9. String grade=req.getParameter("grade"); 10. String passenger_id=req.getParameter("passenger_id"); 11. String contact=req.getParameter("contact"); 12. String contact_phone=req.getParameter("contact_phone"); 13. 14. 15. /* 16. * System.out.println(f_i); System.out.println(passenger_name); 17. * System.out.println(date); System.out.println(grade); 18. * System.out.println(passenger_id); System.out.println(contact); 19. * System.out.println(contact_phone); 20. */ 21. 22. if(f_i!=""&&passenger_name!=""&&date!=""&&grade!=""&&passenger_id!=""&&contact!=""&&contact_phone!="") { 23. db_conn conn=new db_conn(); 24. String sql="insert into t_order (f_n,order_user,p_name,date,grade,p_id,contact,c_p) values('"+f_i+"','"+user_id+"','"+passenger_name+"','"+date+"','"+grade+"','"+passenger_id+"','"+contact+"','"+contact_phone+"')"; 25. Integer res=conn.executeInsert(sql); 26. System.out.println(res); 27. if(res.equals(1)) { 28. resp.sendRedirect("default/order_list.jsp"); 29. }else { 30. resp.sendRedirect("default/order.jsp"); 31. } 32. 33. }else { 34. resp.sendRedirect("default/order.jsp"); 35. } 36. 37. }else { 38. resp.sendRedirect("default/order.jsp"); 39. } 40. 41. }
    5.操作方法用户访问首页

    用户进行登录

    用户进行注册

    登录或注册成功,进入用户个人首页

    用户修改个人资料

    用户订购航班

    用户查询航班

    用户查看航班订单

    用户查看留言

    管理员登录界面

    管理员添加航班信息

    管理员查看航班列表信息

    管理员查看航班订单

    管理员查看用户列表信息

    管理员查看留言列表

    6.测试结果用户能成功订购航班,并且查看订单



    管理员查看航班并成功添加航班


    7.心得体会通过JavaEE的综合课程设计感触很深,在数据库的课设的基础上,又一次用JSP做相关项目,这不仅又一次加强了自己对JSP这门课程的理解也很好的锻炼了自己的动手能力。这一技术是需要有一定基础、而且动手能力强的学科。书上也强调一点是:要想真正地掌握JSP技术,必须有较好的java语言基础,以及HTML语言方面的知识。
    JSP是一门新技术,他基于Java Servlet以及整个java体系的Web开发技术。通过这个大作业,使我初步掌握和了解了JSP的基本运行原理、各个对象的结构和功能、怎样连接数据库、能自己手动写code 开发一些小网页。并且,自己能够组建一台JSP服务器,而且还了解了安装过程中,所要注意的事项。对于一些简单的小问题,能够自己动手排除。
    15 评论 207 下载 2020-08-04 12:31:18 下载需要11点积分
  • 基于JAVA的即时通信软件

    一.设计任务书1.1 设计任务本文设计的是一个简单的即时通信软件,利用 Java Socket 进行点到点通信,其工作机制模仿即时通信软件的基本功能,已实现的功能有:

    客户端登录客户端退出群组成员之间传输文字或图片信息
    该软件分为客户端与服务器端,客户端负责与服务器建立连接,且执行收发消息的操作,服务器端负责等待客户端连接并保存用户的昵称与客户端 Socket 的输出流的对应关系。
    1.2 技术指标本程序使用的是 TCP 协议实现的即时通信软件,程序是基于 Java 语言开发的,主要用到的技术有:

    Socket 编程自定义协议
    如果使用普通的方法来标记一条消息的结束,如换行符,那么程序就不易扩展,只能发送纯文本消息,所以需要自己定义一种消息的格式,并且我们还需要提供发送消息与解析消息的方法。
    服务器端创建一个 ServerSocket,循环等待客户端的连接,每当有客户端连接,就获取到客户端的 Socket 对象,并将该对象交付给一个服务器端线程处理,服务器端线程会不断从 Socket 的输入流中解析出消息类型、长度及消息内容,然后根据类型执行不同的操作。
    客户端与服务器建立连接,同时开启一个客户端线程接收服务器端发送的消息,客户端登录是向服务器发送一条登录命令,客户端向服务器发送一条消息首先需要包装成定义的消息格式,然后再发送给服务器。
    不管是发送消息还是发送命令其实本质都是一条消息,向服务器发送的消息都必须按照定义的格式来。
    1.3 论证结果经论证,这个任务是可行的。TCP 协议的实现细节 Java Socket 已经帮我们做好了,我们需要做的是定义一个协议工具类,实现发送消息与接收消息的方法,然后客户端与服务器端都利用这两个方法来进行消息的发送与解析。
    二.实现原理2.1 基于 TCP 协议的即时通信TCP 协议是一种端到端协议,当一台计算机要与远程的另一台计算机连接时,TCP 协议会让他们建立一个用于发送和接收数据的虚拟链路。TCP 要负责收集数据信息包,并将其按照适当的次序放好传送,接收端收到后再正确的还原,TCP协议使用了重发机制,当一个通信实体发送一个消息到另一个通信实体后,需要接收到另一个通信实体的确认消息,如果没有收到确认消息,则会重发消息。所以 TCP 协议保证了数据包在传输中不发生错误。通信示意图如图 1 所示。

    在通信实体 1 与通信实体 2 建立虚拟链路前,必须有一方主动来接收其他通信实体的连接请求,作出“主动”的通信实体称为服务器,发出连接请求的通信实体称为客户机。
    2.2 自定义协议的定义2.2.1 通信原理客户端与服务器端相互通信,首先要建立 Socket 连接,连接建立好后双方都会拿到一个 Socket 对象,通过 Socket 对象拿到输入、输出流可以实现写、读的功能。服务器端接收到客户端的连接,将客户端的 Socket 对象交付给一个线程,该线程负责维护该客户端,在线程体中需要使用死循环不断的获取客户端发给服务器的消息。
    2.2.2 存在的问题那么问题来了:怎么标志客户端发送的消息的结尾?如果不对结尾标志,服务器端将不知道客户端本次客户端发送的消息到哪里。
    2.2.3 文本消息的解决办法对文本消息的一般做法是将‘\n’作为结尾标记,操作过程如下:

    客户端与服务器端建立连接,服务器端将客户端的 Socket 加入集合中保存,并将客户端的 Socket 交付给一个服务器端线程处理,服务器线程初始化套接字、输入输出流,然后一直循环等待客户端发送消息
    客户端向服务器发送消息“Hello World!\n”,服务器线程获取到客户端发送的消息,然后使用输入流读取一行消息,读取到的消息是“Hello World!”,然后遍历服务器端的那个集合,获取到集合中每个 Socket 的输出流,向每个输出流中写入消息。

    以上是一般意义上群聊的实现原理:客户端向服务器发送消息,服务器获取到消息后转发给群组中的所有成员。
    2.2.4 依然存在的问题
    问题一:如果发送的是图片、文档应该怎么标记消息的结束?问题二:在实际应用中,客户端向服务器端发送消息并不像刚才的例子那么简单,还需要登录、注销、登录成功等命令,怎么来区别这些命令?
    2.2.5 自定义协议的内容为解决以上问题,我们规定:消息的发送与解析都必须使用以下格式:

    由表 1 知,数据分为三个部分

    type:1 字节,表示发送的消息类型,所以可以表示 65535 种消息类型。totalLen:4 字节,整型数据,表示发送的消息的总长度,包含 type、totalLen的长度以及消息内容的长度,totalLen 占用 4 字节,所以最大可以发送 2G 的数据。bytes[]:字节数组,表示发送的消息的内容,大小没有限制。
    2.2.6 使用自定义协议制定消息的规范后以上两个问题都会迎刃而解了,客户端向服务器端发送消息的过程如下:
    例 1:发送纯文本
    客户端:

    客户端的视图与用户交互获取到用户要发送的文本内容“你好啊”客户端将获取到的文本内容转化为字节数组 bytes客户端将消息包装成自定义的消息格式,如表 2 所示


    客户端往输出流中写入消息
    服务器端:

    服务器端线程一直等待接收客户端的消息服务器端线程获取到客户端发送的消息,按照格式解析出消息的类型、长度以及消息内容服务器端线程获取到的消息类型是文本类型 TYPE_TEXT,那么需要遍历服务器端的集合,获取到集合中每个 Socket 的输出流,使用这个输出流对消息转发,在转发前同样需要包装成定义的消息格式。
    例 2:登录功能
    客户端:

    客户端与服务器端建立连接之后,将用户输入的昵称包装成一条消息,如表 3 所示,消息类型是 TYPE_LOAD,字节数组 bytes 是用户昵称。


    在建立连接的同时客户端会开启一个线程等待接收服务器端的消息。将消息发给服务器端。客户端线程如果收到服务器端反馈的信息,就将信息告知用户。
    服务器端:

    接收到消息后获取到消息类型为 TYPE_LOAD,服务器端就可以知道这条消息是登录请求,然后 bytes[]数组里的数据就是用户昵称,将用户昵称、该客户端的 Socket 对象的输出流先保存到 Map 中,然后将该 Map 保存到集合中。服务器端线程对客户端的登录请求处理完成后,向客户端反馈一条标记着是否操作成功的消息,类型是 TYPE_LOADSUCCESS 和 TYPE_LOADFAIL,bytes 数组是服务器端反馈的消息。
    如果登录成功,服务器反馈的消息格式如表 4 所示。

    如果登录失败,服务器反馈的消息格式如表 5。

    2.2.7 小结其实不管客户端发送的消息是哪种类型,客户端只需要负责将要发送的消息转化为字节数组,然后对数据包装后发送给服务器。对于一些非命令类的消息,服务器接收到消息后只需要根据数据类型对数据进行解析、包装、转发即可。对于一些命令类的消息,如登录,退出等功能,则需要服务器端执行相应的操作,服务器端不需要对消息转发,可能需要对一些命令给予反馈。
    通过自定义协议可以解决上述的两个问题,并给出了客户端与服务器端使用自定义协议发送消息的两个详细步骤
    2.3 自定义协议的实现这个自定义协议就是自己定义的一个发送消息、解析消息的规范,无论是发消息还是收消息都必须按照这个规范来,实现这个协议无非需要考虑三个问题:

    问题一:如何发送消息?问题二:如何解析消息?问题三:如何表示解析消息后的结果?
    我们只需要定义两个类,协议工具类 Protocol 负责消息的发送与解析,消息结果类 Result 封装了一个消息的三个部分:type、totalLen、bytes,协议工具类对消息解析后会返回一个 Result 对象表示一次解析的结果。所以这两个类结合起来使用就可以解决以上三个问题。
    2.3.1 协议工具类的实现协议工具类 Protocol 负责消息的发送与解析,内部需要定义消息的格式,协议工具类的设计如图 2 所示。

    2.3.1.1 消息类型消息类型是协议工具类的静态的公共的整型常量,这样的设置为程序后期的扩展提供了方便,提供的消息类型如表 6 所示。

    2.3.1.2 发送消息发送消息就是按照定义的格式往输出流中写入数据,我们首先要做的是包装数据定义方法签名,如表 7 所示。


    包装数据
    一条数据有三部分,消息类型、消息内容已经通过参数获取到了,消息的长度还要程序计算:消息长度=消息的内容的长度+5 字节。
    int totalLen = 1 + 4 + bytes.length;

    按格式写入输出流,先写入消息类型,然后写入消息的总长度,最后再写入消息的内容。
    dos.writeByte(type);dos.writeInt(totalLen);dos.write(bytes);dos.flush();
    2.3.1.3 解析消息解析消息是指将从输入流中读取到一条消息,然后按照格式转化为一个结果对象 Result。定义方法签名如表 8 所示。


    消息提取
    从输入流中依次读取三部分:type、totalLen、bytes[],dis 是方法的参数,调用方法时需要传入输入流
    byte type = dis.readByte();int totalLen = dis.readInt();byte[] bytes = new byte[totalLen - 4 - 1];dis.readFully(bytes);

    结果返回
    将提取出来的数据的三个部分封装成一个结果对象作为方法的返回值,注意第一个参数:type & 0xFF,因为 type 是字节,需要与 0xFF 进行“与”运算得到一个整型值。
    return new Result(type & 0xFF, totalLen, bytes);
    2.3.2 结果类的实现结果类 Result 封装一条消息的三个部分,主要提供了 setter、getter 方法来设置或者获取消息的三个组成部分,结果类的设计如图 3 所示。

    2.3.2.1 消息格式Result 类定义了消息的格式,消息的组成如表 9 所示。

    2.3.2.2 方法Result 类的方法签名如表 10 所示。

    2.4 服务器端的实现2.4.1 服务器类Server 类负责等待客户端连接并将连接上的客户端交付给服务器线程类。Server 类的设计如图 4 所示。

    clients 维护一个 List 集合,集合中每个元素都是 Map,每个 Map 中都有两个 item,保存着客户端的昵称和对应的输出流。
    main 方法中要实现的是等待客户端连接,使用 ServerSocket,有客户端连接时开启一个线程来处理。代码如下:
    ServerSocket serverSocket = new ServerSocket(30000);while (true) { Socket socket = serverSocket.accept(); new Thread(new ServerThread(socket)).start();}
    2.4.2 服务器线程类ServerThread 类负责接收客户端的消息并对消息进行相应的处理,ServerThread 类的设计如图 5 所示。

    2.4.2.1 变量ServerThread 类的变量以及其含义如表 11 所示。

    2.4.2.2 方法签名ServerThread 类的方法签名以及含义如表 12 所示。

    2.5 客户端的实现2.5.1 客户端界面界面的元素有:登录输入框、聊天内容文本域、消息输入文本域、发送按钮。客户端界面初始化时会调用 Client 的方法执行客户端与服务器的连接请求,连接成功后客户端与服务器端会形成一个虚拟链路,当用户输入用户名后回车,客户端通过该虚拟链路向服务器端发送一条登录命令。View 类的设计如图 6 所示。

    2.5.2 客户端客户端 Client 负责处理客户端连接、客户端发送消息的任务,Client 类的设计如图 7 所示。

    2.5.2.1 建立连接socket = new Socket(address, port);dos = new DataOutputStream(socket.getOutputStream());// 监听服务器发回的消息new ClientThread(socket).start();
    2.5.2.2 登录public void load(String user) { Protocol.send(Protocol.TYPE_LOAD,user.getBytes(), dos);}
    2.5.2.3 发送消息public void sendMsg(String msg) { Protocol.send(Protocol.TYPE_TEXT, msg.getBytes(), dos);}
    2.5.2.4 退出public void logout(){ Protocol.send(Protocol.TYPE_LOGOUT, "logout".getBytes(),dos);}
    客户端线程负责接收服务器端发的消息,其对消息的处理方法与服务器端线程的处理方法类似,都是先解析消息,然后根据消息类型执行相应的操作。
    2.5.2 客户端线程客户端线程主要负责接收消息,并对接收到的消息进行显示。ClientThread类的设计如图 8 所示。

    ClientThread 类维护的是客户端的套接字以及输入流,那三个方法的作用和服务器端线程类似,这里不再细说。
    三.实验结果3.1 运行结果
    服务器端启动后是没有运行界面的,运行结果如图 9 所示。


    客户端启动后初始界面如图 10 所示。


    输入用户名后回车登录,登录后如图 11 所示。


    两个客户端互发消息,如图 12 所示。


    单个客户端退出

    3.2 主要问题及故障分析3.2.1 主要问题
    不知道如何标记一条消息的结尾界面问题
    3.2.2 故障分析对于第一个问题:如果只是发送一条文本消息的话,是没有这个问题的。但是为了使程序拥有更好的扩展性,使其可以发送图片以及文档,这个问题还是值得思考的。定义一种消息的格式,无论是发送还是接收消息都按照这个标准来,这个就是我们定义的协议工具类的作用。
    对于第二个问题:本程序是基于 Java 语言开发的,AWT 和 SWING 是 Java 语言开发 GUI 的工具包。SWING 和 AWT 写界面都不是很方便,所以本程序的界面有点粗糙。
    3.3 设计结论由于之前写过这类的程序,所以在程序层次上的实现并不难,本次实验不仅巩固了编写程序的功底,还加深了对 Socket 通信底层理论的理解,可以说是收获非常大。至此,本论文已经接近尾声,所研究的是一个简单的即时通信软件的实现过程以及实现原理。
    四.附录一:实验相关4.1 实验数据客户端与客户端 2 发送的消息数据,[]内部表示的是发送方的昵称,昵称外部是发送的消息内容,具体实验数据如下:

    [客户端 1]我是客户端 1[客户端 1]你好啊![客户端 2]我是客户端 2
    4.2 系统软硬件环境4.2.1 硬件环境
    系统:Window7 旗舰版系统类型:64 位操作系统处理器:i5-4210U安装内存:4.0GB
    4.2.2 软件环境已安装 JRE、JDK 并配置好环境变量
    4.3 使用说明本程序分为客户端与服务器端,首先需要启动服务器端,然后可以打开多个客户端,客户端打开后可以进行聊天。
    4.4 参考资料[1] 李刚,疯狂 Java 讲义第 3 版,北京:电子工业出版社,2014.7
    [2] James F.Kurose,Keith W.Ross,计算机网络-自顶向下方法上册(第 5 版),北京:高等教育出版社
    7 评论 412 下载 2018-11-03 13:32:16 下载需要10点积分
  • 基于C语言的飞机票预订系统

    1 解题思路本题需要综合使用数据结构的知识。以此,将航班数据设计成链表形式即定义结构体,其中包含飞机序号,登机口作为数据域,next作为指针域,将此结构体称为Node。将乘客信息设计成特殊的结构体,结构体中包含乘客姓名,性别,目的地,舱位,座位号和身份证,并且用数组包含每个乘客的信息。再设计一个结构体,其中包含刚刚的数组,以及乘客总人数,将此结构体称为Sqlist。而函数执行时,首先将Sqlist初始化。然后进入switch选择,通过选择来执行不同的函数。首先创建航班链表,通过判断输入的飞机序号是不是等于0来判断是否输入完毕。然后输入乘客数据,输入所在飞机号和该飞机乘客容量,使用for循环依次将数组赋值。之后可以通过飞机链表和乘客数据分别查询航班的信息和乘客的信息。并且可以删除飞机信息。最后是将所输入的信息保存成txt格式的文件,以及可以从txt格式的文件中读出数据进行处理。
    2 函数调用图
    3 各函数功能// 创建飞机链表int createPlane(Node *L); // 删除飞机节点int deleteNode(Node *L); // 容器初始化int initSqList (sqList *S); // 构造乘客容器int createSqList (Node *L, sqList *S); // 创建新乘客int createCustomer(int i); // 搜寻航班int searchPlane(Node *L); // 搜寻航班int searchPlane(Node *L); // 保存数据int reserve(Node *L, sqList *S); // 读取数据int read(Node *L, sqList*S); // 主函数,流程控制int main();
    4 测试










    5 评论 332 下载 2018-11-05 09:16:45 下载需要10点积分
  • 基于JAVA实现的超级马里奥(Super Mario)游戏

    一、项目简介刚进入的时候会有一个界面,为地图编辑器。可以使用此编辑器进行地图编辑,地图编辑器的内容包括:关卡、向左箭头、带有金币的砖块、带有花朵的砖块带有蘑菇的砖块、带有星星的砖块、普通砖块、向左运动的板栗仔、向右运动的板栗仔、向左运动的乌龟、向右运动的乌龟、金币、带有食人花的管道、普通管道、洞、向右的箭头、橡皮擦、可以使用鼠标点击图标然后拖动到面板上点击面板进行地图编辑,橡皮擦可以擦除已经建立好的模型。
    部署完地图之后可以选择下一关进行下一个关卡的编辑,也可以点击开始游戏开始游戏。游戏开始后从编辑的第一关卡开始进行闯关,人物可以移动通过ad键进行控制,可以跳跃,通过k控制,跳的时候可以跳到管子和砖块上面。
    人物有两种状态:大马里奥和小马里奥。小玛丽奥可以撞普通的砖块或者带有包含物的砖块使得砖块可以向上稍微移动,砖块上的一些包含物也会随着砖块移动。大马里奥可以顶破普通砖块。
    怪物分为三种,分别为:板栗仔、乌龟和食人花。马里奥可以通过跳跃的方式踩死怪物,板栗仔在被踩的时候会变扁,乌龟被踩的时候。走动状态会变成龟壳状态,龟壳状态被碰到可以变成跑动的龟壳状态,跑动的龟壳可以杀死马里奥。板栗仔和其他的乌龟。运动的龟壳在运动的时候被马里奥踩到会变成静止的龟壳,食人花长在管道中,会定时出现对管道上方的物体进行攻击,当马里奥踩在管道上的时候不会出现。
    还有三种物体是包含在砖块中的,分别是星星、蘑菇、花朵。马里奥自下向上顶砖块之后砖块上方会生长出相应的植物星星和蘑菇会向右方向行走,花朵会在原地。马里奥可以通过触碰的方式吃掉植物,不同植物有不同的加成效果。其中,吃掉蘑菇之后会变成大马里奥。吃掉星星之后会变成无敌状态。吃掉花朵之后会有发射子弹的技能。
    任何物品,尤其是可移动物,包括子弹,在碰到洞之后会掉落到洞中人物掉落之后会损失一命,人物一共有五条生命。每次正面碰到乌龟或者板栗仔,或者掉落到洞中之后便会损失一条生命,每次损失生命则该关卡从头开始当五条生命全部损失之后便会到game over状态。
    当马里奥走到地图的最后一个模型之后的位置的时候说明本关通过,本关通过时会有马里奥跳下拉动旗帜旗帜拉倒底端的时候会向右跑到城堡位置。跑到城堡位置即属于本关卡已经通过,则消除所有的加成状态转到下一关卡。
    最后通关所有的关卡即为game ends,跳跃的时候有重力效应,降落的会越来越快游戏界面上方会有剩余生命,当前时间为0的时候会损失一命,还有计分系统。当玩家杀死怪物,或者吃掉某种可生长物,或者过关的时候都会获取相应的分数加成。分数显示在面板上方。吃掉金币会有金币数量统计,统计结果在生命右边。本项目的亮点在于应用ioc技术的地图编辑器和精美的人物模型。
    二、需求分析人物跳跃的重力,条约落下的时候碰到其他的硬物可以停止下落。踩死怪物。怪物死亡方式不同展现的画面不同。吃东西,有属性加成。大马里奥顶破砖块。小玛丽奥顶砖块砖块可跟随移动。砖块上方的东西可以跟随移动。地图编辑功能。声音功能。人物胜利拉旗进城堡。
    三、系统设计
    本项目共有20个公共类,5个接口。分成三种类,分别是:控制类、模型类、工具类
    功能方面有两大块,分别是地图编辑器和正式游戏
    地图编辑器部分使用了spring框架的ioc技术

    程序功能流程图如下图所示:

    控制类中有两个类分别为Main和Control作用分别为控制地图编辑,地图编辑的思路如下:玩家点击图标之后鼠标的状态变成点击的图标的状态值,本类中有一个map键值分别为Integer和model鼠标移动到某位置点击之后会使integer加一。构造出相应的model然后put到map中如果用户点击的是橡皮擦。那么会计算哪一个类在橡皮擦点击的位置,并且把相应的位置的model设为忽略。最后解析这个map构造xml文件和保存着各个类的数量的一个properties文件Control类通过解析xml和properties文件解析关卡信息还原用户编辑的地图。
    还有一个全局的properties为game.properties保存着关卡数目。在点击开始游戏之后开始运行Control类中的work方法。Work方法的作用是初始化整个游戏的完整页面读入xml中的内容实例化对象存到容器中。然后启动paintThread线程画出面板,启动其他的必要线程进行工作,根据用户的操作对容器中的对象的一些参数进行改变呈现不同的视觉效果。
    四、系统实现本项目由于需要实现用户自由设计地图,所以应该尽量降低耦合度,从全局的角度出发,对类的设计应该分为实物模型,统筹控制,工具,抽象出来的接口。接下来一一介绍。类结构图如下图所示:

    统筹控制包含Main和Control在上一部分已经介绍。接口被抽象出来以下几种:

    Dangerous类所有的可以杀死主角的实物模型类应该去实现该接口
    Flint类,砖块和管子应该去实现该接口。Growable接口,所有的可以被马里奥从砖块中顶出的实物模型应该实现该接口。Kill接口,所有的可以伤害到别的实物模型类的类都应该实现该接口。Moveable接口,所有的可以移动的物体都应该实现该接口

    实物模型类一共有12个:

    Badflower类是食人花类,实现Dangerous接口
    Bullet类是子弹类,实现Moveable和Kill接口
    Flower类是吃了以后可以发射子弹的类,实现了Growable接口
    Hole类是地面上存在的洞类。没有去实现任何接口
    Mario类,是主角类,实现了Moveable,Kill接口
    Money类,因为可以直接被主角吃掉并且在砖块上被顶出之后不需要生长移动过程所以不实现任何接口
    Monster类是板栗仔,实现了Dangerous,Moveable接口
    Mushroom类是吃了以后变大的蘑菇类实现了Growable和Moveable接口
    Pipe是管道类实现了Flint接口
    Star是吃了以后变成无敌状态的星星,实现了Growable和Moveable接口
    Turtle是乌龟类,实现了Dangerous,Kill,Moveable接口
    Wall是砖块类,实现了Flint方法

    还有6个工具类,其中的方法和字段大部分是静态的和final的:

    ApplicationUtil类可以通过传入的关卡值去加载spring上下文,为程序提供对象实例
    CrashType定义了一些物体之间的碰撞类型的常量
    ImageTool类中包含了程序用到的所有的图片以及为了克服延迟加载而写的事先加载所有图片的方法
    Null类是一个Growable类的空实现,因为在构造砖块的时候定义构造方法里面应当传入所包含的可生长物,而在使用spring框架进行实例化得时候不允许出现null.本人又极不愿意在写另外一种构造方法,所以索性构造一个Growable接口的空实现类,通过传出特殊的Type值进行识别
    Property类,用于解析配置文件,获取数据
    SoundTool类包含所有的使用到的音乐,以及静态的播放音乐的方法

    五、调试改错在实现的过程中出现了很多错误。比如声音播放问题和人物碰撞检测的问题等。不过最后解决的还算满意。
    六、美工素材本项目是一个人写的,代码和图片美工都是自己实现的。由于互联网上找不到相关素材,所以本人现学的ps,通过录制游戏中的人物动作分帧截图,使用抠图等技术自己做的图。
    七、总结要有统筹整个项目的意识。对整个项目有总体的把握。类的编写应当事先分好类,分清楚每种类的任务。最大化解耦,以免改动的时候涉及到过多的地方。分清楚每个类的任务。合理设计避免冗余。
    八、关键代码碰撞检测部分代码:
    public int getCrashType(int down,int direction,Rectangle rec1,Rectangle rec2)//rec1为wall,rec2为Mario 获取撞击类型 { //rec1是硬物。rec2是移动物 if(die)return CrashType.NO_CRASH; int rec1X=(rec1.x+rec1.x+rec1.width)>>1; int rec1Y=(rec1.y+rec1.y+rec1.height)>>1; int rec2X=(rec2.x+rec2.x+rec2.width)>>1; int rec2Y=(rec2.y+rec2.y+rec2.height)>>1; int width=rec1.width+rec2.width; int hight=rec1.height+rec2.height; if(rec2Y>=rec1Y) { if(rec1X>=rec2X) { if(down!=1||(rec1X-rec2X)/((double)width)>((rec2Y-rec1Y)/(double)hight)+CrashType.POINT) return CrashType.WALL_L;else { if(control.getMario().isCanWork())work(); control.getMario().down(); return CrashType.WALL_D; } }else { if(down!=1||(rec2X-rec1X)/((double)width)>((rec2Y-rec1Y)/(double)hight)+CrashType.POINT) return CrashType.WALL_R;else { if(control.getMario().isCanWork())work(); control.getMario().down(); return CrashType.WALL_D; } } }else { if(rec1X>=rec2X) { if((rec1X-rec2X)/((double)width)>=((rec1Y-rec2Y)/(double)hight)+CrashType.POINT) return CrashType.WALL_L;else { return CrashType.WALL_U; } }else { if((rec2X-rec1X)/((double)width)>=((rec1Y-rec2Y)/(double)hight)+CrashType.POINT)return CrashType.WALL_R;else return CrashType.WALL_U; } } }
    马里奥跳跃代码:
    private class JumpThread extends Thread//跳的线程 { private int n=jumpHight; public void run() { if(down==-1)return; if(downThread!=null) { downThread.stop(); downThread=null; } if(jumpThread!=null) { jumpThread.stop(); jumpThread=null; } jumpThread=this; //while(!Control.isALL_START()){try{sleep(Control.TIME);} catch (InterruptedException e){}} SoundTool.play(SoundTool.jumpSound); try { int site=locaY; double count=Math.sqrt((2*0.085*n)); for(int i=site;count>0;i-=(count-=0.1))//向上跳的时候改变状态 { if(getCrashType()&&(crashType==CrashType.WALL_D||crashType==CrashType.WUWL||crashType==CrashType.WUWR))//如果发现从下撞击了硬物则跳出向上的过程改为向下 { down=-1; break; } locaY=i; sleep(10); down=1; } new Down().start(); }catch(Exception e) { e.printStackTrace(); } down=0; } }
    马里奥降落代码:
    private class Down extends Thread//二类下落线程 //控制最终下落的线程如果在正常下落时由于碰撞被打断则启动该线程监视是否需要再次落下 { public void run() { if(down==1)return; //while(!Control.isALL_START()){try{sleep(Control.TIME);} catch (InterruptedException e){}} if(downThread!=null) { downThread.stop(); } downThread=this; // System.out.println("enter down!"); // while(down!=-1&&locaY!=control.getCutLine())//没有落地面上一直在循环 while(locaY<control.getCutLine()) { boolean flag=false;// int site=locaY; // System.out.println(crashType+" "+down+" "+canWork); if((getCrashType()&&(crashType==CrashType.NO_CRASH)&&(down!=1))||canWork==false)//多线程重要判断应该靠紧 { flag=true;//已经下落 double count=1; for(int i=site;i<=control.getCutLine();i+=(count+=0.1)) { down=-1; locaY=i; downSpeed=count; // System.out.println(i+" "+control.getCutLine()); if(getCrashType()&&(crashType==CrashType.WALL_U||crashType==CrashType.PIPE_U||crashType==CrashType.WUWL||crashType==CrashType.WUWR))//如果在某个硬物的上方、启动二类下落线程且退出本线程 { down=0;//落道硬物上面则运动状态为0 downSpeed=0; downThread=null; new Down().start(); setCanWork(true); return; } try { sleep(10); } catch (InterruptedException e) { down=0; downThread=null; downSpeed=1; setCanWork(true); new Down().start(); } } locaY=control.getCutLine(); } if(flag)//在该线程中如果已经下落则跳出 { if(!control.getMario().isDownDie()) for(int j=0;j<control.getHoles().size();j++) { if(control.getHoles().get(j).canPaint()) control.getHoles().get(j).DownDie(control.getMario()); } if(!control.getMario().isDownDie())downSpeed=1; down=0; downThread=null; setCanWork(true); return; } } }
    12 评论 480 下载 2018-10-31 12:18:12 下载需要10点积分
  • 基于C++实现的学校员工管理系统

    一、设计内容及其要求
    模拟一下学校员工管理系统:主要是人员管理,具体的人员有学生,教师,管理人员有系主任,组织有系部教师里面分为:讲师,教授每个类必须实现的功能函数有:构造函数 、析构函数开会函数:必须设置为虚函数。在该函数里要显示开会人员的所有信息,即显示其所有成员变量的信息,并表示:这是 XXX 在开会
    建议在所有人员类的基础上抽象出 CPerson 类作为基类。其余类,都是从 CPerson 类派生而来
    具体分析如下:学生,教师都是人,教授是在讲师的基础上晋升的,系主任必须由教授职称的人担任。
    以上所有人员都统一受某个系部的管理 ,所以建议有个类似系部的类,系部可以组织该系的所有人或者某一部分人开会。这里的所有人包括:该系的“系主任,教授,讲师,学生”
    建立 main 函数,要求在 main 函数中 可以选择读入所有人或者某个系或者某一类人的信息,然后召集所选人员开会 。
    二、基本原理设计类,以老师给的数据只是作为参考,数据格式根据自己的需要进行修改,使用面向对象程序设计里的内容。虚函数,构造函数 、析构函数等知识的运用。
    三、具体设计方案3.1 设计说明本系统主要实现学校成员信息的查询,以及召集开会功能,首先用户进入主菜单界面,然后根据需求输入数字,以此选择功能。本系统简单通俗,操作界面友好。
    先划分为具体的类,明确类与类之间的关系。从 CPerson 类开始,写其构造函数和析构函数,同时写一个 virtual 虚函数 meeting,friend 友元 Department,以及 CPerson 类的基本数据:姓名、电话、地址,在类外实现声明的功能:

    之后写 student 类,继承自 CPerson,继承构造函数,增加新的数据成员 score 成绩

    讲师 teacher 与 student 类同理,继承 CPerson,继承构造函数,增加新的数据成员 wage 工资和 course 课程

    教授 professor 继承自讲师 teacher,继承构造函数,增加新的数据成员 book 书名和 postgraduate 研究生名

    系主任 Department_head 继承自教授,继承构造函数,增加新的数据成员 title 头衔

    以上是 CPerson 类及其派生类,之后便是另一个 Department 系部类
    同样的声明构造函数和析构函数,声明一个 void read_file();用于读入文件,声明 void display_1();void display_2();分别用于进行人员信息的查询和召集人员进行开会,然后便用以上各类声明一个对象数组,用于储存从文件中读入的数据


    实现召集人员进行信息查询和开会


    最后写主函数,先利用 cout 输出提示区

    之后用 department 类声明一个对象 a ,用其实现对文件中数据的读入,最后用 while(1)无限循环实现控制台上对各项数据的选择

    3.2 框图流程图
    四、设计小结本次课程设计的难点我个人认为主要在与后面对读入文件数据的处理以及如何从文件中读入数据,将这两点处理好程序就很好编写了。
    五、运行结果


    1 评论 4 下载 2021-07-02 18:06:29 下载需要7点积分
  • 基于C#和Sql Server的网上书店管理系统

    摘 要本系统是建立在 Windows 平台上,基于 B/S 结构的一个网上书店。通过这个网上书店,可以实 现简单的电子商务功能。
    整个网站风格一致,较为美观,有完善的导航机制。普通用户从前台首页进入,员工用户从后台首页进入(也即实现两个模板页)。用户使用的页面上必须有书籍广告轮播。
    前台部分由普通用户使用,后台部分由员工使用,任何对新闻、产品等的修改,只可从后台登录操作。
    1 绪 论1.1 概述本文以网上书店项目系统建设为开发为背景,以电子商务系统为原型,论述了管理信息系统的概念、结构及系统开发的基本原理和方法,全文共分为绪论、系统分析、系统设计、系统实施、开发总结等。
    1.1.1 问题的提出数据库是一门研究数据管理的技术,始于20世纪60年代,经过40多年的发展,现在已经形成了理论体系,成为计算机软件的一个重要分支。数据库技术体现了当代先进的数据管理方法,使计算机的应用真正渗透到国民经济各个部门,在数据处理领域发挥着越来越大的作用。
    随着社会的发展和经济时代的到来,管理信息系统在各行各业都越来越重要,特别是教育事业。在经济发达的国家,许多教育机构(如公办、私立、培训机构等),都投入了大量的资金开发 MIS 系统,以求在将来激烈的竞争中立于不败之地。在我国,民办教育是新兴的一个行业,是随着改革开放和市场经济的发展根据中国特有的国情发展起来的,特别是中国民办教育促进法的出台,从一定的程度上规范和促进了中国民办教育的发展,这是一个很有发展前途的新兴产业,但是同发达国家相比,我国的民办教育行业的信息技术的应用程度还很低,只有在大城市中发展较早、规模较大的民办院校中 才使用计算机进行大规模操作,从各方面提高工作效率,取得良好的社会和经济效益,而一些新兴的、规模较小的民办机构还没有全部具备这种功能。因此可见,随着我国民办教育的迅速发展,信息技术在其上的应用会更加地广泛和深入。
    1.1.2 本实训项目的意义首先,是一个简单的电子商务模型。一个书店,如果还采用原始的手动管理,那么将会极大的影响书店的工作效率,采用一种专门的管理系统,那么将会解放人力资源,提高学校的工作效率。其次,方便用书对图书的查询,本系统采用B/S模式,不需要安装任何附加的软件,只需要一个浏览器,就可以完成用户对自己喜爱的图书查询。
    1.2 开发环境与工具介绍
    开发环境

    windows 10Visual Studio 2015SqlServer 2016
    Web服务器

    IIS
    开发语言

    C# ASP.NET
    开发工具

    Visual Studio 2015
    网络协议

    TCP/IP

    1.2.1 C#简介C#是微软公司发布的一种面向对象的、运行于.NET Framework 之上的高级程序设计语言。并定于在微软职业开发者论坛(PDC)上登台亮相。C#是微软公司研究员 Anders Hejlsberg 的最新成果。C#看起来与 Java 有着惊人的相似;它包括了诸如单一继承、接口、与 Java 几乎同样的语法和编译成中间代码再运行的过程。但是C#与Java有着明显的不同,它借 鉴了 Delphi 的一个特点,与 COM(组件对象模型)是直接集成的,而且它是微软公司 .NET windows网络框架的主角。
    1.2.2 SqlServer 简介SQL Server是由Microsoft开发和推广的关系数据库管理系统(DBMS),它最初是由 Microsoft、Sybase和Ashton-Tate三家公司共同开发的,并于1988年推出了第一个OS/2 版本。Microsoft SQL Server近年来不断更新版本,1996年,Microsoft 推出了SQL Server 6.5版本;1998年,SQL Server 7.0版本和用户见面;SQL Server 2000 是Microsoft 公司于2000年推出,目前最新版本是2015年份推出的SQL SERVER 2015。
    1.2.3 IIS 简介iis 是 Internet Information Services 的缩 写,意为互联网信息服务,是由微软公司提供的基于运行 Microsoft Windows 的互联网基本服 务。最初是Windows NT版本的可选包,随后内置在 Windows 2000 、 Windows XP Professional和Windows Server 2003 一起发行,但在Windows XP Home版本上并没有IIS。IIS是一种Web(网页)服务组件,其中包括Web 服务器、FTP服务器、NNTP服务器和 SMTP服务器,分别用于网页浏览、文件传输、新闻服务和邮件发送等方面,它使得在网络(包 括互联网和局域网)上发布信息成了一件很容易的事。
    2 系统需求分析与设计2.1 用户需求分析2.1.1 用户需求通过对网上书店日常管理中的内容、广告、用户、管理员、新闻等相关内容进行分析,完成具有公司介绍、产品浏览、产品管理等相关功能的小型数据库管理应用系统。
    2.1.2 系统功能需求
    产品管理
    新闻
    产品浏览
    产品管理
    用户管理
    购物
    订单管理

    2.1.3 系统性能需求
    操作简便、快捷
    具备一定的安全性
    具有良好的用户体验

    2.1.4 数据分析系统中角色主要有:用户、类别、新闻、管理员

    用户:账号、姓名、性别、类型、登录密码等
    类别:青春文学、小说、悠闲、所有等
    新闻:类型、关键字、时间等
    管理员:管理员号、管理员名称、登录密码等

    2.2 功能模块图及分模块功能描述2.2.1 系统的功能模块图
    2.2.2 系统功能模块简介
    3 系统实施3.1 登录模块的开发系统登录

    注册模块

    如上图所示,系统的登录模块有二种登录方式,分别是:用户、管理员。从不同的登录方式登录后,会有不同的功能提供给用户。该登录模块采用的是Ajax技术,实现无刷新的登录验证,登录 信息错误时将会弹出图3.3-2所示的提示框,信息正确则自动跳转到系统主界面。

    3.2 系统主页模块的开发
    系统主页主要是为登录后的用户提供方便的访问服务,有前往系统各个模块的快捷方式。
    3.3 用户管理模块的开发用户管理——录入用户信息

    用户管理——个人信息

    用户管理——修改密码

    用户管理中有两个功能,分别是个人信息和修改密码。个人信息中可以查看、修改用户自己的相关信息,修改密码可以修改用户的登录密码。
    3.4 管理员后台管理模块的开发新闻管理—录入新闻、查看新闻、编辑新闻、增加新闻、删除新闻

    书籍管理

    分类管理

    用户管理—修改权限 搜集用户详细信息,修改用户详细信息

    3.5 管理员管理模块的开发
    3.6 系统测试系统运行正常,各种功能使用方便,但是在浏览器兼容性方面有些问题,虽然在 Chrome 和 FireFox下未出现问题,但是在IE下表现有些不尽人意。
    4 系统说明4.1 开发环境本系统的是在ASP.NET平台下开发的,系统的后台数据库为SQLSERVER数据库; 因此在使用本系统前,应先安装framework框架和SQLSERVER数据库,否则该系统无法运行。
    4.2 系统安装、配置与发布应用程序的步骤系统的原文件直接复制到机器上后,在网上书店管理系统上建立一个的数据库后,系统便可以运行。
    5 总 结这次的网上书店管理系统实训作业使我感触颇深,通过做这个小型的项目,我思考了很多。此次项目给我们提供了一个很好的契机,以此为动力,完成一个自己独自开发的小型项目。我们所做的课题是网上书店管理系统,整个过程没有想象中的那么容易,但好在最终还是完成了这次的作业。自己对整个课程设计工作的评价是:项目一般,水平有点一般,但付出却不是减半的。在整个过程中,我又把一本开发工具的书仔细的看了一遍。
    经过了一段时间努力,最近终于把项目做得完善了,在这过程中很想谢谢和我一起自习的朋友,你们的鼓励和帮助让我一直坚持着做下来。谢谢老师给的指点,我们会在接下来的时间把缺少的那些功能逐渐完善。
    16 评论 275 下载 2019-06-15 12:59:59 下载需要12点积分
  • 基于JSP和MySQL的网上零食销售系统的设计与实现

    摘 要本文介绍了网上零食销售系统的整个开发过程,采用国内认准的B2C商城建站系统模式,并按照现有的购物系统的现状而设计开发的网络买卖平台。
    本文主要阐述的了整个系统的完成过程,模拟了一个具备卖家,买家和管理员的网络交易系统。而本平台对不同的用户进行了细致的分划。对各个模块进行了功能上的丰富和优化。利用这些模块之间的交互完成整个物品的交易过程,为消费者和商家提供方便快捷的商务体验。说明书中已经简单的引述了电子商务的历史和现状,同样也介绍了该系统需要完成的功能,对整个项目的完成流程和进行时间进行了详细的规划。最后,对网上零食销售系统的前台应用软件进行了一些简要介绍。
    网上零食销售系统以JSP为主要的网页开发技术。利用B/S三层架构作为开发的基础框架,出于对系统的维护性,耦合性和安全性的考量,利用JavaBean对项目中关键部分进行封装的处理。数据库采用了后期维护十分便捷的MYSQL5.0数据库,其拥有的用可视化工具可以对字段进行快速准确的修改。
    关键字:JSP;B/S三层架构;JavaBean;MYSQL5.0
    AbstractThis article describes the online snack sales system throughout the development process, the use of domestic B2C mall to build the system model, and in accordance with the existing shopping system, the current design and development of network trading platform.
    This paper focuses on the completion of the whole system, simulates a network transaction system with sellers, buyers and administrators. But this platform carries on the detailed division to the different user. The modules are enriched and optimized in function. Use the interaction between these modules to complete the transaction process of the whole article, providing consumers and businesses with convenient and quick business experience. The manual has briefly quoted the history and current situation of e-commerce, and also introduced the functions that the system needs to complete. It also gives a detailed plan for the completion process and the time of the whole project. Finally, the online snack sales system of the front application software are briefly introduced.
    Online snack sales system to JSP as the main web development technology. The B/S three tier architecture is used as the basic framework of the development, and the encapsulation of the key parts of the system is processed by using JavaBean for consideration of system maintainability, coupling and security. The database adopts the MYSQL5.0 database which is convenient for later maintenance, Its own visual tools allow for rapid and accurate changes to the field.
    Key Words: JSP; B/S structure; JavaBean; MYSQL5.0
    1 绪论目前,我国的网民数量已经达到7.31亿人,随着互联网购物和互联网支付的普及,使得人类的经济活动进入了一个崭新的时代。淘宝,京东等网络消费平台功能的日益完善,使得人们足不出户就可以得到自己想要的东西。如今的互联网已经成为了我们生活中无法替代的部分,越来愈多的人感受到了互联网所带来的方便和快乐,也有越来愈多的人喜欢通过互联网购物来丰富自己的生活。如今的购物已不是当年去实体店挑选商品那种单一的存在,而是在一个虚拟的交易平台中,只需简单几步就可以实现整个购物的过程。
    JSP是一种动态的以网页为平台的开发技术,它具备很好的兼容性,可以引用JSP中自带的标签将Java代码导入到HTML网页中。相对于CGI程序JSP在性能方面更加快捷,而服务器端有着强大的兼容性等优势。随着互联网技术的日益完善,JSP技术在网络编程中也显得更加举足轻重。因此我采用了JSP作为我毕设的首要开发工具,建设了一个能实现简易的互联网交易的购物网站——网上零食销售系统。这个系统能够满足游客的注册和用户的登陆功能;可以满足用户对产品类别的查询,产品的下单,订单信息的查看等功能。基本上已经可以完成一个简单的交易过程,并且通过对数据库的编写和对代码的编写及完善,对于一个交易系统所需的技术都基本体现出来了,总的来说,目前的大型交易网站基本就是在我这个系统的基础上完善和扩充的。
    这次毕业设计中,我通过对相关电商网站运作原理的调查,初步绝定了整个项目的需求,并了解了当前最流行的动态网页技术JSP,对其有关知识和技术进行了深入的学习,实际的操作更是使得原本只存在与概念中的雏形得以实现。后期对于bug的修复和页面的美化更是锻炼了自己刻苦和谨慎的态度,这对于将来以后的工作和学习将是一笔不小的财富。
    1.1 开发背景在时代发展的今天,VR技术的出现使得人们可以在虚拟空间内进行活动,而AR则使得现实中可以模拟出你想要看到的东西。如果将这些与电子商务相联系的话,一个新的时代将会到来,若想足不出户就想得到这些虚拟的东西,购物网站成为了时下最为流行的选择,完善的购物系统,多样的支付方式,在体验虚拟的物品的同时打开购物网站,将其变为现实,短时间内天南海北的东西将会送到我们的手中,而这些都得益与物流的快速发展。正是在这一大趋势下我将“网上零食销售系统”作为了我的毕业设计。
    1.2 国内外现状
    网络交易(Electronic Commerce):从概念上讲是指产生在信息网络企业之间、电商和消费者之间还有个人与个人之间通过英特网的方式而进行的交易行为。国外因为网络发展起步早,因此国外的网络环境的都比较完善,功能齐全。
    进入21世纪以后,通过互联网技术,计算机技术和远距离交互技术,使得原本复杂的交易过程完全电子化和人性化。主流信息系统是基于B\S架构来设计并实现的管理系统[1]。而经济全球化的今天,国内外的消费者仅仅只需要在电脑或者手机前简单的对商品进行选择和付款便可足不出户获得远在大江南北的东西。网络所带来的便利已经开始影响到日常的生活,原本纸质的交易方式,已经实现到“互联网+”这种新兴的交易方式。
    由此可见,不管是在国内还是国外,如果要建立一个完善的电子商务系统,需要对大批的信息进行分析和处理,建设过程中还必须掌握数据库系统的理论和实际操作能力。对于如今已经成为不可或缺的网络交易平台,对于该系统的实现显得更加重要了。
    1.3 系统说明网上零食销售系统是在JSP的基础上进行开发和完善的。可以为卖家和买家两种用户提供在线交互平台,经过反复优化已符合我国目前流行的购物交互方式。卖家可以在平台中实现注册,上架新商品,商品打折,商店信息更新等功能;买家可以在平台中实现简单的注册,商品关键字的查询,将商品添加到购物车,订单付款等功能;网站维护人员可通过对商城各模块信息进行完善和删改,会员的信息的完善和删改等功能对商城进行改进和维护。
    2 开发环境介绍  2.1 JSP简介JSP动态网页技术的出现,得益于在Sun Microsystems公司的努力下,将行业内大小公司汇总起来,共同确定了现在所使用的动态网页技术规则。JSP=HTML+JAVA即在HTML中利用JSP自带的标签将原本存在于java文件中的代码导入进去,得到了我们现在所使用的.jsp文件。
    用JSP开发的Web应用拥有很好的兼容性,不光在传统操作系统Windows下可以运行,而在其他操作系统中也能完成其拥有的功能并且运行良好。
    JSP与Java Servlet两者有许多共通之处,例如都是在服务器端开始运作的,这时候客户端那边会得到一个HTML的文件,这时你只要拥有一个浏览器就可以很轻松的进行浏览了。
    在JSP已经飞快成长的今天,各大企业因其方便管理和较低的耦合性已经成为主流的网站建设方式。接下来我会讲述几个对于JSP关键性的几个问题,并对其进行简单的分析。
    2.1.1 Java Server Pages的工作原理JSP即HTML与Java的联合体。接下来将介绍怎样利用JSP来建立网页的:

    首先打开浏览器,利用浏览器对服务端发送一个HTML的申请
    服务端接受到申请后,会判断这是一个JSP网页的需求,接下来把这个需求发送给JSP引擎。利用URL或是.jsp文件来完成
    JSP引擎得到JSP文件后将其转换为servlet。其实就是将所有模块中的文本替换成了println()语句,而JSP元素则经过处理变成了java代码
    得到了servlet的JSP引擎将其进行编译,最终得到了可执行类,同时将最初的需求传递给了servlet引擎
    服务端的部分组件会对servlet引擎进行调用的同时加载并且运行servlet类。该部分运行时,servlet会生成HTML格式的输出,这个输出将会内嵌于HTTP response中发送给服务端
    服务端将静态的HTML页面的方式将HTTP response投射到我们的浏览器上
    服务端将HTTP response中处理得到的动态的HTML网页,其处理方式与静态页面相通

    以下是上述步骤的工作原理图,如图2.1所示:

    2.1.2 Java Server Pages的生命周期JSP的生命周期类似Servlet,而其关键在于基层的功能。
    以下是JSP生命周期中所经历的几个阶段:

    编译阶段:servlet容器编译成servlet源文件,产生servlet类
    初始化阶段:加载与JSP相对的servlet类,建立它的实例,同时调用它的初始化方法
    执行阶段:调用与JSP相对的servlet实例地服务方法
    销毁阶段:调用与JSP相对的servlet实例地销毁方法,紧接着销毁servlet实例

    以下为JSP生命周期的图示,如图2.2所示:

    2.2 Servlet技术简介Servlet其应用最重要的语言就是Java,其技术是作为JSP的发起者SUN建立地。作为现今主流的动态网页开发技术,程序员只需实现其已经拥有的接口和相应的继承类就可以轻松的将java文件变成动态网页。简单的说Servlet可以看作是在服务器端上运行的java程序。
    Servlet工作流程分为以下几步:

    客户端向服务端发送所需得到的消息
    服务端获得消息后需要将其传递到Servlet进行必要的处理
    Servlet对获得的消息进行处理,其产生的响应内容会被导入到Servlet
    服务端向客户端做出反馈

    以下为Servlet工作流程图,如图2.3所示:

    Servlet架构为我们提供了简化的开发过程,而这些过程可以细分为更加简单的类,这些类在开发过程中将使得原本复杂的代码变得更加条理。
    以下是我总结的Servlet提供给我们的类:

    控制程序流程的类
    实现和执行程序事务逻辑的类
    自定义的标记库使得创建和验证HTML表单更加容易

    Servlet体系结构:
    在项目的开发过程中,MVC设计模式被分为:模型,视窗和控制器。
    而Servlet在MVC模式的情况下,模型被分为:

    系统的内部状态
    可以改变状态的操作(事务逻辑)

    以下为Servlet的实现MVC框架的流程图,如图2.4:

    框架中所使用的组件:

    ActionServlet:控制器
    ActionClass:包含事务逻辑
    ActionForm:显示模块数据
    ActionMapping:帮助控制器将请求映射到操作
    ActionForward:用来指示操作转移的对象
    ActionError:用来存储和回收错误
    Servlet标记库:可以减轻开发显示层次的工作

    2.3 系统数据的介绍2.3.1 数据库的概念数据库好比是一个存放大量信息的仓库,以计算机为媒介将大量的数据长时间存放其中的一个集合体。数据库拥有集成、数量多、可分享和耐久强地特点。而数据简单地说就是对某些东西的所记录的符号,也就是说可以是简单的数字或是字母,还可以是图片或是声音都可以经过机器语言化后以数据的形式存入计算机中。
    数据库有以下特点:

    数据集成化:数据库将数据集合在一起,通过文件内部的约束机制,将本来混杂在一起的数据变得有条有理,防止了数据出现重复或着数据错乱等情况。方便了今后对于数据库的维护
    数据数量庞大性:作为众多数据的载体,其会被要求存在大量的数据,在同一时间内如果同时调用将会对存储器造成不小的负荷,要想解决这些问题必须利用移动硬盘,固态硬盘等数据存储设备来进行分担
    数据分享性强:其冗余度非常低,维护和增添新的数据将会变得非常便捷,同一个库可以对多个用户进行分享,同一时间可以处理不通的操作
    数据耐久性强:简言之就是长时间存储库中的数据

    而我们平时进行的商城中的交易,数据库的作用显得尤为重要,商城开发商将页面与后台数据库进行交互,将页面数据进行处理,完成存储等关键的行为。而数据库将这些收到的信息利用其集成化的特性将数据分门别类。而实现这些功能JSP技术就成为了这个项目的关键,其作为应用编程的接口,将页面与数据库进行连接。作为商城当访问数量过于庞大时,如果不能进行有效的处理将会出现系统瘫痪等不可预料的后果。这时,程序员利用JSP占用计算机资源少的特点对其功能进行拓展,使其在执行能力高的情况下还能提高资源的利用率。
    2.3.2 MySQL数据库简介MySQL源于瑞典的MySQL AB公司创造的,经过几次转手最终MySQL成为了Oracle公司的一员。虽然MySQL相对于大型数据库而言有许多无法与之媲美的能力,但是这并不能让其退出历史舞台,而其以功能的实用性,成本低和开源性成功占领了个人和中小企业的市场。其简单易学,维护方便,执行效率高,可兼容诸如Linux,windows这些主流平台更是使其成为了程序员不得不去学习和了解的主流数据库。
    MySQL能够有如今的成就还得益于其使用不需要支付任何费用,免费的经营手段让其用户获得了最大的收益。
    2.4 系统运行环境配置
    操作系统:Windows7、Windows10等主流系统
    CPU:最低要求能够运行Windows系统即可,如果想提高执行效率建议使用最新的CPU
    内存:建议使用500M以上的内存
    硬盘大小:建议预留100M的空间来对相关软件进行安装

    3 总体设计3.1 功能分析经过对时下大型电商网站的调查,对该系统的功能进行的大体的划分,网上零食销售系统将划分为两大管理模块。前台模块涵盖物品类别的查询,物品信息的查看,物品的订购,购物车,个人信息的修改等功能。后台模块涵盖平台中新闻的删改,商城中物品的维护,交易单的维护和注册人员的维护等模块。
    前台的具体描述如下:

    浏览商品

    商品详细资料商品编号
    订购商品
    购物车
    用户信息维护

    用户注册用户登陆用户资料修改

    后台管理具体描述如下:

    新闻管理

    添加新闻修改新闻删除新闻
    商品管理

    添加商品类别修改商品类别删除商品类别添加商品信息修改商品信息删除商品信息查看商品信息
    订单管理

    处理订单办理发货办理结帐删除订单
    友情连接

    增加友情连接删除友情连接修改友情连接
    会员管理功能

    注册用户修改用户信息删除用户信息
    系统用户管理功能

    添加系统用户修改系统用户信息删除系统用户信息

    由此可见本系统需求将获得6个完善的功能。
    以下为两个管理模块之间的关系图,如图3.1所示:

    经过反复设计之后,我需要一个系统开启前就拥有一个最初的管理员,因此我在数据库中添加了一个名为“Admin”的初始管理员方便今后的维护,他可以对网站已注册会员进行修改和调整,还可添加新的系统维护人员。
    以下为用户管理功能模块的示意图,如图3.2所示:

    3.2 系统流程分析本系统分以下两个流程:
    以下为用户交易流程图,如图3.3所示。

    以下为后台交易单管理流程图,如图3.4所示:

    3.3 数据流图以下为注册时数据流图,如图3.5所示:

    3.4 系统结构分析3.4.1 逻辑结构本系统是利用B/S三层架构作为开发的基础框架,将其以一个网页的形式展示在网络平台中,访问者可以通过网页实现商品的实时查看,实时购买,实时查看交易单等功能。而该系统可以作为各大电子商务网站的基础,拥有非常大的拓展性,能够经过程序员二次加工增加更多所需要的功能。
    以下为网站工作情况示意图,如图3.6所示:

    以下为网站物理结构示意图,如图3.7所示:

    4 数据库设计4.1 数据表的介绍该系统地数据库采用MYSQL5.0数据库,其作用是将网站中得到的数据进行存储,我将系统数据库地名字设为FOODEMARKET,其中包括9张表。以下为数据库中的数据表:
    4.1.1 messages(留言表)


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




    id
    int

    id


    saver
    varchar(255)

    发布人


    savetime
    varchar(255)

    发布时间


    [content]
    varchar(255)

    发布内容


    recontent
    varchar(255)

    回复内容



    4.1.2 news(站内新闻表)


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




    id
    int

    id


    title
    varchar(255)

    标题


    [content]
    text

    内容


    savetime
    varchar(255)

    保存时间


    infotype
    varchar(255)

    信息类别


    filename
    varchar(255)

    相关图片



    4.1.3 pinlun(商品评论表)


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




    id
    int

    id


    saver
    varchar(255)

    发布人


    savetime
    varchar(255)

    发布时间


    [content]
    varchar(255)

    内容


    pid
    varchar(255)

    商品ID


    infotype
    varchar(255)

    信息类别



    4.1.4 pros(商品表)


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




    id
    int

    id


    proshop
    varchar(255)

    卖家


    proname
    varchar(255)

    商品名称


    price
    varchar(255)

    价格


    discount
    varchar(255)

    折扣


    filename
    varchar(255)

    相关图片


    bei
    varchar(5000)

    商品说明


    extbei
    varchar(255)

    说明


    status
    varchar(255)

    状态


    savetime
    varchar(255)

    保存时间


    cjnum
    varchar(255)

    成交量



    4.1.5 proscar(购物车表)


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




    id
    int

    id


    uname
    varchar(255)

    用户


    pid
    varchar(255)

    商品ID


    num
    varchar(255)

    数量



    4.1.6 prosorder(订单表)


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




    id
    int

    id


    uname
    varchar(255)

    发送人


    savetime
    varchar(255)

    发送时间


    prosinfo
    varchar(1000)

    订单信息


    toshop
    varchar(255)

    卖家


    status
    varchar(255)

    订单状态


    fkstatus
    varchar(255)

    付款状态



    4.1.7 sysuser(用户表)


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




    id
    int

    id


    uname
    varchar(255)

    用户名


    upass
    varchar(255)

    登录密码


    utype
    varchar(255)

    用户类别


    tname
    varchar(255)

    姓名


    sex
    varchar(255)

    性别


    age
    varchar(255)

    年龄


    tel
    varchar(255)

    联系电话


    addrs
    varchar(255)

    地址


    filename
    varchar(255)

    头像


    qq
    varchar(255)

    QQ


    bei
    varchar(255)

    说明


    savetime
    varchar(255)

    注册时间



    4.1.8 splb(商品类别表)


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




    id
    int

    id


    pid
    varchar(255)

    上级类别


    lbname
    varchar(255)

    类别名称



    4.1.9 yqlj(友情链接表)


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




    id
    int

    id


    ljname
    varchar(255)

    链接名称


    ljurl
    varchar(255)

    路径


    filename
    varchar(255)

    图片



    4.2 用户模块设计概述4.2.1 系统原理本系统是利用B/S三层架构作为开发的基础框架,以下为其原理图,如图4.1所示:

    网上零食销售系统的主要体系结构包括:

    数据服务器
    WEB服务器
    后台管理平台
    客户端

    影响应用系统设计的因素包括:

    业务处理方式
    数据处理量,存储量
    应用功能设计
    服务器设计
    存储设计
    安全设计

    4.2.2 用户模块的程序流程图用户模块的设计,其主要功能的程序流程图设计如图4.2所示:

    5 详细设计5.1 前台伴随着我国人民消费水平的日益提高以及网络消费的飞快普及,在购物网站上买东西已经成为时下最为流行的一种消费手段。不光如此在购物网站的发展进程中还催生了新的节日,例如双十一购物节,双十二购物节,这些节日的产生低于得益于电子商务等的蓬勃发展,商家在赚取更多资金的情况下还优惠了消费者,这种双赢的经销手段使得交易双方变的更加紧密。
    以下为网上零食销售系统的前台首页,如图5.1所示:

    首页功能涵盖游客的注册、用户的登陆、最新活动的展示、物品关键字的查询、最新物品的展示等模块。
    5.1.1 会员登录游客只有进行用户登陆后才可以正常在购物平台内进行购买物品。

    登录:登陆是建立在原本游客已经注册会员的情况下进行的,用户只需点击登陆在文本框内按照提示将自己的“用户ID”和“ID的密码”输入进去,点击提交便可完成登陆
    注册:注册是针对未在本网站进行信息填写的游客,只有对信息进行填写才可以享受到平台内作为购物者完整的消费权限。游客只需点击界面右上角“注册”,就会跳转到注册页面。游客只需在相应的文本框内按照提示将信息完善后点击“提交”,如收到“注册成功”的提示即完成注册

    代码如下:
    <form name="form" method="post" action="memberAction.do?action=1" onSubmit="return land()"><table width="80%" height="90" border="0" align="center" cellpadding="0" cellspacing="0"> <tr> <td width="39%" height="20"><div align="right">用户名:</div></td> <td width="61%"><input name="name" type="text" size="13"></td> </tr> <tr> <td height="20"><div align="right">密  码:</div></td> <td><input name="password" type="password" size="13"></td> </tr> <tr align="center"> <td height="27"> </td> <td><input type="submit" name="Submit3" value="登录"></td> </tr> <tr align="center"> <td height="23"> <div align="right"> <table width="82%" height="77%" border="0" cellpadding="0" cellspacing="0"> <tr> <td bgcolor="#FFFFFF" class="linkBlack"><div align="center"><a href="member/memberRegister.jsp">注   册</a></div> </td> </tr> </table> </div></td> </tr></table></form>5.1.2 会员资料修改用户登陆后如果想对注册时的信息进行二次修改,只需点击“个人信息”,这时会跳转到用户信息修改页面。在这里你可以修改除了用户ID以外的信息,通过文本框内提示的信息即可完成,最后点击“提交”即修改成功。
    5.1.3 购买商品登陆用户需要购买商品,可以选择在首页中展示的最新上架的商品,或者用户可以在“商品一览”,“打折专区”和“销售排行”中点击自己喜欢的商品名称,在右上角选择“加入购物车”,然后进入用户中心对加入的商品进行简单的购买和付款操作,然后等待卖家发货即可。
    代码如下:
    <form method="post" action="cart_modify.jsp" name="form"> <table width="96%" border="1" align="center" cellpadding="0" cellspacing="0" bordercolor="#FFFFFF" bordercolordark="#819BBC" bordercolorlight="#FFFFFF"> <tr> <td width="16%" height="28"><div align="center">序号</div></td> <td width="23%"><div align="center">商品的名称</div></td> <td width="22%"><div align="center">商品价格</div></td> <td width="22%"><div align="center">商品数量</div></td> <td width="17%"><div align="center">总金额</div></td> </tr> <% float sum=0; Vector cart=(Vector)session.getAttribute("cart"); for(int i=0;i<cart.size();i++){ SellGoodsForm form=(SellGoodsForm)cart.elementAt(i); sum=sum+form.number*form.price; %> <tr> <td height="28"><div align="center"><%=i+1%></div></td> <td><div align="center"><%=dao.selectOneGoods(new Integer(form.ID)).getName()%></div></td> <td><div align="center"><%=form.price%>元</div></td> <td><div align="center"><input name="num<%=i%>" size="7" type="text" value="<%=form.number%>" onBlur="check(this.form)"></div></td> <td><div align="center"><%=form.number*form.price%>元</div></td> </tr> <script language="javascript"><!-- function check(myform){ if(isNaN(myform.num<%=i%>.value) || myform.num<%=i%>.value.indexOf('.',0)!=-1){ alert("请不要输入非法字符");myform.num<%=i%>.focus();return;} if(myform.num<%=i%>.value==""){ alert("请输入修改的数量");myform.num<%=i%>.focus();return;} myform.submit(); }--> </script> <%}%> </table> </form>
    作为一个合格的购物系统,用户在购买时可能需要买多个同样的商品,这时我们可以在购买时对数量进行修改或是在购物车中进行修改。
    5.1.4 查看订单用户只需进入会员页面,点击“查看订单”便可跟踪所有的交易单信息。
    5.1.5 交易记录在首页中点击“成交记录”便可查看。
    5.1.6 商城资讯在首页中点击“商城资讯”便可查看。
    5.2 后台通过 http://localhost:8080/foodemarket/login.jsp ,进入如下图5.2 所示的后台登录界面:

    在“用户名”和“密码”的文本框中输入用户名:admin,密码:123,点击“提交信息”,即可跳转到后台维护界面。在商城管理界面拥交易信息、网站信息、基础信息、系统管理和个人信息五大板块。
    以下为后台管理页面,如图5.3所示:

    5.2.1 交易信息点击“进行中的订单”,界面中将会出现实时的交易情况,在这里你可以完成对商品的监控。
    5.2.2 网站信息点击“商城介绍”、“商城资讯”、“广告图片”、“联系我们”、“商城公告”、“留言板”和“友情链接”可以对首页中这些模块信息进行修改。
    5.2.3 基础信息这里可以对买家,买家用户进行信息的管理,点击“商品管理”还可以对商城内所有正在销售的物品进行和卖家一样的操作,这里还有对商品评价和属性的管理。
    5.2.4 系统管理这里可以对管理员信息和成员的维护,点击“添加管理员”即可在出现的界面中填写信息加入新的管理员。而点击“管理员维护”则可看到现在商城内已存在的管理员信息。
    5.2.5 个人信息这里可以点击“基本资料管理”对当前的账号进行除了ID以外信息的修改,而点击“修改登陆密码”则可以更改当前账号的密码。
    5.2.6 退出后台点击右上角的“退出系统”,将会跳转到网上零食销售系统的首页。
    经过多次的测试和优化,本系统将所有模块的内容全部完成与数据库的交互,小到一个数字,大到一个图片内容完成了整个系统的整合。如果说现在的淘宝,京东等大型电子商场是一个已经羽翼丰满的老鹰,那我这个系统就是一个刚破壳而出的雏鹰,只要肯花时间去完善对其进行内容和功能上的扩展,便可缩短与它们之间的差距,成为更为可靠的购物平台。
    参考文献[1] 魏松.基于UML的学生信息管理系统的设计与实现[D].南京:南京理工大学,2010.
    [2] 云舟工作室编著.精通ASP3.0网络编程.人民邮电出版社.2001
    [3] 曹建主编.Dreamweaver与ASP实战演练.电子工业出版社.2001
    [4] Time创作室编著.office2000系列丛书Access2000.人民邮电出版社.1999
    [5] 武晓军、陈海滨编著.Javascript/VBScript网页编程实例解析.清华大学出版社.2001
    [6] [美]Greg Buczek著,王小娟、陈代川译.Access2002数据库开发即时应用.人民邮电出版社.2002
    [7] 林金霖.ASP实务经典.中国铁道出版社.2000
    [8] 使用MD5加密数据库中的用户密码 .http://www.ccw.com.cn
    [9] 刘禾,蔡锋. 精通ASP架站技巧[M]. 北京:中国青年出版社,2002.
    [10] 张海藩. 软件工程[M]. 北京:人民邮电出版社,2002.
    [11] Alberto Manuel Ricart.Active server pages 3 exploitation enchiridion[M]. 北京:电子工业出版社,2003.
    [12] Eric A.Smith Active server pages[M]. 北京:电子工业出版社,2003.
    [13] Dave Mercer.ASP 3.0 programme[M]. 北京:人民邮电出版社,2003.
    [14] 张建章. 浅谈ASP开发WEB数据库应用技术. 计算机应用系统[J],1998,9.
    [15] 龚玉清.网页设计的色彩运用. 现代教育技术[J],2003,5.
    [16] 段永红,李春海. 基于JSP的网站建设. 电脑开发与应用[J],2000,8.
    [17] 裴树军,张仁伟. 基于JSP的动态WEB技术设计. 哈尔滨理工大学学报
    [18] 杨青. JSP的主要技术特点分析. 电脑与信息技术[J],1999,4.
    [19] 曹淑琴. JSP技术的网站建设.华北科技学院学报[J],2003,1.
    [20] 吴玉新. JSP后台解决方案[M]. 北京:人民邮电出版社,2003.
    [21] 黄明,粱旭. JSP信息系统设计与开发实例[M]. 北京:机械工业出版社,2003.
    4 评论 140 下载 2020-08-03 19:00:52 下载需要13点积分
  • 基于SSM的网上购物系统的设计与开发

    摘 要本论文主要对网上购物商城的设计与开发进行了一些论述,包括了系统的设计和实现一共两个大部分,设计部分主要对系统和数据库的分析与设计进行了描述;实现部分主要包括系统的各个功能的实现。
    网上购物商城包括两大模块:前台用户模块和后台管理员模块,前台用户可以通过浏览器客户端页面进行登陆和一系列的购物操作。后台管理员可以查看所有用户的所有信息;可以对网站中所有的商品分类进行修改,同时也可以对所有用户的订单状态进行查看。
    系统前台通过JSP页面来来展示数据,后台基于java技术和eclipse (朱诺)和tomcat 7.x开发,前台运用html+css技术渲染页面,后台使用springmvc、spring、myBatis对数据进行封装和操作,该系统运用MySql 5.X 数据库进行数据的维护。页面美观,使用方便。
    关键词:MySql数据库; JAVA; SSM;网上购物商城
    AbstractThis paper mainly focuses on the clothing sales system design and development of a number of paper, including the system design and implementation of a total of two parts, part of the system design and database analysis and design were described; the realization part includes the various functions of the system.
    Clothing sales system includes two modules: front user module and the background administrator module, the front desk users can browse through the browser client page and a series of shopping operations. The background administrator can view all the information of all users can be on the site of all the clothing category to modify, but also for all users to view the order status.
    In front of the system through the JSP page to display the background data, Java technology and based on eclipse (Zhu Nuo) and Tomcat 7.x development, the use of html+css technology to render the page, the background using springmvc, spring, myBatis package and operation of data, the system uses MySql 5.X database for data maintenance. Beautiful page, easy to use.
    Keywords: MYSQL DB;JAVA;SSM;CLOTHING SALES SYSTEM
    1 绪论1.1 研究背景在如今这个信息时代,“网上购物”这种购物方式已经为越来越多的人所接受。在这种背景之下,一个安全稳定并且强大的网络购物平台不可或缺,在这种成熟的市场需求的推动下,在先进的信息技术的支持下,商品产品销售系统应运而生。它可以使消费者和商家更紧密地联系起来,以更快地满足顾客的需求,也可以让用户选择自己真正喜欢的商品。目前市面上已经有此类的网上购物商城,但是现有商品网站系统或多或少存在着功能比较单一、维护比较复杂、操作比较繁琐等问题。有的系统甚至直接采用静态网页发布商品商品信息,这些因素在一定程度上限制了网上购物商城在目前市场上的推广。如何开发出费用低廉、功能强大的系统正是我们需要解决的课题。
    1.2 目的和意义本软件旨在降低商品销售商家的工作强度,提高工作效率,大大地减少了操作员手工录入数据的工作量,极大限度的避免了人力浪费,有效避免重复操作时间消耗;而且此软件方便了用户对自己所需商品的查询和购买,打破了传统的销售模式,极大限度的方便了用户。商家应用此软件之后,可以拓展销售门路,增加销售业绩。应用此软件是为了在传统销售模式之外,再开辟一条销售通路,减少库存堆积,利用网络共享和互动的优点,结合地面销售的优点,借助数据库管理技术,开发此平台,是为了实现规范化、个性化、人性化的商品网上销售。此软件的数据统计分析功能灵活完善,稳定安全、使用方便、界面友好、操作简单,可以成为一个能真正帮助商品销售行业管理发展的有力工具。
    1.3 开发工具及技术该网上购物商城前端使用了jsp来实现数据的展示,后端通过java代码来对数据进行一系列的操作,前端使用了原生的html页面技术进行渲染,同时也加入了jquery技术制作了一下控件效果,后端使用了经典的spring技术对整个系统进行统一调度,使用springMvc框架实现了前端和后端的交互。开发工具使用了Eclipse以及tomcat服务器,同时使用了Mysql数据库对数据进行存储和维护。
    在该系统实现的过程中,使用spring和springMvc的同时后端还使用了MyBatis技术对数据进行封装和操作。前端还采用了dtree框架规范了页面的显示。整个系统的架构也是基于经典的mvc设计模式来设计的。
    Mybatis是一个经典的后端开源框架,它的前身就是iBatis,MyBatis的执行原理是应用程序根据XML配置文件创建出SqlSessionFactory,然后SqlSessionFactory根据配置文件或者注解创建出SqlSession,SqlSession这个对象包含了所有的执行sql所需要的所有方法,可以通过SqlSession这个实例执行所有的方法对数据库进行操作,操作结束后执行相应的事物控制,本系统中的事物控制全部交由spring容器进行统一调度,本次采用的是spring的申明式 方式。MyBatis相对于 其他的ORM框架具有很多的优点,比如mybatis本身属于轻量级框架简单易学,没有第三方的依赖。mybatis比较灵活,开发人员可以自己编写sql语句来对数据进行操作。mybatis提供了xml标签,支持编写动态sql.
    dtree框架就是一个简单的树形菜单js组件,开源免费,自身不需要复杂的操作,同时也支持动态的将数据引入jsp页面。
    MVC模式是一种软件架构模式。它将系统分为三个部分:模型,视图和控制器。MVC模式出现的目的就是方便了后续程序的修改和扩展简化,同时使系统中某一段代码的重复利用成为可能。此模式降低了模块之间的耦合度,对自身各个部分进行了分离的同时也使得各个部分具备了应有的功能。
    Spring是从实际开发中抽取出来的开源框架,为企业的开发提供一个轻量级的解决方案。该解决方案包括:基于Ioc(控制反转)的核心机制,以及AOP(面向切面编程)的思想,能与多种持久层技术的整合,是优秀的Web MVC框架等。Spring致力于Java EE应用各层的解决方案而不是仅仅专注于某一层的方案,它贯穿表现层、业务层、持久层,降低各层组件的耦合度,实现软件各层的解耦.Spring内部最核心的就是IOC了,动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射,反射其实就是在运行时动态的去创建、调用对象,Spring就是在运行时,跟xml Spring的配置文件来动态的创建对象,和调用对象里的方法的。还有一个核心就是AOP这个就是面向切面编程,可以为某一类对象 进行监督和控制(也就是 在调用这类对象的具体方法的前后去调用你指定的 模块)从而达到对一个模块扩充的功能。这些都是通过配置类达到的。Spring是一个容器,凡是在容器里的对象才会有Spring所提供的这些服务和功能。
    2 需求分析2.1 功能需求分析2.1.1 网站前台功能
    首页:提供一个网站首页,显示该企业的商标,该网站用户的登录,注册,所有商品的一级分类,热门商品和最新商品的展示等
    用户的注册:针对还未注册的用户完成注册功能的使用,在注册的过程中涉及数据的合法性校验,以及利用ajax完成用户名是否已被注册的异步校验
    用户的登录:对于已经注册并且激活的用户提供的登录操作
    用户的退出:对于已经登录的用户,退出系统
    首页商品展示:展示出最新商品和热门商品
    分类页面商品展示:根据一级分类和二级分类去展示该分类下的所有商品
    商品详情展示:点击某个商品时可以展示该商品的具体详细信息
    购物车:用于存放用户的购物内容,用户可根据自己的情况修改自己的购物车
    订单:对于已经登录的用户可以对购物车内容进行付款生成订单,可以为自己的订单进行付款或者查看
    留言评价分享:网站单独开辟了留言分享区域,供登录的用户自由发表评价分享心得信息,进行交流互动

    2.1.2 网站后台功能
    管理员登录:管理者根据账户和密码进行登录
    商品一级、二级分类管理:管理者可以对前台显示的一级、二级分类进行管理,包括添加、删除、修改操作
    商品管理:管理者可以对前台显示的商品进行管理包括添加,修改,删除,查询的功能,也可以上传商品的图片
    用户管理:管理者可以查看该网站中已经注册过的所有用户的所有信息

    2.2 性能分析响应时间:忽略网络、硬件以及插件的因素,以本地测试为准,前台响应时间为0.8秒,后台操作响应时间:0.9秒。
    2.3 系统用户用例图用户用例图
    用户为系统的使用者,可以通过前台注册激活登录后进行一系列的购物操作。

    管理员用例图
    管理员是整个系统的最高权限拥有者,他用于对所有用户的所有信息的查看,网站商品显示的增删改查,更换图片,所有商品所属一级二级分类的修改。

    3 系统设计3.1 系统的总体设计该系统的开发采用B/S模式,整个系统的构建基于ssm(Spring+SpringMvc+MyBatis)整合框架。
    深入研究JavaEE体系结构,所项目的技术选型中选取的个个框架分别进行分析和研究。SpringMvc是一个web端框架。Mybatis是一个轻量级的持久层框架,以面向对象的方式提供了持久化类到数据库之间的映射,是一种优秀的ORM框架。Spring也是一种轻量级框架,它的IOC和AOP思想,值得架构师学习。通过三大框架的整合,可以很方便的构建出可扩展,可移植,可维护的软件系统。
    SSM框架是目前J2EE领域中最热门而且用的比较成熟的一套开源框架,它是基于MVC设计模式之上,充分发挥了MVC的优点。SSM是一套轻量级框架,相对于EJB而言,SSM继承了它的优点的同时,在开发和执行效率上也有了明显的提高,而对于开发者而言,它比EJB更加易学和掌握。目前SSM框架也正在不断地进行优化和维护,运行也是越来越稳定。
    根据以上功能分析,得到系统功能模块结构图如图3-1所示:

    3.2 数据库的分析与设计数据库,我们可以形象的将它称为一个仓库,因为它一般被用来存放汉字、字符、数据、货币、日期等信息,并且对这些信息按照一定规则存放,对数据进行安全、低冗余性、规范的进行集成化管理。从发展的历史历程来看,数据库可以看成是由文件管理系统发展而来的。
    数据库的基本结构可以分为三个层次包括物理数据层、概念数据层、逻辑数据层。数据库不同层次之间的联系是通过映射进行转换的,数据库的特点包括实现数据共享、减少数据的冗余度、数据的独立性、数据实现集中控制、数据一致性和可维护性。
    本系统采用的的数据库是Mysql5.0,本系统所有与数据库相关的开发都遵循Mysql5.0数据库开发原则。
    3.2.1 数据库概念设计用户实体
    用户实体包括编号、用户账号、姓名、联系方式、性别、用户状态、用户邮箱和密码等属性。用户实体的实体联系图(E-R图)如下所示:

    管理员实体
    管理员实体包括编号、账号和登录密码属性。管理员实体的实体联系图(E-R图)如下所示:

    商品实体
    商品实体包括商品id、商品名称、市场价、商场价、商品图片、商品描述、上架日期、所属二级分类id。商品实体的实体联系图(E-R图)如下所示:

    订单实体
    订单实体主要包括订单id、订单总价、订单状态、收货人、收货地址、收货电话、下单时间、购买者id、购买商品id。订单实体的实体联系图(E-R图)如下所示:

    3.2.2 数据库物理结构为该系统设计了7张表,在这里列出7张表分别为如下所示:



    数据表
    描述




    adminuser
    后台管理员表


    category
    一级分类表


    categorysecond
    二级分类表


    orderitem
    订单项表


    orders
    订单表


    product
    商品表


    user
    前台用户表



    管理员表主要记录了管理员的基本消息,表结构如表3-1所示。



    字段
    数据类型
    允许空值(默认NO)
    自动递增
    备注




    id
    int(11)
    YES
    YES
    账号


    username
    varchar(1000)
    NO
    NO
    用户名


    password
    varchar(1000)
    NO
    NO
    密码



    一级分类表主要记录了一级分类的基本信息,表结构如图3-2所示。



    字段
    数据类型
    允许空值(默认NO)
    自动递增
    备注




    cid
    int(11)
    YES
    YES
    一级分类ID


    cname
    varchar(1000)
    NO
    NO
    一级分类名



    二级分类表主要记录了二级分类的基本信息,表结构如图3-3所示。



    字段
    数据类型
    允许空值(默认NO)
    自动递增
    备注




    Csid
    int(11)
    YES
    YES
    二级分类id


    Csname
    varchar(1000)

    NO
    二级分类名称


    cid
    varchar(1000)

    NO
    所属一级分类id



    订单项表主要记录了订单项的基本信息,表结构如图3-4所示。



    字段
    数据类型
    允许空值(默认NO)
    自动递增
    备注




    Oiid
    int(11)
    YES
    YES
    订单项id


    count
    varchar(1000)


    购买数量


    subtotal
    double


    单项总价id


    Pid
    int(11)


    所购商品id


    cid
    int(11)


    所属订单id



    订单表主要记录了订单的基本信息,表结构如图3-5所示。



    字段
    数据类型
    允许空值(默认NO)
    自动递增
    备注




    oid
    int(11)
    YES
    YES
    订单id


    money
    double


    订单总价


    state
    Int(11)


    订单状态


    Receiveinfo
    Varchar(255)


    收货地址


    phonum
    Varchar(255)


    收货人电话


    Order_time
    datetime


    下单时间


    Uid
    Int(11)


    所属用户id



    商品表主要记录了商品的基本信息,表结构如图3-6所示。



    字段
    数据类型
    允许空值(默认NO)
    自动递增
    备注




    Pid
    int(11)
    YES
    YES
    商品id


    Pname
    Varchar(255)


    商品名称


    Market_price
    Int(11)


    市场价


    Shop_price
    Varchar(255)


    商城价


    image
    Varchar(255)


    商品图片


    Pdesc
    Varchar(255)


    商品描述


    Is_hot
    int(11)


    是否热门


    Pdate
    datetime


    商品上架日期


    csid
    int(11)


    所属二级分类id



    前台用户表主要记录了前台用户的基本信息,表结构如图3-7所示。



    字段
    数据类型
    允许空值(默认NO)
    自动递增
    备注




    Uid
    int(11)
    YES
    YES
    用户id


    Username
    Varchar(255)


    用户名


    password
    Varchar(255)


    用户密码


    Name
    Varchar(255)


    用户真实姓名


    Email
    Varchar(255)


    用户游戏


    Phone
    Varchar(255)


    用户手机号


    Addr
    Varchar(255)


    用户地址


    State
    int(11)


    用户状态



    3.3 小结本章主要是对数据库进行了设计和说明。对数据库的概念设计思路和物理结构进行了详细的说明,并对数据库中涉及到的实体进行了说明。
    4 系统主要功能实现4.1 系统注册页面实现4.1.1 客户端用户注册用户登录网站出现页面,点击“注册”,进入注册页面,填写数据,点击注册按钮进行注册,注册完之后保存数据库表中,即可登录网站。
    注册效果如图4-1所示:

    var username = document.getElementById("username").value;var xmlHttp = creatXMLHttpreauest();xmlHttp.open("GET","${pageContext.request.contextPath}/registFindByid.action?username="+ username, true); xmlHttp.send(null); xmlHttp.onreadystatechange = function() { if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { document.getElementById("span1").innerHTML = xmlHttp.responseText;
    服务器端二次数据合法性校验(此处采用的配置文件加注解的方式)
    user.username.length.error=用户名的名字的长度必须是1至30user.email.notNull=邮箱不可为空@Size(min=2,max=30,message="{user.username.length.error}") private String username; @NotNull(message="{user.email.notNull}") private String email;
    4.2 系统登录页面实现4.2.1 用户登录用户在注册后,在客户端登录页面输入正确的用户名和密码,进入网站进行购物。 程序运行如下图4-2所示:

    设计思路
    编写用户登录的页面login.jsp,用户在首页点击“登录”按钮后,浏览器跳转到登录页面,用户可以填写用户名和密码进行登录,当用户填写用户名并使光标移开 时,触发onblur()事件,进行ajax异步请求,判断用户名是否可以登录,用户在填写验证码时可以点击图片,进行跟换验证码,触发onclick=”change()” 事件进行更换,当用户点击“登录”按钮时,服务器进行数据判断,如果用户名和密码都正确则跳转到首页并显示该用户的用户名,如果有错误则跳转到msg.jsp全局页面显示错误消息。
    4.2.2 管理员用户登录后台管理员通过访问正确的路径之后进入到管理员登录页面,如果访问的不是正确页面但出现了admin路径则自动跳转到admin页面,然后输入正确的用户名和密码进行登录,如果出错,服务器会将错误信息回显到登录页面,如果正确则跳转到管理员页面。
    程序运行结果如图所示,图4-3显示了管理员登录的页面,图4-4则是管理员登录成功后的主页面:


    4.3 系统前台功能实现系统前台页面包括以下几个部分:首页一级分类,热门商品,最新商品的显示,二级分类的显示,已登录用户的订单以及用户所操作过的购物的展示,其中一级分类和二级分类在各个页面中都有所设计,因此这里采用的是页面包含技术。
    4.3.1 一级分类模块查询一级分类描述
    本系统中首页显示的一级分类都是存放于数据库中,当用户访问该网站首页的同时就查询了一级分类。一级分类显示效果如图4-5所示:

    设计思路
    一级分类展示于系统的首页,当用户访问index.action时,最终跳转至系统首页即index.jsp,跳转之前,服务器内部已经进行了一级分类的查询,并将已经查询到的以及分类存放于List集合中,最终存放于session域中。
    查询某个一级分类描述
    用户在进入系统首页时,当点击一级分类时就要求查询系统在下一个页面中显示出该一级分类中包含的所有二级分类。查询某个二级分类的效果图如图4-6所示:

    设计思路
    当用户点击首页中的一级分类时系统则根据此一级分类的id查询出该一级分类下所有的二级分类,并存放于session域中,将页面进行跳转,并进行展示。
    主要代码
    request.getSession().setAttribute("cid",cid);PageBean<Product> proPageBean = productService.findProductyBycid(cid,page);model.addAttribute("pageBean",proPageBean);return "category";
    4.3.2 商品模块查询最热商品描述
    当用户访问该网站时,首先显示的是网站的首页,首页中将显示本网站中最热的商品。程序运行结果如图4-7所示:

    设计思路
    用户访问首页index时,根据路劲“/index.action”首先调用的是系统的index.action,最后跳转至系统的首页index.jsp,因为最热商品显示于首页中,因此在页面跳转之前必须前往数据库查询出本系统中所有的热门商品,因此使用了findHotProduct()这个方法,由于首页中仅仅显示了最新商品中的前十个,因此这里是使用的分页查询,最终查询的结果是一个list集合,最终保存在Model中。
    前段控制层代码
    List<Product> hList= productService.findHotProduct();
    service层代码
    List<Product> list = productMapper.selectByExample(example);
    查询最新商品描述
    当用户访问该网站时,首先显示的是网站的首页,首页中将显示本网站中最新的商品。程序运行结果如图4-8所示:

    设计思路
    用户访问首页index时,根据路劲“/index.action”首先调用的是系统的index.action,最后跳转至系统的首页index.jsp,因为最新商品和最热商品一样都是显示于首页中,因此在页面跳转之前必须前往数据库查询出本系统中所有的最新商品,因此使用了findNewProduct()这个方法,查询最新商品的依据是商品被上传的时间,根据时间来进行排序,由于首页中仅仅显示了最新商品中的前十个,因此这里是使用的分页查询,最终查询的结果是一个list集合,最终保存在Model中。
    前端控制层代码
    List<Product> nList =productService.findNewProduct();
    service层代码
    ProductExample example = new ProductExample();ProductExample.Criteria criteria = example.createCriteria();example.setOrderByClause("pdate DESC");example.setBeginPage(0);example.setEnd(10);
    查询分类商品描述
    用户在点击首页的一级分类时,系统自动跳转页面,同时要求在右面显示某个二级分类下的商品。程序运行结果如图4-9所示:

    设计思路
    首先导入页面,页面和查询二级分类下的商品使用的是同一个页面category.jsp。当用户点击按钮时,客户端向服务器请求发送请求并携带一级分类的主键id,因此服务器端应该接受参数并使用这个参数来调用方法然后去数据库进行查询数据,最后将查询出的数据把保存于Model中,最后跳转页面。
    由于页面大小的关系,这里仅仅显示12个商品,因此这里采用了分页查询,并在右下角设置相应的按钮,方便用户来回查看该分类下所有的商品。
    前端控制层接收参数并调用service层代码
    //根据一级目录查找二级目录下面的商品productService.findProductyBycid(cid,page);model.addAttribute("pageBean",proPageBean);
    Servive层代码
    int totlePage = 0;totlePage = productMapper.countProducyByCid(cid);if(Math.ceil(totlePage % limitPage)==0){totlePage=totlePage / limitPage;}else{totlePage=totlePage / limitPage+1;pageBean.setTotlePage(totlePage);int beginPage= (page-1)*limitPage;
    查询二级分类商品用户在点击首页的一级分类时,系统自动跳转页面,并且在页面的左面显示所有一级分类包含的二级分类,同时要求在右面显示某个二级分类下的商品。程序运行结果如图4-10所示。

    设计思路
    首先编写页面category.jsp,这个页面用来显示某个二级分类下的所有的商品,当用户点击二级分类时系统访问对应的action,并且携带参数(相应二级分类的主键id),到前端控制层,然后findCategorySecond1()方法接收主键id和分页的数目去product表查询商品,最终将查询到的结果存放于Model中。由于页面大小的关系,这里仅仅显示12个商品,因此这里采用了分页查询,并在右下角设置相应的按钮,方便用户来回查看该分类下所有的商品。
    前端控制层接收参数并调用service层
    // 根据csid来分页查询商品PageBean<Product> proPageBean = productService.finbProductByCsid(csid,page);model.addAttribute("pageBean",proPageBean);
    查询商品信息用户再浏览该商场,查看某个商品的详细信息。程序运行结果如图4-11所示:

    设计思路
    首先编写页面,这里使用的是product.jsp,在这个页面中显示了以及分类的信息,还有每个一级分类下的二级分类,右下方是某个商品的具体信息,其中包括商品的名称,商品的商城价和市场价,包括一个选择框,用于用户选择购买数量,最下面则是商品的具体介绍。当用户点击某个想要查看的商品图片时,其实就是点击了某个超链接,向服务器发送链接并携带参数(商品的主键id),服务器端接收这个参数,并使用这个参数去数据库中查看这个商品的具体信息最后封装于product中,最终存放于Model中。
    前端控制层接收参数并调用service层,Service层直接调用Mybatis提供的mapper接口
    //根据pid来查询商品Product product = prodcutService.productFindByPid(pid);model.addAttribute("product", product);
    4.3.3购物模块添加到购物车对于已经登录的用户,可以将看中的商品具体信息保存于自己的购物车中。

    设计思路
    首先编写cart.jsp用于显示登录用户的购物车,如果用户没有登录会有提示,用点击查看商品的详情之后会出现一个“加入购物车”按钮,当点击此按钮时,自动访问服务器,并通过隐藏表单携带参数(商品的主键id),服务器端在接受此参数,并接收用户选购的数量,最终保存于我们为每个用户在session域中创建的cart。最后进行页面跳转,在cart.jsp中展示购物车的信息,主要包括:商品的具体信息和每项的价格和购物车的总价。对于已登录用户的页面,可以看到一个购物车的图标,用户可以查看自己的购物车。
    主要代码
    //添加到购物车Product product = productService.finbProductByPid(pid);//存进一个购物项CartItem cartItem = new CartItem();cartItem.setCount(count);cartItem.setProduct(product);cartItem.setSubtotle(count*product.getShopPrice());//存进购物车Cart cart=getCart(request);cart.addCart(cartItem);
    从购物车中移除商品用户点击购物车页面中每个购物项后面的删除按钮即可删除该购物项。程序运行结果如图4-13所示:

    设计思路
    当用户点击 “删除”按钮时,向服务器端进行请求,并携带参数(商品的主键id),服务器端在设计购物车时采用的是用Map集合存储的,key值即商品的id,因此删除的时候只需从session中拿到购物车直接根据主键删除,最后将页面重定向到cart.jsp.
    主要代码
    Cart cart=getCart(request);cart.delProFromCart(pid); //删除某个购物项
    清空购物车用户点击“清空购物车”按钮,购物车里面的购物项全部删除。程序运行结果如图4-17所示:

    设计思路
    当用户点击 “清空购物车”按钮时,向服务器端进行请求,服务器端收到请求之后,从session域中取出cart购物车,由于cart在设计的时候使用的是Map集合,所以只需调用Map中的clear()方法即可,并且还需将购物车的总价改为0,最后将页面重定向到cart.jsp.
    主要代码
    // 清空购物车Cart cart=getCart(request);cart.clearCart();
    4.3.4 订单模块生成订单当用户点击“生成订单”按钮时,页面跳转至order.jsp,并让用户填写相关信息。程序运行结果如图4-15所示:

    设计思路
    首先编写order.jsp页面,其中包含用户的购物信息和收货地址、收货人和联系方式。当用户点击cart.jsp中的生成订单按钮时,向服务器发送请求,服务器端从session域中拿到cart中的信息,并将这些信息保存于order表中,此时,需要清空购物车并且将订单信息保存到session域中,最后跳转到order.jsp页面让用户填写相关信息,并付款。
    主要代码
    Orders orders = new Orders();Cart cart = (Cart) request.getSession().getAttribute("cart");User loginUser = (User) request.getSession().getAttribute("loginUser");if(loginUser==null){ model.addAttribute("message", "对不起您还没有登录"); return "msg";}//生成订单
    我的订单用户对自己的选购的商品所生成的订单项进行付款。即可生成订单,进入我的订单列表界面;程序运行结果如图4-16所示:

    设计思路
    为订单付款页面还是使用的是order.jsp,当用户点击cart.jsp中的提交按钮时,页面进行跳转并显示相关的订单信息,此时,用户可以暂时不对订单进行付款,此时订单的状态为0。如果用户在生成订单的同时一并付款,或者点击用户的最上方右边的红色字体“我的订单”时,页面会进行跳转,并显示该用户的所有订单和订单的状态,此时想要付款则点击按钮“付款”,也会跳转到order.jsp,此时需要用户填写订单的具体信息,包括收货地址、收货人、联系方式以及付款的银行,此时客户端和服务器端一样会进行非空和数据合法性校验,当用户填写好信息并点击“付款”按钮时,其实就是服务器端拿订单的具体信息,并将订单的状态改为“1”,同时将用户填写的关于收货的信息保存于数据库order表中,最终服务器端会将页面重定向到orderList.jsp,向用户展示他的所有的订单以及订单的具体信息。在orderList.jsp中展示该用户的所有订单时采用的是分页查询,在订单的右下角同时也设置了按钮,方便用户查看自己的所有按钮。
    4.3.5 留言模块留言板当用户点击“留言板”按钮时,页面跳转至messageList.jsp,并让用户填写相关信息。程序运行结果如下图所示:

    4.4 系统后台功能实现4.4.1 用户模块查询用户管理员进入后台管理页面之后,当他点击“用户管理”按钮时,则在主页面中显示所有用户的详细信息。程序运行结果如图4-17所示:

    设计思路
    先编辑list.jsp页面,当用户点击“用户管理”按钮时,服务器端收到请求,调用service层的admin_findAll()方法由service 层调用myBatis提供的mapper接口,返回一个list集合,最终所有信息封装于Model中将页面跳转到list.jsp并进行展示。
    主要代码
    if(adminuserLogin==null){ request.getSession().setAttribute("message","对不起您还没有登录"); return "admin/index";
    4.4.2 一级分类模块添加一级分类此功能属于管理员的权限范围内,用户管理员为网站添加新的一级商品系别。程序运行结果如图4-18所示:

    设计思路
    首先编写add.jsp页面,当用户在一级分类list.jsp页面点击“添加”按钮时, 服务器将页面跳转至add.jsp,在此页面共有三个按钮,“确定”按钮用于提交信息,“重置”按钮清空表单中的内容,“返回”按钮返回前一个页面。当用户填写好要添加的一级分类的名称之后点击“确定”按钮,服务器端接收此表单中的内容,然后调用service层的addCategory()方法,将新增的一级分类保存到数据库category表中,最后将页面重定向到list.jsp页面,展示所有的一级分类。
    主要代码
    Category addCategory = new Category();addCategory.setCname(cname);categoryService.addCategory(addCategory);
    修改一级分类此功能属于管理员的权限范围内,管理员用户修改网站中各大服饰的一级分类的名称。程序运行结果如图4-19所示:

    设计思路
    首先编写edit.jsp页面,当用户在一级分类list.jsp页面点击“添加”按钮时, 服务器将页面跳转至edit.jsp,在此页面共有三个按钮,“确定”按钮用于提交信息,“重置”按钮清空表单中的内容,“返回”按钮返回前一个页面。当用户填写好要修改的一级分类的名称之后点击“确定”按钮,服务器端接收此表单中的内容,然后调用service层的adminCategory_update()方法,将修改的一级分类更新到数据库category表中,最后将页面重定向到list.jsp页面,展示所有的一级分类。
    删除一级分类后台管理员点击每个一级分类后面的删除按钮即可删除该一级分类。程序运行结果如图4-20所示:

    设计思路
    当用户点击每个一级分类后面的“删除”按钮时,服务器接收到请求然后接收携带过来的参数(一级分类主键id),当我们准备删除一级分类时,如果删除了改一级分类那么相应的二级分类和二级分类下的商品就得全部删除,因此我们根据myBatis的规则。先根据外键删除二级分类然后再删除一级分类,因此首先调用adminCategorySecond_deleteByCid(cid)删除二级分类然后再调用categoryService.deleteCategoryByCid(cid);删除一级分类,最终将页面重定向到list.jsp页面。
    主要代码
    categorySecondService.adminCategorySecond_deleteByCid(cid); categoryService.deleteCategoryByCid(cid);
    查询一级分类管理员点击“一级分类管理”按钮时,展示所有的一级分类的详细信息。程序运行结果如图4-21所示:

    设计思路
    首先编写list.jsp页面,当管理员用户点击“一级分类管理页面”按钮时,服务器端接收请求然后调用adminbFindCategory()方法最终由service层调用myBatis提供的Mapper接口将所有的一级分类的信息查询出来保存到list集合中,最终保存到Model中并将信息进行展示。考虑到一级分类比较多,这里使用了分页查询,在页面展示的效果就是每页显示固定的个数,并在右下角提供了相应的按钮方便用户进行查看其他的一级分类。
    主要代码
    List<Category> categoryList = categoryService.adminbFindCategory();model.addAttribute("categoryList", categoryList);
    4.4.3 二级分类模块添加二级分类管理员用户为新增加的一级分类添加二级分类。程序运行结果如图4-22所示:

    设计思路
    首先编写二级分类添加页面add.jsp,管理员用户点击“添加”按钮时,页面跳转到add.jsp,同时服务器端将查询出所有的一级分类的名称,用于管理员选择新增的二级分类的归属,这在add.jsp页面中通过一个下拉列表进行显示。管理员用户在填写好新增的二级分类的名称并选择好所属的一级分类之后点击“确定”按钮,服务器端接收新增的二级分类名称和所属的一级分类的主键id,然后调用adminCategorySecond_save()方法将新增的Categorysecond保存于数据库的categorysecond表中。最后将页面重定向到二级分类的list.jsp页面进行展示。
    主要代码
    Categorysecond categorysecond = new Categorysecond();categorysecond.setCsname(csname);categorysecond.setCid(cid);categorySecondService.adminCategorySecond_save(categorysecond);
    修改二级分类管理员用户可以为网站中所有的二级分类的名称进行编辑。程序运行结果如图4-23所示:

    设计思路
    首先编写二级分类修改页面edit.jsp,管理员在list.jsp点击“编辑”按钮时,页面跳转到edit.jsp页面,跳转之前,服务器端查询到对应的二级分类的名称并将二级分类的名称保存到edit.jsp对应的表单中,这样方便用户知道自己修改的是哪个二级分,增加了用户体验度
    查询出对应的二级分类的名称存放于表单中,增加了用户体验
    Categorysecond findByCsid = categorySecondService.findByCsid(csid);model.addAttribute("findByCsid", findByCsid);
    更新修改的二级分类
    Categorysecond categorysecond = new Categorysecond();categorysecond.setCsname(csname);categorysecond.setCsid(csid);CategorySecondService.adminCategorySecond_update(categorysecond);
    删除二级分类后台管理员根据查询出的二级分类列表对二级分类进行操作,根据系统的要求,管理员用户在删除二级分类的同时应该删除该二级分类下的所有商品。
    设计思路
    管理员用户在点击“二级分类用户”按钮时,在管理员页面展示所有的二级分类,当用户点击“删除”按钮时,服务器端收到客户端发来的请求,并接受客户端传来的数据(二级分类的主键id),然后根据二级分类的主键id调用adminCategorySecond_delete(csid)方法,删除二级分类,然后根据外键删除商品。最后将页面重定向到二级分类的list.jsp页面。
    主要代码
    // 删除二级分类,二级分类关联二级分类下面的商品categorySecondService.adminCategorySecond_delete(csid);categorySecondService.adminProduct_deleteByCsid(csid);
    查询二级分类管理员通过点击“二级分类管理”来查看网站中所有的二级分类。程序运行结果如图4-24所示:

    设计思路
    首先得编写二级分类的list.jsp页面。管理员用户点击“二级分类管理”按钮时,给服务器发送请求,并携带分页参数,服务器端接收此参数之后开始查询所有的二级分类,这里创建了一个pageBean对象用于封装查询出来的数据,包括二级分类的集合,当前的页数,一共的页数等信息,最后直接返回一个pageBean对象,因为二级分类较多,这里采用了分页查询,需要用到这些数据因此直接封装在了pageBean对象里。用户可以通过二级分类的list.jsp页面右下方的按钮来查看所有的二级分类。
    4.4.4 商品分类模块添加商品管理用户通过点击商品展示页面list.jsp上的“添加”按钮可给网站添加新的商品。程序运行结果如图4-25所示:

    设计思路
    首先编写商品添加页面add.jsp。管理员用户点击商品展示页面list.jsp上的“添加”按钮之后客服端跳转到add.jsp页面,在客户端页面跳转之前,服务器端需要查询出所有商品的二级分类,方便上传用户选择该商品所属的二级分类。管理员需要填写页面上的信息包括商品名称、选择是否热门、市场价格、商城价格、上传商品图片、选择所属二级分类和编写商品描述这些信息。管理员用户点击“确定”按钮之后客户端将数据提交给服务器,客户端在上传上传组件时必须将上传组件表单type设置为file类型,这样服务器端才能正确的识别。最后服务器端接收到数据之后封装于product对象中,并调用adminProduct_save(product);将新上传的product保存到数据库中的product表中,最后将页面重定向到商品的list.jsp页面。
    主要代码
    product.setPdate(new Date());if (file != null) { String path = request.getServletContext().getRealPath("/products"); String uploadFileName = file.getOriginalFilename(); String fileName = UUIDUtiils.getUUID()+uploadFileName; File diskFile = new File(path + "//" + fileName); product.setImage("products/" + fileName);
    删除商品管理员用户点击“商品管理”来到展示所有商品页面,通过点击页面上的删除按钮即可删除指定的商品。
    设计思路
    这个功能是基于商品的展示页面list.jsp进行开发的,展示用户页面时pageBean里面封装了product的所有信息,当用户在点击“删除”按钮时即向服务器发送请求并携带参数(商品的主键id),服务端在接收到请求之后,根据客户端传来的参数进行删除该商品,最终将页面重定向到商品的展示页面list.jsp.
    jsp页面方法主要代码
    function deletecs(pid) { window.location.href = " ${pageContext.request.contextPath}/ admin/adminProduct_deletecs.action?pid="+pid;
    查询商品管理员通过点击“商品管理”按钮来查看本网站中所有的商品信息。程序运行结果如图4-26所示:

    设计思路
    首先编写商品下面的list.jsp页面,管理员用户在点击“商品管理”按钮时,给服务器发送请求,并携带分页参数,服务器端接收此参数之后开始查询所有的商品信息,这里创建了一个pageBean对象用于封装查询出来的数据,包括商品的集合,当前的页数,一共的页数等信息,最后直接返回一个pageBean对象,因为商品个数较多,这里采用了分页查询,需要用到这些数据因此直接封装在了pageBean对象里。用户可以通过商品文件夹里面的list.jsp页面右下方的按钮来查看所有的是商品信息。
    主要代码
    // admin的商品管理(查询所有的商品)PageBean<Product> allProPageBean = productService.findAllProduct(page);model.addAttribute("allProPageBean", allProPageBean);
    4.4.5 留言管理模块管理用户通过点击留言管理链接,即可打开前台顾客的留言列表界面,并且可以删除不合时宜的留言信息。程序运行结果如图4-26所示:

    5 系统测试与维护5.1 系统测试环境5.1.1 硬件环境
    CPU:英特尔酷睿四核
    内存:4G

    5.1.2 软件环境
    操作系统:windows 7
    服务器:Tomcat 7
    浏览器:Mozilla Firefox 和chrome

    5.2 系统测试内容使用eclipse编程软件编写Java源程序是遇到语法错误会自动报错,需要及时修改错误。对系统进行测试视为系统能有效运行并且没有异常产生。
    在程序模块编写时,每编写完一个模块需要进行模块单元测试,保证单元模块功能正常,在所有单元测试进行结束之后,需要进行整个系统的集成测试。本系统需要做如下的测试:

    登录注册测试:多次注册用户并且登录。则表达式检验的文本框输入错误信息,检测代码是否可行,注册成功后,检验用户是否可以正常显示,并查看数据库,检验数据是否成功插入。登录时,交叉使用正确和错误的密码进行登录测试,校验是否有异常
    查询一级分类测试:测试当用户访问index.action时,是否可以至系统首页即index.jsp,测试成功
    查询二级分类测试:测试用户在点击首页的一级分类时,系统是否会自动跳转页面,并且在页面的左面显示所有一级分类包含的二级分类
    购物车测试:测试已登录的用户是否可以将商品添加到购物车、移除购物车内商品、清空购物车
    订单模块测试:测试是否可以正常生成订单、取消订单、为订单付款

    5.3 系统维护系统维护是为了让系统能够在正常运行的基础上,对系统中的一些小问题进行修复并且不断完善的过程,通过系统维护能够使系统保证在不同的运行环境下均可以正常的工作,各个模块功能正常运行。
    由于本系统的本质就是一个电子商城,所以难免会有很多过期的没用的数据。所以需要定期进行“垃圾”信息的删除,对于系统中重要的一些内容如用户和商品等。要定期对数据库备份,保证数据的正确性。本系统的维护就是为了使本系统能够稳定的运行,所以需要定期维护,并且备份数据。
    小结:本章首先介绍了系统的测试环境,接下来详细介绍了单元模块测试的方法和整体集成测试的主要内容,最后介绍了系统维护的方案。
    6 总结如今,JavaEE是一个非常优秀的企业信息化开发平台,由于其拥有一些很好的性质包括稳定的性能、良好的开发性和非常高的安全性因此被广泛运用于企业级开发。这篇论文基于当前比较流行的电商系统为项目背景,遵循javaEE应用软件的规则进行开发,将系统划分为四个层次包括模型model层,持久层,业务逻辑service层和表现层,并整合了目前在企业中广泛运用的spring、springMvc和myBatis框架进行开发。Spring用于整个系统的统一调度,贯穿于各层之间,springMvc框架着重于mvc模式的实现,myBatis框架完成数据的映射和持久化工作,myBatis的逆向工程极大的方便了dao层的开发,也方便了系统dao层的维护。
    本论文主要完成了以下的任务:

    正确分析了电商目前的发展形势,特别是对网购的发展进行了深入的调查和研究
    深入明确了系统的总体架构,在技术选型上选取了三个主流的框架,对三者的功能,整合做了详细的描述
    系统项目的开发严格遵循软件的开发规范,制定了详细的系统开发步骤,开发之前做了大量的工作包括:需求分析、技术选型、架构设计等
    完成了预期赋予系统的功能的实现

    本文虽然完成了预期研究和目标,但后期还有很多工作需要完成:,随着web应用的快速发展,处于信息时代下会有更多的技术应运而生,不光需要对框架进行深入学习和研究还要对系统的架构进行研究。目前客户端技术正在崛起,我们需要认真做调查和研究做出一能让用户体验度更好的产品。以上只是目前的构想,接下来会继续深入研究并作进一步的完善和设计开发。
    7 参考文献[1] 杨开振等. Java EE互联网轻量级框架整合开发— —SSM框架(Spring MVC+Spring+MyBatis)和Redis实现[M]. 电子工业出版,2017.07.
    [2] 李俊民.HTML 5+CSS 3网页设计经典范例[M].电子工业出版,2010.
    [3] 邹红霆. 基于SSM框架的Web系统研究与应用[J]. 湖南理工学院学报(自科版), 2017, 30(1):39-43.
    [4] 王珊 萨师煊 数据库系统概论[M] 北京:高等教育出版社 2007
    [5] 陈雄华 Spring企业级应用开发详解[M] 北京:电子工业出版社 2009
    [6] 原著施奈德 成栋翻译 电子商务[M] 北京:机械工业出版社 2008
    [7] 阿里巴巴网络技术有限公司 中小企业电子商务之路[M] 北京:清华大学出版社 2007
    [8] 刘克强 电子商务平台建设[M] 北京:人民邮电出版社 2007
    [9] 程杰 大话设计模式[M] 北京:清华大学出版社 2010
    [10] 雷之宇 朱训雨 张麟 JAVA实用组件集[M] 北京:电子工业出版社 2008
    24 评论 716 下载 2019-05-15 16:31:24 下载需要15点积分
  • 基于JAVA和MYSQL数据库实现的图书资料管理信息系统

    第一章 概述1.1 项目背景随着人们知识水平层次的提高,图书馆成为日常生活中不可缺少的一部分, 基于图书数目不断增加,读者数目不断增长,对图书信息管理自动化和准备花要 求日益强烈的背景下,实现读者信息管理工作网络化以及查询和统计一体化的管 理信息系统。该系统为学校职员和学生提供图书的详细信息和馆内库存情况,建 立庞大的数据库;图书管理员需要管理借书、还书情况,并进行借阅者的登记, 工作量较大,图书管理系统可以高效率地处理这些功能,减轻管理员的工作量。
    1.2 编写目的实现图书的智能化、信息化和简单化;实现图书信息的增加、删除、修改、 查找、借阅、还书的显示操作及实时数据库的提交和更改;提高图书管理员工作 信息报送及反馈的工作效率,减轻管理员的劳动负担;提高信息的及时性和汇总统计信息的准确性,使图书和读者管理更加合理化和科学化。
    1.3 开发环境
    系统开发环境:Eclipse Java Neon
    系统开发语言:Java
    数据库:MySQL Workbench 6.3 CE
    运行平台:Windows 8.1

    第二章 需求分析2.1 概要分析经过对图书管理系统的分析,这里把系统的层次划分为了四个部分:图书维护,人员信息管理,图书借阅管理,信息查询。能够实现以下功能:

    进行新书入库、现有图书信息修改以及删除
    能够实现对读者基本信息的查询和编辑管理
    能够进行超期罚款功能
    能够进行借阅信息的查询功能

    2.2 详细分析通过详细分析所得的信息如下:
    2.2.1 处理对象
    读者信息:学号,姓名,性别,学院,专业,年级,登录口令,办证日期, 登录次数,最近一次访问系统时间
    管理员信息:管理员编号,姓名,性别,登录口令,住址,电话
    馆藏图书信息:图书编号(即 ISBN),索书号,图书名称,作者,出版社, 出版日期,单价,摘要,关键字,副本数,借出数量,分类号,所在馆室
    对应在借图书——借阅信息:图书编号(即 ISBN),读者编号,图书名,作 者,借阅日期,归还日期,应还日期,续借次数(每续借一次应还日期固定 增加一周),罚金
    对应借阅历史——借阅历史信息:图书编号,读者编号,图书名,作者,借 阅日期,还书日期
    罚款信息:读者编号,图书编号,图书名,作者,借阅日期,应还日期,归 还日期,罚款金额,处理状态,管理员编号

    2.2.2 处理功能及要求用户对图书管理系统的功能及要求如下:

    能够存储一定数量的图书信息,并方便有效的进行相应的书籍数据操作和管理
    图书信息的录入、删除及修改
    图书信息的多关键字检索查询
    图书的借阅续借、归还及超期罚款
    对一定数量的读者、管理员进行相应的信息存储与管理,包括读者信息的登 记、删除及修改
    管理员信息的增加、删除及修改
    读者资料的统计与查询
    提供一定的安全机制,提供数据信息授权访问,防止随意删改、查询
    对查询、统计的结果能够列表显示

    第三章 数据库设计3.1 ER 模型图
    3.2 定义表及其关键字3.2.1 馆藏图书信息表图书编号,索书号,图书名称,作者,出版社,出版日期,单价,摘要, 关键字,副本数,借出数量,分类号,所在馆室

    3.2.2 读者信息表学号,姓名,性别,学院,专业,年级,登录口令,办证日期,登录次数, 最近一次访问系统时间

    3.2.3 管理员信息表管理员编号,姓名,性别,登录口令,住址,电话

    3.2.4 借阅信息表图书编号,读者编号,借阅日期,归还日期,应还日期,续借次数,罚金, 罚款处理状态,管理员编号

    3.2.5 图书馆室信息表馆室编号,馆室地址

    3.3 描述表之间的关系
    第四章 程序设计4.1 软件功能设计4.1.1 管理员角度
    查询图书功能
    修改图书功能
    删除图书功能
    新增图书功能
    查询读者功能
    修改读者功能
    删除读者功能
    新增读者功能
    查询借阅记录功能
    查询罚款记录功能
    查看个人信息功能
    修改密码功能

    4.1.2 读者角度
    查询图书功能
    借阅新书功能
    续借旧书功能
    按时还书功能
    过期缴费功能
    查看个人信息功能
    修改密码功能
    查询借书、缴费记录功能

    4.1.3 系统功能模块图
    4.1.4 读者信息查询、更新模块
    4.1.5 图书基本信息的查询和更新模块
    4.2 界面设计4.2.1 登录界面
    4.2.2 读者操作界面查询图书界面

    借阅、续借图书界面

    归还、缴费界面

    查看信息界面

    我的图书馆界面

    4.2.3 管理员操作界面查询图书界面

    新增图书界面

    修改图书界面

    删除图书界面

    查询读者界面

    新增读者界面

    修改读者界面

    删除读者界面

    记录查询界面

    查看信息界面

    第五章 课设心得这次课程设计题目是图书资料管理信息系统。在我看来,数据库课程设计主要的目标是利用课程中学到的数据库知识和技术,较好地开发设计出数据库应用系统,去解决各行各业信息化处理的要求。通过这次的课程设计,可以巩固我们对数据库基本原理和基础理论的理解,掌握数据库应用系统设计开发的基本方法,进一步提高我们综合运用所学知识的能力。
    在课程设计初期,我选择了大学图书馆系统进行调研,结合此次课设要求确定了最终的功能和相应界面的设计。通过概念设计、逻辑设计,建立 ER 模 型图,并按照要求删除冗余使最终结果都能达到 BC 范式,创建数据字典,建立 数据表、视图、触发器以及存储过程等等,完成相应的数据库设计,并从已有图 书馆中向数据库插入原始数据。在软件设计阶段,因为之前有过设计界面的经验 所以做起来没有什么困难,但是在 Java 链接数据库进行相应操作时,偶尔会有 逻辑上的错误以及 SQL 语法错误,经过上网搜索相关信息、翻书查阅资料,最 终都一一修改了过来,程序能够完成预期的目标,界面友好简洁,便于操作,比较满意。
    当然本次课程设计还存在着需要改进的地方:点击菜单栏的时候菜单栏选项可以变色,方便用户清楚自己目前在哪个功能面板;读者借了一本书之后就立即刷新查询书籍表格中的借出数。感谢老师给予的改进建议和帮助,我一定会继续努力学习相应理论知识,结合实际,提高自身各方面的能力,更好地完成今后的课程设计任务。
    15 评论 273 下载 2018-11-25 15:29:06 下载需要12点积分
显示 75 到 90 ,共 15 条
eject