day05-离线留言和离线文件
2023-04-18 12:33:15 时间
多用户即时通讯系统05
4.编码实现04(拓展)
拓展功能:
- 实现离线留言,如果某个用户不在线 ,当登陆后,可以接收离线的消息
- 实现离线发文件,如果某个功能没有在线,当登录后,可以接收离线的文件
4.8功能实现-离线留言&离线文件
4.8.1思路分析
在服务端中使用ConcurrentHashMap集合来存放离线message(后期可以连数据库)
ConcurrentHashMap存放形式为:
key = getterid [接收者id]
value = ArrayList<Message> [message对象]
- 当有客户发送消息或者文件
- 如果接收者不在线就把message对象存放到服务端的db中(ConcurrentHashMap)
- 当身为接收者的用户登录后,就到服务端的db中查找,如果有getterid = userid,就取出ArrayList的一个或者多个Message对象,发送给接收者,然后在该db中删除对应的数据
![image-20220923232748402](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220923232748402.png)
4.8.2功能实现
只需要修改服务端
1.修改QQServer类
- 在该类中创建一个ConcurrentHashMap集合 offlineMessage,用来存放用户发送的离线消息或者文件
/*
同样创建一个集合,存放多个用户发送的离线消息或者文件
使用 ConcurrentHashMap,可以处理并发的集合,没有线程安全问题
存放的形式为
key = getter id [接收者id]
value = ArrayList<Message> 在一个ArrayList集合中可以存放多条 message对象,实现多条留言或者文件
*/
static ConcurrentHashMap<String, ArrayList<Message>> offlineMessage = new ConcurrentHashMap<>();
- 在该类中新增一个方法,用来判断当用户登录时,是否需要发送离线留言给该用户
/**
* @param getterId 接收离线数据的用户userId
* @param socket 用户对应的通信socket
* 写一个方法,当有用户登录成功时,获取该用户id名,
* 在离线集合中搜索该id,如果有,就返回给该用户,然后删除该离线留言或者文件
*/
public void isOfflineMessage(String getterId,Socket socket){
//搜索 map 集合中是否有该用户的id
if (offlineMessage.containsKey(getterId)) {
//如果有,就说明该用户有离线留言或数据要接收
//在map中获取该 message数据集合arrayList
ArrayList<Message> arrayListMessage = offlineMessage.get(getterId);
//遍历arrayList集合将一个或者多个message数据发送给该用户
for (Message message:arrayListMessage) {
try {
//获得输出对象
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);//发送数据
} catch (IOException e) {
e.printStackTrace();
}
}
offlineMessage.remove(getterId);//遍历完则在数据库中删除该数据集合
}
}
- QQServer构造方法中的while循环中,在用户验证通过的if分支语句 的最后面调用isOfflineMessage方法
//调用方法,查看是否有离线数据
isOfflineMessage(u.getUserId(), socket);
2.修改ServerConnectClientThread类
- 在该类中新增方法processOfData(),用来判断接收用户是否在线,发送的数据应该怎样处理的问题
public void processOfData(Message message) throws IOException {
//业务三or五:客户请求给某个用户发送-->普通的聊天消息or文件
//当用户给某用户发送 message时,如果接收用户不在线(即通过getterId找不到该用户的通讯线程)
if (ManageClientThreads.getServerConnectClientThread(message.getGetter()) == null) {
//就将离线 message放入这个用户对应的arraylist集合中,再把该arrayList集合放到 map中
/*
* 这里有个缺陷,因为map的key值不允许重复(重复的话,value会覆盖为最新值),
* 所以当有多个用户分别给某一个用户进行留言,该接收用户只能接收到最近一个人的离线留言
* 为了解决这个问题,这里每次添加留言之前 都会将该接收用户的所有留言复制一份,再在 最后添加新的留言
* 然后把所有的留言再放回 map集合中,这样效果等于追加新留言
*/
// 先判断map中该接收用户的userId是否存在
// 如果有,就说明已经有人给该用户留言了,就获取map集合对应 getter id的arraylist留言表
// 然后在该用户的留言表中"追加"留言即可
if (offlineMessage.containsKey(message.getGetter())) {//如果接收用户的留言表已经存在
//获取 接收留言的用户的 留言集合
ArrayList<Message> arrayListMessage = offlineMessage.get(message.getGetter());
//在该集合中追加新的留言
arrayListMessage.add(message);//增加新的留言
//留言表再覆盖进去,这样相当于在留言表中追加留言
offlineMessage.put(message.getGetter(), arrayListMessage);
} else {//如果接收用户的留言表不存在
//如果map集合中没有接收用户的id,说明还没人给这个用户留言,要先创建一个留言表arrayListMessage
ArrayList<Message> arrayListMessage = new ArrayList<>();
//把信息添加到新创建的留言表中
arrayListMessage.add(message);
//将新留言表添加到 map集合中
offlineMessage.put(message.getGetter(), arrayListMessage);
}
} else {//接收用户在线,就直接发送数据
//根据接收的message对象的getter id 获取到对应的线程,将message对象进行转发
//先拿到线程
ServerConnectClientThread serverConnectClientThread =
ManageClientThreads.getServerConnectClientThread(message.getGetter());
//获取socket,将socket输出流转为对象流
ObjectOutputStream oos =
new ObjectOutputStream(serverConnectClientThread.getSocket().getOutputStream());
//转发
oos.writeObject(message);
}
}
- 分别修改业务三和业务五的else if分支,因为已经在方法processOfData中封装了业务,所以这里只需要调用该方法即可
业务三分支:
//业务三:客户请求和某用户私聊
//调用方法,判断用户是否在线,在线就直接发送,不在线就将message对象先存在集合中
processOfData(message);
业务五分支:
//业务五:客户请求给某用户发送文件
//调用方法,判断用户是否在线,在线就直接发送,不在线就将message对象先存在集合中
processOfData(message);
3.运行测试
1.运行服务端
![image-20220924201114366](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220924201114366.png)
2.运行客户端--用户100 分别给用户200 和用户300 发送多条离线留言
2.1用户100 登录:
![image-20220924201907939](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220924201907939.png)
2.2用户100 给用户200 发送两条离线留言:
2.3用户100 给用户300 发送两条离线留言:
3.分别登录 用户200和用户300 ,两个用户都接收到了用户100 的留言:
4.服务端监听情况:
![image-20220924202454674](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220924202454674.png)
5.多个用户对一个用户进行留言测试:
用户200不在线时,用户100和300分别给200发送了多条留言:
![image-20220924202720608](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220924202720608.png)
功能实现完毕
相关文章
- 如果美国断供我们的Windows电脑系统会怎样?
- 想知道某个软件的安装日期吗,这是在Windows 10中查找的方法
- 火狐浏览器 Firefox 85 正式发布:停止支持 Flash,增加超级 Cookie 保护功能
- Chrome浏览器可在屏幕分享时将通知静音
- 存隐私担忧 谷歌推进从浏览器中移除第三方Cookie
- 鸿蒙HiSpark IPC DIY摄像头开发套件开箱报告
- 更新Windows10通常会变成一场噩梦,如何避免?
- GCC:优化Linux、互联网和一切
- Linux内核是如何巧妙的初始化各个模块的
- 详解Cortex-A9 uboot启动代码
- Window十二问(快扶我起来,我还能问)
- 懒人都在用的7款chrome插件!网友:爱了爱了
- 解放双手!5M的免费小工具,Windows有救了
- FireFox 火狐浏览器将采用圆角标签页设计
- 鸿蒙移植树莓派(中)添加单板
- Windows Terminal 将在下个版本提供设置 GUI
- 如何在Windows 10上编辑系统环境路径变量
- 千万不要在您的系统上运行的那些Linux命令
- 微软Windows10 21H1版本服务体验包更新与Build19043已现身系统说明
- 如果Windows 10更新卡住了怎么办?