前提提要:大一下高级程序设计(Java)的课设,只有一周不到的时间
加上已经考完试进入白兰模式,所以写得乱七八糟基本不过脑
这篇东西是老师要求提交的顺便传到博客和README,权当记录一下

一、分析和设计

1.设计思路

本程序是一款支持在线聊天,离线留言,传送文件,发送表情的在线聊天室,服务端与客户端分离,客户端负责将信息通过图形化界面展示给用户,并允许用户执行发送消息,发送私聊,创建房间,上传文件,下载文件等功能,同时承担保存聊天数据的职责,客户端通过SSLSocket访问服务端,将本地信息传输至服务端,再将其他人的消息从服务端拉取,已达到在线聊天的功能。
本程序为本人根据这一学期的高级程序设计课程的学到的知识和一些课外补充的知识制作,主要用到了Java面向对象,SQL,Swing等知识,符合现实中对于在线聊天的需求,支持以十分简单的方式扩充表情库,具有一定的实用性。

2.需求分析

为了更好的设计程序,我首先分析了程序所需要的功能,将程序的功能分为三个部分:聊天,文件,用户,大致如下图所示:
c741fa96446a95fc8e72d5483d412551.png

3.功能描述

3.1 程序的构成

3.1.1 包构成

本程序的客户端部分主要由五个包构成,分别为:Files,Chat,Net,UI,Utils。
其中,Files包负责程序与文件交互的部分;Chat包为程序会使用的到一些数据结构,如File类用于描述一个文件的真实名称,服务器名称,上传时间,所属群聊,Message类描述了一个聊天记录发送的用户名,发送的时间,发送的ID等;Net包为与网络交互的部分,包括了对聊天服务器和文件服务器的连接,和一些请求的格式;UI包为客户端的前端部分,包括了一些UI的form文件和对应的管理窗口的类。Utils包为一些全局变量和静态方法的存放处。
同时,包的划分也同样可以作为程序的功能模块划分,将程序的各个部分独立出来。
本程序的服务端与客户端结构相似,由于不需要显示图像界面所以去除了UI包,其他部分结构基本一致,这里就不多赘述了。

3.1.2 整体思想

在程序设计之初,我就有意识地尝试将程序分层,从更为底层的文件,数据库着手开始构建整个应用程序,使上层的组件依赖于下层的某些功能,最后的程序大概可分为三层:显示层、逻辑层、数据层。显示层负责将信息传递给用户,数据层负责读取和写入数据,逻辑层位于显示层和数据层之间,负责对数据进行处理,传递给用户,或将用户的指示处理后传输给数据层。
b1991b7e8293ba83e15870a80e022355.png

3.1.3 类的构成

下面将以包为单位分别介绍程序的各个类。

(1)Chat包

Chat包较为简单,主要由几个相互独立的类组成:File,Message,PrivateMessage,Room,User,分别用于描述对应的对象。

(2)Files包

Files包中只有一个类——FileStream,负责对需要储存的用户信息,房间信息,私聊信息的序列化和反序列化,并存入文件。

(3)UI包

UI包中包含了所有前端图像界面类和form,每个类中均包含该图像窗口的一些设置,如字体,组件等,同时也包含一些对于窗口事件的监听器。以发送消息举例,当用户点击发送按钮将会触发对应按钮的监听器,监听器中将会创建新的SendMessage对象并通过ChatSeverConnection发送至服务器。

(4) Net包

Net包是整个程序最为复杂的包,主要分为五个部分:Request包中的类定义了所有的请求形式,Feedback包中定义了所有服务器返回信息的形式,FileServerConnection类负责与文件服务器的连接,ChatServerConnection类负责与聊天服务器的连接,Handler类处理接受到的所有网络请求。
9d7e3b1bd73e82b6bc926e12ddd212dc.jpg
ChatServerConnection类会在类的加载时就启动一个与聊天服务器的连接,每当收到消息就启用一个新的线程将收到的信息发送给Handler处理,而考虑到文件传输的需求可能并没有这么频繁,所以FileServerConnection则没有实现持久化连接,而且当需要传输时在启用一个新的连接。
Request包和Feedback包中均包含数十种请求和返回的类型,以Feedback包为例,内部定义了各种类型的类来储存需要传输的信息,并利用继承关系提高代码的重复利用率:
b3d6b12391b3ee2848242b1e09a5106a.png
Handler类首先会接受到来自ChatServerConnection中收到的Object类,并将其先转换为Feedback类,读取其中的type变量以确定其具体数据包类型并转换成对应的类,然后再进行对应的处理。

(5)Utils包

