基于Android的聊天软件的设计与实现-一个聊天软件开发起来没那么难不是?(1)https://developer.aliyun.com/article/1558196
3.3系统功能模块结构设计
安卓聊天系统主要包括用户注册模块、用户登录模块、添加好友模块,上传头像模块、聊天模块。如图3.3:
图3.3 系统模块划分图
- 注册模块
- 用户申请流程:用户进入注册界面,按照相关的提示信息输入信息,信息经封装后由服务器接受处理,并给客户端返回注册的id号码,如图3.4:
图3.4 注册申请流程图
- 登陆模块
用户登陆流程:用户首次登录,填入相关信息,点击登录,客户端发送信息至服务器端,服务器端验证是否正确;正确的话,保存用户名和密码,直接转到用户列表界面,错误的话提示错误信息;第二次登陆时直接跳转到好友界面。如下图3.5:
图3.5 登陆流程图
- 添加好友模块
用户添加好友流程:用户输入id号码搜索好友,如果id号码合法并且该用户存在,则会显示出该好友的基本信息,而且可以发送添加请求;如果该好友在线,则会收到是否同意添加的对话框;如果同意,则系统向服务器插入该好友对,并且本地数据库也会有该好友的信息。如下图:
图3.6 添加好友流程图
- 聊天模块
聊天流程:用户点击好友进入到与该好友的聊天界面,在输入框输入文本信息、点击表情和发送图片(有两种方式:拍照和本地照片),点击发送后信息经过封装后传输到服务器进行转发给相应的好友,同时聊天信息保存在本地数据库。如下图:
图3.7 聊天流程图
3.4 数据库设计
聊天系统(微聊)采用MYSQL数据库和SQLITE数据库。
-MYSQL是一种开放源代码的关系型数据库管理系统(RDBMS),它使用最常用的数据库管理语言—结构化查询语言(SQL)进行数据库管理。MYSQL软件采用双授权政策,它分为社区版和商业版,由于其体积少、速度快、总体拥有成本低,尤其是开发源码这一特点,一般中小型网站的开发都选择MYSQL作为网站数据库。连接在服务器端。
SQLITE是一款轻型的数据库,是遵守ACID的关系型数据库管理软件。连接在手机本地。
3.3.1 抽象数据对象
根据业务及系统功能我们大致可以从中抽象出及格数据集合,如:用户,好友,信息等。
3.3.2 数据库设计命名规范
表名命名规范:根据主要数据模型将数据表分为用户表、好友表、信息表。
表项命名规范: 代表表名的单词或单词简写作为字段名的开头,命名中其他的单词或简写首字母大写。
3.3.3 数据库逻辑结构设计
数据库逻辑设计主要描述抽象数据如何在数据库中表示,以及抽象数据与数据库表之间的关系。其中包括数据库表、数据库表的详细设计、数据库表中数据的获取方式,数据库表与抽象数据类型的对应关系。
- 下面首先列出了数据库表名汇总,具体如下表所示。
表3.2 服务器端数据库表名
数据库表名 | 中文名 | 文字说明 |
user | 用户表 | 保存用户信息 |
friend | 好友表 | 保存好友对 |
message | 消息表 | 保存消息 |
表3.3 客户端数据库表名
数据库表名 | 中文名 | 文字说明 |
friend | 好友表 | 保存好友信息 |
message | 消息表 | 保存消息 |
- 数据库表E-R图。
数据库E-R图主要描述数据库各表之间的关系,该系统主要有user表、friend表、message表,具体如下图所示。
图3.8 数据库表E-R图
- 数据项。
该部分描述了数据表中的字段以及字段的含义、字段类型、约束条件、描述。具体如下图所示。
表3.4 user表的数据项
字段名 | 数据名 | 数据类型 | 约束条件 | 描述 |
ID | userId | int(11) | 非空 主键 自动增长 | Id号码从111111开始 |
昵称 | nickName | varchar(20) | 非空 | |
密码 | pwd | varchar(32) | 非空 | |
主键 | 密码进行了加密 | |||
邮箱 | varchar(50) | 非空 | ||
性别 | sex | char(2) | 非空 | |
头像 | head | varchar(100) | ||
修改时间 | modyfyTime | longtext | 头像最近修改的时间 |
表3.5 message表的数据项
字段名 | 数据名 | 数据类型 | 约束条件 | 描述 |
发送Id | sendId | int(11) | 非空 主键 外键 | 发送人的ID |
接受Id | receiveId | int(11) | 非空 主键 外键 | 接收人的ID |
消息类型 | type | int(11) | 非空 | 消息类型 |
时间 | time | varchar(20) | 非空 主键 | 发送时间 |
内容 | content | varchar(100) | 非空 |
表3.6 message表的数据项(Sqlite)
字段名 | 数据名 | 数据类型 | 约束条件 | 描述 |
本人Id | self_Id | varchar2(10) | ||
好友Id | friend_Id | varchar2(10) | ||
方向 | direction | int | 发送消息的方向 | |
消息类型 | type | int | ||
内容 | content | varchar2(240) | ||
时间 | time | varchar2(12) |
表3.7 friend表的数据项(Sqlite)
字段名 | 数据名 | 数据类型 | 约束条件 | 描述 |
本人Id | selfId | varchar2(10) | ||
好友Id | friendId | varchar2(10) | ||
昵称 | nickname | varchar2(20) | ||
性别 | sex | varchar2(2) | ||
头像 | head | varchar2(100) | ||
修改时间 | modifyTime | varchar2(20) | ||
消息类型 | type | int | ||
内容 | content | varchar2(240) | ||
时间 | time | varchar2(12) |
表3.8 friend表的数据项
字段名 | 数据名 | 数据类型 | 约束条件 | 描述 |
本人ID | selfId | int(11) | 非空主键外键 | |
好友ID | friendId | int(11) | 非空主键外键 |
3.3.4 数据库物理结构设计
图3.9 物理结构图
数据库物理结构设计:就是根据DBMS的特点和处理的需求,进行物理存储安排,建立索引,形成数据库的内模式。由于Android聊天系统的服务器端数据库使用的是mysql数据库,所以物理结构设计有以下特点:
- 每个数据项的存储操作,访问操作以及保密操作的都是在表结构完成,由sql查询语句来完成存储访问操作,由mysql的数据库来完成数据的保密工作。
- 为各个模块和功能提供数据支持的表在数据库中都采用外键的方式来维持数据之间的关联性。**
3.5系统出错处理
3.5.1 出错信息
程序在运行时主要会出现两种错误:
- 由于输入信息,或者无法满足要求时产生的错误,称为软错误。
- 由于其他问题,如网络传输超时等,产生的问题,成为硬错误。
3.5.2 补救措施
- 软错误补救:
- 用户输入数据类型错误,输入数据不完整以及用户操作失误等软错误,直接前台显示界面提示错误信息,由用户自行处理;
- 系统服务器崩溃,系统遭受到黑客攻击以及系统前台界面出现问题,则需要通过系统管理员来维护。
- 硬错误补救:
- 采用磁盘做备份准备,使用mysql的备份服务系统对数据库数据进行备份,如果系统遭到破坏,用备份的数据进行还原,数据的备份和还原可以通过应用程序实现,也可以通过系统管理员直接使用mysql的备份系统进行备份。建议用户每天对数据库的数据进行备份;
- 当系统运行效率过低时,通过重新启动可以重新组织数据库索引,提高系统运行效率;
- 在系统运行的过程中,可能会突发一些不可预测的故障,如断电、死机等。为了提高系统的安全性,我们采用了基于挂接操作系统接口的服务器自身监控安全模型。在本系统的服务器操作系统中,可以远程DLL注入技术,修改操作系统中进程的导入地址表,挂接Windows操作系统的关机函数,截获Windows的关机消息,从而实现在服务器每次系统关机时,自动检测当前是否有正在运行的业务,保证所有业务都顺利结束,并自动备份一次数据库,再转回windows操作系统的关机执行。从而保证了系统服务器的业务稳定性,和数据完整性,提高了系统的安全性和稳定性。
4.详细设计与实现
4.1服务端模块
4.1.1 项目总体框架搭建
聊天系统的服务器模块采用MVC三层架构开发,即模型(Model)、视图(View)和控制器(Controller)。 common包中的是抽象数据模型,包括用户类,好友类和消息类;util包中是各种工具类,包括数据库操作类,日志类,文件操作类等;net包中包括线程池类和任务类;test包中是该模块程序的主入口。具体如下图所示。
图4.1 项目源文件分布图
4.1.2 配置环境
本项目在服务器端采用的数据库是mysql数据库,所以需要导入mysql的jar包:mysql-connector-java-5.1.7-bin.jar,配置完成后可在Referenced Libraries中找到相应的jar包。
4.1.3 服务端具体功能及实现
- 服务端具体功能:
- 接受客户端连接:服务器启动后,只要一有客户端连接,就会在打印台上显示,从而接受客户端发来的各个任务。
- 接受任务和处理任务:客户端一旦连接上服务器,只要有任务要处理,就会发给服务器,服务器会处理相应的任务,然后返回信息给客户端,从而完成交互过程。
- 实现:
如图 4.2 所示,当服务器启动服务系统会输出“服务器已启动…”,这时服务器处于线程等待阶段,等待客户端连接。
图4.2 服务器启动
主要代码:
ServerSocket serverSocket=new ServerSocket(9999); ThreadPool pool=ThreadPool.getInstance(); while(true){ Socket socket=serverSocket.accept(); System.out.println("服务器接收到一个客户端连接"); ForwardTask task=new ForwardTask(socket); pool.addTask(task); }
如图4.3 所示,当有客户端连接时会输出如图 的信息。并且将该用户所暂用的线程加入线程池:
图4.3 客户端连接
线程池主要代码:
/** * 循环执行任务 * 这也许是线程池的关键所在 */ publicvoid run() { while (isRunning) { Task task = null; synchronized (taskQueue) { while (taskQueue.isEmpty()) { try { /* 任务队列为空,则等待有新任务加入从而被唤醒 */ taskQueue.wait(20); } catch (InterruptedException ie) { ie.printStackTrace(); } } /* 取出任务执行 */ task = (Task) taskQueue.remove(0); } if (task != null) { isWaiting = false; try { /* 该任务是否需要立即执行 */ if (task.needExecuteImmediate()) { new Thread(task).start(); //开启新线程执行这个Task } else { System.out.println("一个任务正在执行"); task.run(); //执行这个Task的是同一个线程 } } catch (Exception e) { e.printStackTrace(); } isWaiting = true; task = null; } } }
如图4.4所示,当用户发来各种请求时,会在控制台打印相应的请求信息以及服务器是否成功处理请求,以注册为例:
图4.4 打印台信息
任务类主要代码:
/* * 任务执行入口 */ publicvoid run() { while (onWork) { // 读数据 try { receiveMsg(); } catch (Exception e) { // 发生异常————通常是连接断开,则跳出循环,一个Task任务执行完毕 e.printStackTrace(); break; } } try { if (socket != null) socket.close(); if (dis != null) dis.close(); if (dos != null) dos.close(); socket = null; dis = null; dos = null; } // 接收消息 publicvoid receiveMsg() throws IOException { // 读取请求类型,登录,注册,更新头像等等 intrequestType = dis.readInt(); switch (requestType) { case Config.REQUEST_LOGIN: // 处理“登陆”请求 handLogin(); break; case Config.REQUEST_REGIST: // 处理“注册”请求 handRegist(); break; ….. } }
如图 4.5 ,4.6所示,当用户注册成功后,会在服务器端数据库中插入相应的数据信息,包括用户ID,昵称,密码,性别,邮箱,头像和头像的最近修改时间。这块重点强调是头像的保存,其保存形式为在服务器端保存后的绝对路径,其命名规则为所对应用户的id。
文件类主要代码:
//根据用户ID,创建一个以该ID为文件名的jpg图片 publicstatic File createHeadFile(intuserId){ File fileParent = new File(WORK_HEAD_PATH); if (fileParent.exists() == false) { fileParent.mkdirs(); } File file = null; file = new File(WORK_HEAD_PATH + "\\" + userId+ ".jpg"); try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } returnfile; }
基于Android的聊天软件的设计与实现-一个聊天软件开发起来没那么难不是?(3)https://developer.aliyun.com/article/1558199