写在最前面

关于类和方法的命名问题

类名和方法名的命名使用ideaTranslation,将每个中文词单独翻译为英文。例如:处理文件请求拆分为最小的词处理文件请求

关于开发环境

项目全程使用IntelliJ IDEA 2024.3.4 (Ultimate Edition)进行开发。

jdk版本为java version "23.0.2" 2025-01-21

git版本管理工具版本 2.47.1.windows.2

Windows版本Windows 11 家庭版 24H2

关于测试环境

使用VMware Workstation Pro安装Windows10 企业版进行测试。

我的Github主页

点击此处打开我的Github主页。

点击此处打开项目主页。

github1.png
github2.png
github3.png

运行时的注意事项

服务端启用一个即可,客户端因为SQLite的存在,所有无法在同一目录下运行多个。

如果导入后无法正常运行,可能的原因为压缩文件没有被以项目的形式导入。

以项目形式导入在 Eclipse 中:

  • File → Import → General → Existing Projects into Workspace → Next

  • 选择 Select archive file → 点击 Browse 找到 ZIP 文件。

  • 或选择 Select root directory → 定位到解压后的文件夹。

  • 勾选项目 → 点击 Finish

功能情况

以实现功能

客户端

运行时要输入服务器的IP和端口

登录注册

登录页面

登录界面

此处实现了用户登录的功能,在登录时可对客户端的IP和端口进行更改。

登录时输入的所有内容都会发送给服务器(此时密码为SHA256编码后的值),用以验证账号归属,以及服务器主动联系客户端。

注册页面

注册页面

此处实现了用户注册的功能,在注册时可自定义账号(必须)。

注册时,密码必须大于8位且必须包含大小写字母、数字、和特殊符号。然后密码会经过SHA256编码后发送给服务端。

公共聊天

该功能为最后添加,因老师最后要求此功能必须实现。

公共聊天

已完全实现上课时所要求的全部内容,禁言将在服务端部分演示。

注意: 此处的内容不会被存储到数据库,所以无持久化。

好友名单

该功能在使用前,需要通过添加好友按钮添加好友,好友账号公共聊天中他人发送的ID。好友请求发送后自动通过。

好友名单

该部分实现了更强的功能,如设置好友备注信息,未读消息提醒,聊天记录持久化等。

群聊名单

群聊名单

该功能在使用前,需要通过创建群聊按钮创建群聊,该部分实现功能与好友名单部分相似,但无备注功能。

群成员昵称部分依靠本地数据库搜索好友的昵称,如果没有搜索到则使用好友的唯一ID。

我的信息

该部分只实现了修改昵称功能(不会修改已经添加的好友名),最初设计原因为存在好友拉黑好友群聊三个标签不好看,用来凑数。

我的信息

服务端

服务端

功能明显,包含了用户管理和违禁词管理两部分。

用户管理

实现了用户的封禁状态切换,被封禁的用户将无法在下线后再次登录服务器(可配合设置禁言实现用户的提出)。

实现了用户的禁言设置,被禁言的用户将在规定时间内无法发送消息。

违禁词管理

实现了违禁词的检查,用户一旦发送包含违禁词的聊天,将触发五分钟的禁言。

允许用户添加和删除违禁词。

禁言示例:

禁言1
禁言2

其他高级功能

消息队列: 实现了消息队列,将用户离线时别人发送的消息在上线时发送到用户的客户端上。

多IP的通讯: 服务器在部署在多网络环境的电脑时,可沟通处于不同网段的用户。

未实现功能

文件和图片的发送

在编写中遇到文件只能发送一次的BUG,未能修复成功,方法以弃用,所以未修复服务器的转发逻辑。分析原因: Socket的关闭和开启问题引起(暂时无法解决)。

与其配套的方法以全部废弃。

拉黑列表

该部分在添加新功能公共频道时以废弃。

聊天气泡

Swing的html和css解析无法识别css,无法实现。

技术细节

客户端

架构图

客户端

网络通信​

一般请求

  • 自定义的类http协议,使用ClientsUtils.constructRequest()构造请求。

  • 采用JsonPayloadBuilder构造Json

文件请求(已废弃)

  • 使用Json库,先发送JSON头(包含文件保存路径等信息),然后发送文件内容。

安全机制​

密码加密

  • SHA-256哈希算法加密后进行传输和存储。

  • 密码复杂度要求:大小写字母+数字+特殊符号

文件安全(已废弃)

  • 随机文件名生成(UUID+随机数)

​​输入端口验证

  • 端口号限制:1000-9999

  • JSON字段转义处理

数据管理​

SQLite数据库

  • JDBC(每次操作新建连接)

  • 结果集转换

数据类

  • 用于主程序轮询,放置轮询数据库

图形化界面

Swing优化

  • 自定义字体加载(加载字体文件,防止用户无所需字体)

  • HTML渲染聊天内容

核心逻辑

消息

  • 消息类型:文本/图片/文件

  • 存储结构ChatMessage

  • 未读消息管理​​

    • 内存缓存

    • 持久化存储

1
2
3
4
5
6
7
8
9
10
11
class ChatMessage {
int messageId;
String chatType; // "single" or "group"
String groupId;
String peerId;
String senderId;
String messageType; // "text"/"image"/"file"
String content;
boolean isSent;
Timestamp timestamp;
}

文件传输​(已废弃)

  • 服务器流式写入

其他机制

广播

  • 独立存储

上下线通知

  • 上线通知:Online.handle(userId)

  • 下线处理:Offline.handle(userId)

服务器

架构图

服务器

SQLite数据库

  • 使用SQLite嵌入式数据库

​​网络通信

  • 自定义类HTTP协议格式

  • 端口管理(1000-9999),复用客户端代码。

安全控制

禁言系统

违禁词禁言
  • 五分钟自动国企
1
2
3
4
5
6
7
8
9
10
11
12
public static boolean isDisableMessage(String userId, String message) {
if (message == null || message.isEmpty()) {
return false;
}
for (String word : disableWords) {
if (message.contains(word)) {
addDisableUser(userId);
return true;
}
}
return false;
}
管理禁言
  • 内存缓存+数据库持久化

​文件传输(已废弃)

  • 10GB大文件支持

  • 目录自动创建

  • 断点续传实现

1
2
3
4
// 跳过已处理字节
if (skipBytes > 0) {
long skipped = in.skip(skipBytes);
}

离线消息处理

  • 存储结构
1
2
3
4
public class PendingRequest {
private final String requestUrl;
private final String jsonBody;
}
  • 上线同步流程
1
2
3
4
if (RequestNotSent.hasPendingRequests(userId)) {
List<PendingRequest> requests = getAndRemoveRequests(userId);
// 逐个发送离线消息
}

管理后台

功能模块

  • 用户状态管理

  • 实时禁言设置

  • 违禁词管理

图形化操作界面

  • Swing框架

  • 自定义字体渲染

  • 表格数据绑定

  • 自动刷新机制

1
2
3
4
Timer refreshTimer = new Timer(5000, e -> {
refreshUsers();
refreshBannedWords();
});

参考文档

C/C++网络编程–文件分块传输

Quirks, Caveats, and Gotchas In SQLite

ConcurrentHashMap的使用方法及其内部实现原理

Java ConcurrentHashMap

如何实现实时文本过滤

常见的敏感词过滤方案汇总以及高效工具sensitive-word快速实践!

其他的找不到了