提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 概述
- QQServerRewrite项目
- QQServer类
- ServerConnectClientThread类
概述
这里就不过多赘述,实现了离线留言和离线文件两个功能,这两个相当于扩展功能。
方法很多,我这边分享一下我的方法。
优点在于,只需要在 QQServer类 和 ServerConnectClientThread类 中增加代码
可以存储多条message和文件
当然,如果可以用mysql肯定最好还是用mysql
QQServerRewrite项目
QQServer类
private static ConcurrentHashMap<String, ArrayList<Message>> offlineDb = new ConcurrentHashMap<>();//存放离线消息
private static ConcurrentHashMap<String, ArrayList<Message>> offlineFiles = new ConcurrentHashMap<>();//存放离线文件
QQServer构造器/构造方法中
//当离线用户登录时,就将存储在offlineDb中的消息,发送到对应的客户端
ConcurrentHashMap.KeySetView<String, ArrayList<Message>> keys = offlineDb.keySet();
//遍历 keys
for (String key : keys) {
if (user.getUserId().equals(key)) {//此处判断,现在登录成功的用户,是否有离线留言
ArrayList<Message> messages = offlineDb.get(key);//取出 该用户对应的 message集合
//遍历messages
for (Message offlineMessage : messages) {
//创建对应的对象输出流
ObjectOutputStream oos2 =
new ObjectOutputStream(ManageClientThreads.getServerConnectClientThread(key)
.getSocket().getOutputStream());
//发送 offlineMessage
oos2.writeObject(offlineMessage);
}
//遍历该用户的messages后,就将它从 offlineDb中移除
offlineDb.remove(key);
}
}
//同时,让离线缓存的文件也传输到 客户端的程序上
ConcurrentHashMap.KeySetView<String, ArrayList<Message>> keys2 = offlineFiles.keySet();
//遍历 keySet
for (String key : keys2) {
if (user.getUserId().equals(key)) {
ArrayList<Message> messages = offlineFiles.get(key);
for (Message offlineMessage : messages) {
ObjectOutputStream oos2 =
new ObjectOutputStream(ManageClientThreads.getServerConnectClientThread(key).getSocket().getOutputStream());
oos2.writeObject(offlineMessage);
}
//遍历后,从集合中移除
offlineFiles.remove(key);
}
}
QQServer中添加两个静态方法
/**
* 将message对象,存入到 offlineDb中
* @param getter 接收者
* @param message Message对象
*/
public static void addOfflineMessage(String getter, Message message) {
if (!offlineDb.containsKey(getter)) {//当offlineDb中没有保存过 key为的getter的数据时
ArrayList<Message> messages = new ArrayList<>();
messages.add(message);
offlineDb.put(getter, messages);
} else {
ArrayList<Message> messages = offlineDb.get(getter);
messages.add(message);
}
}
/**
* 根据 接收的客户端的id,将 id-message 存入到 offlineFile中
* @param getter 接收者id
* @param message 带有文件的字节数组的,离线消息
*/
public static void addOfflineFile(String getter, Message message) {
if (!offlineFiles.containsKey(getter)) {//如果之前没有储存过 该用户的离线文件
ArrayList<Message> messages = new ArrayList<>();
messages.add(message);
offlineFiles.put(getter, messages);
} else {//之前存储过,就在原先基础上进行添加
ArrayList<Message> messages = offlineFiles.get(getter);
messages.add(message);
}
}
ServerConnectClientThread类
这里需要做一些小小的修改,不只是单纯添加
1.
else if (message.getMessageType().equals(MessageType.MESSAGE_COMM_MES)) {//客户端要私聊
//将接收到的 message转发给 客户端
//获取 getter对应的线程
ServerConnectClientThread serverConnectClientThread = ManageClientThreads.getServerConnectClientThread(message.getGetter());
//判断接收消息的用户是否在线
if (serverConnectClientThread == null) {//用户不在线就将消息缓存在服务端
//这里我们在QQServer编写一个方法,将message 存入到 offlineDb集合中
QQServer.addOfflineMessage(message.getGetter(), message);
} else {//用户在线就正常发送消息
//获取 该线程对应的对象输出流,并将消息转发给客户端
ObjectOutputStream oos =
new ObjectOutputStream(serverConnectClientThread.getSocket().getOutputStream());
oos.writeObject(message);
}
}
else if (message.getMessageType().equals(MessageType.MESSAGE_FILE_MES)) {//客户端要发送文件
//获取对应的线程
ServerConnectClientThread serverConnectClientThread =
ManageClientThreads.getServerConnectClientThread(message.getGetter());
//在这里加入对离线文件的处理
if (serverConnectClientThread == null) {//如果用户离线,就将 message对象存入到 offlineFiles中
QQServer.addOfflineFile(message.getGetter(), message);
} else {
//获取该线程对应的对象输出流,将message转发给接收消息的客户端
ObjectOutputStream oos =
new ObjectOutputStream(serverConnectClientThread.getSocket().getOutputStream());
oos.writeObject(message);
}
}