Utils包中包含四个部分:EmojiParsers, StaticBuffer, StaticConfig, Utils。
EmojiParsers类负责将聊天信息中对应的表情代码转换为HTML图片格式,以便于前端显示对应正确的表情。
StaticBuffer类中主要保存一些不需要被储存的全局变量,如当前在线的用户的名字,文件列表等。
StaticConfig类中主要保存一些需要被储存的全局变量,如所有房间的聊天记录,个人的聊天记录等。
Utils类中包含一些静态方法,主要用于提高代码的复用率,如时间格式转换等。

3.2 运行流程

3.2.1 窗体流程

3a99c08a8cc28d003ca07cc0f69beca1.png

3.3 运行截图

3.3.1 登录界面

4de82a2a0583ce74f17dd9f239631a59.png

3.3.2 注册界面

b94dbd58e6628d29a1e341050d9d1516.png

3.3.3 主界面

8f0aff2384f93cea49d1abca876b1991.png

3.3.4 文件列表

75217c9a447b56846561749eab8a0720.png

3.3.5 私聊界面

63eaa10c32890a8281ae4840071c12c7.png

3.3.6 上传成功

8f4695a7e59cca6fb077f63488809a6e.png

3.3.7 表情显示

4f1253e6ee1f3bf4a8e985176bc4d549.png

4 系统实现

4.1 系统关键技术

客户端前端主要采用Swing图形化界面实现,后端的网络连接采用SSLSocket实现。服务端采用MYSQL配合SSLSocket实现。

4.1.1 Swing

(1)表情的显示

本程序支持相对丰富且易于自定义的表情,主要通过Swing的Textpane控件实现:
4f1253e6ee1f3bf4a8e985176bc4d549.png
Textpane支持展示HTML格式的文件,因此我们只需要先定义一个关键的字符串,如 /jiaran/ 然后在文字被输入进Textpane之前使用HTML的标签功能替换掉对应的关键字符串,就可以达到展示图片表情的效果。
替换前的字符串和替换后的字符串均在EmojiParsers中定义,只需要通过修改里面的字符串数组就可以便捷的添加更多自定义的表情。

(2)聊天记录的刷新

本程序采用了定时轮询的方式去获取服务器的聊天信息,设定为每一秒向服务器询问一次是否有新的群组聊天记录或者私密聊天记录。然后再与本地的聊天记录对比,如果有新增就清空前端,重新写入聊天记录。
本部分主要使用了TimerTask类来实现定时执行某个线程的功能。

4.1.2 本地数据的持久化

本部分主要采用了Java便捷的序列化和反序列化功能,由于本程序所有的关键对象均实现了Serializable接口,所以只需要简单的几行就可以实现序列化和反序列化功能。文件的读写也可以采用FileOutputStream类轻松实现。

4.1.3 网络连接

考虑到明文传送用户密码是一种非常不负责的实现方法,本程序在所有的网络传输中均应用了SSLSocket的双向加密以保证用户信息的安全可靠。相较于普通的Socket连接,本程序需要服务端和客户端都有对方可接受的证书,否则将不会连接。

4.1.4 密码存储

本程序采用用户密码加盐后SHA加密的方式存储密码,登录时仅对比加密后的值,服务器不储存用户密码明文,以保证用户密码安全。

4.1.5 文件上传与下载

本程序将文件服务的端口与聊天服务的端口相分离,因此所有的文件传输均需要使用额外的端口,同时,它也是SSL加密的。
传输中主要用到了DataOutputStream与OutputStream,由DataOutputstream先行传输请求的类型(上传/下载)和文件的信息(文件名,文件大小),再由OutputStream传输文件,由于先前已经传输了文件的大小信息,所以程序可以通过已传输的文件大小和实际文件的大小对比来判断文件是否传输完毕,在客户端,可以通过JProgressBar控件将上传/下载进度反馈给用户。

5 系统实施和部署

5.1 开发环境

Java 17
MYSQL8.0
理论亦支持其他主流版本,未有实际测试。

5.2 程序的获取

客户端Github地址: https://github.com/WiDayn/QuickChat
服务端Github地址: https://github.com/WiDayn/QuickChatServer
可以下载源码编译或直接下载Releases中构建好的jar包运行。

5.3 程序的部署

  1. 将服务端src目录下的Dump_QuickChat.sql数据库结构导入mysql数据库中,设置数据库名字为QuickChat。
  2. 在服务端和客户端目录下均创建Files文件夹用于保存文件。
  3. 通过JDK自带的keytools.exe生成双向加密的客户端证书与服务端证书,或直接使用程序根目录已经生成好的证书用于测试。
  4. 启动服务器后再启动客户端,即可正常执行,第一次使用需要现行注册。所有的用户初始时都将加入ID为1的大厅群聊。