多用户即时通讯系统05

4.编码实现04(拓展)

拓展功能:

  1. 实现离线留言,如果某个用户不在线 ,当登陆后,可以接收离线的消息
  2. 实现离线发文件,如果某个功能没有在线,当登录后,可以接收离线的文件

4.8功能实现-离线留言&离线文件

4.8.1思路分析

在服务端中使用ConcurrentHashMap集合来存放离线message(后期可以连数据库)

ConcurrentHashMap存放形式为:

key = getterid   [接收者id]
value = ArrayList<Message> [message对象]
  1. 当有客户发送消息或者文件
  2. 如果接收者不在线就把message对象存放到服务端的db中(ConcurrentHashMap)
  3. 当身为接收者的用户登录后,就到服务端的db中查找,如果有getterid = userid,就取出ArrayList的一个或者多个Message对象,发送给接收者,然后在该db中删除对应的数据

4.8.2功能实现

只需要修改服务端

1.修改QQServer类
  1. 在该类中创建一个ConcurrentHashMap集合 offlineMessage,用来存放用户发送的离线消息或者文件
/*
同样创建一个集合,存放多个用户发送的离线消息或者文件
使用 ConcurrentHashMap,可以处理并发的集合,没有线程安全问题
存放的形式为
key = getter id [接收者id]
value = ArrayList<Message> 在一个ArrayList集合中可以存放多条 message对象,实现多条留言或者文件
*/
static ConcurrentHashMap<String, ArrayList<Message>> offlineMessage = new ConcurrentHashMap<>();
  1. 在该类中新增一个方法,用来判断当用户登录时,是否需要发送离线留言给该用户
