分类

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

资源列表

  • 基于Android的天气预报APP

    摘 要随着移动通信技术的发展和无线数据业务的进步,手机已被赋予了除通话以外的其它许多功能。全新的手机软件领域已逐渐聚焦了众多软件开发商的目光,软件开发者和软件用户将共同面临这个振奋人心的新境界。
    本设计使用Android设计技术开发了一种运用在Android系统上的手机天气预报软件系统,本系统通过选择城市来获得天气,风向,风向,温度等信息。基于手机的天气预报系统软件可以使用户对于各地的天气情况的实时掌握,极大的方便了用户的出行和行程安排,避免了不必要的麻烦,具有很强的实用性。
    关键词:Android;手机天气预报软件。
    AbstractWith the development of science and technology, the mobile terminal gradually into the people’s attention, related to more widely, and play an increasingly important role in people’s daily lives. Therefore, the development of critical applications has become an important factor in the popularity of the mobile terminal, the design and development of practical, convenient application is of great significance and good market prospects. Android as the most popular operating platform, naturally, there are a lot of demand for application services.
    The study of this topic is the weather software, based on the Android platform is designed to help the user to query weather information and weather changes anytime, anywhere, to make life more comfortable and convenient. This paper describes the software interface design of the Android platform under the weather and exception handling part, including the contents of the interface implementation, the use of controls, the layout of the interface, and exception handling, combined with weather data of the China Meteorological Association, will be accurate weather conditions presented to the user-friendly way, allows the user to experience more enjoyable the service of this software.
    KEY WORDS:Android,interface,control,weather software
    1 绪论Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发。Android操作系统最初由Andy Rubin开发,主要支持手机。2005年8月由Google收购注资。2007年11月,Google与84家硬件制造商、软件开发商及电信营运商组建开放手机联盟共同研发改良Android系统。随后Google以Apache开源许可证的授权方式,发布了Android的源代码。第一部Android智能手机发布于2008年10月。Android逐渐扩展到平板电脑及其他领域上,如电视、数码相机、游戏机等。2011年第一季度,Android在全球的市场份额首次超过塞班系统,跃居全球第一。 2012年11月数据显示,Android占据全球智能手机操作系统市场76%的份额,中国市场占有率为90%。2013年09月24日谷歌开发的操作系统Android在迎来了5岁生日,全世界采用这款系统的设备数量已经达到10亿台。
    1.1 课题研究内容本课题研究的是基于Android平台下的天气软件,目的是使用户能随时随地的查询天气信息及天气变化情况,让生活更加舒适方便。本文讲述Android平台下天气软件的界面设计以及数据的获取和解析,主要包括界面的实现,控件的使用,界面的布局和数据处理等内容,结合中国气象网的天气数据,将准确的天气情况以友好的方式呈现给用户,使用户更加赏心悦目的体验本软件的服务。通过对界面的布局及控件的应用等相关内容的学习,使我们对Android平台下界面开发工作有一个初步的了解,并且经过这次开发过程,能够基本掌握这些内容。
    1.2 课题研究需求分析课题研究需要达到的基本要求:

    能够查询城市的天气情况
    系统能通过手机查看并显示天气数据
    系统必须具有安全性,可靠性,独立性

    1.3 研究目的和意义天气软件是一种非常实用的信息服务,随着智能手机的不断普及,各种智能手机平台下都有各种各样的天气软件。Android作为现在主流的智能手机之一,自然也需要这方面的软件。天气关系到人们的日常生活,如告知温暖,方便出行等。一款简单实用的天气软件会很吸引用户。
    基于Android平台的天气软件已经有很多,经过分析,用户第一眼往往是一个软件的外观,一个好看的界面才能让用户以一种爱美之心去尝试,才能进一步了解一个软件的好坏,所以吸引眼球的界面是争取用户的第一步。因此,界面设计工作对应用程序来说非常重要,在界面上吸引了用户,才能进一步让用户体验应用程序中的功能,使用这个软件。
    1.4 研究前景Android最吸引人的特点是开源特性,因其开源,允许所有人对其代码进行开发和修改,同时又由于其代码的简单易学性,Android在全世界拥有众多的粉丝。Android在中国的前景十分广阔,首先是有成熟的消费者,在国内,Android社区十分红火,这些社区为Android在中国的普及做了很好的推广作用。国内厂商和运营商也纷纷加入了Android阵营,包括中国移动,中国联通,中兴通讯,华为通讯,联想等大企业,同时不仅仅局限于手机,国内厂家也陆续推出了采用Android系统的产品,我们可以预见Android将会被广泛应用在国产智能上网设备上,将进一步扩大Android系统的应用范围。
    Android采用了软件层(Software stack)的构架,主要分为三个部分。底层以Linux为内核作为基础,由C语言开发,只提供基础功能,中间层次包话函数库和虚拟机,由C++开发。最上层是各种应用软件,包话通话程序,短信程序。应用软件可以由各公司或个人自行开发,以JAVA编写。
    2 Android开发环境及平台搭建2.1 Android开发环境介绍Android平台使用Java编程语言来开发应用程序,而Android提供了对Java的核心支持。考虑到Java虚拟机的执行效率和占用资源情况,Google重新设计了Java的编译器,命名为Dalvik。Dalvik是经过优化的Java编译器,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个Dalvik应用作为一个独立的Linux进程执行,独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。
    项目的开发在Eclipse环境中进行,由于进行的是Android应用程序的开发,需要在Eclipse安装ADT插件,即Android开发工具,这样Eclipse就可以和Android SDK建立连接,在Eclipse中启动Android模拟器、调试程序等工作。
    由以上分析可知,Android平台的搭建需要Android SDK、Java SDK、Eclipse和ADT四个软件。
    2.2 Android开发平台搭建在进行Android应用程序的开发前,要先搭建Android平台,然后才能在开发环境中进行编程。根据官方指导,对Android平台的搭建过程介绍如下:
    STEP1:在官方网址上下载JDK6.0并安装,网址是:
    http://www.oracle.com/technetwork/java/javase/downloads/index.html安装后设置系统环境变量JAVA_HOME、CLASS_PATH、PATH的值;
    STEP2:在官方网址上下载更新的SDK进行安装,官方网址为:
    http://development.android.com/sdk/index.html下载完后解压到指定文件夹,启动SDK Manager进行安装,选择需要的Android版本,然后更新,这次更新需要的时间比较慢,所以更新前要做好准备。安装完成后,将ADB命令所在的目录platform-tools的完整路径添加到系统的环境变量PATH中,就能够在命令中使用ADB命令了;
    STEP3:接下来要安装的是ADT插件,即Android开发工具。因为ADT在线安装容易遇到问题,增加一些不必要的麻烦所以需要下载后在本地安装。指定网址为:
    http://development.android.com/sdk/index.htmlSTEP4:下载Eclipse,建议选择Eclipse3.4以上版本,网址为:
    http://www.eclipse.org/downloads/解压到指定位置后运行,选择Eclipse菜单中的Help>Install New Software选项卡上的Available Software,点击右侧的Add,然后在Name框中填写Android,在Location框中选择上步下载的ADT文件,然后点击OK>Finish>Install All,这时关闭Eclipse再重新启动。重启后选择Eclipse菜单中的Window>Preferences,在左侧的Android项目中SDK Location中填入Android SDK解压后的目录,然后点击Apply。
    至此,整个平台的搭建工作就完成了,可以进行相应的安卓应用开发。
    3 项目分析3.1 用户界面分析根据应用程序的功能需要,对用户界面做如下分析:
    实时天气界面:显示城市当前的实时天气状况,包括城市名称、城市名片、天气情况、温度高低、星期等信息。界面左边有一列城市列表,显示中国各个城市名称,当用户想知道哪个城市的天气情况时,点击这个城市名就可以获取天气状况,考虑到使软件占用尽量小的内存,软件去掉了不必要的花哨,显示城市名称,城市名片,温度和天气情况,同时对未来6天的天气情况简要描述,简要显示星期、天气描述、温度高低等数据,使用户一目了然,使人们及时了解天气变化,对日常生活出行、穿衣做好准备。
    3.2 相关技术介绍3.2.1 Activity在Android应用程序中,一个活动Activity通常就是一个单独的界面。每一个界面都被实现为一个独立的类,并且从Activity基类中继承而来,Activity将会显示由空间组成的用户接口,并对事件做出响应。大多数的应用都是由多个Activity显示组成。
    简单的说,Activity代表一个用户所能看到的界面,主要用于处理应用程序的整体性工作,例如,监听系统事件如按键事件、触摸屏事件等,为用户显示指定的View,启动其他Activity等。所有应用的Activity都继承于android.app.Activity类,该类是Android提供的基层类,其他的Activity继承该父类后,通过父类的方法实现各种功能,这种设计在其他领域也较为常见。
    3.2.2 IntentAndroid基本的设计理念是鼓励减少组件间的耦合,因此Android提供了Intent,Intent提供了一种通用的消息系统,它允许在你的应用程序与其他的应用程序间传递Intent来执行动作和产生时间。使用Intent可以激活Android应用的三个核心组件:活动、服务和广播接收器。
    Intent可以划分为显示意图和隐式意图。显示意图调用Intent,SetClass方法明确制定了组件名的Intent为显示意图,显示意图明确制定了Intent应该传递给那个组件,在同一个应用内部使用的。隐式意图没有明确指定组件名的Intent为隐式意图,Android系统会根据隐式意图中设置的动作(action)、类别(category)、数据(URI和数据类型)找到最合适的组件来处理这个意图。
    Intent负责对应用中一次操作的动作、动作涉及数据和附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的结构。
    3.2.3 Service如果把Activity比喻为前台程序,那么Service就是后台程序,Service的整个生命周期都只会在后台执行。Service跟 Activity一样也由Intent调用,由于Service在后台运行,所以没有界面,用来处理耗时比较长,而且Service不是一个单独的进程,也不是一个单独的线程。Service有两种类型:

    本地服务(Local Service):用于应用程序内部
    远程服务(Remote Sercie):用于android系统内部的应用程序之间

    前者用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。后者可被其他应用程序复用,例如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
    Service的生命周期,Service有startService和bindService两种启动Service方法,每种方法Service的生命周期是不一样的。
    通过startService()——Service会经历 onCreate —> onStartCommand(),stopService的时候直接onDestroy,如果是调用者直接退出而没有调用stopService的话,Service会一直在后台运行,下次调用者再起来仍然可以stopService;
    通过bindService()——Service只会运行onCreate()—>onBind() 这个时候调用者和Service绑定在一起 unbindService的时候onUnbind() —> onDestroyed(),调用者退出了,Srevice就会调用onUnbind() —> onDestroyed()。在这里需要注意的是Service的onCreate的方法只会被调用一次,就是你无论多少次的startService又 bindService,Service只被创建一次。如果先是bind了,那么start的时候就直接运行Service的onStart方法,如果先是start,那么bind的时候就直接运行onBind方法。如果你先bind上了,就stop不掉了,只能先UnbindService, 再StopService,所以是先start还是先bind行为是有区别的。
    3.3.4 Layout布局布局方式有很多种,比如线性布局(Linear Layout)、相对布局(Relative Layout)、表格布局(Table Layout)、网格视图(Grid View)、标签布局(Tab Layout)、列表视图(List View)和绝对布局(Absolute Layout)。本文设计主要采用相对布局(Relative Layout)、线性布局(Linear Layout),所以就相对布局和线性布局我们来做简单地介绍。
    相对布局 Relative:里面可以放多个控件,允许子元素指定它们相对于父元素或其他元素的位置(通过ID指定)。因此你可以按正确的顺序对齐两个元素,或者让一个视图在另外一个下面,居于屏幕中间,左边的中间,等等。元素通过给定顺序来绘制,因此如果第一个元素在屏幕中间,其他以它对齐的元素都会对齐到屏幕中间。同样,因为这个顺序,如果使用XML来指定这个布局,你将引用的元素(为了定位其它视图对象)必须被列在XML文件中,在你通过引用ID从其他视图中引用它之前。其中一些特性直接由元素支持,另外一些由它的LayoutParams成员变量支持(为所有这个屏幕中的元素子类化RelativeLayout,因为所有元素都是RelativeLayout父对象的子元素)。已定义的相对布局RelativeLayout参数是:width,height,below,alignTop,toLeft以及padding[Bottom|Left|Right|Top]和margin[Bottom|Left|Right|Top]。注意其中一些参数明确是相对于其他元素的布局位置,所以它们的数值必须是你的相对位置元素的ID。
    线性布局 LinearLayout:线性布局是所用布局中最常用的方式之一,RadioGroup, TabWidget,TableLayout,TableRow,ZoomControls类的父类。LinearLayout可以让它的子元素垂直或水平的方式排成一行(不设置方向的时候默认按照垂直方向排列)。LinearLayout以你为它设置的垂直或水平的属性值,来排列所有的子元素。所有的子元素都被堆放在其它元素之后,因此一个垂直列表的每一行只会有一个元素,而不管他们有多宽,而一个水平列表将会只有一个行高(高度为最高子元素的高度加上边框高度)。LinearLayout保持子元素之间的间隔以及互相对齐(相对一个元素的右对齐、中间对齐或者左对齐)。
    LinearLayout还支持为单独的子元素指定weight 。好处就是允许子元素可以填充屏幕上的剩余空间。这也避免了在一个大屏幕中,一串小对象挤成一堆的情况,而是允许他们放大填充空白。子元素指定一个weight 值,剩余的空间就会按这些子元素指定的weight比例分配给这些子元素。默认的weight值为0。例如,如果有三个文本框,其中两个指定了weight值为1,那么,这两个文本框将等比例地放大,并填满剩余的空间,而第三个文本框不会放大。
    3.3.5 控件介绍TextView——文本控件,可以用它来显示文字,就像一个标签一样,对TextView是怎么设置显示的文本,怎样设置字体的大小,字体的颜色,字体的样式。TextView包含以下子类:Button, CheckedTextView,Chronometer,DigitalClock,EditText。

    android:id —— 控件的标识符
    android:layout_width —— 设置控件的宽度
    android:layout_height —— 设置控件的高度
    android:layout_marginTop —— 设置文本的上外边距
    android:textSize —— 设置文本文字的的大小
    android:paddingLeft —— 设置元素左内边距

    Button——按钮控件,在button内部可以放置内容,比如文本或图像。<button>与</button>标签之间的所有内容都是按钮的内容,其中包括任何可接受的正文内容,比如文本或或多媒体。例如,我们可以在按钮中包括了一个图像和相关的文本,用它们在按钮中创建一个吸引人的标记图像。不过button禁止使用的元素是图像映射,因为它对鼠标和键盘敏感的动作会干扰表单按钮的行为。下面是Button的部分属性:

    android:id —— 控件的标识符
    android:layout_width —— 设置按钮的宽度
    android:layout_height —— 设置按钮的高度
    android:textSize —— 设置按钮里文字的大小
    android:layout_marginTop —— 设置按钮的上外边距
    android:text —— 设置按钮中的文字
    android:visibility —— 设置按钮里的元素是否可见

    EditText——文本编辑框,TextView的直接子类,所以EditText会继成父类TextView的一些方法。在布局中配置EditText也需同时配置一个Button,这样可以在代码中监听Button的事件,以便获取当前在EditView中输入的内容并且显示出来。在EditView可以限制输入的字符串类型。下面是EditText的部分属性:

    android:id —— 控件的标识符
    android:layout_width —— 设置输入框的宽度
    android:layout_height —— 设置输入框的高度
    android:layout_weight —— 设置输入框占父控件的比例
    android:inputType —— 设置输入框内的字符串类型
    android:hint —— 设置在输入框输入内容前默认的文字

    ImageView——标签可以显示任意图像,例如图标,图片等。ImageView类可以加载各种来源的图片,需要计算图像的尺寸,以便它可以在其他布局中使用,并提供例如缩放和着色等各种显示选项,在本文用来显示城市图片。下面是ImageView的部分属性:

    android:id —— 设置图片的标识符
    android:layout_width —— 设置图片的宽度
    android:layout_height —— 设置图片的高度
    android:visibility —— 设置图片是否可见性

    4 天气预报软件界面设计与实现4.1 Android平台用户界面的实现Android 提供的可变化的用户界面(UI)开发模块是基于XML 文件的。这些XML 文件放在工程/res/layout 下面。这个目录可包含所有应用程序所需的代码部分,比如图片、字符串、xml 文件。当要使用到这些资源时,在代码目录中打开R.java文件即可。在XML 文件里编辑界面的代码,实现起来不仅方便,使用时也会更加灵活。
    在Android 程序设计中要用到一些基本的Android UI 元素,通过使用Views、View Groups 和layouts 可为Activity 创建功能性的、富有直观力的UI.通常是使用Android SDK 中提供的一些控件,进行布局、扩展和定制这些控件,并使用ViewGroups 去组合Views,创建由相互作用的子控件组成的原子的、重复利用的UI 元素。也可以创建自己的Views,来实现显示数据和与用户交互的新途径;或使用一些继承自View Group 的Layout 管理器来组织Android UI中的单个元素到屏幕上。
    在一个Android 应用中,用户界面由View 和View Group对象构建。View 与View Group 有很多种类,而它们都是View类的子类。View 对象是Android 平台中用户界面的基本单元。View 类是widgets(工具)类的父类,它们提供了诸如文本输入框和按钮之类的UI 对象的完整实现。View Group 类是Layouts(布局)类的父类,它们提供了诸如流式布局、表格布局以及相对布局之类的布局架构。
    View 对象是一个数据体,它的属性存储了用于屏幕上一块矩形区域的布局参数及内容。并负责它所辖的这个矩形区域之中所有测量、布局、焦点转换、卷动以及按键/触摸手势的处理。作为一个用户界面对象,View 同时也担任着用户交互关键点以及交互事件接受者的角色。天气实时预报系统程序功能比较单一,其UI 也相对比较简单,只要有一个显示所有中国城市信息的列表,一个显示城市图片的Imageview即可。为了建立Android 平台的用户界面,首先要在Package Explorer 窗口中展开Layout 后新建xml 文件,用来对窗口界面进行布局,主要有系统运行的主配置文件activity_main.xml ,listview.xml和weatherfragment.xml。
    Layout 是一类特殊的ViewGroup 控件,它们本身没有任何可显示内容,存在的惟一原因就是其中的内部结构,能够更好地摆放它的子控件。比如Linearlayout,可将子控件按水平或垂直方向按顺序排列下去;Tablelayout,可以将子控件按照表格的形式,一枚枚放置好;Relativelayout 更灵活,可以设定各个控件之间的对齐和排列关系,适合定制复杂的界面。有了Layout 的存在,控件和控件之间不再是割裂地存在,而是更有机地结合在一起,设定起来也更为方便。在activity_main.xml 文件中主要是添加一些界面的布局设置。
    4.1.1 主要的项目工程文件为了给用户清晰,直观的体验,界面设计要做到简明,友好,因为考虑到各个城市的不同特点,所以给每个城市添加一张城市名片的图片,能使用户感觉更加友好,界面左边是城市列表,用户可以选择具体城市查看天气信息。考虑到软件的简洁明确性,只设定一个界面用来显示城市和天气信息,weather工程目录结构及其源代码文件如图1所示:

    4.1.2 创建中国城市列表根据天气预报系统功能需求分析,系统启动后,应在主界面上呈现出中国国内所有城市的列表数据,因此需要创建中国城市列表数据,包括获取、解析城市列表数据,并在用户界面上呈现出来。同时为了给用户更好的交互,每个城市对应显示城市名片,通过代码实现,具体代码如下:
    @Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mLayoutInflater = LayoutInflater.from(this); cityList = (ListView) findViewById(R.id.citylist); cityImage = (ImageView) findViewById(R.id.cityImage); cityName = (TextView) findViewById(R.id.cityName); cityWeather = (TextView) findViewById(R.id.cityWeather); cityTemp = (TextView) findViewById(R.id.cityTemp); viewpager = (ViewPager)findViewById(R.id.viewpager); citys.add(new City(R.drawable.city1, "桂林", "101300501")); citys.add(new City(R.drawable.city2, "北京", "101010100")); citys.add(new City(R.drawable.city3, "哈尔滨", "101050101")); citys.add(new City(R.drawable.city4, "大连", "101070201")); citys.add(new City(R.drawable.city5, "南京", "101190101")); citys.add(new City(R.drawable.city6, "成都", "101270101")); citys.add(new City(R.drawable.city7, "广州", "101280101")); citys.add(new City(R.drawable.city8, "乌鲁木齐", "101130101")); citys.add(new City(R.drawable.city9, "香港", "101320101")); citys.add(new City(R.drawable.city10, "台北", "101340101")); citys.add(new City(R.drawable.city11, "沈阳", "101070101")); citys.add(new City(R.drawable.city12, "呼和浩特", "101080101")); citys.add(new City(R.drawable.city13, "济南", "101120101")); citys.add(new City(R.drawable.city14, "西安", "101110101")); citys.add(new City(R.drawable.city15, "兰州", "101160101")); citys.add(new City(R.drawable.city16, "武汉", "101200101")); cityadapter = new CityAdapter(); weatheradapter = new WeatherAdapter(getSupportFragmentManager()); cityList.setAdapter(cityadapter); viewpager.setAdapter(weatheradapter); cityList.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) { // TODO Auto-generated method stub selectid = position; cityadapter.notifyDataSetChanged(); cityImage.setImageResource(citys.get(position).image); callHTTP(citys.get(position).code); } }); cityImage.setImageResource(citys.get(selectid).image); callHTTP(citys.get(selectid).code);}
    这段代码的作用是在创建城市列表的同时,将城市名称,城市名片和城市接口结合在一起,使得显示的时候同步,具体效果如图2所示:

    4.2 天气信息的获取基于Android 操作系统的天气实况预报系统设计的核心是通过调用通信协议SOAP(Simple Object AccessProtocol)的接口,从Web Service 提供商中提取天气预报的数据信息,为客户端服务。其基本功能是当用户运行天气预报系统程序时,在手机屏幕上显示出中国的城市名称,用户单击任意一个城市名,可获得该城市的天气实时预报信息。为此,需要解决的问题是手机终端从Web 服务器获取了所有类型的数据之后,将这些数据进一步交给Android 手机终端View 组件,在手机界面上显示给用户。
    4.2.1 天气信息数据的获取在开发中我们经常提到”接口”这个词,什么是接口呢?简单的说,接口其实就是一个http地址。一个标准的网络应用肯定需要两个部分,一部分是咱们正在学习的android开发,还有另一部分是服务器开发。
    大多数android程序都是基于网络的,比如基本上大家都在使用的QQ手机客户端。那么假设我们现在要开发一个类似QQ的通信客户端。第一步,需要开发一个登录界面来验证用户登录。很显然的,为了验证登录,我们需要和服务器进行通信,把用户输入的用户名和密码传递给服务器,然后服务器来判断这组用户名密码数据是否正确,并返回给客户端,告诉我们用户登录是否成功。一般接口由三部分组成:接口地址+接口名称+接口参数。比如下面这个是中国气象网提供的天气信息查询接口:http://www.weather.com.cn/data/cityinfo/101300501.html ,该接口提供的数据是实时天气情况,通过这个接口我们可以得到以下信息,如图3所示:

    代码实现接口获取数据如下:
    // 请求接口private void callHTTP(final String cityCode) { // 创建一个runnable Runnable runnable = new Runnable() { @Override public void run() { // step1 :创建HttpGet, 就是创建我们要访问的接口地址 HttpGet getMethod = new HttpGet("http://m.weather.com.cn/data/"+cityCode+".html"); // step2 :HttpClient, 我们要通过它来将step1创建出来的地址发送给服务器 HttpClient httpClient = new DefaultHttpClient(); try { // step3: 通过httpClient.execute()方法,我们把url发送给了服务器, // 而服务器返回的信息就会被保存在HttpResponse中了 HttpResponse response = httpClient.execute(getMethod); // 发起GET请求 // 用EntityUtils.toString把HttpResponse转换成string String result = EntityUtils.toString(response.getEntity(), "utf-8"); // 将返回的json字符串解析并显示出来 try { paresJson(result); } catch (JSONException e) { e.printStackTrace(); Log.v("TAG", "解析失败 "); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }; // 开启线程执行runnable new Thread(runnable).start();}
    4.2.2 解析数据从图3可以看出,我们获得了桂林的天气信息,但是这些数据看着很乱,为了使用户清晰的获得信息,我们可以采用json协议解析数据:
    // 将返回的json字符串解析并显示出来private void paresJson(String jsonString) throws JSONException { // 首先,把这个字符串转换成jsonobject JSONObject jsonObject = new JSONObject(jsonString); // { // "weatherinfo": { // "city": "桂林", // "cityid": "101300501", // "temp1": "28℃", // "temp2": "19℃", // "weather": "多云", // "img1": "d1.gif", // "img2": "n1.gif", // "ptime": "11:00" // } // } // 理解json格式我们可以把它当成window里的文件系统, 大括号表示文件夹 // 假设上面是字符串的内容, // 那么最外面的"文件夹"里包含着一个叫"weatherinfo"的子文件夹. // 然后weatherinfo文件夹里包含着许多文件, 有的叫city ,有的叫 temp1, // city 后面的 "桂林" 表示的是city这个文件的实际内容是"桂林" //
    4.3 在UI上显示天气信息当获得天气数据之后,就可以把它绑定到activity_main.xml 定义的ListView 组件上,在WeatherFragment.java 中的代码段为:
    public class WeatherFragment extends Fragment { Weather weather; @Override public void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); weather = (Weather)getArguments().getSerializable("weather"); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO Auto-generated method stub View view = inflater.inflate(R.layout.weatherfragment, null); TextView dayTextView = (TextView) view .findViewById(R.id.time); TextView tempTextView = (TextView) view .findViewById(R.id.yubaoTemp); TextView weatherTextView = (TextView) view .findViewById(R.id.yubaoWeather); dayTextView.setText(weather.day); tempTextView.setText(weather.temp); weatherTextView.setText(weather.weather); return view; }}
    5 软件测试5.1 天气预报软件在电脑模拟环境下测试软件编写完成,对其进行测试,首先将手机天气预报系统在电脑模拟环境下测试的方案,以下是对系统进行测试,在Eclipse 的Package Explorer 窗口中用鼠标右键选择weather工程名,在弹出的窗口中选择”Run As”→”Android Application”安装该应用程序到Android 模拟器并启动它,如图4所示:

    等待模拟器启动完成软件的安装,然后单击所要查询的城市名称列表项,稍等片刻便会显示出该城市的天气实况信息。电脑模拟测试结果如图5所示:


    通过网站查询桂林的天气情况如图6所示:

    通过对图5和图6的数据比较,可以知道软件获得的数据是正确的,说明软件的可行性基本满足要求。
    5.2 天气预报软件在Android手机下测试在工程名weather上点右键,然后选择“Run As”,然后选择“Android Application”。进入界面后,选择测试手机,如图7所示:

    等待程序安装完成,保证手机连接互联网的情况下,启动后可以得到各个城市的天气信息,如图8所示:




    该测试说明开发的天气预报软件可以独立在Android设备运行,满足设计要求的独立性,通过与网络的数据比较,可以发现,天气预报软件获取的数据与实际的天气情况非常接近,说明数据的准确性,实时性;从图9可以看出,当选择不同的城市时,软件可以通过网络获取不同城市的天气信息,说明该天气预报软件可以获取不同城市的气象信息,满足设计要求。
    6 总结在本次Android天气预报软件开发过程中,我通过学校的图书馆资料和网上查询,了解了Android的搭建、Intent、Activity、Service等知识。Android环境搭建的基本工作完成后,本文对界面的控件、布局和美观方面进行设计,对数据获取和解析做了分析,通过模拟器显示城市名片,实时天气情况和未来5天天气情况,这个软件还可以进一步发展,比如“短信预报”、“新闻模块”等功能,如果这些功能都能实现将会对用户有更多的帮助,使他们的生活更加愉悦和方便。Android 智能手机应用程序的开发涉及了它的整个体系结构,是一项非常复杂的工程。
    3 评论 27 下载 2019-05-18 15:31:02 下载需要15点积分
  • 基于C++的全国交通咨询系统

    一. 设计目的全国交通咨询模拟。处于不同目的的旅客对交通工具有不同的要求。例如,因公出差的旅客希望在旅途中的时间尽可能的短,出门旅游的游客则期望旅费尽可能省,而老年旅客则需要中转次数最少。编制一个全国城市间的交通咨询程序,为旅客提供两种或三种最优决策的交通咨询。
    二. 设计内容提供用户以及管理员功能,用户可以对交通图进行查询,而管理员可以对交通图进行增删查改,同时管理员可以登陆、修改密码等待操作,界面采用字符界面。这样操作,更加真实地模拟了交通咨询系统。关于要求的功能,实现了城市线路的增加、删除、显示,基于 Dijkstra 的从源点到汇点的最小费用算法与最小时间算法。
    三.概要设计3.1 功能模块图
    3.2 各个模块详细的功能描述
    查询城市编号:头结点建立顶点表时存储的是城市对应的序号

    手动添加城市从文件读取以添加城市
    删除城市:删除城市时需要删除与该城市相关的所有线路

    输出所有城市
    更新城市列表:当新建城市个数加原本已存在城市个数大于 MAXSIZE 时,需要开辟空间存储新城市并 ++MAXSIZE

    手动添加线路
    插入线路:由于线路信息存于表结点里,所以需要新建表结点并加入对应起始城市的边表

    从文件中读取线路删除线路求最少花费路径求最少时间路径

    四.详细设计4.1 功能函数的调用关系图
    4.2 各功能函数的数据流程图



    4.3 重点设计及编码用优先队列优化的基于dijkstra 算法的最小费用与最小时间算法,代码如下:
    //最少花费路径struct Node{int id; //源顶点 idfloat money; //估算距离(费用)//由于stl 中优先队列的第三个参数是greater,而我们需要的是小顶堆,所以因重载运算符 <friend bool operator < (struct Node a, struct Node b) { return a.money > b.money;}};void ALGraph::dijkstra_Money (int v0, int *parent, Node *dis) { priority_queue<Node> q;//优化插入(更新)和取出最小值两个操作,队列存储最短距离与索引的编号//parent[]记录每个顶点的父亲结点//dis[]记录源点到每个估算距离,最后更新为源点到所有顶点的最短距离bool visited[MaxCityNum]; //判断下标对应的顶点是否算出最短路径或者说是否在最短路径树中//初始化int i;for (i = 0; i < CityNum; ++i){ dis[i].id = i; dis[i].money = INF; parent[i] = -1; //每个顶点都没有父结点 visited[i] = false; //都未找到最短路}dis[v0].money = 0; //源点到源点最短路权值为 0 q.push(dis[v0]); //压入队列while (!q.empty()){ //队列空说明完成了求解v0 到其余各顶点的最短路径 Node cd = q.top(); //取最小估算距离顶点q.pop(); int u = cd.id; if (visited[u]) { //被标记了,就无需对其进行更新最短距离等等操作continue; } visited[u] = true; LineNode *p = CityList[u].FirstLine; //松弛操作 while(p) { //找所有与它相邻的顶点,进行松弛操作,更新估算距离,压入队列int v = searchCityNum(p->EndName); float m = p->Info->SpendMoney; if (!visited[v] && dis[v].money > dis[u].money + m) { dis[v].money = dis[u].money + m;parent[v] = u; q.push(dis[v]); } p = p->NextLine; }}// while (!q.empty()) }//dijkstra_Money//最少时间路径struct Node1 { int id; //源顶点 id int tt; //估算距离(时间) Time et; //到达时间 friend bool operator < (struct Node1 a, struct Node1 b) { return a.tt > b.tt; }};int ALGraph::timeTransWeight (const Time& t) { return (t.day*24 + t.hour)*60 + t.minute;}void ALGraph::dijkstra_Time (int v0, int *parent, Node1 *dis) { priority_queue<Node1> q1;//parent[]记录每个顶点的父亲结点//dis[]记录源点到每个估算距离,最后更新为源点到所有顶点的最短距离 bool visited[MaxCityNum]; //判断下标对应的顶点是否算出最短路径或者说是否在最短路径树中 int i; for (i = 0; i < CityNum; ++i) { dis[i].id = i; dis[i].tt = INF; dis[i].et = {0, 0, 0}; parent[i] = -1; //都一个顶点都没有父结点 visited[i] = false; //都未找到最短路径 } dis[v0].tt = 0; q1.push(dis[v0]); while (!q1.empty()) { Node1 cd = q1.top(); //取出最短距离的点的序号q1.pop(); int u = cd.id; if (visited[u]) { continue; } visited[u] = 1; LineNode *p = CityList[u].FirstLine; //找出所有相邻点,进行松弛操作,即更新 dis while (p) { int v = searchCityNum(p->EndName); int t = timeTransWeight(p->Info->SpendTime); Time st = p->Info->StartTime; //本条线路开始时间 //计算中转的时间开销 if (u != v0) { //注意源点到任何点都没有中转时间 int change = timeTransWeight(st - dis[u].et); //当前路线的开车时间-始发站的上一到站时间 t += change; } if (!visited[v] && dis[v].tt > dis[u].tt + t) { dis[v].tt = dis[u].tt + t; dis[v].et = p->Info->EndTime; parent[v] = u; q1.push(dis[v]); } p = p->NextLine; }//while (p) }//while (!q1.empty())}//dijkstra_Time
    五. 测试数据及运行结果5.1 正常测试数据和运行结果要求提供 3 组正常测试数据和运行结果

    昆明 成都 (最小花费)


    导入线路


    删除线路


    5.2 异常测试数据及运行结果显示所有线路:输出格式异常
    1 评论 86 下载 2018-11-09 15:14:54 下载需要8点积分
  • 基于Pubmed数据库的蛋白质修饰后的信息挖掘

    摘 要如今Pubmed文献检索系统上发表的医学文献的数量十分庞大,且数量逐年增加,研究人员如果想人工地去查看找出Pubmed文献里面的知识是绝对不可能,因此,人们转而利用计算机去获取文献里面的知识。
    本篇论文介绍了如何借用文本挖掘技术去挖掘出Pubmed文献里面的知识,并且结合了目前文本挖掘技术,讲述了如何实现了一套蛋白质磷酸化修饰的文本信息挖掘系统。
    本系统主要应用于挖掘出Pubmed文献里面蛋白质磷酸化的修饰的一些信息,包括被修饰的蛋白质,激酶,修饰位点,以及它们之间的关系。
    本文详细叙述了整套系统瀑布流模型的软件过程,首先是需求,然后是设计,再是实现,依次展开。在实现的阶段里面又包含了文本预处理阶段,命名实体识别阶段,实体关系提取阶段,数据可视化阶段,其中着重介绍了文本挖掘技术中两个的关键也是核心阶段的原理:命名实体识别和关系提取。同时也介绍了Abner工具和Rlims-p工具的原理和应用。此外文献数据库的数量庞大,为了提高程序性能和用户体验,于是介绍了几种提高效率,提高用户体验的解决方案,其中有多线程处理,缓存机制,预处理机制。
    关键词:文本挖掘;软件工程;Pubmed;多线程
    AbstractNowadays, The number of published medical literature on Pubmed document retrieval system is very large, growth year after year. It is absolutely impossible to researchers manually discover knowledge among the Pubmed literatures. As a result, researchers turn to use the computer to acquire knowledge inside the literature.
    This paper introduce how to acquire knowledge in Pubmed literature by using the technology of text mining and how to implement a text mining system for extracting protein phosphorylation information among Pubmed literature using the current text mining technology. This system is main used for extracting protein phosphorylation information among the Pubmed literatures such as substrate, kinases, sites, and relation among these substances. With the current text mining technology, I
    This paper describes the waterfall model of software process about this system. First step is requirement, second step is design, and then implementation, step by step.In the step of implementation, there are four steps as follow: text preprocessing, named entity recognizeation, relationship extracting, Visualization. This paper highlights the principle and application of two very important steps in text mining: named entity recognization, and relationship extracting. At the same time, Abner tools and Rlims-p tools are also introduced in this paper. Moreover, the number of the Pubmed literatures in database is very large, and in order to improve the program performance and user experience,this paper had introduced several method for improve the program performance and user experience such as multithreading, caching, preprocessing.
    Keyword: Text mining, Software engineering, Pubmed, Multithreading
    第一章 引言1.1 概述在近十几年来,计算机领域发展迅猛,个人计算机,终端互联设配也越来越普及,几乎是人人随时随地都能上网,在当今互联网这个巨大的生态圈里面,每年互联网用户产生的数据正以惊人的速度增涨。这些逐年增长的数据中绝大多数的数据都是非结构化的数据,这些数据主要存储的形式都是文本、网页、图片、视频、音频等非结构化的形式。结构化的数据它是经过了一定的存储格式,处理规则加以封装,所以它能够被计算机根据其存储的规则来进行识别,而非结构化的数据比如说文本数据,这些数据没有规则,格式,通常情况下它是不能被计算机直接识别的。当人们想对这些数据进行分析,统计,挖掘的时候,由于其不是结构化的数据,很难通过数据挖掘的技术对其进行处理。人工筛选的方法在这个大数据时代显然是天方夜谭,虽然说人工筛选的方法在上世纪80年代之前都是的确存在的,有需求就有市场这句话放在科研的领域也是行的通的,正因为有对非结构化文本识别和分析的需求,所以研究者们也想出了各种相关的方法。文本挖掘(Text Mining),图像识别,模式识别等一些相关技术就对分析和识别这一些非结构化的数据起到很好的作用。在此篇论文中我们主要讨论一下文本挖掘技术。
    文本挖掘(Text Mining)是一个从非结构化文本信息中获取用户感兴趣或者有用的模式的过程[1]。首先它会把非结构化的文本数据通过一定的方法转换成为结构化的数据,然后再从这些结构化的数据中分析提取出我们用户所感兴趣的模式和东西。文本挖掘技术是一项非常复杂的技术,它是一个多学科混杂的一门学科,其中包含有信息技术、机器学习、统计学、数据可视化、数据库技术、数据挖掘[2]。集这么多门学科于一身,它在我们这个大数据时代,信息化时代发挥了重要的作用,也是在信息学科领域中比较热门的学科之一。
    在生物医学领域,借助着计算机科学技术也在快速的发展,每年发表在互联网上的生物医学文献资料和研究者们在实验室产生的实验数据也正以惊人的速度增长[3],产生的这些文献资料和实验数据大部分都是以文本的形式存储在计算机设配上面。所以也是非结构化的数据,不能被计算机直接识别。那么我在此篇论文里主要讨论针对文本形式存储的非结构化数据的处理以及信息的提取。
    1.2 选题的背景和意义基因和蛋白质一直都是生物医学工程方面的两大热点词汇,人类从刚开始发现它们到现在一直都在研究它们,并从未停止过对它们的研究和实验。经过科学家们的众多次探索和实验让我们对它们有了一定的了解和认识,并且也享受到了研究成果给人类带来的益处.蛋白质是由氨基酸排列组合生成的,人体氨基酸种类有20种,这20种氨基酸排列组合可以生成成千上万种的蛋白质[4],随着研究者们不断深入研究蛋白质和不断实验,发表在科学文献期刊上的文献数量也随之增加,这个数量正在指数级地增长,如此多的学术文献给研究者们带来了无比多的信息和知识,但是蛋白质的种类如此繁多,有关蛋白质的文献也就越多,这么多的科学文献,研究者是不可能全部阅读完的,这样一来数量如此庞大的科学文献对于研究者们来说是一种浪费,然而研究者们发现他们在阅读每一篇文献时,仅仅只是要获取其中的蛋白质的关键信息,但是他们不得不逐一整片阅读,这大大阻碍了他们的研究效率,所以研究者们迫切需要借用计算机大数据的手段来支持他们完成更深入的探索和研究[5]。他们希望通过计算机的文本挖掘和文本分析来帮他们迅速定位到他们想要得到的蛋白质信息,所以文本挖掘技术迫切需要应用与生物医学文献挖掘上,这也是我本论文的核心研究的方向。
    在如此庞大的生物医学文献库当中加之以文本挖掘技术进行适当分析和处理,处理的结果给研究人员提供了一个客观可靠的数据基础,这大大地减少人工检阅和人工处理等繁杂的工作,提高了研究者们的效率,同时这些数据基础上研究人员们能够更深一步的论证、假设、探索、实验。从而加快了生物医学领域的发展进程。
    第二章 入门概念2.1 蛋白质以及翻译后修饰概述蛋白质(protein)是生命的物质基础,是有机大分子,是构成细胞的基本有机物,是生命活动的主要承担者。中学课本学习过,蛋白质是由氨基酸构成的,而氨基酸是由基因表达产生的。所以可以认为蛋白质是基因表达的产物。蛋白质翻译是蛋白质合成过程中的第一步,翻译是根据遗传密码的中心法则,将成熟的信使RNA分子(由DNA通过转录而生成)中“碱基的排列顺序”(核苷酸序列)解码,并生成对应的特定氨基酸序列的过程。此过程产生的蛋白质是没有活性的,想要具有活性,常常要进行一个系列的翻译后修饰和加工,从而使其具有一定的功能和特性。据研究统计,人类有50%~90%的蛋白质都在翻译后进行了修饰[6]。蛋白质的翻译后的化学修饰一般是对蛋白质的附加一些生物化学官能团或是改变其结构来让它改变其化学性质,从而让它具有某项特性或功能。翻译后的蛋白质正因为有了修饰加工这一个步骤,就可能使相同的蛋白质具有完全不一样的功能和特性,也大大地增加的蛋白质的复杂性和多样性。所以这种类远远地超过了有天然20中氨基酸经过排列组合可生成的蛋白质的种类。所以,一个基因表达产生一个蛋白的说法就不存在了。据统计,人体类的可以编码合成蛋白质的基因组有两万多个,但是却可以表达出高达20万种不同功能的蛋白质[6]。
    到目前已经发现了超过400种的蛋白质翻译后修饰的方式。但是目前发现的蛋白质翻译后修饰的方式还是比较少的,还有大量的蛋白质修饰过程还是未知的。然而我们比较常见的修饰方式有磷酸化、甲基化、泛素化、乙酰化、亚硝酸化、糖基化、氧化等[7]。
    2.2文本挖掘技术概述文本挖掘(Text Mining)是以计算语言学、统计数理分析为理论基础 ,结合机器学习和信息检 索技术 ,从文本数据中发现和提取独立于用户信息需求的文档集中的隐含知识。它是一个从文本信息描述到选取提取模式 ,最终形成用户可理解的信息知识的过程[8]。它其实也是数据挖掘技术的一个分支学科,它和数据挖掘不同的是,数据挖掘技术主要是对结构化的数据进行挖掘处理,比如说关系表(Table),事务表等,这些表里面的数据(特征)在积累的时候就已经通过键值对(key-map)的方式做好了结构化的存储,所以计算机在解析数据的时候根据不同key去取相应的数据,所以结构化的数据是能被计算机所识别的,但是文本挖掘技术主要针对的是文本形式存储的非结构化数据,比如说新闻,网页,书籍等,这些文本数据是通常是由人类所撰写,文本中充满了人类语言规则和定义,这些规则因地区而异,比如说不同国家的语言不一样,计算机必须为每种语言去适应其语法规则,或者时间而异,比如说随着科研不断发展,新的名词可能被创造,这个时候必须让计算机学习人类创造的新的词语,由此可见计算机是无法直接识别这些非结构化的数据。
    2.3 Pubmed生物医学文献检索系统Pubmed是美国国家医学图书馆(NLM)所属的国家生物技术信息中心(NCBI)于2000年4月开发的,基于WEB的生物医学信息检索系统。PubMed的数据库来源于MEDLINE,OLDMEDLINE,Publisher-Supplied Citations,其中包含了大量的生物医学先关的期刊,论文,综述等[9]。它给生物医学研究人员提供了丰富的有关蛋白质,基因等重要的文献信息。
    第三章 需求分析和系统设计3.1 需求需求最初是由中山大学生物工程学院的几位师姐提出来的,她们研究蛋白质翻译后修饰的时候会经常去Pubmed生物医学文献检索系统里面去找有关蛋白质翻译后的文献,比如想要找找有关蛋白质磷酸化修饰的文献,学习这一类修饰后的蛋白质的知识,她们可以在Pubmed文献检索系统里输入phosphorylation关键字,接着就可以找到几千或者上万篇有关磷酸化的一些文献。这些根据关键字检索到的文献的数量有点庞大,人工每一篇地去阅读显得有些吃力,但是她们发现她们每次阅读文献的时候都有一个共同点,就是只要找出文献里面的关键信息,比如说只要找出某某蛋白质被某某酶在某个位点上修饰了。这样问题就来了,能不能借助计算机来识别这些关键信息并找出这些关键信息呢?如果可以的话就不用通篇阅读了,大大地节省了时间,提高了效率。于是她们就提出了这样一个需求:通过计算机来识别并找出文献中的一些关键信息,关键信息就是蛋白质的名称,酶的名称,酶修饰蛋白质的位点。
    3.2 需求分析接到这个需求的时候,给我的第一感觉就是要在一篇文章中找出摘要信息,用几个关键词概括出全文,这有点类似于文章目录提取和文章摘要概括。于是我去Pubmed数据库查了几篇有关于磷酸化修饰的文章。文章的主要的意思就是描述了某个激酶在某个位点上修饰了某个蛋白质,当然也有一些是无关紧要的文章,这些无关紧要的文章我们要把它们除去,因为它们并不能给我们带来知识和信息。图3-1是一篇标准的Pubmed数据库中关于磷酸化修饰的一篇文章。在示例文中以标签ArticleTitle为例,ArticleTitle内容为GRK6 phosphorylates IκBα at Ser(32)/Ser(36) and enhances TNF-α-induced inflammation.在这句话中GRK6是一种激酶,IκBα是一种蛋白质,Ser(32)/Ser(36)是修饰的位点,它们三者之间的关系是GRK6激酶在Ser(32)/Ser(36)位点上磷酸化修饰了IκBα蛋白质。这就是研究人员想要找出的知识模型。

    3.3 用户用例分析需求我们已经知晓了,在这基础上,我们要建立一条完整地用户使用示例,这样我们才能了解整个系统的来龙去脉。假设一个用户需要在Pubmed生物医学文献检索系统中找出蛋白质磷酸化修饰的一些信息,用户可能想要输入关键词phosphorylate(磷酸化),然后用户想得到所有(当然不可能找出所有的被磷酸化修饰的蛋白质,有些蛋白质研究人员们还在进一步在探索,这里的所有指的是目前已经发现的并且已经被收录于MEDLINE文献数据库中的所有被磷酸化修饰过的蛋白质)被磷酸化修饰过的蛋白质,以及修饰的激酶和修饰的位点,并且这些数据以一种直观、可视化的图表来展示在他面前。简单抽象一点概括的话,用户输入一个pubmed文献,然后期望得到一个可视化的图表。图3-2展示了用户和系统这样一种关系。

    根据用户用例分析,接来下把用户和系统交互的流程按照时间顺序来列出来,于是可以设计出时序图如图3-3所示。

    3.4 系统设计3.4.1 系统工作流程和场景根据以上需求描述和用户用例分析,我们首先可以建立起用户和系统的工作场景,图3-4展示了用户和整个系统的一个工作场景。从图中可以看出整个工作环境下有两大类,一个是客户,一个是服务,这就是典型的客户端-服务端(C/S)架构的模式,在论文中稍后会提及到这种架构。从图发现整个系统主要处理工作流程的是在服务端,于是结合上述所有,我把此次的系统工作流程大致的分成以下5个步骤:

    从Pubmed文献数据库中获取有关蛋白质磷酸化修饰相关的文献
    对这些原始文献文本做一次预处理,整理出具有一定格式的文档集
    针对于文档集中的每一个文档,识别出文档里面的命名实体
    挖掘出这些命名实体之间的关系
    对挖掘出来的数据和关系进行可视化处理


    3.4.2 模块化设计根据以上总结的5大工作流程,我们可以发现以上5个步骤顺序执行,下一个步骤总是依赖上一个步骤,并使用上一个步骤产生的数据作为这一步的输入数据。每一个步骤都有一个输入数据和输出数据,由上往下以此传递。所以我们在实现整套系统的时候要依次实现这5个步骤,并且每个步骤都有一个input和output。每一个步骤都有一个明确的功能,我们可以把每一个步骤对应地划分成系统的各个模块,然后以其功能来命名。这样我们就可以把它划分成文本预处理模块,命名实体识别模块,实体关系提取模块,数据可视化模块五大模块。系统整体设计图如图3-6所示。由图3-5可以看出各个模块的输入和输出总结如下表格图3-5所示。



    模块名称
    输入数据
    输出数据




    文本预处理
    粗糙、冗余的文件
    具有一定格式的文档集


    命名实体识别
    具有一定格式的文档集
    被标注命名实体的文档集


    实体关系提取
    被标注命名实体的文档集
    实体、关系


    数据可视化
    实体,关系
    实体+关系图表(统计)




    各个模块内部遵循模块相互独立原则,仅在模块的出口和入口提供对外数据交接的接口,这样就便于以后维护方便。
    3.4.3 软件开发架构从系统的使用场景图3-4上来看,我们采用C/S(客户端/服务器)的架构来实现整套系统,因为从用户用例上,这是基于请求—响应式的模型的事件过程,这也是典型的C/S架构的模型,所以采取C/S架构是非常贴切的。
    由于文本集数量庞大,在处理这么多文档集的时候会非常耗时,所以显然不能时时同步响应用户的请求,当然也不能处理完所有的文档再响应用户的请求,因为处理完所有的文档集再返回给用户,用户就回觉得系统响应非常慢,非常卡,从而造成用户体验效果不佳。所以我们服务端方面要每处理完一篇文档的时候就及时的返回数据给用户,直至处理完所有的文档集。这样的话,有数据时时返回,虽然不是全部的数据,但是用户就不会觉得卡,反应慢。客户端方面,要做到异步加载服务端传回的数据并展示。
    为了加快系统的运行效率,服务端在处理文档集的时候应当采用多线程的方式,并发处理每一篇文献,因为在处理每一篇文献的事件是相互独立的,前提是每个线程在处理资源的时候,不能同时访问同一个文件,因为这样的话,可能会导致结果有重复,所以在线程调度方面,对于同一个文件的处理的时候要加上互斥锁,以保证每个线程在相同时刻都在处理不同的文件。
    3.4.4 开发环境
    开发语言;Java
    操作系统:MacOS

    Java是一种跨平台式的语言,可以方便移植到不同平台使用,所以此次开发主要采用Java语言。采用J2EE里的JSP和java servlet作为服务端的开发架构,客户端就可以认为是H5网页前端。
    第四章 程序设计和系统实现4.1 程序设计程序的主体是服务端,而客户端简单的来说就是前端H5网页通过浏览器就可以打开,所以服务端最后返回的数据是html,css,js等等。服务端的开发采用的是Jsp+Tomcat技术。图4-1展示了服务端内部的一个大致的结构,从图中可以看出来整个程序分文三个大区域,第一是资源区,这个主要是托管一些文档、缓存、数据库这样一些体积比较庞大的资源,第二个是主程序逻辑控制区,这个区域是运行的是程序的主线的逻辑,从请求的开始到返回这里面复杂的逻辑过程都是由主线来严格控制。第三个区是文档处理区,由于文档处理这一步非常耗时,里面的逻辑也非常复杂,但是功能相对独立,所以我就把它单独列出来,相当于是程序的一个分支。

    4.2 文本数据源获取由于需求提出者提出了主要针对蛋白质磷酸化修饰的信息挖掘,所以关键词即为’磷酸化’(phosphorylate)。Pubmed文献检索系统上收录的大部分是以英文为语言的生物医学文献,所以我们要把关键字’磷酸化’翻译成phosphorylate来作为Pubmed文献检索系统的关键词。Pubmed文献检索系统支持AND和OR来接连关键词,这样就可以限制和放宽检索的范围,因为此次研究的对象是整个和磷酸化有关的蛋白质文献,所以我们在输入关键词的时候把磷酸化的主动式(phosphorylate)和被动式(phosphorylated)两个词通过OR的方式来扩大检索的范围,通过检索后,最后我们从中得到了76604个文献文本结果。文献结果以XML的文件格式下载到本地文件系统上面,这样我们就得到了一个最原始的文本数据。
    通过以上方法得到了单一的文件,里面包含了76604篇有关磷酸化的文献,文件大小1.05GB,一共2000多万行,这么大的文件肯定不能同时加载到内存里去处理,所以我就把这么大的文件拆分成20个50多M的小文件,这样每个文件里包含了3000-4000篇的文献,用1-20来对每个拆分过的文件命名,这样下来,我们就得到了20个XML文件如图4-3所示,这20个文件就是我们文本数据源,也是文本数据获取模块的输出,文本预处理模块的输入。

    4.3 文本预处理文本预处理是文本挖掘中的一个关键的步骤,预处理的结果可以直接影响到最终挖出数据的质量和效果,所以这一步非常关键。文本预处理的主要的思想就是把源文本数据简单化,结构化,便于下一步的处理。
    经过上一步的处理,已经得到了源文本数据,这一步就对这些源文本数据作进一步的处理。仔细观察这20个XML文件的内容,图4-3展示了一篇XML的大致格式,发现里面对一篇文献描述的时候附加了很多的信息,比如说创建日期、收录日期、公司版权、作者等等,这些信息都是我们不关注的,无关紧要的信息,但是却占用非常大的空间内存,同时这些冗余的数据可能还会对接下来的文本处理带来不必要的麻烦。我们只关注数据是这篇文献的标题<ArticleTitle>,文献内容<ArticleTitle>,pubmed_ID标示符<PMID>,所以在文本预处理的阶段,我们要把这些冗余,无关紧要的数据给去掉,只要求保留Pubmed标示符、文献标题、文献内容这三个关键数据。这样下来,我们就做到简化了数据的目的。接下来我们要使这些文本数据具有一定的结构(这里的结构化并不是只能被计算机直接识别的那种结构化)。于是我们把每一个文件里面的3000-4000文献拆分成3000-4000个小txt文档,txt文档的文件名就是序号加文献标题,txt文档里的内容就是文献内容,于是我们就可以得到70000多个文献文档,这就是我们对文本预处理之后得到的文档集(Document Set),每一篇文档都对应于一篇文献,并且包含了文献的标题和内容。

    用Java程序实现上述的过程。首先XML文件的内容是一种它本身就是一个标示性可扩展标记语言(Extensible Markup Language),我们可以通过一些java开源库提供的API来对其进行解析。dom4j是一个非常优秀的JAVA开源库,处理的效率高,对于这么庞大的文本数据来说,dom4j的处理比其他的开源库的效果会更好。首先对20个XML文件进行for遍历,对于每一个文件,遍历每一篇文献<PubmedArticle>从中解析得到一些属性和标签,由于只要文献标题和文献内容,所以直接取<ArticleTitle>和<AbstractText>这两个标签下面的内容,然后再把<AbstractText>内容输出到新建文档中,文档命名为序号<ArticleTitle>。如果我们只在单线程拆分这些文件的话,效率可能不够高,我们也可以用多线程来预处理,用多线程的话,就不用for遍历这20个文件了,可以直接启动20个线程,每个线程里处理一个文件,启动20个线程的好处就是每个线程都处理不同的文件,不会发生资源互斥的问题。
    代码里面我先创建一个XMLParser静态工具类,里面全部实现两个静态方法,一个是解析XML得到里面的文献标题articleTitle和文献内容articleContent,另个是把文献标题和内容输出到一个文本文档里面,构成文档集中的一个文档。整个预处理过程的伪代码如图4-4所示。整个处理过程代码中有四个值得注意的地方,一是XML文件里面有些文献的标题的长度非常长,超过了linux文件系统下面支持的最大文件名称长度256字节,所以如果出现超过256的字节要进行相应的裁剪。二是有些PubmedArticle标签下没有包含Abstract标签,所以在处理的时候要加以判断,如果Abstract为空的话,那么就跳过这篇文献的处理,如果还继续输出一个空白的txt文档的话,空的文档对我们的数据挖掘根本没有贡献,反而在文本挖掘的时候或者统计的时候还可能会导致误差。三是有些Abstract标签下面会包含多个子标签,这些子标签里面的内容都是文献的内容,所以在输出的时候要把他们全部输出,不仅仅只输出单个的AbstractText。四是文献标题字符串中会有一些”/”这样的字符,我们把它作为文件名称输出的话,java的File类会认为这是一个子目录的标示符(类似dir/sub里面’/’表示的子目录的意思),所以在处理文献标题的时候要把标题里面的’/’字符用:代替,这样File类就会把这当成文件名称去处理。
    //文档预处理-生成文档集main(){ //第一步解析xml文件,把每一篇文献存入List中 List pubmedArticleList = parsexml(xmlFile); //第二步,对于xml里面的每一篇,都要把它写入文档及文件夹下面 for each pubmedArticle in pubmedArticleList{ addToDocSet(pubmedArticle,docSetPath); }}//对于每一篇article增加到文档集addToDocSe(pubmedArticle,docSetPath){ //1.首先要指定一下文档的名字 //这里采用pmid + title的形式来作为文件名 fileName = pubmedArticle.pmid + pubmedArticle.title; //2.建立文本文档 //文档的内容为pubmedArticle.content createFile(fileName,pubmedArticle.content,docSetPath);}4.4 命名实体识别和实体关系提取4.4.1 命名实体识别概述命名实体识别是文本挖掘过程中一个重要的过程,它在文本挖掘中的作用就是找出文本中具有特定意义的实体词语,比如说人名,歌名,影视名等等,同样地,生物医学命名实体识别(Biomedical Named Entity Recognition, Biomedical NER)也是生物医学文本挖掘过程中的关键任务,其目的是从生物医学文本集合中识别出指定类型的名称, 如蛋白质、基因、核糖核酸、脱氧核糖核酸等[10]。这是进一步抽取关系和其他潜在信息的关键步骤。
    命名实体识别是整个文本挖掘过程中的关键任务,因为有了识别出的实体,接下来的步骤才可能得到执行,同时它也是非常复杂的任务,里面夹杂着概率统计学,人工智能,机器学习,自然语言处理等各方面的学科知识。目前命名实体识别的方法主要分成三类,一是基于规则的方法,二是基于词典的方法,三是基于概率统计的方法[11],基于规则的方法就是特定的实体词语在文本中总是以一定的格式和规则呈现的,比如说书名,它一般是出现在《》书名号里面的。大多数的实体名词都是没有明显的特征和规则的,所以这种基于规则的实体命名方法非常不精准,而且局限性很大,但是它简单快捷。第二种命名实体识别的方法是基于词典的,它的思想就是把所有我们想研究的实体名词都收录在一本词典上,当在解析文本的时候就回去词典库里面去进行匹配,就像我们去查字典一样,这一方法需要人工录入巨量的词语到词典库里,它在识别词语的时候不会根据上下文的语境来识别,更加不会识别一词多义,有歧义的语法情况,只能匹配词典库里的词语,词典库里面有就能匹配,没有就不能匹配,所以这种方法在处理人类语言的时候不免捉襟见肘,漏洞百出。第三种实体识别的方法是基于概率统计的方法,也可以说成是基于机器学习的方法,这种方法也是在当今命名实体识别领域里面研究的重点,因为这种方法能够较为精确地识别出文本中的实体名词。它能够根据上下文语义环境来识别出里面的文本中的实体,并且能够识别出一词多义的词语。它的主要思想就是我们人工的将训练文档集中的实体名词找出来,并给其赋予一个词性标注,再根据上下文关系统计出一套可以让计算机学习的识别模型(语料库),然后计算机就能够根据这个模型来识别出未知文本中的实体名词了[12]。这样说的比较抽象,打个比方,我们要识别south china university of technology(华南理工大学)这个学校实体名词,首先我们的(识别模型)语料库里面有了这个词语,并且这个词语我们已经给与了其学校词性的标注,统计出了五个单词中每个单词出现在这五个单词中的概率和出现在整个语料库的次数,接下来有了这套概率,计算机在识别未知文本中的south | china | university | of | technology词语的时候就每个单词出现在上下文的环境下的概率最高的就是当它出现在语料库中词组south china university of technology学校实体名词,这样计算机就识别出了一个学校实体名词。目前有很多种建立语料库的概率模型,如贝叶斯模型、隐马尔可夫模型、支持向量机等等[13],这些方法都需要大量的训练数据,但是相对准确。
    4.4.2 ABNER命名实体识别工具生物医学领域上的应用非常广泛,ABNER,BallE等工具是比较出著名的命名实体识别的工具[11],本文以ABNER为实验工具来进行实验和开发,我们选择它的原因主要是第一,它是基于JAVA平台下开发的软件;第二,它是一个开源的系统;第三,它能够提供给我们JAVA的API接口,可以让我们进行第二次开发,我们能够把它的代码嵌入到我们的系统中去。图4-5是Abner工具一个简单的界面。

    ABNER是一款用于生物医学文本分析的软件,主要用于识别生物医学实体,它所使用的识别的方法就是基于统计概率的方法,首先它包含了NLPBA和BioCreative两个庞大的语料库其中包含了绝大多数已经发现的生物医学的实体,这两个语料库的F1测度分别是70.5和69.9[14]。它目前能够识别出得实体的类型大致有五类:蛋白质,DNA,RNA, 细胞系,细胞类型。此外,它不仅提供我们识别命名实体的接口,还提供了训练数据集、培养语料库的接口,所以理论来说,我们只要有足够多的语料库,我们就可以识别更多类型的实体,也不仅仅仅限于生物医学实体的识别。ABNER本质上就是一个基于概率统计的机器学习系统,采用了基于上下文特征的线性条件随机场的方法,线性条件随机场方法又是建立在隐马尔科夫模型(Hidden Markov Model,HMM)上的[15],隐马尔科夫模型是一个可以通过可观察到的状态(好比文本单词,这是我们可以观察到的状态)根据相关概率去发现隐藏的状态(好比文本单词的词性标注,单词词性标注是我们未知),所以如果发现了未知文本的词性标注,就可以识别出了实体。
    应用ANBER工具到我们的系统。首先我们进入ANBER网站http://pages.cs.wisc.edu/~bsettles/abner/ [16],下载abner.jar可执行的jar包,这也是可以依赖的三方库,图4-6展示了这个jar包里面重要的类的说明。如果直接运行的话,可以得到如图4-5的画面,输入一段待识别的文本,按下annotation按钮,它就可以识别出了文本中的生物医学实体,并且用不同的颜色进行标注和高亮显示出来。



    Input2TokenSequence
    Input2TokenSequence is a text processing Pipe for the MALLET framework.




    Scanner
    ABNER’s Scanner class implements the finite state machine used in tokenization.


    Tagger
    This is the interface to the CRF that does named entity tagging.


    Trainer
    The Trainer class will train a CRF to extract entities from a customized dataset.



    现在我把它通过三方库的方式引用到我的工程里面。首先实例化一个Tagger的对象Tagger t = new Tagger();再条用Tagger里面的方法getEntities(fileContent, “PROTEIN”);函数里面的第一个参数表示文献文本字符串,第二个是具体的哪一个标签,我们要识别文本里面的蛋白质实体就可以用”PROTEIN”作为函数的第二个参数。这样我们就可以获取文献里面所有的蛋白质的实体,图4-7是部分关键的代码:
    //实例化tagger对象Tagger t = new Tagger();//调用API方法,获得文中的实体String protein[] = t.getEntities(fileContent, "PROTEIN");由于系统还要挖掘出与蛋白质磷酸化修饰有关的激酶和修饰位点,所以我们必须还要继续识别文本中的激酶和修饰位点的实体名词,但是ABNER工具只提供了蛋白质,DNA,RNA, 细胞系,细胞类型五个类型的实体,所以我们还要对这些实体进行训练,培养一个能够识别激酶和修饰位点的语料库。ABNER工具给我们提供了训练语料库的接口。我们可以初始化一个Trainer的实例,调用Train里面的train(trainFile, modelFile)方法,trainFile就是训练文本的路径,modelFile就是语料库模型文件的路径,比如想识别一个磷酸化修饰的位点(Ser32),我们可以在trainFile的文件里面填写训练的规则,官方的demo里面介绍了如何填写训练集文件,图4-8是官网demo的一个训练格式。训练文件的规则概括成四点:一,每一句话要按照每个token(可以理解为每个单词)空格间开,并且一句话写在一行;二,每一个token的左边的单词,右边是词性标注,两者用‘|’符号间隔开;三,每一个实体的第一个单词的词性标注前要加前缀B-,剩下其他的单词前面要加前缀I-;四,每个不是实体的单词的词性标注要设为O。用着我们训练一段能够识别位点的训练集如图4-9所示。生成一个model,然后用model作为语料库去识别出文档里面的为位点实体。图4-10中的代码说明了如何训练一个语料库,并使用语料库进行识别文档的。
    <pre>IL-2|B-DNA gene|I-DNA expression|O and|O NF-kappa|B-PROTEIN B|I-PROTEIN activation|O ...</pre>GRK6|O phosphorylates|O IκBα|O at|O Ser32|B-POSITION or|O Ser36|B-POSITION and|O enhances|O TNF-α-induced|O inflammation|O .|O//第一步 训练得到语料库Trainer t = new Trainer();t.train(trainTextPath, modelTextPath);//第二步,用训练出来的语料库去识别文本Tagger t = new Tagger(new File(Config.MODEL_PATH));String res[] = t.getEntities("GRK6 phosphorylates at Ser32 and enhances TNF-α-induced inflammation.", "POSITION");经过以上的步骤,我们可以通过abner里面自带的语料库去识别文本中的命名实体,也可以自己训练想要识别的实体的语料库来识别。
    4.5 实体关系提取4.5.1 关系提取概念经过命名实体识别之后,现在就要提取实体之间的关系,这一步称之为实体关系提取。实体关系的提取性能的关键因素在于实体识别的准确率,实体识别越准确,关系提取的性能就越高。目前主要有五种实体关系提取的方法[17],第一种是基于模式识别的提取方法,基于模式识别的方法是普遍使用的提取方法,这种方法主要使用了语言学的知识,在提取实体关系之前,先预先定义出一些基于句法、语义、等一些结构的模式,然后在提取的过程中,把待处理的文本片段与这些模式进行匹配,然后通过一定的计算得出是否匹配,如果匹配则这文本片段具有该模式所包含的关系特征,从而可以判断出改文本中的实体之间具有某种那个关系;第二种是基于词典驱动的提取方法,基于词典的方法相比模式匹配的方法具有较高的复用性,用户想匹配新的实体关系的时候不用具备所有的语法,语义模式,而只需往词典里面添加新的关系词语,系统即可根据词典来提取相应的关系;第三种是基于机器学习的提取方法,这种方法的核心思想就是把实体关系提取看做是一种分类,进而关系提取就相当于是一次类别的判断。运用此方法之前我们需要手动地对分类器培养一批语料库,然后分类器应用这些语料库对文本进行分类,从而得出相应的关系;第四种基于Ontology的 提取方法,最后一种是混合式的提取方法。
    4.5.2 Rlims-p工具介绍及其工作原理Rlims-p是一款典型的基于规则的文本挖掘工具[18],它是针对于挖掘提取蛋白质磷酸化修饰的信息,包括蛋白质底物信息,修饰激酶信息,修饰位点信息,还包括了前三者之间的关系信息等等。本篇论文中的核心文本处理的机制就是围绕着Rlims-p程序展开的。采取此工具的原因主要概况为两点,一是从功能上来说,这款工具恰好完全能够帮助我提取文献里的实体,并且找出其中的关系,这也是本次论文设计的主要目的,二是这款工具给我们开发者提供了Rlims-p文本处理的接口,只要把文献的内容通过传参的形式发送至对方的服务器,对方就会及时处理并且把结果返回,这样就可以在rlims-p的帮助下进行二次开发。
    Rlims-p工具里面主要包含两个主要的模块构成,第一个模块是自然语言处理模块(NLP Pipeline),第二个模块是信息提取模块。每个模块里面有分很多个处理步骤。图4-11展示了Rlims-p的模块结构图[19]。

    第一个自然语言处理模块其实就类似于一个命名实体识别的一个过程,输入一个文档集进去,输出的结果就是文本里每个短语的词性,当然这个短语并不一定就是命名实体,词性就是描述这个短语在上下文中的类型,比如说是动词,名词,基因,蛋白质,蛋白质附属物,化学物质等等。自然语言处理模块内部又分为了若干的小步骤包括了格式化数据,句子拆分,token化,单词标注,分词,短语类型标注等等,这些标注对第二个模块里面的模式匹配有着重要的作用,稍后再提到。第二个信息提取模块就是把第一个模块里的输出作为输入,然后提取出文中短语之间的关系,判断出短语具体是蛋白质还是激酶还是位点等等,最后输入的就是检索的标注了,这个标注里面包含了,各个蛋白质,激酶,位点的名称,以及实体之间的关系。这个模块所使用到提取关系的方式就是基于规则的关系提取方法。首先它预先定义了触发器-参数模式,扩展模式,链接关系模式三大模式,然后根据这三大模式再在文本中进行模式匹配,根据匹配的结果再进行判断。
    模式一:触发器-参数模式,它是最普遍的模式,里面包含了名词加动词的语法结构,比如说A phosphorylate B,A phosphorylate B in C,B phosphorylated by A in C等等,phosphorylate是触发器,A,B,C都是参数。根据语法规则,在描述蛋白质磷酸化的句子中语法结构一般都是激酶磷酸化了蛋白质在某某位点上,所以在上述我们可以大概推出A可能是激酶,然后再结合A的类型(第一个模块里面已经获取了短语A的词语类型)加以判断,如果A类型是蛋白质类型,那么就认为A就是一种激酶(激酶也是一种特殊的蛋白质)。在语法结构A phosphorylate B中,根据英语的语法我们可以大概退出B可能是被修饰的蛋白质,也可能是位点,那B具体是啥,这样根据模块一种得出的短语B的词语类型,假如说B是蛋白质类型,那么B就是被修饰的蛋白质,如果B是蛋白质上的附属物,那么B就是位点(位点是蛋白质上的一部分)。由此可见在这个模块里不仅可以发现短语之间的关系,还能够确定短语究竟是属于被修饰的蛋白质,还是激酶,还是位点。模式二:扩展模式,由于英文语法的多样性,表示这三者之间的关系不仅仅只靠以上几种语法结构就能匹配的,于是又新增了很多扩展的模式来匹配,模式三:链接关系模式,在英文语法中会出现这样的情况,A phosphorylate protein such as x,xxx,protein先行再前,其真正的主体是x,xxx,所以protein和x,xxx有着链接的关系。这样的先行词和先行词后面紧跟定义的链接关系还有很多种,所以在这里必须要考虑这样一种情况。
    4.5.3 嵌入使用Rlims-p工具打开Rlims-p工具的网址http://research.bioinformatics.udel.edu/rlimsp ,点击页面的Web Service超链接,他给我们提供了一个网页服务编程接口,我们可以通过Http请求中的post方法并把待处理的文本数据转换成post参数,发送至服务地址http://annotation.dbi.udel.edu/text_mining/bioc/bioc.php 上[20],服务器就回处理并返回一个XML格式的文本文件,里面包含了处理之后得到的实体名称,和实体之间的关系。
    4.6 多线程处理文档优化考虑到我们文档集中的文件数量非常庞大,如果在同一个线程里面处理这么庞大的文件的话将会非常耗时,所以我不得不采用多线程的方式来并发的处理文档集里面所有的文档。JAVA语言特性也是支持多线程开发的,更方便的是JAVA库java.util.concurrent中提供了线程池的工具,方便我们管理和调度线程。为了避免多个线程同时处理同一个文档,尽量让每个线程都独立,互斥的运行,我设计了两套解决方案,第一种方案是在同一时候只允许一个线程去文档集里面取文档,并把文件标记为已读,取到要处理的文档之后各个线程该干嘛就干嘛,互不影响,直到文档集全部处理完毕。(PS : 取文档只是一个获取对文档的引用标识,耗时远远低于处理文档的时候,所以同一时刻只有一个线程获取文档的引用并不影响程序的效率)。Java运用synchronized关键字和同步锁的机制可以实现同一时刻只用一个线程在取文件,线程在执行带有关键字synchronized的方法的时候会检查一下同步锁有没有被释放,没有释放就表示正有线程在运行这个方法,就会一直等待直到同步锁被释放再运行。第二种方案是首先预先分配线程池的大小,然后再把文档分给各个线程去处理,每个线程要处理的文件的数量都保持差不多的水平。比如说,我有一万个文档要处理,文档编号从1-10000,那么首先分配一个最大支持50个线程同时运行的线程池,再给每个线程分配200个待处理文档,文档的序号要分段开来,线程1处理1-200的文档,线程2处理201-400的文档,依次类推,直到所有的文档集都分配完成,这样一来每个线程都知道自己要处理哪一批文档,不会发生越界的情况。但是第二种方法的不好之处在于假如某个线程所处理的文档内容非常小,一下子就处理完毕了,那么这个时候这么线程就结束了,它不会去为别的线程分担压力了,线程池里面就少了一个线程,就不能时时刻刻发挥线程池处理的最大能力了,而第一种方案,线程池里面时时刻刻都能够保持最大的线程数量,除非待处理的文档数量少于线程数量了。形象地来说,第一种方案像一个非常团结的团队,团队中的每一个人做完了一个任务后就争着去抢下一个任务做,直到任务全部完成为止。第二种方案像一个自私的团队,团队中的每一个人随机的领了相同数量的任务,任务做得快的人就早早地下班了,不会帮别人分担,任务做得慢的人就加班加点完成任务,但是最终的效率是由最后一个完成任务的人决定的,所以从效率来说显然是第一种好过第二种,所以在程序设计的时候,我采用的是第一种方案,图4-12展示了方案一的处理流程图。Pubmed文献库中和磷酸化先关的文献有20多万篇,如果只用一个线程去处理的话,再加上用Rlims-p工具本身就非常耗时的网络请求的话,那么处理这20万篇的文献的耗时将会达几十天,如果处理的文献数量达到几百几千万篇的时候,那么我相信一台电脑的计算能力就不太够用了,可能就要用到分布式机制的才能够提高处理的效率。

    4.7 文档预处理和缓存机制
    在客户端发起的请求,服务端要处理一段时间后才会返回给用户,这个时候用户就需要等待了,文档数量如此庞大,如果有很多个用户同时来请求的话,那服务器处理的时间就会变得很长,返回给用户的时间也就会变得很长,为了解决此问题,提升程序的用户体验,我们要预先对所有的文档进行处理,并且把处理后文档的结果保存再缓存区里面,然后每次用户请求的时候,服务端这边直接把缓存区里面的结果直接返回给用户,这样的话就减少了很多用户等待的时间,图4-13展示了缓存机制的一个逻辑流程图。第一步我们需要对文档进行预处理,预先找出文档里面的实体和关系,这一步也需要用到先前提到的多线程的处理方式来处理,然后把这些结果通过文件的形式保存在文件系统里面,通过文件名来作其的键值key,文件内容则是value。在JAVA里面把一个java Object(文档处理结果)输出成一个文件,用到了序列化的机制,通过让这个java object实现序列化,然后通过FileOutPut把它以字节流的方式输出,最后得到的文件就是我们的缓存文件。有了缓存之后,用户请求发送过来之后,首先我们会根据用户发送过来想要处理的文档的id来去缓存文件夹下面去找对应的缓存文件,如果找到了就把这个结果返回给用户,如果没找到的话就按照正常的流程来处理文件,处理完成之后再把处理结果存进缓存文件夹,这样一来,对于文档集新增的文档还没来得及做一次预处理,这个时候用户只需再第一次请求的时候进行等待,之后的请求都可以从缓存直接获取不用等待了。
    第五章 数据库设计和数据可视化5.1 数据库设计从需求上来看,需求是要从给定的pubmed文献中挖掘出文本中的被修饰的蛋白质,激酶,和位点这三种实体,以及这三种实体之间的关系。由此我们可以归纳出数据库中表里的字段,表5-1给出了表中的字段以及字段的含义。



    Id
    自动增长的id,主键




    Pmid
    pubmed文献在文献检索系统中的id


    Title
    pubmed文献的标题


    Text
    Pubmed文献的内容


    Substrate
    被修饰的蛋白质


    Kinase
    修饰蛋白质的激酶


    Position
    修饰蛋白质的位点


    Acid
    文中氨基酸实体


    phosphorylation
    磷酸化的词语或短语


    Relation
    实体之间的磷酸化的关系



    表中一共有十个字段,其中蛋白质,激酶,位点等这种实体的每个字段可能有多个实体短语,所以我们规定这些短语之间用逗号隔开,另外同一个实体可能出现在不同的字段里面,例如实体A在关系R1里面充当了蛋白质的角色,而在关系R2里面充当了激酶的角色(激酶也是一种特殊的蛋白质),这样的话实体A既出现在蛋白质字段里面,也出现在激酶字段里面。实体关系这个字段比较特殊,因为文献中可能包含多种关系,或者不包含关系,而每一个关系包含了五种类型的实体,为了简单起见我们还是把这个关系保存在一个字段里面,而不是新建一个表专门用来存储关系,首先relation字段在程序里面的数据结构是一个List,List中的每一个element就是每一种不同的关系,关系element的数据结构又是一个map<key,value>,key就是字段名,value就是识别出来的实体。综合来说关系在程序中的数据结构就是List<Map>,在java程序中采用List中的toString成员方法可以把关系结构转换成一个字符串,再把这个字符串保存至数据库。
    本系统采用的是mysql数据库,通过jdbc驱动实现了java代码新建数据库,表,插入数据等操作。往数据库插入数据的时机和缓存是一样的,首先是预缓存一遍,同一样也是预插入数据库一遍,然后对于文档集中新增的文档,如果没缓存的话,用户在请求处理此新增的文档后,服务端就会对新增文档处理的结果进行一次缓存,然后再把处理的结果插入到数据库当中去。建立此数据库是为了之后对结果进行归纳,分类整理等处理,图5-2展示了本系统中数据库的图形界面。

    5.2 数据可视化经过以上几个步骤我们大致就将一个粗糙的文件里面的有用的信息全部挖掘,并整理出来了。但是以上挖掘出的数据仅仅只是java里面的object对象,或者是数据库里面存着的一些字段,这些数据对于用户显然是未知的,用户希望看到的是图片或者表格这种直观的表现形式的数据,所以最后还需要把挖掘出的数据通过直观的形式展现给用户。
    整体系统采用的是C/S的架构,服务端用来专门处理来自客户端的请求,并返回数据给用户,客户端是发起请求和处理从服务端返回的数据,除此之外客户端也是直接和用户交互的设备,所以数据可视化的工作处理理论上应该由客户端来处理,大概思路就是客户端收到服务端返回的数据之后,通过图形化控件将数据整理,封装。我理解的客户端是只是用来呈现数据的一个软件或者一种手段,客户端软件和平台有关,客户端软件一般和平台有关,比如说Android客户端,IOS客户端,window客户端,Mac客户端等等,各种操作系统的平台都有。Html也是一种解决方案,各个平台的设备上都包含有游览器这个软件,所以只需打开游览器查看服务器返回的数据即可,游览器内核会自己去解析数据里面的各种标签。Html相比其他各个平台的客户端来说,首先html是跨平台的,其次html是不需要下载客户端软件的,直接打开游览器出入地址就行了,简单方便明了。所以本系统也是采取了html的解决方案,通过服务端返回html格式的文本文件给浏览器处理。


    本系统采用的是JSP技术,所以每个客户端页面可以看做是一个jsp页面,jsp中包含了html标签页和java代码。一共有两个页面,第一个页面是搜索页面searchpage.jsp,如图5-3所示,这个JSP里面包含了一个搜索框和一个列表,搜索框可以输入关键字和pmid,可以从文档集中搜索出相关的文献,列表里面装有所有搜索出来的文档,如果没有搜索列表里面默认就是文档集中所有的文档,搜索页支持分页的展示如图5-4所示。,然后点击列表里面的一个item文档的话,就会跳转到第二个JSP页面,这个JSP是对应的详情页面,就是展示挖掘出这篇文档的结果,如图5-5和图5-6所示。图中里面展示了整篇文档的pmid,标题,原文,文中的实体,以及实体之间的关系,识别出来的实体会在原文中通过高亮的形式展现出来。实体高亮是通过给文中的实体字符串的两边加上一个特殊的标签,比如在文中被修饰蛋白质实体的两边添加一个类型为蛋白质的标签<span class = ”protein”></span>,然后通过CSS语法指定<span>标签下的文本的背景色,各个实体的具体颜色由标签<span>里面的class属性决定。实体和关系的表格则是通过html5下面标签<table>来实现的。


    第六章 总结及展望6.1 总结本篇论文主要叙述了文本挖掘技术在生物医学领域上的应用,并且切合实际需求开发了一套有关于蛋白质翻译后磷酸化修饰的信息挖掘系统。随着当今互联网时代信息数据高速增长,文本挖掘技术在处理大量非结构化的数据变得越来越重要,文本挖掘技术在相关领域中的应用也变得越来越重要。
    结合当今的文本挖掘技术和实际需求,文本详细叙述了蛋白质翻译后磷酸化修饰的信息挖掘系统的设计与开发。从整个系统工程来看,从需求到设计再到开发,这一流程是严格遵循软件工程中的瀑布流模型的规范。开始首先是通过需求分析获取需求或者是程序的功能,给出具体的需求场景和用例图,然后根据需求来设计整个系统的大体框架,把整体系统分为不同模块,然后依次进行各个模块的开发工作。文本挖掘技术的思想贯穿整个程序,一般的文本挖掘技术的步骤有4个大致步骤:首先是文档预处理,接着是命名实体识别识别,再是知识模型提取,最后是知识模型的评估等等,这对应程序里面的首先是对pubmed文献文件进行预处理,把pubmed文献整理成一个文当集,接着是识别文档里面的文档里面的蛋白质,磷酸化实体等,再是对实体之间关系的提取(知识模型提取),最后是评估。
    通过整套系统,生物医学研究者们可以快速获取pubmd文献里的关键信息,比如说被修饰的蛋白质,参与修饰的激酶,修饰位点等等信息,研究者们可以不用通读全文,也能得到这些信息,大大提高了他们阅读文献的效率。对于pubmed文献数据库里面上千万篇的文章,研究者们不可能去用肉眼一一去判别,必须通过计算机去处理得到研究者们想要的东西。
    6.2 展望如今文本挖掘技术已经日趋成熟,并且已经在多个领域已经开始使用,所以文本挖掘技术的准确率和召回率也是却来却多人关注,文本挖掘技术综合了人工智能,机器学习,概率统计学,自然语言处理等各方面的学科,所以我们最希望的就是每一个学科都可以在自己的领域里达到100%的准确率,这些精确度很大一部分取决于机器学习的好和坏,理想情况下,给训练机器训练的东西足够多,训练库也是足够好的,它是能够根据学过的知识给出一个非常满意的判断,当然各个领域都在充实自己机器的训练集,让机器不断学习,来提升准确率,这在未来应该也是一种趋势,因为世界在不断变化,知识、概念、词汇在不断扩展,机器不仅要学会现已有的,更要学会未来人类新增的知识,才能不断成长。此外,未来文本挖掘的重点应该是去从茫茫文本中挖掘出人类未知的知识模型,就好像Marti Hearst说的文本挖掘和信息挖掘最大的区别就是,信息挖掘是你输入一个关键字,挖掘出的信息是你已经预料到的,是已经被发现了的东西,而文本挖掘是输入一个关键字,挖掘出的是你并未知道的知识模型[21]。
    结束语本篇论文主要叙述了文本挖掘技术在生物医学领域上的应用,以及蛋白质磷酸化修饰后信息挖掘系统的具体实现,本系统能够有效的识别出有关于磷酸化信息的文献,并且也能够识别出文本里面的蛋白质实体,激酶实体,和位点实体,效果图可参见图5-5和图5-6,准确率召回率和rlims-p工具本身保持一直,和rlims-p训练语料库的有关。本系统避免了研究人员们人工去查阅文献,大大提高了他们的效率
    参考文献[1] 梅馨,邢桂芬.文本挖掘技术综述〔J〕.江苏大学学报(自然科学版),2003
    [2] 谌志群,张国煊.文本挖掘研究进展〔J〕.安徽: 模式识别与人工智能
    [3] Wilco W.M. Fleuren, Wynand Alkema.Application of text mining in the biomedical domain. Elsevier,2015
    [4] 百度百科.蛋白质合成. http://baike.baidu.com/view/1945127.htm,2015
    [5] 周雪忠.文本挖掘在中医药中的若干应用研究〔R〕.浙江大学计算机科学与技术学院,2004
    [6] 阮班军,代鹏,王伟.蛋白质翻译后修饰研究进展〔J〕.中国细胞生物学学报,2014
    [7] 胡笳,郭燕婷,李艳梅.蛋白质翻译后修饰研究进展〔J〕. 科学通报,2005
    [8] 薛为民,陆玉昌.文本挖掘技术〔J〕.北京:研究北京联合大学学报(自然科学版),2005
    [9] 李希明,邓大军. PubMed免费MEDLINE检索方法与技巧研究〔J〕. 情报理论与实践,2004
    [10] 王浩畅,赵铁军.生物医学文本挖掘技术的研究与进展〔J〕.北京:中文信息学报,2008
    [11] 吕婷,姜友好. 􏰈􏰉􏰊􏰋􏰌􏰍􏰎􏰏􏰐􏰑􏰅􏰒􏰓􏰔􏰕􏰖􏰗􏰘􏰙􏰚文本挖掘在生物医学领域中的应用及其系统工具〔J〕.北京:中华医学情报杂志,2010
    [12] 赵红丹,王希杰.基于隐马尔科夫模型的词性标注〔J〕.安阳师范学院学报,2013
    [13] 孙镇,王惠林.命名实体识别研究进展综述〔J〕. 现代图书情报技术,2010
    [14] Burr Settles .ABNER: an open source tool for automatically tagging genes,proteins and other entity names in text. http://burrsettles.com/pub/settles.bioinf05.pdf , 2005
    [15] Burr Settles. Biomedical Named Entity Recognition Using Conditional Random Fields and Rich Feature Sets. http://burrsettles.com/pub/settles.nlpba04.pdf , 2004
    [16] Abner.A Biomedical Named Entity Recognizer. http://pages.cs.wisc.edu/~bsettles/abner/,2005
    [17] 徐健,张智雄,吴振新.实体关系抽取的技术方法综述〔J〕.现代图书情报技术,2008
    [18] 殷蜀梅.基于Medline的医学数据挖掘系统研究〔J〕. 现代图书情报技术,2007
    [19] Manabu Torii, Cecilia N. Arighi. RLIMS-P 2.0: A Generalizable Rule-Based Information Extraction System for Literature Mining of Protein Phosphorylation Information. IEEE/ACM Transactions on computational biology and bioinformatics, 2015
    [20] RLIMS-P webservice. http://research.bioinformatics.udel.edu/rlimsp/,2005
    [21] Marti Hearst . What Is Text Mining?http://people.ischool.berkeley.edu/~hearst/text-mining.html, 2003
    1 评论 1 下载 2019-07-08 10:57:54 下载需要15点积分
  • 基于cocos2d-x实现的全民打飞机小游戏

    一、概述1.1 介绍本程序是本科生毕业设计做的一款飞行射击类游戏,模仿的是微信上的游戏全民打飞机,本游戏中大多数的素材也都是来自于全民打飞机游戏中。
    本游戏主要是以Cocos2d-x为游戏引擎,以C++高级程序语言为编程语言,在Windows 8.1操作系统下使用Microsoft Visual Studio 2013、Eclipse等工具开发并最终移植到Android手机平台上。
    下面是本游戏的游戏画面(动态图):

    1.2 文件说明1.2.1 Classes本文件是游戏主代码所在,至于各个代码的用途请参看说明文档。
    1.2.2 resources本文件中存储的有本游戏使用的音效、字体、以及材质包。其中材质包使用texturepacker软件打包。
    1.3 游戏截图游戏欢迎界面

    选关界面

    选择主角飞机

    游戏进行中

    左上角为暂停按钮右上角为积分面板左下角为导弹按钮右下角为血量面板
    图中心性飘动物是加血道具

    图中飘动的是加导弹道具

    图中飘动的是加子弹攻击力道具
    还有一个未显示道具是增加子弹列数,即可以增加发射子弹数。




    结束画面

    二、开发工具及技术C++高级语言程序
    C++是在 C 语言的基础上开发的一种通用编程语言,其编程领域众广,常用于系统开发,引擎开发等应用领域,是至今为止最受广大受用的最强大编程语言之一。
    Cocos2d-x 引擎
    Cocos2d-x 是一个开源的移动游戏框架。Cocos2d-x 提供框架围绕 Cocos2d 跨平台为重点发展,其项目很容易在 iOS,Android 等手机平台上运行。
    Microsoft Visual Studio 2013
    Vs2013 是微软公司在 2010 年第二季度推出的开发环境。其集成开发环境的界面被重新组织与设计,使用起来更加简单明了。这是本软件编写的主要工具。
    Eclipse
    Eclipse 是一个基于 Java 的、开源的、可扩展开发平台。是人气最旺的 Java IDE 之一。
    Python 高级语言
    Python 会在软件开发周期中有一些简单的运用。
    三、系统基本功能基本规则
    各种各样的敌机从远处不断的袭来,他们攻击力、飞行速度、形态各不相同,但他们的目的是一样的,那就是杀死主角。当飞机碰到主角飞机是,主角飞机会受到伤害,同时敌机也会受到伤害,直至生命值为零。当然主角飞机会不断发射子弹以阻止无穷无尽的飞机冲向自己,当子弹碰到敌机时会给敌机造成伤害,直至生命值为零。
    操控
    无论是攻击敌机还是躲避敌机的攻击都需要玩家操控主角飞机进行移动。本游戏的移动操作是通过手指(鼠标)在屏幕上移动实现的。当手指(鼠标)触摸在飞机的碰撞体积上时,碰撞事件被触发。
    敌机 AI
    为了让游戏看起来更加生动,本游戏给所有的敌机添加了一定程度的 AI。有的敌机会按既定的曲线行进,有的会自爆似的冲向主角飞机,有的飞机并排出现。这些动作不一的敌机大大增加了游戏的乐趣和体验。
    游戏模式设置

    闯关模式。闯关模式设有三个关卡,每个关卡都会有不同的敌机和 BOSS
    无尽模式。无尽模式中没有 BOSS,只有无限多的普通敌机
    BOSS 模式。BOSS 模式中只有闯关模式中的 BOSS,是游戏模式中最难的

    游戏难度设置
    游戏基础难度设置总共分为三种:easy、normal、hard。 若游戏为闯关模式。越到后面关卡敌机和 BOSS 的血量和攻击都会上升。若游戏为无尽模式。无尽模式游戏难度不仅会随着游戏基础难度变化而变化,也会随着游戏积分的增加而增加。 若游戏为 BOSS 模式。BOSS 模式中的 BOSS 也会随着游戏基础难度的增加而增加。
    游戏礼物
    为了增加游戏的乐趣,本游戏为玩家添加了游戏道具。 本游戏的游戏礼物共有四种:

    增加子弹的列数。得到该道具后主角飞机外观会做出相应改变
    增加子弹的伤害。得到该礼物后子弹的外观会做出相应改变
    大招礼物。得到该礼物后,会有一次机会释放一排导弹,导弹从屏幕底部飞至屏幕上部
    加血礼物。得到该礼物后,主角飞机血量会增加

    成就
    为了增加玩家对游戏的不断挑战的乐趣。本游戏增加了成就系统。
    本地储存
    为了激励玩家挑战自己,游戏增加了最高分数设置。每次游戏结束,游戏都会读取本地历史最高分数,如果当前分数超过了历史最高分数,则将当前分数作为最高分数存储起来。
    游戏帮助
    为了使新手玩家能够更快适应游戏,本游戏设置有游戏帮助,使其能快速了解本游戏。
    游戏音效
    为了使游戏更加立体、生动,本游戏设置了游戏音效,当然如果主角不喜欢游戏中音乐,可以在游戏中关闭。
    四、系统设计4.1 系统流程图玩家启动游戏后,游戏会预先载入必要的游戏音效和图片等资源文件。进入欢迎界面后可以选择查看游戏帮助还是开始游戏。点击开始游戏进入选关界面,在此玩家可以选择自己想玩的关卡。进入游戏后游戏会检测玩家战机是否与敌机相撞、子弹是否击中敌人。 当子弹打中敌人后,若敌人血量降为零,执行爆炸动画并增加积分。若主角与敌机发生碰撞,判断敌人是否血量降为零,执行爆炸动画并增加积分,并且判断主角血量是否降为零,若是,直接进入结束界面。若本场分数超过最高分数,则将分数写入本地。在结束界面中可以选择是否接受和是否重新开始。若玩家选择的是闯关模式,游戏会在一定时间后加入关主(BOSS)相关资源。若玩家选择的是无尽模式,游戏难度会随着时间难度的增加而增加。若玩家选择的是关主模式,游戏只会载入关主(BOSS)资源,不会载入普通敌机资源。系统流程图如图 2.1 所示。

    4.2 系统基本思路几乎所有软件的开发阶段都是从系统设计正式开始。这部分任务是把之前所做的分析模型转换为软件的设计模型。设计模型会描绘出软件的总体概貌。但由于此过程一般为迭代过程,在设计之后有可能再回到分析,又由于篇幅有限,所以在本文中会以最简洁的方式描述(若在系统设计中回到了分析,本文将不再过多描述,直接描述出主要成果)。最终,会把软件的每一个环节细化,把它加工成非常接近目标程序的模型表示。
    4.2.1 游戏执行模块设计游戏执行模块会在游戏每一帧中执行,算法分为以下几步:

    判断主角战机是否与敌机相撞。若相撞则执行主角模块和敌机模块
    判断子弹是否击中敌机。若击中则执行敌机模块和积分模块
    判断主角是否与礼物相撞。若相撞执行相应礼物模块和主角模块
    判断敌机子弹是否击中主角。若击中则执行主角模块

    4.2.2 主角战机移动模块设计游戏添加了三种战机,属性如表 3.1 所示:



    主角战机
    血量
    攻击力
    大招攻击力




    主角战机一
    500
    150
    800


    主角战机二
    1000
    100
    400


    主角战机三
    1500
    50
    200



    主角战机移动算法分为以下几步:

    检查每一帧,鼠标是否点击屏幕,若触摸则进入下一步
    判断鼠标点击位置是否在飞机碰撞矩形内,若在则进入下一步
    判断鼠标是否抬起,若未抬起进入下一步,若抬起返回第一步
    判断此时主角飞机是否超过屏幕,若超过则将飞机坐标设置为屏幕最大边缘处。 若没有则执行下一步
    将飞机坐标设置为当前鼠标位置

    4.2.3 主角模块的设计主角模块分为闯关模式主角模块、无尽模式主角模块、关主(BOSS)模式主角模块,分为以下几步:

    游戏每一帧执行主角战机移动模块
    判断主角血量是否小于零,若小于则执行下一步
    执行主角爆炸动画,移除主角和主角发射的子弹

    4.2.4 子弹模块设计子弹模块设计可以分为主角战机模块和 BOSS 子弹模块。子弹属性如表 3.2 所示:



    子弹
    初始伤害
    加伤害礼物加伤害量




    主角子弹
    100
    25


    关主(BOSS)子弹
    100




    算法分为一下几步:

    获取主角(BOSS)坐标位置
    计算主角(BOSS)坐标与屏幕顶部距离,再计算出子弹运行时间
    添加子弹精灵到场景中,并使子弹从飞机位置向屏幕顶部移动
    判断子弹是否击中敌机(主角),若击中跳转游戏执行模块并回收子弹,否则执行下一步
    子弹移动至屏幕外后回收子弹

    4.2.5 敌机模块设计敌机一共有五种类型,属性如表 3.3 所示。



    敌机
    血量
    速度(像素每秒)
    飞行路径
    积分
    几率




    敌机1
    300
    200
    贝塞尔曲线
    100
    30/100


    敌机2
    400
    200
    三架并列飞行
    200
    15/100


    敌机3
    500
    180
    单架敌机飞行
    100
    15/100


    敌机4
    350
    250
    冲向主角
    100
    20/100


    敌机5
    150
    200
    三架并排飞行
    100
    20/100



    算法分为以下几步:

    对五种飞机素材进行渲染,并加入到敌机数组中
    随机添加各种敌机精灵,并按各自的飞行速度以及飞行路径飞行
    若敌机被摧毁,执行爆炸帧动画,在敌机数组中删除敌机精灵并增加积分
    若敌机飞行至屏幕底部,在敌机数组中删除敌机精灵
    判断是否为闯关模式,若是则执行下一步
    判断是否加入 BOSS,若是添加 BOSS,并执行 BOSS 模块

    4.2.6 积分模块设计积分模块算法分为以下几步:

    每击毁一架敌机,增加相应分数并显示
    判断游戏结束时比较当前分数是否比历史最高分数高,若是则覆盖历史最高分数并显示

    4.2.7 礼物模块设计礼物分为四种,分别是大招礼物、伤害礼物、子弹列数礼物和加血礼物。礼物会根据当前积分随机添加礼物。各礼物属性如表 3.4 所示。



    礼物
    功用
    出现概率




    大招礼物
    增加大招数目(最大为1)
    3/10


    伤害礼物
    增加每个子弹伤害
    3/10


    子弹列数礼物
    增加子弹列数(最大为3)
    1/5


    加血礼物
    增加主角100血量
    1/5



    算法如下:

    渲染礼物图片,添加礼物到礼物数组中并且随机添加一种礼物到场景中
    礼物从屏幕顶端移动至屏幕底部
    判断礼物是否与主角相撞,若是为主角增加相应功用,并从礼物数组中删除该礼物。否则执行下一步
    若礼物位置超过屏幕底部,则从礼物数组中删除该礼物

    4.2.8 关主模块设计关主模块分为闯关模式关主模块和关主模式关主模块。其中闯关模式有三种 BOSS,关主模式有四种 BOSS。下面以关主模式关主模块为例。各 BOSS 属性如表 3.5 所示。



    关主
    关主血量
    出现几率




    关主1
    18000
    3/10


    关主2
    23000
    3/10


    关主3
    28000
    2/5


    关主4(仅关主模式)
    28000
    2/5



    渲染 BOSS 图片,添加 BOSS 图片至 BOSS 数组中并且随机添加一个 BOSS 到场景中。 BOSS 出现后开始发射子弹。

    判断子弹与主角是否相撞,若是则执行主角模块。否则进行下一步
    判断 BOSS 与主角是否相撞,若是则执行主角模块
    判断 BOSS 是否摧毁,若是从 BOSS 数组中删除该 BOSS。并且跳转至结束场景

    4.2.9 游戏模式模块设计游戏模式分为闯关模式、无尽模式和 BOSS 模式。闯关模式相当无尽模式会有三个关卡,每个关卡都有一个关主,通过每关后会进入下一关。BOSS 模式相对于闯关模式,区别是 BOSS 模式只会出现 BOSS 精灵,而且 BOSS 模式会比闯关模式多一种 BOSS。
    4.2.10 碰撞检测模块设计碰撞检测模块包括有主角子弹与敌机之间的碰撞检测、主角与敌机之间的碰撞检测、主角与 BOSS 子弹之间的碰撞检测、主角与 BOSS 之间的碰撞检测。
    Cocos2d-x 中每个精灵自带一个碰撞矩形,如果两精灵矩形有交集的话说明两精灵发生了碰撞。

    4.2.11 音效模块设计游戏需添加静音按钮以方便有的玩家有不想开音乐的情况。并且游戏需为每个场景加载不同的背景音乐,需添加了子弹发射的音效以及敌机爆炸的音效等。
    4.2.12 游戏帮助模块设计添加帮助图片以帮助玩家更快的了解本游戏。
    4.3 子弹渲染优化在游戏的绘制渲染中,往往消耗很多资源和内存,当绘制精灵数量越多,游戏的卡顿会很明显,游戏中的子弹又是会很多,如果每个子弹都进行一次渲染,游戏会出现明显卡顿。为了优化和提升渲染效率,Cocos2d-x 为我们提供了 SpriteBatchNode。
    SpriteBatchNode 是批处理绘制精灵,主要是用来提高精灵的绘制效率的,需要绘制的精灵数量越多,效果越明显。因为 cocos2d-x 采用 opengl es 绘制图片的,opengles 绘制每个精灵都会执行:open-draw-close 流程。而 SpriteBatchNode 是把多个精灵放到一个纹理上,绘制的时候直接统一绘制该 texture,不需要单独绘制子节点,这样 opengles 绘制的时候变成了:open-draw()-draw()…-draw()-close(),节省了多次 open-close 的时间。SpriteBatchNode 内部封装了一个 TextureAtlas(纹理图集,它内部封装了一个 Texture2D)和一个 Array(用来存储 SpriteBatchNode 的子节点:单个精灵)。注意:因为绘制的时候只 open-close 一次,所以 SpriteBatchNode 对象的所有子节点都必须和它是用同一个 texture(同一张图片)。
    4.4 数据存储优化对于数据存储 Cocos2dx 提供了 SQLite、JSON、XML 解析等几种技术。由于游戏中需要处理的数据并不多,为了不给游戏带来不必要的游戏消耗,本游戏采用的是 XML 存储技术。XML 存储技术通过 UserDefault()函数来获取和存储本地数据。
    4.5 系统中类的设计Cocos2dx 引擎设计有几个基本概念:Direct(导演)、Scene(场景)、Layer(层)、Sprite(精灵)。导演在每个游戏中只有唯一一个,导演负责对场景进行调度。场景可以有一个或多个层组成。游戏中的主角和战机等都是精灵。具体调度如图 3.2 所示。 由上所示,游戏中会有很多场景,场景中又有多个层,这就导致了游戏中类较多。由于篇幅有限,再次我们把所有的类分组,并只介绍几个比较主要。分别是:军火库组、音效组、 子弹组、控制层组、敌机组、游戏帮助组、游戏运行组、主角战机组、结果显示组、选关组、礼物组、欢迎界面组。

    军火库组包括

    军火库场景。继承 Scene 类,主要用于加载军火库层军火库层。继承 Layer 类,主要负责加载军火库背景、三种主角及其参数
    音效组包括

    音效层。继承 Layer 类,主要负责加载游戏中的背景音乐和音效加载、是否静音等
    子弹组包括

    主角子弹属性类。主要负责加载主角游戏的属性:子弹伤害、等级等主角子弹层。继承 Layer 类;重写 Layer 类的 init()函数,实现对子弹以及大招特效进行批处理渲染;控制主角子弹开始发射和停止发射;控制主角大招发射。控制主角战机子弹的伤害、列数、外观等属性关主子弹层。继承 Layer 类;重写 Layer 类的 init()函数;重写 Layer 类的 update 函数,函数每一帧都会执行,检测 BOSS 子弹是否会击中主角,更新主角血量显示;控制 BOSS 子弹发射;加载 BOSS 爆炸特效
    控制层组

    控制层。继承 Layer 类;重写 Layer 类的 init()函数,加载暂停/继续按钮,加载血 量显示按钮,加载大招发射按钮,加载分数显示;更新主角血量函数;更新积分函数
    敌机组

    敌机属性类。初始化敌机血量。敌机层。继承 Layer 类。重写 Layer 类 init()函数,批处理渲染敌机,初始化敌机血 量;根据游戏模式添加相应的敌机,并设计敌机飞行路径,检测闯关模式下是否满足添加 BOSS 条件;无尽模式添加战机;关主模式添加 BOSS;设计 BOSS 移动路线;回收 BOSS 子 弹以及战机;加载战机爆炸特效;重写 Layer 类 update()函数,函数每帧执行一次,功能如下:
    检测游戏是否达到通关条件检测主角子弹是否与敌机发生碰撞以及碰撞后的动作检测主角是否与敌机相撞以及相撞后动作检测 BOSS 子弹与主角之间碰撞以及碰撞后动作检测 BOSS 与主角之间碰撞以及碰撞后动作

    游戏帮助组游戏帮助场景。继承 Scene 类;负责加载游戏帮助背景等

    游戏帮助层。继承 Layer 类;重写 init()函数;加载背景;加载游戏帮助页面以及左 翻右翻按钮
    游戏运行组

    游戏场景。继承 Scene 类;负责加载敌机层、主角战机层、控制层、礼物层等游戏背景层。继承 Layer 类;负责加载游戏场景;负责根据游戏模式加载不同游戏背景
    主角战机组

    主角属性类。初始化主角战机血量主角战机层。继承 Layer 类;重写 init()函数,初始化主角战机并加载;防止主角战机模型超出屏幕以外
    结果显示组

    结果显示场景。继承 Scene 类;负责加载结果显示层结果显示层。继承 Layer 类。显示本场游戏挑战结果(WIN/LOSE);显示重新开始和返回主菜单按钮;显示本场分数;显示历史最高分数
    选关组

    选关场景。继承 Scene 类;负责加载选择选关层选关层。继承 Layer 类;负责加载背景;加载进入各种模式以及关卡的按钮;加载军火库按钮
    礼物组

    礼物属性类。设置礼物类型礼物层。继承 Layer 类;重写 Layer 层的 init()函数,实现礼物渲染批处理。重写 Layer 层 update()函数,函数每帧执行,检测礼物是否与主角相撞;加载礼物与主角相撞后动画
    欢迎界面组

    欢迎界面场景。继承 Scene 类;负责加载欢迎层欢迎层。继承 Layer 类;加载背景;加载 LOGO;加载开始游戏和游戏帮助按钮;加载游戏难度设置;加载静音按钮

    如图 3.3 游戏类图所示。
    下面对游戏中主要类以及类中函数进行说明:
    敌人层类 EnemyLayer。其属性和函数如表 3.6 和表 3.7 所示。



    属性
    类型
    说明




    getBossSprite
    sprite*
    返回游戏中 BOSS


    baseEnemyAppearProbab ility
    float
    用来计算 Boss 是否出现


    deltaEnemyAppearProba bility
    float
    用来计算 Boss 是否出现


    nowEnemyAppearProbabi lity
    float
    用来计算 Boss 是否出现


    enemyTextureName
    vector<string>
    缓存各敌人纹理


    enemyFlyTime
    vector<int>
    存储各敌人飞行时间


    enemyInitHP
    Vector<int>
    存储各敌人血量






    函数
    返回类型
    说明




    init()
    virtual bool
    对敌机纹理进行渲染、飞行速 度及 时间进行设置


    enemyMoveFinished(Nod e* pSender)
    void
    回收敌机


    startAddEnemy()
    void
    开始添加敌机


    stopAddEnemy()
    void
    停止添加敌机


    Update(float useless)
    void
    监测游戏各精灵是否发生碰撞,监测游戏是否达到结束标准


    addBossSprite()
    void
    闯关模式中添加 BOSS


    changeSceneCallBack(f loat useless)
    void
    跳转结束场景


    setBossWarningOn()
    void
    加入BOSS出现前警告声


    bossStartMove()
    void
    设计 BOSS 移动路径


    addEnemySprite(float useless)
    void
    添加闯关模式敌机精灵


    addEnemySpriteEndless (float useless)
    void
    添加无尽模式敌机精灵


    addEnemyBossSprite(fl oat useless)
    void
    添加关主模式敌机精灵



    主角飞机类 PlaneLayer。PlaneLayer 属性和函数如表 3.8 和表 3.9 所示。



    属性
    类型
    说明




    myPlane
    Sprite*
    当前飞机精灵实例


    initHP
    int
    主角飞机初始血量


    winSize
    Size
    记录当前屏幕大小



    飞机类函数表



    函数
    返回类型
    说明




    getMyPlane()
    Sprite*
    返回当前主角飞机实例


    getInitHP()
    int
    返回当前主角飞机血量


    init() override
    virtual bool
    游戏初始化、添加背景等


    onTouchBegan( cocos2d::Touchtouch, cocos2d::Event unused_event)
    virtual bool
    判断鼠标是否点击屏幕


    onTouchMoved(cocos2d: :Touch touch, cocos2d::Event unused_event)
    virtual bool
    若手指触摸到手机屏幕且在飞机有效范围移动飞机



    子弹类 BulletLayer。其属性和函数如表 3.10 和表 3.11 所示。



    属性
    类型
    说明




    allBullet
    Vector<Sprite*>
    管理游戏中所有子弹


    eachBulletDamage
    int
    每个子弹伤害量


    bulletTextureName
    vector<string>
    记录每种子弹在素材(.plist)中的 名字


    bulletBatchNodeVector
    vector:SpriteBat chNode*>
    对子弹进行批处理渲染


    nowBulletLevel
    int
    记录当前子弹伤害量


    BulletNum
    int
    记录当前子弹列数






    函数
    类型
    说明




    bulletMoveFinished(No de* pSender)
    void
    回收子弹


    stopShooting()
    void
    停止射击


    setBulletLevelUP()
    void
    增加子弹伤害


    setBulletNumUp()
    void
    增加子弹列数


    launchBigBomb()
    void
    发射


    init()
    virtual bool
    对子弹纹理进行渲染、飞行速度及时间进行设置并显示在屏幕上


    startShooting(int BulletNum)
    void
    开始设计子弹(个数)


    HeroBulletOne(float useless)
    void
    一排子弹


    HeroBulletTwo(float useless)
    void
    两排子弹


    HeroBulletThree(float useless)
    void
    三排子弹



    欢迎界面类 welcomeButtonLayer。欢迎界面类属性和函数如表 3.12 和表 3.13 所示。



    属性
    类型
    说明




    buttonSoundOn
    MenuItemSprite*
    打开声音按钮


    buttonSoundOff
    MenuItemSprite*
    关闭声音按钮


    buttonGameEasy
    MenuItemSprite*
    设置游戏难度为简单按钮


    buttonGameNormal
    MenuItemSprite*
    设置游戏难度为正常按钮


    buttonGameHard
    MenuItemSprite*
    设置游戏难度为困难按钮






    函数
    返回类型
    说明




    init()
    virtual bool
    设置游戏背景以及添加声音按钮和游戏难度按钮


    startGameButtonCallba ck (Ref* pSender)
    void
    玩家点击开始按钮回调函数


    helpGameButtonCallbac k(Ref* pSender)
    void
    玩家点击游戏帮助按钮时回调函数



    礼物类 UFOLayer。结果显示类属性和函数如表 3.14 和 3.15 所示。



    属性
    类型
    说明




    giftTextureName
    vector<string>
    存储各种礼物在纹理包中的名称


    giftFlyTime
    vector<int>
    每个礼物的飞行时间


    winSize
    Size
    保存当前窗口大小


    sequenceFront
    Sequence*
    主角飞机得到礼物后动画


    sequenceBack
    Sequence*
    主角飞机得到礼物后动画


    allGift
    Vector<Sprite*>
    存储当前礼物以便回收






    函数
    返回类型
    说明




    init()
    virtual bool
    初始化纹理名称容器和飞行时间容器


    giftMoveFinished (Node* pSender)
    void
    回收礼物


    update(float useless)
    void
    判断礼物是否与主角飞机相撞以及 相撞后动作


    showAnnotation(Sprite * gift)
    void
    礼物与主角飞机相撞否动画



    游戏控制界面类 CotrolLayer。其属性和函数如表 3.16 和表 3.17 所示。



    属性
    类型
    说明




    score
    int
    记录当前分数


    scoreLabel
    Label*
    显示“积分”标签


    pauseButtonItem
    MenuItemSprite*
    暂停\继续按钮精灵


    launchButtonItem
    MenuItemSprite*
    大招发射按钮精灵


    HPIndicator
    ProgressTimer*
    血条显示


    pauseButton
    Menu*
    暂停\继续按钮


    launchButton
    Menu*
    大招按钮






    函数
    返回类型
    说明




    updateScore()
    void
    更新分数


    menuPauseCallback(cocos2d::Ref* pSender)
    void
    暂停/继续按钮回调函数


    init()
    virtual bool
    各种精灵的初始化


    menuLaunchCallback(cocos2d::Ref* pSender)
    void
    发射大招按钮回调函数


    onKeyReleased(EventKeyboard::Key Code keycode, Event* event)
    virtual bool
    监听键盘



    4.6 系统主要部分顺序图在本游戏关键的几个层(Layer)中都会重写 Layer 类中的 update()函数,update() 函数会在游戏的每一祯中执行。游戏中有三种模式:闯关模式、无尽模式、关主模式。每种模式都有一套顺序图。这里以闯关模式中的顺序图为例。
    在游戏的每一帧中,先在游戏中添加主角飞机、敌机;然后主角飞机开始发射子弹;判断子弹是否与敌机碰撞,若碰撞,计算敌机血量,若敌机摧毁,回收敌机并增加分数;判断敌机与主角飞机是否相撞,若敌机摧毁,回收敌机并增加分数,若主角摧毁,跳转结束场景;添加礼物,判断礼物与敌机是否相撞,若相撞则增加相应的效果;达到条件后增加 BOSS,BOSS 发射子弹,判断 BOSS 子弹是否与主角飞机相撞,同时判断 BOSS 是否与主角飞机相撞;监测玩家是否按下暂停按钮,点击之后执行相关操作。最后,游戏重新绘制游戏帧。顺序图如下图 3.4 所示。

    4.7 系统功能结构本游戏的系统功能主要有主角管理、模式选择、暂停界面、子弹管理、结果显示、游戏帮助、分数存储、音效控制、碰撞检测、分数显示、礼物管理、敌机管理、血量显示、大招显示等。其中模式选择分为无尽模式、闯关模式和关主(BOSS)模式;分数存储分为分数读取与分数更新;游戏帮助有玩法说明;礼物管理分为子弹排数礼物、子弹伤害礼物、加血礼物和大招礼物;敌机管理分为增加敌机、敌机回收、增加关主(BOSS)和关主(BOSS)回收;子弹管理分为主角飞机的子弹管理和关主(BOSS)的子弹管理。
    五、系统实现5.1 安装开发环境安装 Python2.7 并配置环境变量
    配置完成后打开 cmd 控制台,输入 python,如果出现如下提示,则说明 python 安装成功。如图 4.1 所示。

    安装 cocos2d-x-3.3
    cocos2d-x-3.3 项目无需安装,下载 cocos2d-x-3.3 文件并解压。
    安装 MicrosoftVisualStudio2013
    一步步按提示安装即可。
    创建项目
    进入到目录 cocos2d-x-3.3/tools/cocos2d-console/bin/cocos.py 打开终端运行 cocos.py 脚本创建文件: python cocos.py new Plane3 -p com.coco2dx.org -l cpp -d E:\cocos_2d 等待完成即可。完成界面如图 4.2 所示:

    然后在目录 E:\cocos_2d 中打开项目可以看见各个快平台的文件夹。 如图 4.3 所示。

    5.2 游戏关键部分实现5.2.1 地图无限滚动游戏让背景不断的向下滚动来实现在视觉上主角飞机看起来是不断向上飞的状态。为了使主角飞机有不断向前飞行的效果,本游戏采用使地图背景不断逆向滚动的形式来达到主角飞机不断前行的效果。
    其实就是两张相同的背景图片,然后同时向下滚动,当一张图片完全出视野后,就把它调到最上面,于此同时另一张背景图片出现,形成两个图片交替出现。的效果。不过,一般为游戏中我们都感觉像是一张图片,那是因为两张图片的头尾连接处是连起来的。

    具体代码如下:
    background1->setPositionY(background1->getPositionY()-backgroundMoveSpeed);background2->setPositionY(background1->getPositionY()+ background1->getContentSize().height*2 - backgroundMoveSpeed);if(background2->getPositionY() < 0){ background1->setPositionY(0);}
    5.2.2 防止主角飞机超出屏幕外在进行游戏时,如果主角飞机超出屏幕外,会严重影响玩家的视觉体验。游戏实现时必须避免这种情况。实现代码如下:
    //飞机超出左边边界,设置飞机 X 轴位置为 0if((myPlane->getPositionX()-myPlane->getContentSize().width/4< 0)){ myPlane->setPositionX(0 + myPlane->getContentSize().width / 4);}//飞机超出右边边界,设置飞机 X 轴位置为右边界else if((myPlane->getPositionX() + myPlane->getContentSize().width / 4) >winSize.width) { myPlane->setPositionX(winSize.width-myPlane->getContentSize().width / 4);}//飞机超出下边边界,设置飞机 X 轴位置为下边界if (myPlane->getPositionY() < 0) { myPlane->setPositionY(0);}//飞机超出上边边界,设置飞机 X 轴位置为上边界else if (myPlane->getPositionY()+ myPlane->getContentSize().height/2>winSize.height) { myPlane->setPositionY(winSize.height-myPlane->getContentSize().height/2);}
    5.2.3 控制主角飞机移动要在游戏层使用单点触摸首先需要在初始化中设置可触摸,语句为 setTouchEnabled(true)。设置可触摸后,我们还要对 Cocos2d-x 中的两个回调函数进行重写。
    //当触摸到屏幕一瞬间会调用virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) override;//手指在屏幕上移动时调用virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) override;
    对两函数重写后代码如下:
    bool PlaneLayer::onTouchBegan(ouch *touch, Event *unused_event) { return true; //表示当前层接收触摸事件处理} void PlaneLayer::onTouchMoved(Touch *touch, Event *unused_event) { //将飞机坐标位置设为手指抬起位置 myPlane->setPosition(myPlane->getPosition() + touch->getDelta()); }
    5.2.4 碰撞检测碰撞检测是游戏中核心内容,包括:

    主角飞机与敌机之间的碰撞检测
    主角飞机子弹与敌机之间的碰撞检测
    主角飞机与 BOSS 之间碰撞检测
    主角飞机与 BOSS 子弹之间碰撞检测
    主角飞机与礼物之间碰撞检测

    碰撞检测代码实现如下:
    //通过调用精灵自带函数的 intersectsRect()函数来实现if (enemy->getBoundingBox().intersectsRect(getMyPlane()->getBoundingBox()){ .........}
    5.2.5 敌机 AI 的设定为了使游戏更加生动好玩,游戏为战机设定了简单的飞行路线。

    敌机一的飞行路径:从左上侧出现,从右下侧消失敌机一的实现,用到了贝赛尔曲线,贝塞尔曲线是应用于二维图形应用程序的数学曲线。曲线的定义有四个点:起始点、终止点(也称锚点)以及两个相互分离的中间点。定 好起止点和终止点后,只要改变两个中间点就可以改变曲线。
    ccBezierConfig tr0;enemySprite->setPosition(Vec2(0, 450));//起始点 tr0.controlPoint_1 = Vec2(200, 300);//中间点 1 tr0.controlPoint_2 = Vec2(140, 200);//中间点 2tr0.endPosition = Vec2(0, 20);//终止点ActionInterval* bezierFoward = BezierTo::create(3.f, tr0);//创建运行的贝塞尔曲线ActionInterval* forwardBy = RotateBy::create(3.f, 90); // 第二个参数:如果是正数则是顺时针,否则逆时针 Spawn* spawn = Spawn::create(bezierFoward, forwardBy, NULL);//创建合成动作 ……

    敌机二的飞行路径:从屏幕上方冲向主角飞机。
    //添加敌机精灵 Sprite* enemySprite = createWithSpriteFrameName(enemyTextureName[3].c_str()); //设置敌机从屏幕上方随机飞出int randomX = CCRANDOM_0_1()*(winSize.width - enemySprite->getContentSize().height) + enemySprite->getContentSize().height / 2;enemySprite->setPosition(randomX - enemySprite->getContentSize().width/5, winSize.height + enemySprite->getContentSize().height/3); float x = getMyPlane()->getPosition().x;float y = getMyPlane()->getPosition().y; float a = randomX - x;float b = winSize.height - y; //弧度转角度,让敌机“冲向”主角float radians = atanf(a / b);float mDegree = CC_RADIANS_TO_DEGREES(radians); enemySprite->setRotation(mDegree); //添加敌机this->addChild(enemySprite); //设置结束地点 float endX = randomX - (a / b)*winSize.height;//winSize.width float endY = 0; float flyVelocity = 250;//运行速度float flyLen = sqrt((winSize.width - endX)*(winSize.width - endX) + (winSize.height - endY)*(winSize.height - endY)); float realFlyDuration = flyLen / flyVelocity;//实际飞行的时间 //添加动作 FiniteTimeAction* enemyMove = MoveTo::create(realFlyDuration, Point(endX, endY));FiniteTimeAction* enemyRemove = CallFuncN::create(CC_CALLBACK_1(EnemyLayer::enemyMoveFinished , this));Action* enemyAction = Sequence::create(enemyMove, enemyRemove, NULL); enemySprite->runAction(enemyAction);

    敌机三的飞行路径:从屏幕上方飞至屏幕下方。代码较简单,此处省略。
    敌机四的飞行路径:三架并列从屏幕上方飞至屏幕下方。代码较简单,此处省略。
    敌机五的飞行路径:三架并排从屏幕左方飞至屏幕右方。代码较简单,此处省略。

    5.2.6 主角飞机子弹主角发射一个子弹,其实现代码如下:
    //添加子弹精灵Sprite* bullet = createWithSpriteFrameName(bulletTextureName[nowBulletLevel]);Point planePosition =static_cast<GameScene*>( this->getParent())->getPlaneLayer()->getChildByName("PLANE")->getPosition(); float b = winSize.height - y; //弧度转角度,让敌机“冲向”主角float radians = atanf(a / b);float mDegree = CC_RADIANS_TO_DEGREES(radians); enemySprite->setRotation(mDegree); //添加敌机this->addChild(enemySprite); //设置结束地点float endX = randomX - (a / b)*winSize.height;//winSize.width float endY = 0; float flyVelocity = 250;//运行速度float flyLen = sqrt((winSize.width - endX)*(winSize.width - endX) + (winSize.height - endY)*(winSize.height - endY));float realFlyDuration = flyLen / flyVelocity;//实际飞行的时间 //添加动作FiniteTimeAction* enemyMove = MoveTo::create(realFlyDuration, Point(endX, endY));FiniteTimeAction* enemyRemove = CallFuncN::create(CC_CALLBACK_1(EnemyLayer::enemyMoveFinished , this));Action* enemyAction = Sequence::create(enemyMove, enemyRemove, NULL);enemySprite->runAction(enemyAction); //设置子弹出现位置Point bulletPosition = Point(planePosition.x, planePosition.y + static_cast<GameScene*>(this->getParent())->getPlaneLayer()->getChildByName("PLANE")->getContentSize().height); bullet->setPosition(bulletPosition);bullet->setUserData(new BulletUserData(eachBulletDamage, nowBulletLevel)); bullet->setScale(0.5f);allBullet.pushBack(bullet);this->bulletBatchNodeVector[nowBulletLevel]->addChild(bullet); //设置子弹飞行时间float bulletFlyLenth = Director::getInstance()->getWinSize().height - bulletPosition.y + (bullet->getContentSize().height / 2);float bulletFlySpeed = 900 / 1;float bulletFltTime = bulletFlyLenth / bulletFlySpeed; //设计子弹飞行动作FiniteTimeAction* bulletMove = MoveTo::create(bulletFltTime, Point(bulletPosition.x,Director::getInstance()->getWinSize().height + bullet->getContentSize().height / 2));FiniteTimeAction* bulletRemove = CallFuncN::create(CC_CALLBACK_1(BulletLayer::bulletMoveFinished, this));//加入子弹动作auto bulleAction = Sequence::create(bulletMove, bulletRemove, NULL); bullet->runAction(bulleAction);
    主角发射两排子弹。就是在一排子弹基础上加一排子弹然后改一下位置。代码较简单, 此处省略。
    主角发射三排子弹。除了多出一排子弹外,还要设计子弹的偏转度。说明如图 4.3 所 示。
    可以得到主角位置为 (X,Y), 根据图示可以得到右排子弹的结束坐标 (h+h*tan(angle),height)。
    同理可得左排子弹结束坐标(h-h*tan(angle),height) 实现偏转都代码如下:
    //angle 是偏转角度float bulletFlyLenth3 = planeHeight / cos(angle);float bulletFlySpeed = 850 / 1; float bulletFltTime1 = bulletFlyLenth1 / bulletFlySpeed;//设计子弹飞行动作 FiniteTimeAction* bulletMove1 = MoveTo::create(bulletFltTime1, Point(bulletPosition1.x-planeHeight * tan(angle), Director::getInstance()->getWinSize().height + bullet1->getContentSize().height / 2));FiniteTimeAction* bulletRemove1 =CallFuncN::create(CC_CALLBACK_1( BulletLayer::bulletMoveFinished, this));

    5.3 软件移植到 Android
    安装 ADT(Software Development Kit),可以理解为开发工具包集合,是整体开发 中所用到的工具包。
    安装 JDK
    安装 ANT
    安装 Eclipse 软件,用 Eclipse 软件导入现有工程
    进入 proj.android 文件夹下的 jni 文件夹中,打开 Android.mk 文件,在其中添加游戏源代码路径
    把 cocos2dx\platform\android\java\src 下的 org 文件夹复制到工程文件 android 文件夹下的 src 中
    把资源文件复制到 proj.android 文件夹下的 assets 中
    运行项目

    5.4 游戏帮助5.4.1 游戏玩法游戏模式分为关主模式、无尽模式和闯关模式。
    闯关模式分为三个关卡,每个关卡开始不断有敌机飞来挑战主角飞机,每个关卡会添加一种新的敌机。摧毁敌机增加积分,积分每满 1000 分,会随机飞来一种礼物,主角飞机得到礼物后会增加相应效果。当达到某种条件后,会出先 BOSS。每一关都有一个属于自己的关主,关主出现后会发射密集子弹。击败关主决定是否进入下一关或者重新开始。
    无尽模式只有一个关卡。关卡开始后不断由敌机飞来。同闯关模式一样,积分每满 1000 分,会随机飞来一种礼物,主角飞机得到礼物后会增加相应效果。随着积分的增加,游戏难度会增加,直至主角飞机被摧毁。
    关主模式中没有普通敌机的加入,只有闯关模式中的关主外加另一种关主。关主随机出现。关主摧毁增加积分,游戏难度随着积分增加而增加。
    1 评论 1 下载 2019-07-06 09:37:45 下载需要17点积分
  • 基于Android系统手机通讯录管理软件的设计与开发

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    4.6 分类管理点击我的群组界面,可以查看群组并且显示群组。在里面可以对群组进行增删改查操作。
    4 评论 65 下载 2019-01-30 17:26:14 下载需要12点积分
  • JAVA实现的基于内容的图像检索系统设计与实现

    1 图像检索系统工作流程基于内容的图像检索技术是对输入的图像进行分析并分类统一建模,提取其颜色、形状、纹理、轮廓和空间位置等特征,建立特征索引, 存储于特征数据库中。检索时,用户提交查询的源图像,通过用户接口设置查询条件,可以采用一种或几种的特征组合来表示,然后在图像数据库中提取出查询到的所需关联图像,按照相似度从大到小的顺序,反馈给用户。用户可根据自己的满意程度,选择是否修改查询条件,继续查询,以达到满意的查询结果。
    2 图像检索系统框架基于内容的图像检索系统框架如图1所示。系统的核心是图像特征数据库。图像特征既可以从图像本身提取得到, 又可以通过用户交互获得, 并用于计算图像之间的相似度计算。系统框架应主要包含以下几个基本功能模块:检索方法设置、检索结果浏览、数据库管理维护等。其逻辑结构如图2所示。


    3 数据库构建与实现图像数据库包括两个部分:图像库和特征库。图像库是图像的集合,存储数字化的图像信息,具体在系统实现中,可以存放图像的路径和文件名称来表示;特征库存储图像中提取出的特征表达的相关信息,并为提取出的各个特征简历索引,且和图像间存在一一对应的关系。
    3.1 图像数据库图像是图像元灰度值的纪录, 以行列数据矩阵表示, 一般信息量比较大。直接读取图像的信息存入数据库中, 不但增加了数据库的容量, 而且增加了计算机的负担。若直接根据图像的路径名称建立图像地址库, 可有效提高计算机的计算效率。当需要提取图像时, 再根据图像的地址, 对图像进行检索, 平时, 只需对图像的基本信息进行管理。数据库的基本功能包括: 增加删除图像、图像统计、图像的显示等。cusers12801desktopstarfish.txt示例如图3所示。

    3.2 图像索引库的建立与实现3.2.1 数据组织说明由于图库中有大量的图像,每一张图像中有许多像素点,每个像素点又有许多特征值,如果都将其放入内存中,是不可能实现的。因此本实训项目将提取出的特征值存放到txt文件中,每打开应用系统,就可以直接从外存中读取文件,构建图像特征索引库。分别实现图像颜色、纹理和特征值的提取及txt文件的生成,生成结果文件分别如图4 所示。此步骤需要用户先完成图像特征提取后,再来构建图像特征索引库。


    cusers12801desktopstarfish.txt主要存的是图库中每张图像的路径,匹配时程序可以根据这个路径找到图库中图像所在的路径
    RGBHcusers12801desktopstarfish.txt保存的是直方图相交法的特征值
    CMcusers12801desktopstarfish.txt保存的是HSV中心距法的特征值
    EDcusers12801desktopstarfish.txt保存的是欧式距法的特征值
    BHcusers12801desktopstarfish.txt保存的是巴氏系数法的特征值


    3.2.2 图像特征数据库设计说明分别以颜色、纹理、形状特征为例,说明创建各特征表时的工作过程。
    以颜色特征为例,说明创建该表时需要包括的字段如下(实际处理过程中,用户选择的特征描述方法不同,所得到的颜色特征值的数量也不同,由用户酌情处理):



    字段名称
    字段描述
    字段类型
    备注




    ID
    数据库中的编号
    int
    Primary Key


    Name
    图像名称
    string
    NOT NULL


    Color
    颜色特征值
    float
    NOT NULL


    Path
    储存图像的位置
    string
    NOT NULL



    以纹理特征为例,说明创建该表时需要包括的字段如下(实际处理过程中,用户选择的特征描述方法不同,所得到的纹理特征值的数量也不同,由用户酌情处理。



    字段名称
    字段描述
    字段类型
    备注




    ID
    数据库中的编号
    int
    Primary Key


    Name
    图像名称
    string
    NOT NULL


    shape0
    形状特征值
    float
    NOT NULL


    shape1
    形状特征值
    float
    NOT NULL


    shape2
    形状特征值
    float
    NOT NULL


    shape3
    形状特征值
    float
    NOT NULL


    shape4
    形状特征值
    float
    NOT NULL


    shape5
    形状特征值
    float
    NOT NULL


    shape6
    形状特征值
    float
    NOT NULL


    shape7
    形状特征值
    float
    NOT NULL


    Path
    储存图像的位置
    string
    NOT NULL



    4 图像特征的提取与表达图像特征的提取与表达是基于内容的图像检索技术的基础。广义而言,图像的特征包括基于文本的特征(关键字、注释等)和视觉特征( 如色彩、纹理、形状、对象表面等) 两类。视觉特征又分为通用的视觉特征和领域相关的视觉特征。前者描述所有图像共有的特征,与图像的具体类型或内容无关,主要包括色彩、纹理和形状,后者建立在对所描述图像内容的某些先验知识(或假设)基础上,与具体的应用紧密有关。
    4.1 图像预处理主要的参考步骤如下:

    统一图像大小,使得每一幅待检索图像大小一致
    图像降噪,避免图像噪声带来的影响。可使用数字图像处理课程中所学各种方法,如高斯模板、中值滤波等来实现
    图像增强,主要用来增强对比度等。可使用数字图像处理课程中所学各种方法,如直方图均衡化等方法实现

    但是本次实验的图片是专用的图库,因此不需要进行预处理。
    4.2 图像颜色特征颜色特征是在图像检索中应用最为广泛的视觉特征,主要原因在于颜色往往和图像中所包含的物体或场景十分相关。此外, 颜色特征对图像本身的尺寸、方向、视角的依赖性较小, 从而具有较高的检索性。利用颜色特征进行检索的方法主要基于直方图,如:直方图相交法,比例直方图法,距离法,参考颜色表法和聚类算法,累计直方图法,此外,还有HSI中心矩法。
    5 图像特征匹配在基于内容的图像检索中,两幅图像是否相似是指图像的特征向量是否相似。常用的图像相似性测度通常采用几何模型,将图像特征看作是向量空间中的点,通过计算两个点之间的接近程度来衡量图像特征之间的相似度。基于内容的图像检索算法主要有最邻近查询算法和区间查询算法,它们都依赖于距离函数或者相似性度量。
    算法步骤

    按照前文方法,计算出待检索图像的特征
    利用距离度量函数计算待检索图像特征和图像特征库间的距离
    对计算出的距离值按照相似性大小进行高低排序
    对检索出的结果图像进行输出显示

    6 所采用算法思想6.1 直方图的相交法算法步骤

    图像灰度化Gray=R[i]/R+G[i]/G+B[i]/B
    两图像之间的匹配值P(Q, D)可借助直方图相交来实现



    将特征值存放在图像特征数据库中
    6.2 欧氏距离(EuclideanDistance)算法步骤

    图像灰度化Gray=R[i]/R+G[i]/G+B[i]/B
    两图像之间的匹配值P(Q, D)可借助直方图相交来实现



    将特征值存放在图像特征数据库中
    6.3 巴氏系数法算法步骤

    图像灰度化Gray=R[i]/R+G[i]/G+B[i]/B
    其中P, P’分别代表源与候选的图像直方图数据,对每个相同i的数据点乘积开平方以后相加,得出的结果即为图像相似度值(巴氏系数因子值),范围为0到1之间



    将特征值存放在图像特征数据库中
    6.4 中心矩法算法步骤

    图像灰度化Gray=0.30*R+0.59*G+0.11*B
    将图像从RGB颜色空间转至HSI颜色空间
    以HSI空间的Hue分量为例,如果记Hue(pi)为图像P的第i个像素的Hue值,则其前三阶中心矩分别为:



    度量函数


    将特征值存放在图像特征数据库中
    7 详细实现过程主窗口的设计实现代码如下(MainFrame.java),该文件是程序刚运行时加载的窗口。

    图像存储窗口的设计实现如下(IDBMDialog.java),该文件主要实现了用户将指定的文件夹存入数据库中。

    图片特征值存储数据库窗口的实现如下(ICDBMDialog.java),该文件主要实现了待检所图片与数据库中图片基于颜色特征的处理及匹配数据的存储。

    人脸识别的窗口设计如下(LBPDialog.java)。

    帮助窗口设计如下(HelpDialog.java),该文件是程序的说明书。

    Centralmoment.java实现了中心矩法,HistogramRetrieval.java实现了相交法、欧氏距离法和巴氏系数法,interface_main.java是主函数所在的类,MysqlConnect.java实现了java与mysql的连接,MapSort.java和Math.java是图像处理算法中的工具类。线程保证了图片加载与用户操作能同时进行,因为遇到图片很多的时候加载时间较长,这是应仍能允许用户进行其他操作。XLabel.java实现了JLabel类,使得图片能按照自定义的方式显示。
    8 实验结果分析传统的直方图相交法运行效果图

    直方图相交欧式距离法运行效果图

    巴氏系数法运行效果图

    中心矩法运行效果图

    人脸识别运行效果图

    人脸识别的方法:使用haartraining.exe来训练分类器,获取XML文件,从而获得人脸的数据信息,根据该信息就可以识别人脸。
    在本次实训程序中,颜色特征的匹配都能成功运行,形状特征的方法由于计算方法未得到优化,导致数据存储过程中出现数据库中全是0值的情况,因此未能成功展示,纹理特征由于时间关系未能实现。
    9 实训总结和心得通过本次实训,我了解到了CBIR以及实现了其中的一小部分典型功能。基于内容的图像检索系统(Content Based Image Retrieval, 以下简称CBIR),是计算机视觉领域中关注大规模数字图像内容检索的研究分支。是指直接采用图像内容进行图像信息查询的检索,即在图像数据库中检索与用户所提交样本图像在内容上一致或相似的图像集合的过程,通过对图像底层特征的比较来实现检索。主要研究技术包括特征抽取、相似度量、图像匹配、用户反馈。基于色彩特征的检索方法是CBIR的主要方法之一,它所抽取的特征向量是颜色直方图,虽然能够较好地反映图像中各种颜色的频率分布,而且对图像中对象的旋转以及观察位置的变化不敏感,但无法保留各像素。这项技术是为了解决报刊等媒体集团大量图片检索的难题而衍生出来的。
    本次实训目的是完成CBIR的一些典型功能,具体包括:

    实现基于颜色信息的图像检索,可通过颜色直方图、颜色矩、颜色一致性矢量等方法来实现实现基于纹理特征的图像检索,可从四个方面进行:统计法、结构法、模型法、频谱法实现基于形状特征的图像检索,可分别从图像的边缘信息和区域信息来实现实现基于综合信息的图像检索
    在了解完实训要求以及项目要求之后,结合java中的awt框架技术,jdbc链接数据库以及图像处理算法最后终于完成了一些最基本的功能,还抽出了部分时间尝试着完成了一个最简单的人脸识别功能(利用opencv识别技术)。在本次实训中既让我复习了之前学习的java程序设计和数字图像处理等课程,也开阔了我的视野,学习了一些基于内容的图像检索的相关技术,当然了由于自身能力有限,本次实验得以成功完成离不开指导书以及网上的资源。总之本次实训十分有意义,让我受益颇多。
    10 参考文献[1] 翟瑞芳、彭辉、周雄辉、高俊祥.CBIR实训指导书[M/CD]. 武汉:2017
    2 评论 85 下载 2018-11-04 22:53:22 下载需要7点积分
  • 基于QT和UDP Socket实现的即时通信软件

    摘 要随着计算机应用技术的快速发展和日益普及,网络也遍及到我们生活的每个角落,为我们的学习和工作带来极大的方便。现很多人都使用网络通讯软件来进行聊天、交流,这种软件极大地缩短了人与人之间的沟通距离,使人们能够随时随地的进行交流。因此,一个即时通讯软件的设计是有必要的。
    而本设计是基于Qt的开发平台上开发的一款即时通讯软件,通过网络编程SOCKET函数以实现同局域网内的文字传输。
    关键词:通讯软件;网络编程;文字传输
    第一章 设计内容设计一个类似QQ的聊天软件,实现在同一局域网内不同用户之间的即时通信,程序具体功能有:

    sqlite3数据库插入用户表
    登录界面:数据库验证登录
    用户主界面:数据库匹配用户好友列表
    聊天界面:在同一局域网内采用UDP的方式实现即时通信
    聊天记录以文件“.txt”的形式保存

    第二章 总体设计2.1 模块化设计为实现系统功能,本程序主要分为四个模块。他们分别是:登录界面、用户主界面、好友列表界面、聊天界面。这四个模块是通过主函数实例化一个不显示的空用户主界面,在用户主界面的构造函数里还会实例化一个登录界面,当登录界面用户登录成功后,用户主界面转为显示状态并更新登录的用户信息(显示登录账号,更新用户好友列表),双击对应好友就可弹出聊天窗口,实现即时聊天。
    主函数(main)
    // 实例化用户主界面MainWindowmainwin
    登录界面类(logonscreen)
    // 构造函数LogonScreen(QWidget *parent = 0); // 创建数据库连接createConnection(); // 创建用户表,添加可登陆用户createTable();// 查询用户表,显示所有用户selectTable(); // 验证登录信息verify(const Qstring, const QString); // 登录按键的槽on_pushButton_login_clicked(); // 退出按键的槽on_pushButton_close_clicked(); // 自定义用户登录信号,向用户主界面传输当前登录账号值user_signal(QString value);
    用户主界面类(mainwindow)
    // 构造函数MainWindow(QWidget *parent = 0);// 创建数据库连接createConnection();// 匹配用户好友,更新好友列表matchUserFriend(); // 注销按钮的槽,返回登录界面on_pushButton_quit_clicked();// 获取用户登录信号响应的槽getUserValue(QString value); // 鼠标移动事件,单击移动界面mouseMoveEvent(QMouseEvent *event);
    好友列表界面类(userwidget)
    // 原构造函数userwidget(QWidget *parent = 0);// 构造函数的重载userwidget(int receive_port,QString send_ip ,int send_port,QString send_account,QWidget *parent = 0); // 鼠标双击事件mouseDoubleClickEvent(QMouseEvent *event);
    聊天界面类(chatwindow)
    // 原构造函数ChatWindow(QWidget *parent = 0); // 构造函数的重载ChatWindow(int receive_port,QString send_ip,int send_port,QString send_account,QWidget *parent = 0);// 键盘按下事件(ctrl+Enter)keyPressEvent(QKeyEvent *event); // 键盘释放事件keyReleaseEvent(QKeyEvent *event); // udp数据报接收processPendingDatagram(); // 发送按钮的槽,发送udp数据报on_pushButton_send_clicked(); // 关闭按钮的槽,关闭窗口on_pushButton_close_clicked(); // 聊天记录按钮的槽,显示隐藏的界面on_pushButton_chatdata_toggled(bool checked);
    2.2 程序运行示意图
    第三章 详细设计3.1 登录界面设计3.1.1 登录界面UI设计
    3.1.2 登录界面类设计在登录界面类的构造函数里,会做连接sqlite3数据库,创建用户表和查询用户表并显示查询结果于调试窗口的操作。当用户在登录界面输入账号时,就会触发QT的自动补全功能(QCompleter),补全内容为在查询用户表时记录的用户账号(QStringList),方便用户输入体验。当用户输入密码时,lineEdit_password里的值会以密码的形式显示(setEchoMdoe)。用户键入完成,点击登录按钮,调试窗口显示键入内容,并调用verify(account, password)函数,把键入的账号密码作为数据库查询的where条件。如果查询结果存在,则发送accept()信号允许登录,并且还会发送一个自定义的emit user_signal(account)信号给用户主界面,传入当前登录账号值,作为主界面更新该用户好友列表的判断依据;否则,弹出一个dialog提示账号或密码错误。
    3.2 用户主界面设计3.2.1 用户主界面UI设计
    3.2.2 用户主界面类设计当实例化用户主界面时,主界面是不会show() 出来的,用户主界面类构造函数首先会实例化一个登录界面类的指针对象。然后,关联(connect)这个对象的自定义信号user_signal(account),使用户主界面收到这个信号时,能转到槽getUsrValue(QString),获取信号传进来的当前登录账号值。接着,显示登录界面,等待用户在登录界面的操作。最后,用户主界面会等待登录界面的用户登录成功后的Accepted信号,如果收到Accepted信号,主界面show() 出来,并且调用matchUserFriend()函数,匹配当前登录账号的好友列表。
    更新好友列表的功能实现是通过在用户主界面的toolBox部件的page_friend里添加一个垂直布局(QBoxLayout),然后在matchUserFriend()函数里查询数据库里的用户表,查到一个好友则在垂直布局里实例化一个QT设计师类userwidget的指针对象。
    3.3 好友列表界面设计3.3.1 好友列表UI界面
    3.3.2 好友列表类设计这个类是在用户主界面matchUserFriend()函数里实例化使用的,结果是会在用户主界面的toolBox部件里的好友列表显示出来。因为要实现鼠标双击这个类(好友)就会弹出和这个好友的聊天窗口。所以这时候就需要考虑这个聊天窗口的接收UDP数据报的绑定端口和发送UDP数据报的目标IP、目标端口。为要解决这个问题,我这个类使用了构造函数的重载,在实例化该类的过程中同时传入接收端口、发送目标IP、发送目标端口和发送目标的名字。
    好友列表类重载的构造函数主要做记录传入接收端口、发送目标IP、发送目标端口和发送目标的账号,并根据传进来的发送目标的账号从QT资源文件里查找对应的头像、昵称和签名。最后在鼠标双击事件里再用同样的方法把这些值传进聊天窗口界面。
    3.4 聊天界面设计3.4.1 聊天界面UI设计
    3.4.2 聊天界面类设计聊天界面类重载的构造函数,首先记录从好友列表类传进来的接收端口、发送目标IP、发送目标端口和发送目标的账号。然后隐藏聊天记录的textEdit部件,调整窗口的大小。最后绑定接收UDP数据包的端口和IP,关联QudpSocket::readyRead信号,当收到UDP数据报时,触发槽processPendingDatagram(),使收到的数据显示在listWidget上,并写入名为发送对象的txt文件里作为聊天记录保存起来。
    发送按钮的槽函数,把当前时间(QDateTime::currentDateTime())和发送内容里(textEdit里面的数据)一起以UDP数据报发送出去,同时也写入到对应txt文件里面。
    聊天记录按钮的槽函数,点击聊天记录按钮,检查按钮当前状态,如果按钮checked值为true,则显示隐藏的textEdit,并重新调整聊天界面大小,textEdit里面的值为从对应txt文件里读取的全部内容。
    第四章 调试与测试4.1 调试过程中的主要问题
    用户登录成功后,登录界面类的当前登录值怎么传进用户主界面?
    最后的解决方法是在用户主界面实例化登录界面指针对象,然后使用信号和槽传输登录账号值。
    用户主界面收到登录界面发来的信号后,已经知道当前登录账号了,怎么在该用户好友列表显示出来?
    最后的解决办法是新建QT设计师类(好友列表类),查询数据库,查到一个实例化一个好友列表类指针对象到toolBox部件里的垂直布局里。
    鼠标双击好友列表里的一个好友,弹出聊天窗口,聊天窗口的UDP数据报的接收端口和发送IP、发送端口的值怎么获取?
    最后解决办法是通过构造函数的重载,在实例化的过程中传进对应参数。

    4.2 具体测试过程4.2.1 登录界面
    4.2.2 用户主界面
    4.2.3 聊天界面

    5 心得体会通过这次课程设计,我学会了使用Qt制作一个简易的聊天工具,学到了Qt的UI布局、数据库操作、多界面的切换、信号与槽、socket编程、UDP通讯以及文件操作等,希望以后能进一步的深造学习。
    参考文献[1] 陈维兴 林小茶, C++面向对象程序设计教程(第3版). 北京: 清华大学出版社, 2009年5月
    [2] 闫锋欣 曾泉人 张志强 译, C++ GUI Qt4 编程(第2版). 电子工业出版社, 2013年5月
    [3] 金大颐 翻译:张红艳, Qt5开发实践. 北京: 人民邮电出版社, 2015年9月
    1 评论 22 下载 2018-12-13 09:31:56 下载需要5点积分
  • 基于JSP和SSH框架实现的班级管理系统

    1 系统需求的分析1.1 需求分析本项目所开发的班级管理系统完成学校对学生的班级信息的统计与管理,减少数据漏掉的情况,同时也节约人力、物力和财力,告别以往的人工统计。方便学生使用,学生可以在线查看班级信息,学生信息,课程信息,成绩信息,信息修改。
    1.1.1 系统管理员需求分析
    班级管理:管理员在登录之后可以对系统内的班级进行管理,包括对班级的信息进行增加、查询、修改和删除等操作
    课程管理:管理员在登录之后可以对系统内的课程进行管理,包括对课程的信息进行增加、查询、修改和删除等操作
    学生管理:管理员在登录之后可以对系统内学生进行管理,包括对学生的信息进行增加、查询、修改和删除等操作

    1.1.2 教师需求分析基本信息管理:

    成绩录入:管理员在后台添加、编辑成绩,进行成绩录入
    统计查询:统计某一个学生的所修课程信息、汇总出学分、不及格课程(标红)统计每一门课程的最高分、最低分和平均分

    1.2 任务概述1.2.1 目标本系统是为了更好管理班级信息而设计的。由于学校的学生繁多,包含的信息量大且复杂,有必要建立一个班级管理系统,使选班级管理工作规范化,系统化,程序化,提高信息处理的速度和准确性,能够及时、准确、有效的查询和修改选课排课相关信息。
    1.2.2 运行环境服务器配置包括硬件配置和软件配置,它们各自都有详细的要求,下面将分别进行介绍。

    硬件配置安装本软件之前,需要确保计算机具有如下配置,这也是最低硬件要求: 酷睿i5或更高的微处理器(或与之相当的处理器) 使用2G内存
    软件配置安装本软件之前,需要确保计算机已安装:Micorsoft Win10的操作系统

    1.3 系统完整性、安全性1.3.1 对服务的要求为保证该系统平稳、安全地运行,系统为用户提供的服务要有以下限制:

    管理员具有该系统的最高权限,负责系统维护,更新 教师可以查看个人的全部信息,修改个人信息,若要修改课程信息需向教务处申报,由管理员修改学生能查看个人的全部信息、自己的选课结果、修改个人信息,若要修改选课信息,需向教务处申报,由教务处修改
    1.3.2 对性能的要求
    此系统的数据输入大多数为字符串类型,也有表示成绩的浮点数,精度为6
    响应时间:对于管理人员输入的用户信息应该在人们所能接受的等待时间来确定,通常为1-2秒
    更新处理时间要求 :用户输入数据后,对于该操作人员输入的数据处理时间应该是毫秒级的。数据的转换和传输也应该在人们的接受的等待时间内

    灵活性

    在操作方式上若发生变化,如无法使用浏览器进入系统,那么,可以使用命令方式进入如:可以通过编写java程序与数据库联接,实现登录
    因为本系统开发是使用jsp实现,这种开发技术具有java一样的很好的系统移植性
    对于数据精度方面,应在数据库中加以限制;实现实体完整性,用户自定义完整性约束
    在设计界面结构和数据结构是应留有对以后扩充系统功能的余地,如可以在每个数据字段上设计多个自定义字段

    2 系统设计2.1 系统概要设计在需求明确、准备开始编码之前,要做概要设计。概要设计的主要任务是把需求分析得到的DFD转换为软件结构和数据结构。设计软件结构的具体任务是:将一个复杂系统按功能进行模块划分、建立模块的层次结构及调用关系、确定模块间的接口及人机界面等。数据结构设计包括数据特征的描述、确定数据的结构特性、以及数据库的设计。概要设计有多种方法。在早期有模块化方法、功能分解方法;在60年代后期提出了面向数据流和面向数据结构的设计方法;近年来又提出面向对象的设计方法等。本系统采用模块化软件设计,自顶向下逐层把软件系统划分成若干模块。每个模块完成一个特定的功能,最后将所有模块按照某种方法组合成一个整体,达到整个播放器所要求的功能。
    2.2 系统功能设计及描述本选课系统不仅要实现常见的选课功能,而且还要有友好的用户界面。其最终设计目标是:多用户可以同时对系统进行操作、实现学生选课及对个人信息的修改,实现老师可以查看学生选课情况及对个人信息的修改,实现管理员对教师,学生信息修改及对课程的管理、运行平台要求不高、界面美观舒适、操作简单、易维护、高稳定性,能满足用户的常见需求。
    主要划分为以下几个功能模块,每个功能模块的作用描述如下:

    班级管理:主要用来管理班级情况
    课程管理:管理员可以对课程进行管理确定课程的数量
    学生管理:管理员可以对学生进行管理,可以对学生增加或者删除
    成绩录入:将成绩提交到数据库
    统计查询:统计某一个学生的所修课程信息、汇总出学分、不及格课程(标红)统计每一门课程的最高分、最低分和平均分

    3 系统功能的实现3.1 学生登录界面
    关键代码
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <base href="<%=basePath%>"> <title>班级信息管理系统登陆界面</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <link rel="stylesheet" type="text/css" href="styles.css"> <link href="/Wopop_files/style_log.css" rel="stylesheet" type="text/css"> <link rel="stylesheet" type="text/css" href="/Wopop_files/style.css"> <link rel="stylesheet" type="text/css" href="/Wopop_files/userpanel.css"> <link rel="stylesheet" type="text/css" href="/Wopop_files/jquery.ui.all.css"> <script src="/Wopop_files/login.js"></script> <script src="/Wopop_files/JQuery.cookie.js"></script> <script src="/Wopop_files/google_jquery.min.js"></script> <script src="/Wopop_files/google_jquery-ui.min.js"></script><script language="JavaScript">function chkvalue(txt) { if(txt.value=="") alert("文本框里必须填写内容!");}</script></head> <body class="login" id="myform" method="post"><div class="login_m"><div class="login_logo"><h1><strong>班级信息管理系统</strong></h1></div><div class="login_boder"><div class="login_padding" id="login_model"> <h2>用户名</h2> <label> <input type="text" id="username" name="username" class="txt_input txt_input2" onfocus="if(this.value=='请输入用户名'){this.value='';}" onblur="if(this.value==''){this.value='请输入用户名';}" value="请输入用户名" value="${sid}"> </label> <h2>密码</h2> <label> <input type="password" name="password" id="password" class="txt_input" onfocus="if(this.value=='*******'){this.value='';}" onblur="if(this.value==''){this.value='*******';}" value="*******" value="${spassword}"> </label> <font size="3px;" style="color: red"> ${msg} </font> <div class="rem_sub"> <div class="rem_sub_l"> <p class="pull-left" align="right"><a id="iforget" href="register.action"> 注册</a></p> </div> <p class="forgot" ><a id="iforget" href="../index.jsp">忘记密码 ?     </a></p> </div> <div class="rem_sub"> <div class="rem_sub_l"> <input type="checkbox" name="checkbox" id="save_me"> <label for="checkbox">记住用户信息</label> </div> <label> <input type="submit" class="sub_button" name="button" id="button" value="登 录" style="opacity: 0.7;" onClick="IMG1_onclick2()" > </label> </div></div><div id="forget_model" class="login_padding" style="display:none"><br> <h1>Forgot password</h1> <br> <div class="forget_model_h2">(Please enter your registered email below and the system will automatically reset users’ password and send it to user’s registered email address.)</div> <label> <input type="text" id="usrmail" class="txt_input txt_input2"> </label> <div class="rem_sub"> <div class="rem_sub_l"> </div> <label> <input type="submit" class="sub_buttons" name="button" id="Retrievenow" value="Retrieve now" style="opacity: 0.7;">     <input type="submit" class="sub_button" name="button" id="denglou" value="Return" style="opacity: 0.7;">   </label> </div></div><!--login_padding Sign up end--></div><!--login_boder end--></div><!--login_m end--><br> <br> <p align="center"> 班级信息管理系统 <a href="http://www.stdu.edu.cn/" target="_blank" title="铁大官网"></a> - Made by <a >陈鹏</a></p></body><script type="text/javascript"> function IMG1_onclick2() { var sid = document.getElementById("username"); var spassword = document.getElementById("password"); var url = "login_check.action?sid=" + escape(sid.value) + "&spassword=" + escape(spassword.value); if (sid.value == "") { alert("用户名不能为空"); } else if (spassword.value == "") { alert("密码不能为空"); } else if (sid.value.length > 20 ||sid.value.length < 6) { alert("用户名小于6位或大于20位"); } else if (spassword.value.length > 20 || spassword.value.length < 6) { alert("密码小于6位或大于20位"); } else if (spassword.value=="******"||sid.value == "请输入用户名") { alert("请输入正确的用户信息"); } else if (CheckCode(sid.value) && CheckCode(sid.value) ) { alert("有特殊字符请重新填写!"); sid.value = ""; spassword.value = ""; }else { /* alert(0); */ window.location.href = url; } } function CheckCode(s) //有特殊字符为true { var containSpecial = RegExp(/[(\ )(\~)(\!)(\#)(\$)(\%)(\^)(\&)(\*)(\()(\))(\-)(\_)(\+)(\=)(\[)(\])(\{)(\})(\|)(\\)(\;)(\:)(\')(\")(\,)(\.)(\/)(\<)(\>)(\?)(\)]+/); return (containSpecial.test(s)); }</script></html>
    3.2 主页
    关键代码
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="/struts-tags" prefix="s"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>班级信息管理系统</title> <%@include file="/WEB-INF/Z-views/common/head.jsp"%> <%-- <script type="text/javascript" src="/js/jquery1.js"></script> --%> <script type="text/javascript"> $(document).ready( function() { $(".div2").click( function() { $(this).next("div").slideToggle("slow").siblings( ".div3:visible").slideUp("slow"); }); }); function openurl(url) { var rframe = parent.document.getElementById("rightFrame"); rframe.src = url; }</script><style type="text/css">body { margin: 0; font-family: 微软雅黑; background-image: url(images/.jpg); background-repeat: no-repea; background-size: cover; background-attachment: fixed;}.top1 { position: absolute; top: 0px; width: 100%; height: 20px; text-align: center; color: black; font-size: 17px; font-height: 20px; font-family: 楷体;}.title {float:left; margin:-32px 20px; font-size: 35px; color: black; font-height: 30px; font-family: 隶书;}.top2 { position: absolute; top: 20px; width: 100%; height: 77px; text-align: center; color: #ccffff;}.left { position: absolute; left: 0px; top: 97px; width: 200px; height: 85%; border-right: 1px solid #9370DB; color: #000000; font-size: 20px; text-align: center;}.right { position: absolute; left: 200px; top:97px; width: 85.2%; height: 85%; border-top: 0px solid #484860; font-size: 14px; text-align: center;}.end { position: absolute; bottom: 0px; width: 100%; height: 30px; text-align: center; color: #556B2F; font-size: 17px; font-height: 20px; font-family: 楷体; background-color:ABD6E0}.div1 { text-align: center; width: 200px; padding-top: 10px;}.div2 { height: 40px; line-height: 40px; cursor: pointer; font-size: 18px; position: relative; border-bottom: #ccc 0px dotted;}.div3 { display: none; cursor: pointer; font-size: 15px;}.div3 ul { margin: 0; padding: 0;}.div3 li { height: 30px; line-height: 30px; list-style: none; border-bottom: #ccc 1px dotted; text-align: center;}.a { text-decoration: none; color: #000000; font-size: 15px;}.a1 { text-decoration: none; color: #000000; font-size: 18px;}</style> </head> <body> <div class="top1"> <marquee scrollAmount=2 width=300>欢迎使用该系统!</marquee> </div> <div class="top2"> <div class="title" > <br/> <span style="size:18px"> 班级信息管理系统</span> <br/> </div> <div class="fr top-links" align="right" > <br/> <br/> <a href="javascript:void(0);" onClick="openurl('help');"> <i class="ti-user"></i> <span style="color: black">登录用户:DeathGhost</span></a> </div> </div> <div class="left"> <div class="div1"> <a class="a" href="javascript:void(0);" onClick="openurl('student_Studentlist.action');"> <div class="div2"> <i class="ti-user"></i> 学生信息 </div> </a> <a class="a" href="javascript:void(0);" onClick="openurl('banji_Banlist.action');"> <div class="div2"> <i class="ti-view-list-alt"></i> 班级信息 </div> </a> <a class="a" href="javascript:void(0);" onClick="openurl('kecheng_KeChenglist.action');"> <div class="div2"> <i class="ti-text"></i> 课程信息 </div> </a> <a class="a" href="javascript:void(0);" onClick="openurl('score_ChengJilist.action');"> <div class="div2"> <i class="ti-pencil-alt2"></i> <span>成绩录入</span> </div> </a> <a class="a" href="javascript:void(0);" onClick="openurl('tongji');"> <div class="div2"> <i class="ti-map"></i> 统计查询 </div> </a> <a class="a" href="javascript:void(0);" onClick="openurl('help.action');"> <div class="div2"> <i class="ti-bell"></i> 系统信息 </div> </a> <a class="a" href="login.action" onclick="Exit_onclick()"> <div class="div2"> <i class="ti-export"></i> 退出系统 </div> </a> </div> </div> <div class="right"> <iframe id="rightFrame" name="rightFrame" width="100%" height="100%" scrolling="auto" marginheight="0" marginwidth="0" align="top" style="border: 0px solid #CCC; margin: 0; padding: 0;"> </iframe> <div class="copyright pull-right"> <p style="color:black"> 班级信息管理系统 <a href="http://www.stdu.edu.cn/" target="_blank" title="铁大官网">   </a></p> </div> </div> </body> <!-- 退出系统的验证 --> <script language="JavaScript"> function Exit_onclick() { if (confirm("确定退出系统吗?")) { return true; } else{ return false; } } </script></html>
    3.3 查看学生信息
    关键代码
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="/struts-tags" prefix="s"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>学生信息管理界面</title> <%@include file="/WEB-INF/Z-views/common/head.jsp"%> </head><body><s:debug/><br/> <br/> <center> <s:form id="domainForm" action="student_Studentlist" theme="simple"> 名称: <s:textfield name="baseQuery.sname" placeholder="名称" />   <a href="javascript:;" onclick="go(1);" class="add">搜索 </a>   <a href="student_input.action" class="add">添加</a> <br /> <br /> <table border="1" align="center"> <tr style="background-color: PowderBlue;"><!--style="background-color: DodgerBlue;" --> <th width="15%" ><span><strong>学 号</strong></span></th> <th width="15%" ><span><strong>姓名</strong></span></th> <th width="12%" ><span><strong>性别</strong></span></th> <th width="15%" ><span><strong>密码</strong></span></th> <th width="11%" ><span><strong>联系电话</strong></span></th> <th width="11%" ><span><strong>家庭住址</strong></span></th> <th colspan="2" width="11%" align="center"><span><strong>操作</strong></span></th> </tr> <s:iterator value="pageList.rows" var="t"> <tr style="background-color: white;"> <td><s:property value='sid'/></td> <td><s:property value='sname'/></td> <td><s:property value='ssex'/></td> <td><s:property value='spassword'/></td> <td><s:property value='slxdh'/></td> <td><s:property value='sjtzz'/></td> <td><button type="button" class="btn1" onclick="updateDomain('student_updateAction.action?sid=<s:property value='sid'/>');">编辑</button></td> <td><button type="button" class="btn1" onclick="deleteDomain('student_delete.action?sid=<s:property value='sid'/>');">删除</button></td> </tr> </s:iterator> </table> <%@include file="/WEB-INF/Z-views/common/page.jsp"%> </s:form> </center></body><%-- <%@include file="/WEB-INF/Z-views/common/tail.jsp"%> --%></html>
    3.4 班级信息
    关键代码
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="/struts-tags" prefix="s"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head> <title>班级信息管理界面</title><%@include file="/WEB-INF/Z-views/common/head.jsp"%> </head><body><s:debug></s:debug><br/><br/> <center> <s:form id="domainForm" action="banji_Banlist.action" theme="simple"> 名称: <s:textfield name="baseQuery.bname" placeholder="名称" />   <a href="javascript:;" onclick="go(1);" class="add">搜索 </a>   <a href="banji_input.action" class="add">添加</a> <br /> <br /> <table border="1" > <tr style="background-color: ;"> <th width="20%" ><span><strong>编 号</strong></span></th> <th width="40%" ><span><strong>名 称</strong></span></th> <th colspan="2" width="20%"><span><strong>操作</strong></span></th> </tr> <s:iterator value="pageList.rows" var="st"> <tr style="background-color: white;"> <th><s:property value='bid'/> </th> <th><s:property value='bname'/></th> <td ><button type="button" class="" onclick="updateDomain('banji_actionUpdate.action?bid=<s:property value='bid'/>');">编辑</button></td> <td><button type="button" class="" onclick="deleteDomain('banji_delete.action?bid=<s:property value='bid'/>');">删除</button></td> </tr> </s:iterator> </table> <%@include file="/WEB-INF/Z-views/common/page.jsp"%> </s:form> </center></body><%-- <%@include file="/WEB-INF/Z-views/common/tail.jsp"%> --%><center></center></html>
    3.5 课程信息
    关键代码
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="/struts-tags" prefix="s"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>课程信息管理界面</title> <%@include file="/WEB-INF/Z-views/common/head.jsp"%> </head><body><s:debug></s:debug><br/><br/> <center> <s:form id="domainForm" action="kecheng_KeChenglist" theme="simple"> 名称: <s:textfield name="baseQuery.kname" placeholder="名称" />   <a href="javascript:;" onclick="go(1);" class="add">搜索 </a>   <a href="kecheng_input.action" class="add">添加</a> <br /> <br /> <table border="1" > <tr style="background-color: PowderBlue;"> <th width="20%" ><span><strong>课程编号</strong></span></th> <th width="20%" ><span><strong>课程名称</strong></span></th> <th width="20%" ><span><strong>课程性质</strong></span></th> <th width="20%" ><span><strong>课程学分</strong></span></th> <th colspan="2" width="20%" ><span><strong>操作</strong></span></th> </tr> <s:iterator value="pageList.rows" status="st"> <tr style="background-color: white;"> <td><s:property value='kid'/></td> <td><s:property value='kname'/></td> <td><s:property value='knature'/></td> <td><s:property value='kxf'/></td> <td><button type="button" class="btn1" onclick="updateDomain('kecheng_actionUpdate.action?kid=<s:property value='kid'/>');">编辑</button></td> <td><button type="button" class="btn1" onclick="deleteDomain('kecheng_delete.action?kid=<s:property value='kid'/>');">删除</button></td> </tr> </s:iterator> </table> <%@include file="/WEB-INF/Z-views/common/page.jsp"%> </s:form> </center></body><%@include file="/WEB-INF/Z-views/common/tail.jsp"%></html>
    3.7 成绩录入
    关键代码
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="/struts-tags" prefix="s"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head> <title>学生成绩信息管理界面</title><%@include file="/WEB-INF/Z-views/common/head.jsp"%> <script type="text/javascript" src="/js/model/score.js"></script></head><body><s:debug/><br/><br/> <center> <s:form id="domainForm" action="chengji_ChengJilist.action" theme="simple"> 学生学号: <s:textfield name="baseQuery.sid" placeholder=" 学生学号" />     课程名称: <s:select onchange='$("#domainForm").submit();' style="height:23px;" list="#allCnames" name="baseQuery.kid" listValue="kname" listKey="kid" headerKey="-1 " headerValue="------------请选择------------" />  <a href="javascript:;" onclick="go(1);" style="position: relative; left: 3%">搜索 </a>   <br /> <br /> <table border="1" > <tr style="background-color: PowderBlue;"> <th width="18%" ><span><strong>学生学号</strong></span></th> <th width="18%" ><span><strong>学生姓名</strong></span></th> <th width="18%" ><span><strong>学生班级</strong></span></th> <th width="25%" ><span><strong>所选课程</strong></span></th> <th width="10%" ><span><strong>课程成绩</strong></span></th> <th colspan="2" width="5%"><span><strong>操作</strong></span></th> </tr> <s:iterator value="pageList.rows"><!-- var="t" --> <tr style="background-color: white;"> <td><s:property value="STable.sid"/></td> <td><s:property value="STable.sname"/></td> <td><s:property value="STable.BTable.bname"/></td> <td><s:property value="KTable.kname"/></td> <td><!-- <s:property value='ccj'/> --> <input name="ccj" id="ccj" value="${ccj}" /> </td> <td ><a onclick="update(this)"><button type="button">保存 </button></a></td> </tr> </s:iterator> </table> <%@include file="/WEB-INF/Z-views/common/page.jsp"%> </s:form> </center></body></html>
    3.8 统计查询
    关键代码
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="/struts-tags" prefix="s"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>课程信息管理界面</title> <%@include file="/WEB-INF/Z-views/common/head.jsp"%> </head><body><br/> <s:form> <table border="1" align="center"> <tr ><!--style="background-color: DodgerBlue;" --> <th width="11%" ><span><strong>学 号</strong></span></th> <th width="11%" ><span><strong>姓名</strong></span></th> <th width="8%" ><span><strong>性别</strong></span></th> <th width="11%" ><span><strong>出生日期</strong></span></th> <th width="11%" ><span><strong>密码</strong></span></th> <th width="11%" ><span><strong>联系电话</strong></span></th> <th width="11%" ><span><strong>家庭住址</strong></span></th> <th width="11%" ><span><strong>班级编号</strong></span></th> <th colspan="2" width="11%" ><span><strong>操作</strong></span></th> </tr> <s:iterator value="pageList.rows" status="st"> <tr style="background-color: white;"> <td>${sid}</td> <td>${sname}</td> <td>${ssex}</td> <td>${spassword}</td> <td>${slxdh}</td> <td>${sjtzz}</td> <td>${sName}</td> <td><button type="button" class="btn1" onclick="updateDomain('role_input.action?roleId=${roleId}');">编辑</button></td> <td><button type="button" class="btn1" onclick="deleteDomain('role_delete.action?roleId=${roleId}');">删除</button></td> </tr> </s:iterator> </table> </s:form></body><%@include file="/WEB-INF/Z-views/common/tail.jsp"%></html>
    4 心得体会通过这次使用SSH框架编写大作业,初期对于搭框架就遇到了不少问题,后来问同学+百度解决了问题,在后来进行删除操作,涉及到了级联操作,添加的时候也存在主外键约束,有时候查程序感觉是对的,但是运行结果总是不对,就开始调试,在控制台打印文字,根据这些调试和打印出的文字,来使程序能够正确运行,总之,这次还是有不少收获,中间遇到的问题,以及需要注意的地方写了一个TXT文件,也方便以后查看。
    3 评论 59 下载 2018-11-05 17:04:45 下载需要6点积分
  • 基于C#与SQL SERVER数据库的学生选课及成绩查询管理系统的设计与开发

    1 项目背景学生选课及成绩查询系统是一个学校不可缺少的部分,传统的人工管理档案的方式存在着很多的缺点,如:效率低、保密性差等,所以开发一套综合教务系统管理软件很有必要,它应该具有传统的手工管理所无法比拟的优点,如:检索迅速、查找方便、可靠性高、存储量大、保密性好、寿命长、成本低等。这些优点能够极大的提高学校的管理效率,有助于推进学校的信息化建设。
    2 技术选型本系统未采用C#实现MDI——多文档窗口,因为考虑到C#的该技术与java类似,而暑期java实训时,曾用过类似的方法做过停车场管理系统,所以想为这次的系统注入一点新鲜的血液,所以本系统设计的主题采用了了C#的C#TreeView 实现。
    3 需求分析本系统包括两类用户:学生、管理员。管理员可以通过系统来添加管理员信息、修改管理员信息、添加学生信息、修改学生信息;开设课程、查询课程、录入成绩、统计成绩、修改成绩、修改个人密码等,而学生则可以通过系统来选择课程、查询课程、显示自己的课表、查询自己的成绩单、修改个人密码等等。
    3.1 系统实现的功能流程
    3.2 管理员角色拥有的功能3.2.1 管理员信息管理
    添加管理员信息

    管理员可以添加其他的管理员信息
    修改管理员信息

    管理员可以删除其他的管理员信息

    3.2.2 学生信息管理
    添加学生信息

    管理员可以添加学生信息,这些信息包括学生的学号,密码,年级,专业,出生日期等等
    修改学生信息

    管理员可以修改学生的信息

    3.2.3 课程管理
    开设课程

    管理员可以录入课程信息,学生就可以浏览到这些课程信息,从而选课
    查询课程

    可以通过学期查询课程,或通过学期和课程结合的方式查询课程

    3.2.4 成绩管理
    录入成绩

    管理员可以录入学生的成绩
    统计成绩

    管理员可以通过学期和课程信息来统计某门课的学生成绩,平均分、最高分、最低分以及可以通过成绩区间来查询某个学期某门课的学生的成绩信息。并且可以实现排序功能
    修改成绩

    管理员可以对成绩出错的学生的成绩进行修改
    修改个人密码

    管理员可以修改自己的密码

    3.3 学生角色拥有的功能3.3.1 课程管理
    选择课程

    学生可以根据本学期管理员发布的课程来选课
    查询课程

    可以通过学期查询课程,或通过学期和课程结合的方式查询课程
    显示课表

    学生可以根据自己的选课情况来查询自己的课表

    3.3.2 成绩管理
    我的成绩单

    学生可以根据学期来查询自己某个学期所有选修课程的成绩信息
    修改个人密码

    学生可以修改自己的密码

    4 数据库设计4.1 数据库关系图
    4.2 完成系统中数据表的结构设计学生信息表



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




    stuid
    int
    不可

    主键,学生id,无实际意思,每次自增1


    stuname
    Nvarchar(30)
    不可

    学生姓名


    stuxuehao
    Nvarchar(30)
    不可

    学生学号,不能重复,登陆时的用户名默认是学号。


    stupasswd
    Nvarchar(30)
    不可

    学生密码


    stugrade
    Nvarchar(30)


    学生年级


    stumajor
    Nvarchar(30)


    学生专业


    stusex
    varchar(2)


    学生性别


    stuborn
    Nvarchar(30)


    学生出生日期


    role
    Nvarchar(30)

    学生
    角色,学生


    stuhometown
    Nvarchar(30)


    学生籍贯



    管理员信息表



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




    manid
    int
    不可

    主键,管理员id,无实际意思,每次自增1


    manname
    Nvarchar(30)
    不可

    管理员用户名


    role
    Nvarchar(30)
    不可
    管理员
    角色,管理员


    manpasswd
    Nvarchar(30)
    不可

    管理员密码



    课程表



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




    claid
    int
    不可

    主键,课程id,无实际意思,每次自增1


    claname
    Nvarchar(30)
    不可

    课程名


    term
    Nvarchar(30)
    不可

    开课的学期


    teacher
    Nvarchar(30)
    不可

    开课的教师



    课程细节表



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




    sctimeid
    int
    不可

    主键,课程细节id,无实际意思,每次自增1


    claid
    int
    不可

    外键,课程号


    sctime
    Nvarchar(30)
    不可

    课程上课的时间


    location
    Nvarchar(30)
    不可

    课程上课的地点



    选课表



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




    scid
    int
    不可

    主键,选课id,无实际意思,每次自增1


    stuid
    int
    不可

    外键,学生id


    claid
    int
    不可

    外键,课程id


    grades
    int
    不可

    学生成绩



    5 界面设计登录界面

    5.1 管理员角色管理员主界面

    管理员———-添加管理员界面

    管理员——修改管理员界面

    管理员——开设课程界面

    管理员——查询课程界面

    管理员——录入成绩界面

    管理员——统计成绩页面

    管理员——修改成绩界面

    管理员——添加学生信息界面

    管理员——修改学生信息界面

    管理员——修改密码界面

    5.2 学生界面学生登录主界面

    学生——选择课程界面

    学生——查询课程界面

    学生——显示课表界面

    学生——我的成绩单

    学生——密码修改界面

    6 关键技术的介绍6.1 选项使用treeview实现点击不同的选项,在右侧面板中显示不同的界面。
    具体代码如下:
    private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) { switch (this.treeView1.SelectedNode.Text) { case"录入成绩": Form2 f = new Form2(); f.TopLevel = false; f.FormBorderStyle = FormBorderStyle.None; f.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f); f.Show(); break; case"我的成绩单": searchgradeForm f1 = new searchgradeForm(); f1.TopLevel = false; f1.FormBorderStyle = FormBorderStyle.None; f1.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f1); f1.Show(); break; case"统计成绩": countForm f2 = new countForm(); f2.TopLevel = false; f2.FormBorderStyle = FormBorderStyle.None; f2.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f2); f2.Show(); break; case"开设课程": kaisheForm f3 = new kaisheForm(); f3.TopLevel = false; f3.FormBorderStyle = FormBorderStyle.None; f3.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f3); f3.Show(); break; case"选择课程": chooseForm f4 = new chooseForm(); f4.TopLevel = false; f4.FormBorderStyle = FormBorderStyle.None; f4.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f4); f4.Show(); break; case"查询课程": searchclassForm f5 = new searchclassForm(); f5.TopLevel = false; f5.FormBorderStyle = FormBorderStyle.None; f5.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f5); f5.Show(); break; case"添加管理员信息": addmanForm f6 = new addmanForm(); f6.TopLevel = false; f6.FormBorderStyle = FormBorderStyle.None; f6.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f6); f6.Show(); break; case"修改管理员信息": modifymanForm f7 = new modifymanForm(); f7.TopLevel = false; f7.FormBorderStyle = FormBorderStyle.None; f7.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f7); f7.Show(); break; case"添加教师信息": addteacForm f8 = new addteacForm(); f8.TopLevel = false; f8.FormBorderStyle = FormBorderStyle.None; f8.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f8); f8.Show(); break; case"修改教师信息": modifyteacForm f9 = new modifyteacForm(); f9.TopLevel = false; f9.FormBorderStyle = FormBorderStyle.None; f9.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f9); f9.Show(); break; case"添加学生信息": addstuForm f10 = new addstuForm(); f10.TopLevel = false; f10.FormBorderStyle = FormBorderStyle.None; f10.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f10); f10.Show(); break; case"修改学生信息": modifystuForm f11 = new modifystuForm(); f11.TopLevel = false; f11.FormBorderStyle = FormBorderStyle.None; f11.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f11); f11.Show(); break; case"关于": aboutForm f12 = new aboutForm(); f12.TopLevel = false; f12.FormBorderStyle = FormBorderStyle.None; f12.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f12); f12.Show(); break; case "退出系统": Application.Exit(); break; case "显示课表": showkebiaoForm f13 = new showkebiaoForm(); f13.TopLevel = false; f13.FormBorderStyle = FormBorderStyle.None; f13.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f13); f13.Show(); break; case "修改密码": modifymimaForm f14 = new modifymimaForm(); f14.TopLevel = false; f14.FormBorderStyle = FormBorderStyle.None; f14.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f14); f14.Show(); break; case "修改成绩": modifygradeFram f15 = new modifygradeFram(); f15.TopLevel = false; f15.FormBorderStyle = FormBorderStyle.None; f15.WindowState = FormWindowState.Maximized; panel2.Controls.Add(f15); f15.Show(); break; } }
    6.2 在其他的窗口得到在登录窗口输入的信息实现方法:在loginFram中设置两个方法,在其他类中只需要引用loginFram的这些方法即可。
    具体实现如下:
    public static String getStudent() { String stuxuehao = ""; stuxuehao = loginForm.name; return stuxuehao; } public static String getRole() { String role1 = ""; role1 = role; return role1; }
    6.3 管理员开设课程异常处理管理员开设课程时,对于同一时间该教室有课的情况怎么做出异常处理。集体实现如下:
    private void button1_Click(object sender, EventArgs e) { string teacher = textBoxteacher.Text; string classes = textBoxclass.Text; string term = comboBoxterm.SelectedItem.ToString(); string flags = "1"; SqlConnection conn = new SqlConnection(loginForm.connectionString); conn.Open(); SqlCommand cmd = new SqlCommand(); cmd.Connection = conn; //将开课信息插入到开课表里 //MessageBox.Show("开设课程成功!"); string sql = ""; //得到上课的地点 string didian = comboBoxdidian.SelectedItem.ToString(); //checkedListBoxtime for (int i = 0; i < checkedListBoxtime.Items.Count; i++) { if (checkedListBoxtime.GetItemChecked(i)) { String time = checkedListBoxtime.GetItemText(checkedListBoxtime.Items[i]); sql = "select * from sctime where sctime = '" + time + "'and location = '" + didian + "'"; SqlDataAdapter adp = new SqlDataAdapter(sql, conn); DataSet ds = new DataSet(); adp.Fill(ds); if (ds.Tables[0].Rows.Count > 0) { flags = "2"; MessageBox.Show("该时间该教室已经有课!"); break; } else { flags = "1"; break; } } } if (flags == "1") { sql = "insert into class (claname,term,teacher) values ('" + classes + "','" + term + "','" + teacher + "')"; cmd.CommandText = sql; cmd.ExecuteNonQuery(); for (int i = 0; i < checkedListBoxtime.Items.Count; i++) { if (checkedListBoxtime.GetItemChecked(i)) { string time = checkedListBoxtime.GetItemText(checkedListBoxtime.Items[i]); //将开课表的id得到 sql = "select claid from class where claname = '" + classes + "' and term = '" + term + "' and teacher = '" + teacher + "'"; cmd.CommandText = sql; String id1 = cmd.ExecuteScalar().ToString(); int id = 0; int.TryParse(id1, out id); sql = "insert into sctime values(" + id + ",'" + time + "','" + didian + "')"; cmd.CommandText = sql; cmd.ExecuteNonQuery(); } } MessageBox.Show("开设课程成功!"); } conn.Close(); }
    6.4 学生选择课程异常处理学生选择课程时,对选择一门课程与已选择的课程出现上课时间冲突的情况的异常处理。集体实现如下:
    private void button1_Click(object sender, EventArgs e) { string flags = "1"; //得到stuid string stuxuehao = textBox1.Text; SqlConnection conn = new SqlConnection(loginForm.connectionString); conn.Open(); string sql = "select stuid from student where stuxuehao = '" + stuxuehao + "'"; SqlCommand cmd = new SqlCommand(sql, conn); String id1 = cmd.ExecuteScalar().ToString(); int.TryParse(id1, out stuid); //得到课程的id int claid = 0; int.TryParse(textBoxid.Text, out claid); //查询你在该时间是否有课 sql = "select sctime from sctime where claid =" + claid; SqlDataAdapter adp = new SqlDataAdapter(sql, conn); DataSet ds = new DataSet(); adp.Fill(ds); for (int i = 0; i < ds.Tables[0].Rows.Count; i++) { DataRow dr = ds.Tables[0].Rows[i]; string time = dr[0].ToString();//第一列 sql = "select * from sc,sctime,class where class.claid = sc.claid and class.claid = sctime.claid and sctime = '" + time + "' and sc.stuid =" + stuid; SqlDataAdapter adp1 = new SqlDataAdapter(sql, conn); DataSet ds1 = new DataSet(); adp1.Fill(ds1); if (ds1.Tables[0].Rows.Count > 0) { flags = "2"; MessageBox.Show("课程上课时间冲突!"); break; } } if (flags == "1") { sql = "insert into sc(claid,stuid) values(" + claid + "," + stuid + ")"; cmd.CommandText = sql; if (cmd.ExecuteNonQuery() > 0) { MessageBox.Show("选课成功!"); } } if (listBox1.Items.Count > 0) {//清空所有项 listBox1.Items.Clear(); } sql = "select class.claname from sc,class where sc.claid = class.claid and stuid=" + stuid; SqlDataAdapter adp2 = new SqlDataAdapter(sql, conn); DataSet ds2 = new DataSet(); adp2.Fill(ds2); foreach (DataRow row in ds2.Tables[0].Rows) { listBox1.Items.Add(row[0].ToString()); } conn.Close(); }
    7 系统测试怎么提高访问数据库的速度
    改进方法:引入视图、触发器、函数、存储过程,优化表结构,建立索引。
    8 完成情况总结通过几周的努力,从前期的需求分析与架构设计到实际的编码阶段,我完成了学生选课及成绩管理系统的开发与设计。已经大致完成了主要的功能,不过还有一些亟待完善的方面,例如对数据的存储采用加密的措施,UI设计并不是很出色等等,这些问题都需要我再以后的时间里去慢慢弥补,还有刚开始,我对treeview并不熟悉,所以先建立了几个原型来测试,领会了treeview的使用方法后才切入正题进行开发。
    在这开发的过程中,我收获很大,相比前几次的开发,我真正重视起测试在软件开发中的作用,在软件开发的后期,我专门建立一个bug列表,将出现的bug详细记录在列表中,并在软件调试的后期对照列表认真改进软件,考虑以后使用软件来做相关方面的管理。当然,我也遇到不少代码编写的问题,有时要花较长的时间来解决问题,这也是自己平时编写代码较少的原因。通过这次软件的开发,在编写代码上有了一定的提高,同时也知道了软件开发过程中需要注意的问题。比如,开发逻辑思维要清晰,不然可能会把问题想的复杂化。平时多和项目成员交流,这样你才能知道自己的想法有那些出入,利于软件的开发。
    通过这次实验,使我对软件开发有了更深一步的了解。在软件开发中应注意的问题和考虑的问题都能较好的做到。
    2 评论 11 下载 2018-11-06 16:45:43 下载需要5点积分
  • 基于Power Bulider和Oracle数据库实现的学生教务管理系统

    一、分析与建模1.1 系统业务流程图
    项目用例图



    1.2 功能需求分析与建模


    1.3 数据需求分析与建模体之间的联系:学生信息表(student)、教师信息表(teacher)、管理员信息表(Administrator)、课程表(course)、选课表(curricula_variable)、成绩表(score)、公告发布表(announcement)。

    管理员(Administrator):管理号、姓名、性别、年龄、联系电话、密码、邮箱
    公告(announcement):通知编号、管理号、通知标题、 通知内容
    学生(student):学号、姓名、性别 、民族、入学时间、专业、培养层次、学生联系电话、学生QQ、密码、邮箱
    成绩(score):学生编号、 课程编号、教师编号、学期、分数
    教师(teacher):教师编号、教师姓名、教师姓名、职称、所在学院、教师联系电话、教师QQ、密码、邮箱
    选课表(curricula_variable):选课编号、学号、课程号、学生编号、教师编号、上课时间、学生姓名、教师姓名、是否选课、教师审核
    课程(course):课程号、课程名、学分、课程简介

    二、系统设计2.1 功能设计根据学生选课排课—成绩查询管理的需要,学生成绩管理系统从功能上共分几大模块,其结构如图:

    系统管理员模块:可以进行管理员、教师、学生等不同身份选择性的登陆,对用户权限进行限制,方便不同级别用户工作
    学生管理模块:该模块主要功能是完成查看学生成绩信息、打印成绩报表。修改个人信息、查看公告和选课学习课程等功能
    教师管理模块:该模块主要功能是审核学生的选课,查看,学生成绩、选课、当有挂科时候,发布公告通知、以及对相关学生的成绩的录入合提交给管理员管理功能
    数据库管理员模块:该模块主要功能是查看、审核学生的选课情况、发布公告通知学生和教师,以及删除过于陈旧、误发布的公告。新增加、删除、修改、查询学生教师用户的个人信息。审核教师提交的学生成绩。还附带开发出完成数据的备份、,误删除以及恢复功能

    2.2 数据库设计在学生成绩管理数据库中需建立至少7个必要的数据表:学生信息表(student)、教师信息表(teacher)、管理员信息表(Administrator)、课程表(course)、选课表(curricula_variable)、成绩表(score)、公告发布表(announcement)。
    2.3 系统实现对系管理员而言,进入登陆界面后,可直接调用数据库中数据修改、查询本系统现有学生成绩信息等;对教师而言,进入登陆界面后,不仅有对教师自身信息能够得取得相关的权限外,可对全校学生成绩修改、查询,统计补考人员,打印成绩单等的操作。对于学生而言,可以实现自己的选课功能,成绩查询和预览、打印成绩单,查看公告。
    2.4 数据库设计
    三、系统开发与维护中的重难点3.1 系统开发与维护环境近几年来,随着学院新校建设、办学、招生规模的扩大,学校校生从 几千余人增加到 几万余人。与之对应的学生成绩信出现了几何式的增长, 使学校的的教务管理工作变的异常繁重,经常出现成绩查询不准确、补考学生统计不全等情况,采用传统的管理模式不适应学院当前的要求,因此学生成绩管理自动化、信息化也被提上了日程。在学校教务工作中占有很大比重的一项就是每学期末的成绩录入、成绩打印工作,以及部分选课在网上选课,采用传统的人工进行管理不仅任务重、效率低,而且易出错、不易查询、难于维护。
    学生成绩管理系统正是为了减轻教务人员工作量,实现学校管理自动化,解决学院学生成绩管理难这一难题的办公软件。本系统以中文版 Power bulider 12.5 为前台开发工具,PowerDesign 15.1和使用目前到2018年为止的最新的Oracle 11g数据库作为后台数据库。系统对操作人员的计算机水平要求不高,对他们几乎不加培训便能掌握系统的大部分功能使用。

    硬件环境:windows XP/win7 x86 x64/win10 x86 x64
    软件开发环境:Power bulider 12.5/ PowerDesign 15.1/Oracle 11g

    选择原因
    开发时候,因为大部分时间都需要在机房里面进行编写,而XP的系统现在还有一部分在计算机机房存在,所以要考虑到兼容,还有主要占领大部分份额的win7和现在正在推行的外win10的操作系统,都是需要考虑的能够兼容运行的。而实际上面我们开发了中考虑到了PowerBuilder提供了对目前流行的大多数关系数据库管理系统的支持,并且在PowerBuilder的应用程序中对数据库访问的部分一般采用国际化标准数据库查询语言SQL,方便我们使用PowerBuilder开发的应用程序的时候,可以不做修改或者只做少量的修改就可以在不同的后台数据库管理系统上使用。并且PowerBuilder开发的应用程序是独立于服务器上的数据库管理系统的。使用PowerDesigner不仅可以加速了开发的过程,而且也向最终的用户提供了管理和访问项目的信息的一个有效的结构方式。它允许我们编码时候创建和管理数据的结构,和开发和利用数据的结构针时候,使用开发工具环境快速地生成应用对象和数据敏感的组件。后台的数据库使用Oracle 11g则是考虑了它提供的高性能、伸展性、可用性和安全性,并且更方便地在低成本服务器和存储设备组成的网格上运行 ,相对过往版本而言,Oracle 11g具有了与众不同的特性。
    3.2 系统开发与维护的重难点3.2.1 教师登录界面

    user1=sle_1.textpsw1=sle_2.textusername=user1… if rb_2.checked=true then select count(*) into :count1 from teachers where tno= :user1; select count(*) into :count2 from teachers where tno=:user1 and tpsw=:psw1 ; if count2=1 then open(w_teacher_main)close(parent)else if count1=1 then messagebox("提示","密码错误!") count0=count0+1 if count0=3 then messagebox("提示","错误三次!") close(parent) else end if else messagebox("提示","用户名不存在!") count0=count0+1 if count0=3 then messagebox("提示","错误三次!") close(parent) else end if end ifend if3.2.2 课程信息管理:上传课程信息、检查课程信息

    dw_1.dataobject="d_student_view_course"dw_1.settransobject(sqlca)dw_1.insertrow(0)dw_1.retrieve("%")dw_1.settransobject(sqlca)dw_1.getrow()dw_1.retrieve("%"+sle_1.text+"%")integer imessagebox("提示","课程信息上传成功!")dw_1.update()commit;i=dw_1.insertrow(0)dw_1.scrolltorow(i)dw_1.settransobject(sqlca)dw_1.insertrow(0)close(parent)3.2.3 成绩管理:录入学生成绩、查看学生成绩、打印学生成绩


    dw_1.settransobject(sqlca)dw_1.insertrow(0)integer imessagebox("提示","成绩录入成功!")dw_1.update()commit;i=dw_1.insertrow(0)dw_1.scrolltorow(i)close(parent)dw_1.dataobject="d_select_chengji"dw_1.settransobject(sqlca)//dw_1.insertrow(0)dw_1.retrieve("%")dw_1.retrieve("%"+sle_1.text+"%")dw_1.settransobject(sqlca)dw_1.getrow()dw_1.dataobject="d_select_chengji"dw_1.settransobject(sqlca)dw_1.retrieve("%")dw_1.object.datawindow.print.preview=truedw_1.print()3.2.4 个人信息管理:密码修改、查看个人信息

    string psw1username=sle_1.text select tpsw into :psw1 from teachers where tno=:username; if sle_2.text=psw1 then if sle_3.text=sle_4.text then update teachers set tpsw=:sle_3.text where tno=:username; messagebox("提示","密码修改成功") close(parent) else messagebox("提示","两次密码不一致") end if else messagebox("提示","原密码错误")end ifdw_1.settransobject(sqlca)dw_1.retrieve(username)dw_1.settransobject(sqlca)dw_1.getrow()3.2.5 公告管理模块:发布、查看、删除、打印公告


    dw_1.settransobject(sqlca)dw_1.insertrow(0)integer imessagebox("提示","公告插入成功!")dw_1.update()commit;i=dw_1.insertrow(0)dw_1.scrolltorow(i)dw_1.settransobject(sqlca)dw_1.insertrow(0)dw_1.dataobject="d_gonggao1"dw_1.settransobject(sqlca)dw_1.retrieve("%")dw_1.retrieve("%"+sle_1.text+"%")dw_1.deleterow(dw_1.getrow())dw_1.update()3.2.6 选课管理:查看学生选课
    dw_1.dataobject="d_teacher_view_course1"dw_1.settransobject(sqlca)dw_1.insertrow(0)dw_1.retrieve("%")dw_1.settransobject(sqlca)dw_1.getrow()五、总结通过为期五周的课程小学期实训教程的临近结束,有一开始的有一个大概的了解数据库,到后来模糊知道了使用PowerBuild编写界面程序,发现它是能够如此之快的在短时间类完成相关的一个带界面的管理类程序软件。
    随着信息技术的发展,办公自动化已成为社会发展的主要趋势,学生选课—成绩管理系统的开发也就必不可少了,因此在这次的实践活动中,我们决定采用目前流行的PowerBuilder12.5 + Oracle11g + PowerDesign15.0设计了一个小型的学生选课–成绩查询系统,以增加对于项目的经验积累。完成项目之后,且对设计结果进行了一定的总结。总结如下:
    对于E_R图,生成表、和表与表之间的联系一定要正确,最好不要有大的问题。可以在设计过程中反复修改,以达到完美。而学生选课—成绩查询管理因为其日常事务比较繁琐,在设计数据库表之前一定要对系统的设计有一个整体的认识,对学生信息和课程信息进行整理,设计好各功能模块的E-R图。这样,在后期的编码设计时,避免了在后期便编写源码的过程中反复更改之前设计的表和相关E-R图。尤其是注意一点,千千万万不要命名使用英文和拼音混合,不然的话会是一个很悲伤的故事,还经常找不到相关的设计。
    对于公共部分的源码,窗口控件和布局都可以设计成具有通用性质,以提高编写的性能和缩短研发速度。还要注意代码的健壮性、稳定性和测试时候的一些边缘值的测试。在设计各个功能模块时,要考虑和其他模块的联系,更要结合实际情况对窗口要放置的空间进行分析,尤其在编制代码是要充分考虑各种限制条件,对不同的身份规定其不同的登录权限。
    还要注意与组员之间的沟通和交流,毕竟每个小组都是分工合作的。当组员出现了bug的时候,要能够帮助其找出错误,向互联网和组长和老师寻求帮助,以提高团队的氛围和整体水平,还可以促进大家之间的情感交流。何乐而不为?
    最后通过本小学期实践教学环节,我们不仅掌握了设计的基本步骤,懂得了编程的规范化,习惯和命名的规范化,设计初期的重要性和严谨性,编写的源码程序具有容错性和健壮性。并且在这五周之中,也离不开老师的耐心辅导,总是为了我们的知识的完备性,讲着更多的知识点,希望我们能够学的更好,辛苦劳累。最后通过这次的学习,加深了我们对软件开发的认识与理解。也为今后的开发打下了坚实基础和宝贵的经验。
    1 评论 1 下载 2019-07-04 10:08:52 下载需要12点积分
  • 基于JAVA和SQL SERVER数据库实现的酒店管理系统

    1 设计目标就数据库学习应用于生活,以简单数据库应用为例,本小组以制作“酒店管理系统”为目标。该管理系统已经能实现一些酒店住房管理的一些基本功能,适用于中小型宾馆使用及访问,旨在用计算机系统为操作人员提供更方便的操作,并保持很高的灵活性和易操作性,该软件具备以下特点:

    易学易用,操作简便,它是基于Java的应用程序,操作界面友好直观
    功能完善,本系统包括前台经营和后台管理,功能完善,能够实现酒店的数字化经营
    开放型好,采用标准的开发工具和技术,后台数据库采用微软SQL 2008中文版,可以提供开放的数据接口,可同其他软件交流数据
    较为完善的会员机制
    功能完善,分为 4 个主要模块,分别为:查询房间状态、加入会员、宾客入住、结账

    查询房间状态,该功能可以查询当前的房状态,查询已入住和未入住的信息,并且很好的保存了用户的隐私,实现了连接SQL Server 2008 R2数据库从所建的表中查询功能
    加入会员模块:该功能可以实现连接SQL Server 2008 R2数据库从所建的表中插入、修改功能。并且设计会员打折模块(未实现)
    来宾入住模块:该功能实现了和现实生活一样的模式,登记入住信息,连接SQL Server 2008 R2数据库从所建的表中更新功能,把来宾的个人信息插到用来存放数据看guess表中
    结账模块:该功能实现了从数据库中查询自己的入住信息,和点击结账之后的数据更新功能,结账之后更新数据库的guess表,把入住状态设为未入住等


    2 功能设计
    3 数据库设计关于数据库设计方面,我们做的不是很完善,比如设计的这个数据库,有很多的函数依赖都没有消除,主码外码等定义也不是特别完美。名为Hotel的数据库主要分为三个表,分别是:guess,vip,operater.

    其中,guess主要用来存储来访信息和用户住房登录信息的,它的构造如下图:

    数据库主要的实现查询更新插入等功能便是通过这张表。
    Vip表是用于存储用户加入会员的,而operaer则是用于登录的时候存储管理员的信息的。其中guess表是整个数据库乃至整个程序的核心部分,用的java语言只是用来进行流程控制。整个程序通过JDBC操作也主要是这个。虽然有很多不足的地方,但是我们相信,我们是可以慢慢完善的。
    4 系统实现4.1 模块一登录界面模块:通过使用Java swing组件编写的比较友好的登录界面,同时也包括了通过JDBC连接数据库查询管理员的信息,数据库中的管理员表,正确输入密码和用户名才能尽进行登录。

    4.2 模块二使用主界面,界面美观漂亮,可以通过底部的按钮实现相应的功能。

    4.3 模块三查询模块:这个模块可以查询到当前的入住信息,当前的房间状态,而且很好的保护了客户的隐私,是通过JDBC连接数据库的方式得到数据之后插入一张二维表来显示的。可以一目了然的查看当前的空房,并且在允许的情况下让用户自主选择要入住的房型和房间号.

    4.4 模块四会员模块:这个模块可以让使用者加入会员,实现优惠功能,虽然还未实现打折功能,但是相信,只要时间允许,这个打折功能是可以实现的。这个功能是通过数据库的插入操作实现的。是把所有的方法封装在一个数据访问层DAO中,它封装了所有程序中要通过JDBC操作数据库的方法,包括查询,更新,修改,删除。

    4.5 模块五来宾入住信心录入模块。该模块参照了现实生活中的宾馆入住实例,通过把宾客的信息录入到数据库的指定的表中,并且保存起来,之后还可以通过结账模块的查询功能来表现。也是通过JDBC连接数据库实用”UPDATE 表名 姓名 所选的房间等 ”,通过调用DAO(数据访问层)的更新方法来实现,既可以查询,又可以更新:

    4.6 模块六结账模块。该模块实现了查询和更新一体的操作,是通过注册按钮事件来执行数据访问层DAO里的数据查询和数据更新操作.并弹出对话框”您需要付款¥xxx”,并且在弹出的同时,通过JDBC调用DAO层的更新方法来实现重置房间状态。既是用户活动的结束,也是流程的结束。

    也可以更新:

    结账的时候更新数据,设置房间为空。
    5 分析与结论这一次的课程设计给了我们莫大的好处,让我们更熟悉了数据库和高级语言的关联性,又能做到学以致用。在这个课程设计之前,我们都很迷茫,不会学以致用,只是知道跟着老师的步伐学习。通过这次的课程设计,我们还学会了自主学习的方法,明白了怎么样才是正确的学习方法。而不是一味的乱撞,我们通过做这个项目,还参考了很多课外教科书,查找了很多的资料。通过对一个问题的实际分析,良好的综合的运用了所学的知识,既学到了知识,巩固了基础,让我们更深入的学会如何将课本上所学的知识运用到实际上。
    虽然我们做的这个小小的项目不是很完善,也不是很好,还有很多需要改进的地方,很多的bug需要去修复。在这之前,我们成天都是跟着课本上整天加加减减,没什么感觉。通过这个课程设计,有了一点成就感,也大大加深了我们努力钻研的精神,终于可以学以致用了。我们相信在以后我们会更加努力的去探讨知识,开发出更好的软件!
    参考文献【1】王珊 萨师煊第四版 数据库系统概论
    【2】王珊 萨师煊第五版 数据库系统概论
    【3】java语言程序设计
    【4】java编程思想
    【5】清华大学出版社 主编 徐琳等 java程序设计专家门诊
    【6】UML统一建模教程
    6 评论 263 下载 2018-11-06 14:36:13 下载需要8点积分
  • 基于java的多人聊天程序课程设计

    一、设计内容及要求1.1 设计内容聊天工具大多数由客户端程序和服务器程序外加服务器端用于存放客户数据的数据库组成,本程序采用客户机/服务器架构模式。通过Java提供的Socket类来连接客户机和服务器并使客户机和服务器之间相互通信,由于聊天是多点对多点的而Java提供的多线程功能。用多线程可完成多点对多点的聊天。
    1.2 设计要求主要有两个应用程序,分别为服务器程序和客户端程序。服务器应用程序主要用于消息转发、客户登录信息的管理以及向所有用户发送系统消息等;客户端应用程序主要用于客户聊天记录的显示和信息输入。采用Client/Server(C/S)体系结构,即客户机/服务器体系结构。聊天服务器专门用于监控用户状态和转发消息,客户端负责接收消息的用户序列和消息文本发送到服务器。该聊天系统实现私聊,群聊,用户注册,登陆,退出聊天系统等功能。
    二、系统需求分析2.1 系统介绍在当今信息时代,有许多的聊天工具,例如QQ、微信等。本程序就是利用Java网络编程的知识,采用客户机/服务器架构模式来实现客户端与客户端之间的通讯。
    2.2 开发背景在当今信息时代,越来越多的聊天工具被应用,Java语言是当今流行的网络编程语言,它具有面对对象、跨平台、安全、多线程等特点。使用Java语言不仅可以实现大型企业级的分布式系统应用,还能为小型的、嵌入式设备进行应用程序开发。面对对象的开发方法是当今最流行的开发方法,它不仅更贴近现实,而且有利于软件的维护和继承。为了进一步巩固课堂上所学到的知识,深刻把握Java语言的重要概念及面对对象的特性,锻炼我们熟练的应用面对对象的思想和设计方法解决实际问题的能力,所以我选择了开发Java多人聊天程序。
    三、系统总体设计3.1 系统功能结构图
    3.2 系统数据流程图
    四、系统详细设计4.1 本设计所涉及技术和知识点
    C/S体系结构:采用Client/Server(C/S)体系结构,即客户机/服务器体系结构。其中客户端用了发送和接受收显示聊天消息,服务器用来监听客户端的消息,并将接收到的数据转发到所用的客户端上,这样实现群聊功能。Socket套接字:作为多人聊天程序,网络编程的知识必不可少,其中用到了Socket套接字、IP地址、端口号等网络编程的知识。客户端与服务器的窗口用到Java Swing图形用户界面知识,其中包括界面的布局、组件的使用以及各种监听事件的使用。多线程:为了是客户端与客户端之间的消息、客户端发送与接收的消息不发生冲突,将每个客户端的发送和接收用不同的线程。IO流:聊天时客户端与服务器之间肯定有数据的输入输出,所以IO流的知识在这里也十分重要。
    4.2 功能模块详细设计
    客户端:运行客户端时,弹出登录客户端界面,这是需要设置用户名、IP地址和端口号,其中IP和端口号必须和服务器的对应,否则连接不上服务器。登录后进入客户端聊天界面窗口。这时可以与其他客户端之间在一个聊天室中聊天,若想私聊某人,只需在聊天内容前加上@该用户的姓名+:就可以了。点击右上角的下线按钮即退出该聊天室。
    发送消息:当点击发送按钮时,将消息通过DataOutputStream流中的writeUTF发送到服务端,服务端通过DataInputStream中的readUTF接受客户端的消息,紧接着服务端通过DataOutputStream中的writeUTF发送个所有客户端。
    私聊:当用户登录后,在没有点击发送按钮前,先将该客户端的姓名发送到服务器,服务器先接收到用户的姓名,然后在接收聊天消息。
    服务器:启动服务器,弹出设置服务器的窗口,填写服务器的IP地址和端口号,点击确定后,服务器启动,并不断监听客户端的连接和接收客户端发来的消息。

    五、编码与实现5.1 具体功能模块实现该多人聊天程序包括8个文件,功能如下:
    1. Client.java 包含Client类,其中有main、connectServer函数,是客户端启动的入口。在main函数中通过创建一个ClientLogin对象,来打开登陆窗口。 ClientLogin login = newClientLogin();
    2. ClientFrame.java
    包含ClientFrame类,该类继承于Jframe类,用来创建客户端的窗口。 其中包括窗口中的各个组件、布局以及组件的监听事件。
    sendButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { msg = msgText.getText().toString(); ClientSend.send(); msgText.setText(null); });
    发送按钮的监听事件,当点击发送时,将发送栏中的消息保存在字符串msg中,在,然后调用 ClientSend.send()函数,将该字符串发送到服务器。
    3. ClientLogin.java
    包含ClientLogin类,该类继承于Jframe类,用来创建客户端登录窗口,其中包括设置IP地址、端口号、用户姓名的各种组件,和登录按钮的监听事件:
    btn_login.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { name = jtf_userName.getText().toString(); ip = jtf_ip.getText().trim(); port = Integer.parseInt(jtf_port.getText().toString()); //点击登录后,客户端连接服务器 try { Client.connectServer(); } catch (UnknownHostException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } //隐藏当前窗口 dispose(); //关闭 //打开客户端 new ClientFrame(); } });
    点击登录按钮时,将窗口中用户姓名、IP地址和端口号分别赋值给字符串name、ip、port变量,然后调用Client.connctServer()来连接服务器,并且关闭该窗口,创建ClientFrame对象来打开客户端窗口。
    4. ClientReceive.java
    包含ClientReceive类,该类中有Runnable接口,用于创建一个用户接受服务器消息的客户端接受线程。
    线程体:
    public void run() { String msg = null; while(isRunning){ //将接受信息输出到客户端窗口中 msg = receive(); System.out.println(msg); ClientFrame.msgRecordText.append(msg+"\n"); } }
    该线程处于死循环中,其中receive()函数用来接收服务器的消息,并通过ClientFrame.msgReceordText.append(msg+”\n”)将消息显示在客户端的窗口聊天记录面板上。
    5. ClientSend.java
    包含ClientReceive类,该类中有Runnable接口,用于发送消息,该线程的线程体为空:
    public void run() { }
    当用户点击客户端窗口中的发送按钮时,会调用该类中的send函数,用于将消息发送到服务器。
    6. Server.java
    包含Server类,其中包含main、setServer方法和List<ServerForward>集合类。
    其中main函数是服务器的入口,用来打开服务器设置窗口。
    main函数:
    ServerFrame serverFrame = new ServerFrame();
    setServer函数:
    public static void setServer() throws IOException { //从服务器窗口获取ip和端口号 String ip = ServerFrame.ip; int port = ServerFrame.port; ServerSocket server = new ServerSocket(port, 0,InetAddress.getByName(ip)); while(true) { Socket client = server.accept(); System.out.println("连接成功"); ServerForward serverForward = new ServerForward(client); allClient.add(serverForward); Thread thread = new Thread(serverForward); thread.start(); } }
    启动服务器,不断的监听客户端的连接,当有客户端连接上时,在List<ServerForward>集合类中添加该线程,并启动该线程。
    7. ServerForward.java
    包含ServerForward类,服务器接受一个客户端得信息,再转发给其他客户端。该类中主要包括receive、send函数,用于转发客户端的消息。
    线程体:
    public void run() { //接受用户的昵称 while(isRunning) { if (name == null) name = getClientName(); else break; } while(isRunning) { sendToClient(receive()); } }
    因为服务器的工作不间断的,所以用无限循环。getClientName()从客户端中接受用户的姓名,并保存字符串name中。sendToClient(receive())接收一个客户端的消息,并转发给所有客户端。
    8. ServerFrame.java
    包含serverFrame类,该类继承于JFrame,用于创建服务器设置界面,其中包括设置IP地址、端口号,和确认按钮的监听事件:
    btn_set.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ip = jtf_ip.getText().trim(); port = Integer.parseInt(jtf_port.getText().toString()); //关闭窗口 dispose(); //点击确定后,设置服务器ip和端口号 try { Server.setServer(); } catch (UnknownHostException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } } });
    将服务器设置窗口中的IP地址和端口信息ip、port字符串中,并调用Server.setServer函数,开始启动服务器。
    5.2 演示界面5.2.1 服务器设置窗口
    5.2.2 客户端登录窗口
    5.2.3 客户端窗口
    5.2.4 群聊和私聊
    3 评论 144 下载 2018-10-21 14:43:22 下载需要4点积分
  • 基于JSP的车险模拟系统的设计与实现

    摘 要随着科技的发展和时代的进步,使用管理系统来提高工作效率成为各大企业的选择。一个保险企业在日常经营中,如果采用传统的人工管理方式去管理大量的客户和保单信息,往往会造成工作挤压和员工情绪不满的现象。车险管理系统的出现,解决了以往保单理赔审核复杂的问题,公正、客观、快捷地对客户的保单进行管理,实现以人为本的管理战略,提高保险管理工作的效率。
    本文提出的车险管理系统基于B/S模式开发,根据数据建模,结合车险保单理赔管理的实际需求,设计系统架构。后端采用Java技术,选择关系型数据库MYSQL进行信息存储。本系统经过严格的功能性测试,取得了良好的运行效果。系统实现了客户管理,保单管理,理赔,保单情况统计等功能。车险管理系统的实施,满足了用户需求,在实际工作中逐渐完善,对车险管理效果有了显著改善。
    关键词:车险管理;JSP;数据库;B/S模式;Java
    AbstractWith the development of technology, major enterprises have chosen management system to improve working efficiency. If we use traditional manual method to manage large quantities of client and policy information, it will cause work squeeze and dissatisfaction of employees in daily life. The use of vehicle insurance management system has solved the problems of complex claims in the past. It can help manage the policies more fairly, objectively and quickly. It will also realize the people-oriented management strategy and improve the efficiency of insurance management.
    The vehicle insurance management system proposed in this article is based on B/S mode. The system is designed according to data modeling and combined with the actual demand of policy claims in vehicle insurance. The back-end adopts Java technology and chooses MYSQL which is a relational database to store information. This system has passed the strict function test and obtained the good running effect. The system achieves the function of customer management, policy management, claims, policy statistics and so on. The implementation of the vehicle insurance management system has met the needs of users and gradually improved in the actual work. It has also significantly improved the effect of vehicle insurance management.
    Key words: Vehicle insurance management; JSP;Database;B / S structure;Java
    一、绪论1.1 选题背景近年来,随着我国汽车行业的快速发展,我国汽车生产和销售量已经连续三年位居世界第一。在汽车产业迅速发展的同时,我国的汽车保有量随之迅猛提升,截至2018年6月,中国已经成为仅次于美国的世界第二大汽车拥有国。随着中国汽车市场的日益火爆,与之密不可分的车险市场也快速发展起来。近年机动车辆保险已经逐步发展成我国财产保险市场需求量最大的险种。车险管理系统的出现可以帮助各大保险公司更有效地保存客户的数据,为公司的业务管理带来巨大的便利。
    1.2 国内外现状从上世纪末开始,汽车保险在全球范围内都是财产保险的第一大险种,并一直保持高增长率,同时,中国的汽车保险业务进入了高速发展的时期,各大保险公司纷纷推出了各种类型的车险。随着时代的进步,国外的保险公司率先开启电子保单的管理,渐渐国内的保险公司渐渐从开始的纸质化保单过渡到电子保单的管理。车险管理系统主要用来帮助保险公司进行专业的保单管理,公司可以通过无纸化操作来按照客户的需求对每份保单进行创建及一系列的修改,既方便了公司的业务管理工作,又方便客户线上提出理赔,能让顾客得到更高效的服务。
    1.3 目的及主要研究内容本文研究目的在于分析并设计一个模拟车险管理系统来帮助保险公司提高工作效率,更便捷地管理客户的保单数据。并且可以让客户也登录系统,查看自己的个人信息及保单信息,提出取消保单和理赔申请。本文计划首先进行需求分析,确定系统想要实现的功能,分析可行性,确定所需的技术架构,然后逐步完善系统。
    1.4 本论文主要工作与章节安排
    第一章:本章主要介绍了本篇论文的选题背景,国内外现状,主要研究内容以及章节的安排
    第二章:本章主要介绍了本系统所运用的相关技术,对所采用技术进行了简单的说明
    第三章:本章主要介绍了系统的分析及设计,叙述了系统拟实现的模块功能,简述了系统的技术架构及数据库的主要设计逻辑,并且进行了可行性分析。
    第四章:本章主要介绍了系统实现的过程,具体介绍了系统各个模块的功能,包括管理员登录和客户登录两大部分
    第五章:本章主要介绍了所进行的系统测试过程,保证了系统能够顺利运行并实现拟实现的功能
    第六章:本章是本文的总结与展望,总结了实现本系统及完成本论文的心得,并表达了对未来学习及工作的展望与期待

    二.相关技术概述2.1 B/S架构B/S架构的中文全称为浏览器和服务器架构模式。它是继Web兴起后的又一种网络体系结构模式,其中Web浏览器是客户端的主要应用软件。B/S架构是以服务器为核心的系统,将客户端统一,并简化了系统的开发、维护和使用。客户端上只安装了一个浏览器,如Google或Internet Explorer,服务器上安装了Oracle、MySQL或SQL Server。浏览器在此模式下通过Web服务器和数据库发生关联,这种操作模式简化了客户端的负载,大大降低系统维护和开发的成本以及工作人员的总体工作量。
    2.2 HTML语言及CSS样式表HTML是超文本标记语言,是一种在标准通用标记语言下的应用。它也是用来标记网页的是一种标准和规范。HTML语言类似于在一个文本文件中添加标记,然后浏览器识别到这些标记后就能在网页上显示其内容。
    CSS样式表,是可以与HTML语言组合使用的一种语言,其中文名为层叠样式表。CSS通常可以用来静态地修改网页,稍复杂些CSS还可以动态地格式化网页元素,这需要使用各种脚本语言来实现。CSS的优点在于可以近似于像素级别地精确控制网页中元素的位置,支持几乎所有字体大小的样式,并且能够编辑Web对象和模型样式。
    2.3 Java语言Java是面向对象的编程语言。Java语言在囊括C++优点的同时,也淘汰了C++语言中比较难以理解的多继承和指针的概念。因此,Java语言具有功能强大、使用方便的特点。Java语言将面向对象的编程语言以静态方式完美实现,让程序员在编程过程中能够条理清晰的写出解决问题的方法。
    2.4 JSPJSP全名为Java Server Pages,中文名称是Java服务器页面。它基本上是一个简化的Servlet设计。它将类似HTML的标记写在Java编程语言中,进行包装处理逻辑生成动态网页。用户也可以通过网页的标记和脚本来访问服务器的现有资源。JSP实现了页面逻辑和显示的分离,使基于Web的应用程序开发起来更加快捷方便。
    2.5 My EclipseMy Eclipse是加入插件开发的一个基于Eclipse的功能强大的集成开发环境,它主要是为Java,Java EE和移动应用的发展而出现。My Eclipse可以支持Java Servlet,AJAX,JSP,JSF,Struts,Spring,Hibernate,EJB3,JDBC数据库链接工具等多项功能。
    2.6 MySQLMySQL是Oracle旗下的一个关系型数据库管理系统,该系统将数据存储在不同的表中,提高速度和灵活性。MySQL具有开放源码的特点,因此一般是中小型系统开发中较常用的一种数据库技术。
    三.系统分析与设计3.1 需求分析及设计3.1.1 管理员登录

    客户信息模块:本模块可以添加新的客户,查看/编辑/删除已有客户的信息
    添加保单模块:本模块可以选择客户进行添加保单操作,输入车辆信息,选择险种,输入保金,生效期和失效期(保期为一年),并完成保单
    查询保单模块:本模块可以通过输入客户的身份证号码查询出客户的个人信息及保单信息
    取消保单模块:本模块可以看到客户提出的取消保单申请,输入需要退回的保费,成功完成取消保单操作
    理赔模块:本模块可以看到客户提交的理赔申请,进行受理,同时回复赔偿金额,完成理赔操作
    保单情况统计模块:本模块可以能统计出什么牌子的车投保次数最多,理赔次数最多,便于保险公司进行数据统计

    3.1.2 客户登录

    修改登录密码模块:在本模块客户可以进行修改登录密码操作
    客户信息模块:在本模块客户可以看到自己的个人信息,并且允许进行修改操作
    保单信息模块:在本模块客户可以查看自己的保单信息,也可以提出取消保单申请,如果管理员批准取消成功,客户可以看到退回保费的情况
    理赔页面模块:在本模块客户可以进行理赔操作,包括选择报案时间,理赔项目,添加附件(可以上传照片),而且同时也可以看见已提交理赔的受理情况及回复的赔偿金额
    理赔范围介绍模块:在本模块客户可以查看现有的7个险种(交强险,第三者责任险,车损险,盗抢险,不计免赔险,玻璃险,座位险)的理赔范围

    3.2 总体方案3.2.1 技术架构
    车险管理系统拟使用面向对象开发方法,运用Java技术和MYSQL数据库制作。本系统使用MVC结构开发,可以大大缩短开发进程,这种架构在运行方面也很优秀,速度也比较快,主要包括View、Controller、Model层。
    View层提供了用户接口,使用CSS/JSP等技术制作,通过HTTP发送请求给Controller层,并得到POST的响应后,通过JSP方法或者Java标签显示到界面列表。
    Controller层处理前端发送来的请求,使用过滤器处理拦截信息,通过XML配置文件进行路由转发,寻找到对应的业务层的具体处理事件,完成业务逻辑。注入搭配AOP中,进行事务控制,根据权限信息完成操作,并记录操作日志。
    通过Controller层注入方法,提供数据流处理,通过Hibernate实现持久化对象操作,完成数据存储,再返回数据流到业务逻辑层。
    3.2.2 数据库设计本系统共设计了5个表,分别为用户表(t_admin),客户表(t_kehu),保单表(t_baodan),保单细节表(t_baodandetail),理赔表(t_lipei)。
    用户表(t_admin)
    用户表共有3个字段,userId,username,userPw,如表1所示:



    序号
    字段名称
    说明
    数据类型
    是否主键
    长度
    可否为空




    1
    userId
    用户ID号
    int

    11



    2
    username
    用户姓名
    varchar

    50



    3
    userPw
    用户密码
    varchar

    50




    客户表(t_kehu)
    客户表共有11个字段,kehu_id,kehu_name,kehu_sex,kehu_age,kehu_xueli,kehu_zhiwei,kehu_address,kehu_tel,kehu_email,kehu_login_Pw,type如表2所示:



    序号
    字段名称
    说明
    数据类型
    是否主键
    长度
    可否为空




    1
    kehu_id
    客户ID
    int

    11



    2
    kehu_name
    客户姓名
    varchar

    50



    3
    kehu_sex
    客户性别
    varchar

    50



    4
    kehu_age
    客户年龄
    int

    11



    5
    kehu_xueli
    客户学历
    varchar

    50



    6
    kehu_zhiwei
    客户职位
    varchar

    50



    7
    kehu_address
    客户地址
    varchar

    50



    8
    kehu_tel
    客户电话
    varchar

    50



    9
    kehu_email
    客户邮箱
    varchar

    50



    10
    kehu_login_Pw
    客户密码
    varchar

    50



    11
    type
    客户身份证
    varchar

    50




    保单表(t_baodan)
    用户表共有9个字段,id,kehuID,kehuName,baodanName,kaishishijian,jieshushijian,chepai,qicheppai,qichexinghao,如表3所示:



    序号
    字段名称
    说明
    数据类型
    是否主键
    长度
    可否为空




    1
    id
    保单ID(按客户)
    int

    11



    2
    kehuID
    客户ID
    varchar

    255



    3
    kehuName
    客户姓名
    varchar

    255



    4
    baodanName
    保单名称
    varchar

    255



    5
    kaishishijian
    开始时间
    varchar

    255



    6
    jieshushijian
    结束时间
    varchar

    255



    7
    chepai
    车牌号码
    varchar

    255



    8
    qicheppai
    汽车品牌
    varchar

    255



    9
    qichexinghao
    汽车型号
    varchar

    255




    保单细节表(t_baodandetail)
    保单细节表共有5个字段,id,baodanID,baodanName,leixing,je,如表4所示:



    序号
    字段名称
    说明
    数据类型
    是否主键
    长度
    可否为空




    1
    id
    保单ID(唯一)
    int

    11



    2
    baodanID
    保单ID(按客户)
    varchar

    255



    3
    baodanName
    保单名称
    varchar

    255



    4
    leixing
    险种
    varchar

    255



    5
    je
    金额
    double

    255




    理赔表(t_lipei)
    用户表共有8个字段,id,kehuname,shenfenzheng,riqi,xiangmu,fujian,lipeiqingkuang,jine,如表5所示:



    序号
    字段名称
    说明
    数据类型
    是否主键
    长度
    可否为空




    1
    id
    理赔ID
    int

    11



    2
    kehuname
    客户姓名
    varchar

    255



    3
    shenfenzheng
    身份证号码
    varchar

    255



    4
    riqi
    日期
    varchar

    255



    5
    xiangmu
    理赔项目
    varchar

    255



    6
    fujian
    附件
    varchar

    255



    7
    lipeiqingkuang
    理赔情况
    varchar

    2550



    8
    jine
    金额
    varchar

    255




    3.3 可行性分析3.3.1 技术可行性此系统拟采用B/S结构,与C/S结构相比更加简化,开发、维护等核心工作集中在服务器端执行。Java语言较其他语言更加稳定可靠,可以避免许多编程错误。
    3.3.2 经济可行性开发过程使用现有的开发环境,只需一台PC机就可完成开发。使用时在浏览器打开网址就可使用系统。
    3.3.3 社会可行性此系统作为课题研究使用,不涉及任何盈利行为,且所有过程不涉及任何知识产权问题。
    四.系统实现4.1 登录页面设计设置Tomcat服务器后,运行系统。车险管理系统需要先登录后才能进行操作。登录界面是系统运行后的第一个界面。输入用户信息后点击确定后进行登录,这里会进行密码的校验,若输入密码不正确会给出警告,直到输入正确的密码才能成功登入系统。
    程序运行效果图如图4所示

    输入正确的用户名和密码后,点击登录,页面跳转到管理主界面。在主界面中,可以进行一系列的操作。
    登录界面使用div和html进行布局,用户名和密码等输入项为表单,输入信息后,后台可以获取表单value值,通过获取的界面信息进行数据库查询操作。
    管理员登录中,通过点击button按钮,调用check1方法,通过IF判断用户名和密码是否输入,后调用loginService.login的方法,进行数据库查询,返回是或者否。
    4.2 管理员登录后的页面4.2.1 管理员登录后的首页系统通过登录验证后,页面跳转到主界面,界面有导航菜单,包括密码修改,客户管理,保单管理,保单取消,理赔管理,保单情况统计这六大模块,点击每个菜单可以进入相应的界面。
    程序运行效果图如图6所示

    车险管理系统的用户角色不同,对应的菜单也不相同。菜单由两个div组成,用户登录后,把用户角色保存到session服务器对象中,菜单页面通过读取权限信息,判断对应的登录用户显示哪个div,即可控制用户权限。
    主界面的框架由frameset组成,frameset有多个属性,可以设置frameset的边框,是否可以滚动以及name。在点击菜单链接后,通过设置target=’main’来控制对象显示到什么位置中。管理系统的后台一般都是有这种frameset控制,方便制定整体的界面风格,减少开发工作量。
    4.2.2 修改登录密码管理员成功登录系统之后,点击左侧菜单“修改登录密码”,系统跳转到修改登录密码子界面,在这里需要输入正确的原密码和设置新密码,才能实现修改操作,若输入的原密码不正确,会给出警告“输入的密码不正确”。
    程序运行效果图如图7所示

    4.2.3 客户信息管理在此页面添加客户信息,其中用户名,密码,姓名,性别,年龄,身份证号码为必填项,如果不填写就提交会进行校验,提示必须输入。其他学历,职位,住址,tel,email为选填项,不填写也可以提交。
    程序效果图如图8所示

    管理员点击左侧的菜单“客户管理”,页面跳转到客户管理界面,这里显示了所添加客户的个人信息。在右侧有删除和编辑按钮,可以删除该客户,也可以对客户信息进行修改。在下方有添加客户的button,可以添加新的客户,还有导出Excel的功能,可以将现有客户的个人信息导出至Excel表格中。
    程序效果图如下图9所示

    点击客户查询,可以通过输入客户姓名查询到客户的个人信息,在查询页面也可以对客户信息进行编辑,删除,添加以及导出Excel文件。
    程序效果图如下图10所示

    4.2.4 保单信息管理在此页面添加保单信息,包括填写或选择客户名称,车牌,汽车品牌,汽车型号,总金额,开始生效日期等,其中在开始生效日期默认为当前日期,旁边有写明,有效期为一年。
    程序效果图如图11所示

    管理员点击客户信息列表的“保单管理”,页面跳转到保单信息管理界面,这里展示了客户的姓名,身份证号以及保单车辆的信息。上方有一个查询功能,可以通过客户的身份证号码查询到保单信息,右边有修改和删除button,管理员可以修改和删除保单。用红字标出的是添加明细功能,在这里可以选择需要添加的险种以及具体险种的金额,当添加的险种的总金额大于保单总金额时会发生校验提示错误。
    程序效果图如下图12所示

    4.2.5 取消保单管理员在这里可以看到客户的部分信息,保单信息,和客户提出的取消保单申请,上方有一个查询功能,可以通过客户的身份证号码查询到保单信息,红色字体标出的查看明细可以查看到保单的具体信息。右方的取消保单button可以对客户提出的取消申请进行同意,之后保单状态会变为取消成功。
    程序效果图如下图13所示

    4.2.6 理赔管理管理员点击左侧的菜单“理赔管理”,页面跳转到理赔信息管理界面,管理员可以看到客户提出的理赔申请,包括客户的部分信息和车辆的理赔信息,上方有一个查询功能,可以通过客户的身份证号码查询到保单的理赔信息,红色字体的预览可以看到客户上传的事故照片,右边的事故理赔button可以对理赔进行处理,回复赔偿金额。
    程序效果图如下图14,15所示


    4.2.7 保单情况统计在这里可以显示保单的情况统计以及理赔的情况统计,可以看到每种车型的添加保单和理赔的数量,可以方便保险公司分析数据。
    程序效果图如图16所示

    4.3 客户登陆后的页面4.3.1 客户登录后的首页系统通过登录验证后,页面跳转到主界面,界面有导航菜单,包括我的资料,我的密码,我的保单,理赔管理,理赔范围介绍这五大模块,点击每个菜单可以进入相应的界面。
    程序运行效果图如图17所示

    4.3.2 我的资料修改首先客户输入自己的姓名及密码登录,在此可以修改个人信息并保存。
    程序效果图如下图18所示

    4.3.3 我的密码修改客户可以修改自己的登录密码,在这里需要输入正确的原密码和设置新密码,才能实现修改操作,若输入的密码不正确,会给出提示“密码不正确”。
    程序效果图如下图19所示

    4.3.4 我的保单情况客户在这里可以看到自己的部分个人资料及保单信息,右方红字的保单明细查看里客户可以看到保单的具体所加险种和金额。
    程序效果图如下图20所示

    客户在这里可以看到自己的保单信息,红色字的保单明细查看里客户可以看到保单的具体所加险种和金额,右方的取消保单button可以对保单提出取消申请。
    程序效果图如下图21所示

    客户提出取消保单的申请后,在这里可以看到自己的保单是否成功取消以及具体的退款情况,红色字的保单明细查看里客户可以看到保单具体所加的险种和金额。
    程序效果图如下图22所示

    4.3.5 理赔管理当发生事故,需要进行理赔申请时客户在这里可以上传事故的具体原因,发生日期,还可以上传事故图片,当管理员登录系统时能看见客户上传的事故图片。
    程序效果图如下图23所示

    客户在这里可以看到自己已经上传过的理赔申请,点击预览查看上传的事故图片,也可以修改或删除本条申请。
    程序效果图如下图24所示

    客户提出理赔申请后,在这里可以看到自己的保单是否成功受理理赔,若没有受理,理赔情况和理赔金额显示的是null,若成功受理则会显示管理员回复的具体理赔情况和金额,红色字的预览还可以查看上传的事故图片。
    程序效果图如下图25所示

    4.3.6 理赔范围介绍在这里客户可以看到保险公司提供的险种,包括交强险,第三者责任险,车损险,盗抢险,不计免赔险,玻璃险,座位险在内的7个险种,点击查看可以了解每项险种的具体理赔范围。
    五.系统测试进行车险管理系统的测试前,需要编写具体的测试用例,根据测试用例进行逐条测试,并记录测试结果,修正问题,完善功能。其中车险管理系统的部分测试用例如下。
    系统登录测试过程和预期结果,如表6所示:
    输入正确信息:用户名:1;密码:123456;选择角色:管理员输入错误信息:用户名:1;密码:111111;选择角色:管理员输入错误信息:用户名:2;密码:123456;选择角色:管理员输入错误信息:用户名:1;密码:123456;选择角色:客户输入错误信息:用户名:1;密码:123456;不选择角色点击登录,查询数据库,返回结果。
    打开数据库,查看返回的结果是否和数据库数据一致。
    预期结果:输入正确信息可以成功登录,输入错误信息提示无权限。
    测试结果:与预期结果一致,功能正确实现。
    添加客户测试过程和预期结果,如表7所示:

    点击客户录入页面链接,跳转到客户录入界面。使用多个浏览器进行操作
    不输入所有必填项,进行保存
    输入所有必填项,比对客户需求,查看是否都进行了相关验证
    保存信息到数据库中,查看数据库数据是否和录入的信息一致,包括默认值是否输入
    在客户信息列表中,读取到刚添加的客户信息

    预期结果:当不输入所有必填项时,给出warning提示必须输入此项;当输入所有必填项时可以成功添加客户,并保存到数据库,显示到客户列表。
    测试结果:和预期结果一致,功能正确实现。
    删除客户测试过程和预期结果,如表8所示:

    打开客户管理界面,通过查询所有客户信息,点击某条客户记录,进行删除操作
    提示是否确定删除后,点击确定,客户列表中,删除选择的记录
    查询数据库中客户数据,确认真实删除了该客户

    预期结果:可以成功删除客户,客户列表和数据库中均删除成功。
    测试结果:和预期结果一致,功能正确实现。
    编辑客户测试过程和预期结果,如表9所示:

    打开客户管理界面,通过查询所有客户信息,点击某条客户记录,进行修改操作
    跳转到客户编辑界面。使用多个浏览器进行测试,查看页面是否正确显示
    完成修改录入,点击提交数据
    保存信息到数据库中,查看数据库数据是否和修改的信息一致。列表是否更新

    预期结果:可以成功编辑客户,并保存到数据库,显示到客户列表。
    测试结果:和预期结果一致,功能正确实现。
    添加保单测试过程和预期结果,如表10所示:

    打开保单录入界面,填入所有保单信息,点击提交
    跳转到保单管理界面,有此保单信息
    保存信息到数据库中,查看数据库数据是否和添加的信息一致。列表是否更新

    预期结果:可以成功添加保单,并保存到数据库,显示到保单管理列表中。
    测试结果:和预期结果一致,功能正确实现。

    打开上传事故界面,填入所有事故发生日期,理赔项目,添加事故图片,点击提交
    跳转到事故列表界面,有此理赔申请信息
    保存信息到数据库中,查看数据库数据是否和添加的信息一致。列表是否更新

    预期结果:可以成功提出理赔申请,并保存到数据库,显示到事故列表中。
    测试结果:和预期结果一致,功能正确实现。
    六.总结与展望首先,我从专业实习中得到了本次系统设计的灵感,我实习的项目是越南GIC保险公司的车险项目,于是我将选课定为研究中国车险市场的系统设计。在完成系统设计的这段日子里,我查阅了许多Java开发,数据库方面的资料,以及车险项目有关的资料, 我学习到了很多Java开发技术以及数据库的实现方法。除此以外,我也了解了车险有关的知识。
    通过几个月的分析和研究,我的研究课题车险管理系统已经完成并且能够实现基本的功能,通过了实践测试。现在我的系统能够实现添加用户,添加/取消保单,理赔申请/受理,统计理赔情况等功能。不过由于毕业设计的时间有限,我一边进行学习,一边设计系统,我目前掌握的技术还不能使我的系统非常完美。从数据库来看,我的表设计还不够精简,还存在一定的冗余;从系统功能来看,一些功能还不够细致,还有进一步完善的空间。希望在未来的空余时间,我还能继续加工我的作品。
    通过毕业设计,我感受了系统开发的整个过程。毕业设计不仅是对我在大学所学知识的一个综合运用,对我实践能力进行的检测,也是一次增长知识和经验的好机会,同时也使我学会了许多处理、解决问题的方法,我也大大提高了自己的动手能力,使自己得到提升。我希望我在未来的学习和工作遇到困难的时候,都能保持不骄不躁的态度,学会冷静地解决问题。
    参考文献[1]徐雷明.车险智能审核系统的设计与实现[D].硕士学位论文.大连理工大学,2016.
    [2]詹薇.国内互联网车险发展研究[D].硕士学位论文.江西财经大学,2018.
    [3]李政宵,孟生旺.相依风险条件下的汽车保险定价模型[J].保险研究, 2016(7):68-77.
    [4]程阳.互联网车险UBI产品的设计[J].南方农机,2018(2):139-139.
    [5]魏丽,杨斐滟.我国商业车险改革评析[J].保险研究,2018,No.361(5):18-34.
    [6]夏超群.MyEclipse与数据库连接的实现[J].武汉工程职业技术学院学报,2013, 25(2):48-50.
    [7]佚名.“翻转课堂”本科教育实践——以《汽车保险与理赔》课程为例[J].教育教学论坛,2018(17):206-207.
    [8]陈文书.大数据视角下共享汽车保险定价机制研究——与UBI车险对比论证[J].中国商论,2018,No.758(19):14-15.
    [9]秦杨.加强和改善车险理赔服务问题探析[J].纳税,2018,No.198(18):192.
    [10]何宝晶.基于智能化理赔流程的车险理赔风控和反欺诈研究[D].硕士学位论文.兰州交通大学,2018.
    [11]李俊杰.华安财产保险运营信息管理系统设计与实现[D].硕士学位论文.大连理工大学,2016.
    [12]陈宏钊.车辆保险业务系统的设计与实现[D].硕士学位论文.东北大学,2015.
    [13]王东.机动车辆保险出单与决策系统的设计与实现[J].科技经济导刊,2017(2).
    [14]张钟浩,魏金海,彭章友.基于SSM的车辆保险系统设计和实现[J].工业控制计算机, 2017,30(5):141-142.
    [15]佚名.论我国学生平安保险的功能定位与法制完善[J].金融理论与实践,2019(1).
    [16]张晓甜.浅谈我国互联网保险[J].山东纺织经济,2018(4):25-27.
    [17]佚名.保险理赔的新科技应用与展望[J].纳税,2018, 12(27):203.
    [18]郗宏伟,汪爱丽.对汽车保险理赔中查勘定损的模式分析[J].中国市场,2018(6):129-130.
    [19]刘冬.车险理赔难与消费者权益保护研究[J].现代营销(下旬刊),2018(04):249-250.
    [20]薛煜睿.中国机动车车辆理赔风险管控对策探究[J].北方经贸,2018(4):100-101.
    0 评论 5 下载 2019-07-02 21:54:40 下载需要12点积分
  • 基于C语言的小型超市库存与销售管理系统

    1 需求分析1.1 登陆管理员和售货员可通过各自的账号、密码分别进入管理员和售货员的子系统。对于输入不在系统所存储的账号或输入的账号密码不匹配时,要求用户重新输入。
    1.2 用户管理管理员用户可浏览系统内所有的用户的账号、密码、权限类别,可添加用户,可删除用户。
    1.3 库存管理管理员可手动添加商品,也可从文件中批量导入商品,可查看库存内的全部商品信息,对于库存内商品数为0的商品可进行批量清理。
    1.4 查询商品管理员和售货员可通过商品名称、商品生产商、名称和生产商的方式查询商品信息。管理员可获取全部商品信息(商品ID、商品名称、进价、售价、生产厂商、余量),售货员可获取出进价以外的商品信息。查询可支持模糊查找、仅输入前缀。
    1.5 销售商品管理员和售货员可对库存内商品进行销售,对销售请求进行检查,销售后对库存相应商品的余量进行更新,同时记录销售的商品信息、销售时间,更新销售记录数据文件。
    1.6 销售统计管理员可浏览某天的或日期区间内的所有销售记录,可对指定日期区间内的销售记录进行综合统计,统计每种商品的销量、收入,统计总收入,可通过销量、销售额筛选统计结果。
    2 概要设计2.1 数据结构单个商品数据用Goods结构体存储,多个商品用链表存储。
    typedef struct { int id; char name[MAXGOODSNAME]; double buying_price; double selling_price; char manufacturer[MAXMANUFACTURERNAME]; int quantity;} Goods;typedef struct GoodsListNode *GoodsList;struct GoodsListNode{ Goods goods; GoodsList next;};
    单个销售数据用SoldGoodsRecord结构体存储,多个销售数据用链表存储。
    typedef struct{ int id; char name[MAXGOODSNAME]; double buying_price; double selling_price; int sold_quantity; SoldDate date;}SoldGoodsRecord;typedef struct RecordsListNode *RecordsList;struct RecordsListNode{ SoldGoodsRecord record; RecordsList next;};
    2.2 模块划分2.2.1 管理商品模块 manage_goods.c对商品进行操作的函数集。
    // 初始化商品链表GoodsList InitGoodsList();// 销毁商品链表void DeleteGoodsList(GoodsList head);// 向链表添加商品int AddGoodsToList(GoodsList head, Goods goods); // 遍历商品链表void TraverseGoodsList(GoodsList head, void(*Fun)(Goods *));// 显示商品信息void DisplayGoodsInfo(Goods *goods);// 显示商品基本信息void DisplayBasicGoodsInfo(Goods *goods);// 添加某商品数量:int IncreaseGoodsQuantity(GoodsList head, int id, int quantity);// 减少某商品数量:int ReduceGoodsQuantity(GoodsList head, int id, int quantity);// 从文件中导入商品void ImportGoodsFromFile(GoodsList head, FILE *fp);// 导出商品至文件void ExportGoodsToFile(GoodsList head, FILE *fp);// 清空数量为0商品void RemoveZeroQuantityGoods(GoodsList head);// 根据ID查找商品GoodsList FindGoodsByID(GoodsList head, int id);// 打开商品文件FILE* OpenGoodsFile(char *mod);
    2.2.2 管理销售记录模块 manage_records.c// 初始化销售记录链表RecordsList InitRecordsList();// 销毁销售记录链表void DeleteRecordsList(RecordsList head);// 遍历销售记录链表void TraverseRecordsList(RecordsList head, void(*Fun)(SoldGoodsRecord *));// 显示一条销售记录信息void DisplayARecordInfo(SoldGoodsRecord *record);// 向文件追加一条销售记录void AppendARecordToFile(SoldGoodsRecord record, FILE *fp);// 向链表条件一条销售记录void AddRecordToList(RecordsList head, SoldGoodsRecord record);// 从文件中导入销售记录数据至链表void ImportRecordsFromFile(RecordsList head, FILE *fp);// 获取当前销售时间SoldDate GetNowDate();// 打开销售记录文件FILE* OpenRecordsFile(char *mod);
    2.2.3 查询模块 query.c// 按名字在链表中查找商品GoodsList QueryGoodsByName(GoodsList head, char *name);// 按生产商在链表中查找商品GoodsList QueryGoodsByManufacturer(GoodsList head, char *manufacturer)// 按名字和生产商在链表中查找商品GoodsList QueryGoodsByNameAndManufacturer(GoodsList head, char *goods_name, char *manufacturer);// 按日期区间查找销售记录void QuerySoldRecordsByDate(RecordsList head, SoldDate start, SoldDate end);
    2.2.4 统计模块 statistics.c// 按日期区间对销售商品进行统计,通过销量、销售额筛选统计结果void SoldStatisticsByDate(RecordsList head, SoldDate start, SoldDate end, int min_sold_cnt, int min_earnings);
    2.2.5 售货员模块 salesman.c// 判断是否为销售员用户int IsSalesmanAccount(char *account, char *password);// 显示待售商品void DisplaySoldGoods(GoodsList head);// 销售商品void SoldGoods(GoodsList head);// 销售员初始化菜单void SalesmanInitMenu();// 查询商品菜单void SalesmanLookUpGoods(GoodsList head);// 按名称查询商品void SalesmanLookUpGoodsByName(GoodsList head);// 按生产商查询商品void SalesmanLookUpGoodsByManufacturer(GoodsList head);// 按名称和生产商查询商品void SalesmanLookUpGoodsByNameAndManufacturer(GoodsList head);
    2.2.6管理员模块 admin_user.c// 判断是否为管理员用户int IsAdminAccount(char *account, char *password);// 添加用户int AddAccount(UserAccount* user);// 删除用户int DeleteAccount(char *account);// 显示所有用户信息int DisplayAccountInfo();// 管理员初始菜单void AdminInitMenu();// 库存管理菜单void StockManagement();// 添加商品void AddGoodsToStock(GoodsList head);// 商品批量入库void BatchedStock(GoodsList head);// 查看库存商品void LookOverStock(GoodsList head);// 查询商品菜单void LookUpGoods(GoodsList head);// 按名称查询商品void LookUpGoodsByName(GoodsList head);// 按生产商查询商品void LookUpGoodsByManufacturer(GoodsList head);// 按名称和生产商查询商品void LookUpGoodsByNameAndManufacturer(GoodsList head);// 清理库存void ClearStock(GoodsList head);// 用户管理菜单void UserManagement();// 查看用户void LookOverUser();// 添加用户void AddUser();// 删除用户void DeleteUser();// 销售商品void SoldManagement();// 销售统计菜单void SoldStatistics();// 浏览单天销售记录void SingleDaySoldRecords(RecordsList head);// 浏览多天销售记录void DaysSoldRecords(RecordsList head);// 按日期区间浏览销售统计void DaysSoldStatistics(RecordsList head);
    2.2.7 外部Hash模块 uthash.c开源Hash模块,实现商品按id哈希处理,进行销售统计。
    2.3 程序总体框架
    3 详细设计部分重要底层函数:
    3.1 管理商品模块 manage_goods.c//初始化商品链表 创建带头结点的链表GoodsList InitGoodsList(){ GoodsList head = (GoodsList)malloc(sizeof(struct GoodsListNode)); head->next = NULL; return head;}//销毁链表void DeleteGoodsList(GoodsList head){ GoodsList next; while (head) { next = head->next; free(head); head = next; }}//在商品链表中添加一条商品信息,原有此商品数量合并,返回1//原没有,在链表末尾添加,返回0int AddGoodsToList(GoodsList head, Goods goods){ int id = goods.id; GoodsList p = head->next; while (p) { if (p->goods.id == id) { p->goods.quantity += goods.quantity; return 1; } p = p->next; } GoodsList newNode = (GoodsList)malloc(sizeof(struct GoodsListNode)); newNode->goods = goods; newNode->next = head->next; head->next = newNode; return 0;}//从文件中导入商品数据void ImportGoodsFromFile(GoodsList head, FILE *fp){ Goods goods; while (!feof(fp)) {fscanf(fp,"%d%s%lf%lf%s%d\n",&goods.id,goods.name,&goods.buying_price,&goods.selling_price,goods.manufacturer, &goods.quantity); AddGoodsToList(head, goods); } fclose(fp);}
    3.2 管理销售记录模块 manage_records.cconst char GOODS_SALES_RECORD_PATH[50] = "Data\\sold_goods_list.txt";//初始化销售记录裂变,创建带头结点的链表RecordsList InitRecordsList(){ RecordsList head = (RecordsList)malloc(sizeof(struct RecordsListNode)); head->next = NULL; return head;}//销毁销售记录链表void DeleteRecordsList(RecordsList head){ GoodsList next; while (head) { next = head->next; free(head); head = next; }}//在销售记录链表尾部增加一条销售记录信息void AddRecordToList(RecordsList head, SoldGoodsRecord record){ RecordsList newNode = (RecordsList)malloc(sizeof(struct RecordsListNode)); newNode->record = record; newNode->next = NULL; RecordsList p = head; while (p->next) p = p->next; p->next = newNode;}//向文件中新增加一条销售记录数据void AppendARecordToFile(SoldGoodsRecord record, FILE *fp){fprintf(fp, "%d %s %.2f %.2f %d %d-%d-%d-%d:%d:%d\n", record.id, record.name,record.buying_price,record.selling_price,record.sold_quantity,record.date.year,record.date.month,record.date.day,record.date.hour,record.date.min,record.date.second); fclose(fp);}//从文件中导出销售记录数据void ImportRecordsFromFile(RecordsList head, FILE *fp){ SoldGoodsRecord record; while (!feof(fp)) { fscanf(fp, "%d %s %lf %lf %d %d-%d-%d-%d:%d:%d\n", &record.id, record.name,&record.buying_price, &record.selling_price,&record.sold_quantity,&record.date.year, &record.date.month,&record.date.day,&record.date.hour, &record.date.min,&record.date.second); AddRecordToList(head, record); } fclose(fp);}
    3.3 查询模块 query.c//按照商品名和生产厂商前缀查询商品,输出商品基本信息GoodsList QueryGoodsByNameAndManufacturer(GoodsList head, char *goods_name, char *manufacturer){ if (head->next == NULL) return NULL; GoodsList queried_goods = InitGoodsList(); GoodsList p = head->next; while (p) { char goods_name_prefix[MAXGOODSNAME] = { 0 }; char manufacturer_prefix[MAXMANUFACTURERNAME] = { 0 }; strncpy(goods_name_prefix, p->goods.name, strlen(goods_name)); strncpy(manufacturer_prefix,p->goods.manufacturer, strlen(manufacturer)); if(strcmp(goods_name_prefix,goods_name) == 0 && strcmp(manufacturer_prefix, manufacturer) == 0) { GoodsList newNode = (GoodsList)malloc(sizeof(struct GoodsListNode)); newNode->goods = p->goods; newNode->next = queried_goods->next; queried_goods->next = newNode; } p = p->next; } return queried_goods;}
    3.4 统计模块 statistics.cvoid SoldStatisticsByDate(RecordsList head, SoldDate start, SoldDate end, int min_sold_cnt, int min_earnings){ CountStatistics *s, *goods = NULL; RecordsList p = head->next; while (p) { if (CompareDate(p->record.date, start) >= 0 && CompareDate(p->record.date, end) <= 0) { HASH_FIND_INT(goods, &p->record.id, s); if (s) { s->cnt += p->record.sold_quantity; s->earnings += (p->record.selling_price – p->record.buying_price) * p->record.sold_quantity; } else { s = (CountStatistics*)malloc(sizeof(CountStatistics)); s->id = p->record.id; strcpy(s->name, p->record.name); s->cnt = p->record.sold_quantity; s->earnings = (p->record.selling_price- p->record.buying_price) * p->record.sold_quantity; HASH_ADD_INT(goods, id, s); } } p = p->next; } double total_earnings = 0; int total_goods_cnt = 0; printf("----------------------------------------\n"); printf("%-5s %-12s %-6s %-6s\n", "ID", "名称", "销量", "收入"); for (s = goods; s != NULL; s = (CountStatistics*)(s->hh.next)) { if (s->cnt >= min_sold_cnt && s->earnings >= min_earnings) { total_earnings += s->earnings; total_goods_cnt++; printf("%-5d %-12s %-6d %-6.2f\n", s->id, s->name, s->cnt, s->earnings); } } printf("\n总商品数:%d 总收入:%.2f元\n", total_goods_cnt, total_earnings); printf("----------------------------------------\n");}
    3.5 售货员模块 salesman.c//购买商品,并更新商品,销售记录void SoldGoods(GoodsList head){ int id, cnt; GoodsList found_goods; while (1) { system("cls"); DisplaySoldGoods(head); printf("\n输入待销售的商品ID (输入-1退出)\n>"); scanf("%d", &id); if (id < 0) break; found_goods = FindGoodsByID(head, id); if (found_goods) { DisplayBasicGoodsInfo(&found_goods->goods); printf("输入销售数量\n>"); scanf("%d", &cnt); if (cnt <= 0) { printf("商品数量有误\n"); system("pause"); continue; } else { FILE *goods_fp = OpenGoodsFile("w"); FILE *records_fp = OpenRecordsFile("a"); if (goods_fp && records_fp) { if (!ReduceGoodsQuantity(head, id, cnt)) { printf("该商品库存不足\n"); system("pause");; continue; } ExportGoodsToFile(head, goods_fp); SoldGoodsRecord record; record.id = found_goods->goods.id; strcpy(record.name, found_goods->goods.name); record.selling_price = found_goods->goods.selling_price; record.sold_quantity = cnt; record.buying_price = found_goods->goods.buying_price; record.date = GetNowDate(); AppendARecordToFile(record, records_fp); printf("销售成功\n"); system("pause"); continue; } else { if (goods_fp) fclose(goods_fp); if (records_fp) fclose(records_fp); printf("连接系统数据失败\n"); system("pause"); break; } } } else { printf("无此商品\n"); system("pause"); continue; } }}
    3.6 管理员模块 admin_user.c//判断是否为管理员账户,无法打开文件返回-1,是返回1,否返回0int IsAdminAccount(char *account, char *password){ FILE *fp = fopen("Data\\user.dat", "rb"); if (fp == NULL) return -1; fseek(fp, 0, SEEK_END); int size = ftell(fp)/sizeof(UserAccount); fseek(fp, 0, SEEK_SET); UserAccount* user = (UserAccount*)malloc(size * sizeof(UserAccount)); for (int i = 0; i < size; i++) { fread(user + i, sizeof(UserAccount), 1, fp); if (strcmp(account, user[i].account) == 0 && strcmp(password, user[i].password) == 0 &&user[i].permission_level == 1) return 1; } free(user); fclose(fp); return 0;}//增加账户信息,无法打开返回-1,成功返回1,账户已存在返回0(更改密码)int AddAccount(UserAccount *newInfo){ FILE *fp = fopen("Data\\user.dat", "rb+"); if (fp == NULL) return -1; fseek(fp, 0, SEEK_END); int size = ftell(fp) / sizeof(UserAccount); fseek(fp, 0, SEEK_SET); int index = -1; UserAccount *user = (UserAccount*)malloc((size + 1) * sizeof(UserAccount)); for (int i = 0; i < size; i++) { fread(user + i, sizeof(UserAccount), 1, fp); if (strcmp(user[i].account, newInfo->account) == 0) { return 0; } } user[size] = *newInfo; fseek(fp, 0, SEEK_SET); for (int i = 0; i <= size; i++) { fwrite(user + i, sizeof(UserAccount), 1, fp); } free(user); fclose(fp); return 1;}
    4 调试分析
    问题1:链表操作易出错

    解决:为链表增加空的头结点,便于操作。销毁函数用于销毁链表,避免内存泄漏。对于同一级均要操作的链表的,在该级初始化链表,在返回上级时销毁
    问题2:需要读取多个文件

    解决:将文件读取封装为函数调用,对于售货功能,需要同时更新商品文件和销售记录文件,两个文件需要同时可打开时才可写入,采用类似原子操作思想
    问题3:交互逻辑使用不便。

    解决:改进交互逻辑,提供跳转功能、选择错误处理
    问题4:销售记录是分散记录,难于以商品为单位整合统计

    解决:采用开源的Hash库,通过Hash算法以商品id为key进行整合,算出该id商品的总销量和总收入
    问题5:指定日期区间查询或统计时不便

    解决:构造日期结构体,设置日期比较规则

    程序改进

    改进操作逻辑,使得操作更加方便
    增强大量数据时的处理能力
    采用数据库管理信息
    考虑多用户并发问题
    增加程序鲁棒性
    改进交互

    5 测试结果








    6 参考文献[1] 甘勇,李晔,卢冰.C语言程序设计[M].北京:中国铁道出版社,2014
    [2] 谭浩强. C程序设计[M]. 北京:高等教育出版社,2010
    [3] 苏小红,王宇颖,孙志岗. C语言程序设计[M]. 北京:高等教育出版社,2011
    [4] 王新,孙雷. c语言课程设计[M]. 北京:高等教育出版社,2009
    3 评论 83 下载 2018-11-04 14:56:40 下载需要5点积分
  • 基于C++的餐厅管理程序的设计与实现

    摘 要随着计算机应用技术的快速发展和日益普及,网络也遍及到我们生活的每个角落,为我们的学习和工作带来极大的方便。很多人都使用过传统的文字,纸张管理手段,与之不同的另外一种管理方式就是利用电脑程序管理餐厅。主要对追求工作高效、稳定、便捷的餐厅管理人员,电脑程序管理餐厅是一种很好的新型管理手段,它能提高工作效率和方便使用,餐厅管理程序就涉及到了文字、数字、项目信息的输入、读取、修改以及保存。
    本程序针对真实餐厅工作状况进行分析,讨论工作平台的环境影响,比较后采用在VS开发平台下,调用文件读写函数以实现Windows系统下信息的更新和保存。通过同类型软件测试比较可得:餐厅管理系统软件的设计具有先进性,可靠性。
    关键词:餐厅管理;文件读写;数据更新、保存
    第一章 设计内容设计一个模拟实现餐厅管理系统的程序,输入你需要的操作(选择相对的括号里的阿拉伯数字)程序具体功能有:

    查看菜单
    新增菜单
    删除菜单
    修改菜单(含名称及价格)
    查看座位剩余量
    修改座位剩余量
    查看预定情况
    新增预定(含菜式预定)
    查看顾客积分
    顾客兑换积分

    第二章 总体设计2.1 模块化设计为实现系统功能,本程序主要分为八个模块。它们分别为:查看菜单、新增菜单、删除菜单、修改菜单、查看座位剩余量、修改座位剩余量、查看预定情况、新增预定。这八个函数再通过主函数调用分别得以实现。
    主函数,首先提供了程序运行时的友好界面,提供客户选择的菜单。然后,通过执行多分支选择语句——switch语句,分别实现其它各个函数的调用功能。
    其它各个函数的功能分别如下:
    check() // 查看菜单函数add() // 新增菜单函数decrease() // 删除菜式函数change() // 修改菜式函数seat_check() // 查看座位剩余量函数seat_change() // 修改座位剩余量函数booking_check() // 查看预定情况函数booking_add() // 新增预定座位函数draw_check() // 查看顾客积分draw_check2() // 查看礼品列表 draw_main() // 兑换功能
    2.2 程序运行示意图
    第三章 详细设计3.1 数据结构设计本程序中,运用了多种数据结构。首先进入了主界面,查看菜单、新增菜单、删除菜单、修改菜单、查看座位剩余量、修改座位剩余量、查看预定情况、新增预定。在主函数中分别调用各项的函数。
    对于主要数据结构的举例如下:
    //定义菜单类class menu{private: //基本元素 int num,price;//菜式序号、价格 char name[20];//菜式名称 //用于功能实现的元素 int mealnum,delnum,changenum,changeprice;//菜式总数目、删除序号、修改序号、修改菜式序号 char changename[20];//修改菜式名字public: menu(); ~menu();//析构函数 void check();//查看菜单 void add();//新增菜单 void decrease();//删除菜单 void change();//修改菜单,包括修改菜式名称和菜式价格 void change_name();//修改菜式名称 void change_price();//修改菜式价格};//座位类class seat{private: //基本元素 int num,rest;//座位序号,座位剩余量 char size[20];//座位大小 //用于功能实现的元素 int seatnum,changenum,rerest;//座位种类数目,修改序号,剩余量public: seat(int); ~seat();//析构函数 void seat_check();//座位查看 void seat_change();//座位剩余量修改};//预定类class booking:public seat{private: //基本元素 int bnum,phone,peoplenum; char bname[20],bmeal[100]; //功能实现的元素 int bookingnum,cancelnum;//预约信息总数目、取消的序号public: booking(); ~booking();//析构函数 void booking_check();//预约查看功能 void booking_add();//新增预约};//主菜单void working(){ cout<<"======餐厅管理程序======"<<endl; cout<<endl<<"====菜式项目===="<<endl<<"1.查看菜式 "<<"2.新增菜式 "<<"3.删减菜式 "<<"4.修改菜式"<<endl; cout<<endl<<"====桌位项目===="<<endl<<"5.查看桌位 "<<"6.修改桌位剩余量 "<<endl; cout<<endl<<"====预定项目===="<<endl<<"7.查看预定 "<<"8.新增预定"<<endl; cout<<endl<<"====输入0退出系统===="<<endl;}//福利类class draw{private: char dname[20];//名称 int dnum,dphone,dpoint,total,dchange,duse;//序号,手机尾号,积分数目,记录表的总人数,兑换人号码,兑换礼品的序号public: draw(); ~draw(); void draw_check();//查看积分 void draw_check2();//查看奖品 void draw_main();//使用积分};void select(){ menu A; seat B; booking C; int chiose; while(1) { system("cls"); working(); cout<<endl<<"请输入你要实现的功能的序号:"; cin>>chiose; cout<<endl; switch(chiose) { case 0: exit(0); break; case 1: A.check(); break; case 2: A.add(); break; case 3: A.decrease(); break; case 4: A.change(); break; case 5: B.seat_check(); break; case 6: B.seat_change(); break; case 7: C.booking_check(); break; case 8: C.booking_add(); break; default: cout<<"输入无效请重新输入!"<<endl; cout<<endl; break; } getchar(); getchar(); }}
    3.2 程序模块设计本程序执行的入口是main函数,在main函数中首先调用了界面类中的各项操作的函数,在界面类中选择所需要进行的操作,在switch语句进行界面显示,实现对餐厅管理系统算法的操作。其中涉及到被调用的方法有:
    void working(){ cout<<"======餐厅管理程序======"<<endl; cout<<endl<<"====菜式项目===="<<endl<<"1.查看菜式 "<<"2.新增菜式 "<<"3.删减菜式 "<<"4.修改菜式"<<endl; cout<<endl<<"====桌位项目===="<<endl<<"5.查看桌位 "<<"6.修改桌位剩余量 "<<endl; cout<<endl<<"====预定项目===="<<endl<<"7.查看预定 "<<"8.新增预定"<<endl; cout<<endl<<"====输入0退出系统===="<<endl;}void select(){ menu A; seat B; booking C; int chiose; while(1) { system("cls"); working(); cout<<endl<<"请输入你要实现的功能的序号:"; cin>>chiose; cout<<endl; switch(chiose) { case 0: exit(0); break; case 1: A.check(); break; case 2: A.add(); break; case 3: A.decrease(); break; case 4: A.change(); break; case 5: B.seat_check(); break; case 6: B.seat_change(); break; case 7: C.booking_check(); break; case 8: C.booking_add(); break; default: cout<<"输入无效请重新输入!"<<endl; cout<<endl; break; } getchar(); getchar(); }}void main(){ select(); system("pause");}
    3.3 流程图查看菜单

    新增菜单

    删除菜单

    修改菜单(价格和名称)

    查看座位剩余量

    修改座位剩余量

    查看预定信息

    新增预定

    查看积分

    福利兑换

    第四章 调试与测试4.1 调试过程中的主要问题本程序,即餐厅关系系统程序,是涉及到了有关文件的读取、修改、清除、关闭等多个不同方面的操作,其中对文本文件的读取并输出到屏幕、修改最为棘手,同时这也是本程序的核心,关键内容。在开始的时候,我并无头绪,后来在网络上参考了网友的问题和解决方案后,找到了解决问题的思路,即打开文件-保存内容到数组中-清除文件内容-关闭文件-按需求修改数组内容-打开文件(已为空)-数组内容写入文件-关闭文件。使用这思路,简单明了,易于理解,便于操作,思路清晰,解决问题的相关代码也随之而出,复杂的核心问题得到解决,其他内容也就迎刃而解。
    4.2 具体测试过程主界面

    显示菜单

    新增菜单


    删除菜单


    修改菜单(价格)


    修改菜单(价格)


    查看座位剩余量

    修改座位剩余量


    查看预定情况

    新增预定

    查看积分

    兑换功能


    参考文献[1] 陈维兴 林小茶,C++面向对象程序设计教程(第3版)。北京:清华大学出版社,2009年5月
    [2] 严蔚敏 吴伟民,数据结构(C语言版)。北京:清华大学出版社,2011年5月
    [3] Thomas H.Cormen Charles E.leiserson Ronald L.Rivest Clifford Stein, 算法导论。机械工业出版社,2010年11月
    [4] 王晓东,计算机算法设计与分析(第4版)北京:电子工业出版社,2012年2月
    2 评论 24 下载 2018-11-05 09:11:35 下载需要5点积分
显示 15 到 30 ,共 15 条
eject