/**
* @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);//遍历完则在数据库中删除该数据集合
}
}
  1. QQServer构造方法中的while循环中,在用户验证通过的if分支语句 的最后面调用isOfflineMessage方法
//调用方法,查看是否有离线数据
isOfflineMessage(u.getUserId(), socket);

2.修改ServerConnectClientThread类
  1. 在该类中新增方法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);
}
}
  1. 分别修改业务三和业务五的else if分支,因为已经在方法processOfData中封装了业务,所以这里只需要调用该方法即可

业务三分支:

//业务三:客户请求和某用户私聊
//调用方法,判断用户是否在线,在线就直接发送,不在线就将message对象先存在集合中
processOfData(message);

业务五分支:

//业务五:客户请求给某用户发送文件
//调用方法,判断用户是否在线,在线就直接发送,不在线就将message对象先存在集合中
processOfData(message);

3.运行测试

1.运行服务端

2.运行客户端--用户100 分别给用户200 和用户300 发送多条离线留言

2.1用户100 登录:

2.2用户100 给用户200 发送两条离线留言:



2.3用户100 给用户300 发送两条离线留言:

3.分别登录 用户200和用户300 ,两个用户都接收到了用户100 的留言:

4.服务端监听情况:

5.多个用户对一个用户进行留言测试:

用户200不在线时,用户100和300分别给200发送了多条留言:

功能实现完毕

day05-离线留言和离线文件的更多相关文章

  1. 可在广域网部署运行的QQ高仿版 -- GG叽叽V3.2,增加离线消息、离线文件功能(源码)

    (几句题外话:虽然就如何将GG发展为一个有商业价值的产品,我还没有很清晰明确的思路,但是从GG发布以来,通过GG认识了一些朋友,也接了一些小单子,赚了一点小钱.有了一点甜头,目前和2.3个好朋友一起做 ...

  2. 离线Chrome插件安装文件(crx)的安装方法

    离线Chrome插件安装文件(crx)的安装方法 一.正常安装方法 1.开发谷歌浏览器,设置->扩展程序 在打开的谷歌浏览器的扩展管理器中用户可以看到一些已经安装程序的Chrome插件,或者一个 ...

  3. 下载谷歌浏览器(Chrome)扩展离线安装包crx文件最简单的方法

    转:http://alyzq.com/?p=627 如果不会使用,请看下面的操作步骤 引言(可以不看): 下面介绍一下,下载谷歌浏览器(Google Chrome)扩展的离线安装包crx文件最简单的方 ...

  4. 【转】Phonegap离线调用SQLite数据库文件

    按:不可多得的好文章,转过来以免源丢失 文章来源:http://liuwei.co/index.php/default/The-quickest-way-to-execute-many-sql-for ...

  5. XMPP——Smack[6]离线消息和离线文件的实现

    终篇,三天所学所用,也就这些,如果需要大家要自己去查资料研究研究,功能其实可以很强大的 可惜界面做得不好,一大短处,从大一迄今没整好,主要是个人审美不行,哎 毕业季呀毕业季,明天摆摊卖书,再半月就可能 ...

  6. DataX异构数据源离线同步工具json文件配置说明

    DataX 是阿里开源的一个异构数据源离线同步工具,致力于实现包括关系型数据库(MySQL.Oracle等).HDFS.Hive.ODPS.HBase.FTP等各种异构数据源之间稳定高效的数据同步功能 ...

  7. 关于离线底图和离线shp文件的加载

    首先底图是我自己用百度地图18级别的瓦片图在armap中制作的TPK文件,shp图层是我用同样的百度地图18级别的瓦片图矢量化的,二者在arcmap中的空间参考是一致的,所以我以为在移动端加入的时候二 ...

  8. 【iOS开发-47】怎样下载iOS 7.1 Simulator 以及iOS 8离线的Documentation这些文件?

    (1)最官方的解决的方法 在Xcode6里面提供下载. 依照下图找到下载就可以. 一般建议把以下的自己主动检查更新和下载的框框勾起来,这样它会帮我们自己主动下载. watermark/2/text/a ...

  9. 复制D:\\day05目录下的所有文件到D:\\copy,并将.txt文件改为.java文件。

    **解题思路: 1.首先定义一个静态的refile方法,参数传入两个文件路径 2.要复制目录下的所有文件,首先查询File类的方法,可以使用listFiles方法得到目录下的文件 3.想到这问题基本就 ...

随机推荐

  1. PHP进阶玩法

    1. 删除不必要的模块. PHP随带内置的PHP模块.它们对许多任务来说很有用,但是不是每个项目都需要它们.只要输入下面这个命令,就可以查看可用的PHP模块: # php - m  一旦你查看了列表, ...

  2. scrollTop实例

    <!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8" ...

  3. 从零开始Blazor Server(5)--权限验证

    序 之前我们一直使用的是微软自带的身份验证方式,即使用[Authorize]标签来做. 但是这种方式十分不灵活,微软推荐的方式是加Policy,但是这种方式对我们来说还是不够灵活. 所以本节我们用完全 ...

  4. PLC中增益和偏移

    y=kx+b这个直线方程,那么增益就是指k这个斜率,而偏移就是指b. 模拟量转换时一般是不需要设置这两个参数的,只有当外部信号与模块接收的信号在值上有偏差的情况下才会去调整这个参数. 如果的模块信号是 ...

  5. 编译器工程师眼中的好代码:Loop Interchange

    摘要:本文将以Loop Interchange的场景为例,讲述在编写代码时可以拿到更优性能的书写方式. 本文分享自华为云社区<编译器工程师眼中的好代码(1):Loop Interchange&g ...

  6. 循环结构——while、do-while、for循环

    1.while循环 语法格式: while(条件判断){ 循环体 } 解释: (1)关键字while后的小括号中的内容时循环条件. (2)循环条件是一个布尔表达式,它的值为布尔类型 "真&q ...

  7. 用固态U盘让你的办公环境随身移动

    有些人因为家中的电脑设备没有办公环境,或者是软件太多装起来麻烦,以及环境不同步等原因上下班总是背着电脑,其实大可不必,只要将系统装进U盘,就可以让你的办公环境随身移动.在公司时启动U盘系统工作,下班后 ...

  8. 羽夏看Linux内核——中断与分页相关入门知识

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作.如想转载,请把我的转载信息附在文章后面,并 ...

  9. PerfView专题 (第一篇):如何寻找热点函数

    一:背景 准备开个系列来聊一下 PerfView 这款工具,熟悉我的朋友都知道我喜欢用 WinDbg,这东西虽然很牛,但也不是万能的,也有一些场景他解决不了或者很难解决,这时候借助一些其他的工具来辅助 ...

  10. 一文理解Hadoop分布式存储和计算框架入门基础

    @ 目录 概述 定义 发展历史 发行版本 优势 生态项目 架构 组成模块 HDFS架构 YARN架构 部署 部署规划 前置条件 部署步骤 下载文件(三台都执行) 创建目录(三台都执行) 配置环境变量( ...