首页 > 其他分享 >day05-离线留言和离线文件

day05-离线留言和离线文件

时间:2022-09-24 20:58:24浏览次数:62  
标签:留言 离线 用户 day05 集合 message 接收

多用户即时通讯系统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中删除对应的数据
image-20220923232748402

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);

image-20220924185809884

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);

image-20220924200646646

业务五分支:

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

image-20220924200853847

3.运行测试

1.运行服务端

image-20220924201114366

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

2.1用户100 登录:

image-20220924201907939

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

image-20220924201933861 image-20220924201951698



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

image-20220924202028005 image-20220924202049736

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

image-20220924202257296 image-20220924202320910

4.服务端监听情况:

image-20220924202454674

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

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

image-20220924202720608

功能实现完毕

标签:留言,离线,用户,day05,集合,message,接收
From: https://www.cnblogs.com/liyuelian/p/16726553.html

相关文章

  • 离线维护 支持插入数 的序列
    论离线维护插入单点碰到过好多类似的题,都在维护这个序列中卡住了,这是个简单易懂\(O(nlog^2_2n)\)我们考虑从后往前维护序列对于第n个插入的数,它最后所在的位置p就是预......
  • Python离线安装第三方包
    Python离线安装第三方包1.通过pip下载安装包,然后在其他机器上安装python-mpipdownloadtest==1.3.5//安装的库名为test,版本为1.3.5python-mpipinstall--no......
  • openEuler离线安装mysql5.7.24
    1.官网下载程序包https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz2.上传至/usr/local/src目录下,解压3.将解压包移动到/us......
  • Win10离线安装.NET Framework 3.5的方法技巧
    很多办公环境是没有外网的,而Win10又不自带.net3.5,导致很多运行在.net2.0\3.0\3.5的程序无法正常运行,所以存在Win10上离线安装.net3.5的需求。(比如我,,,查了一下午的资料文......
  • 【整理】jenkins插件安装的几种方式(在线安装、离线安装)
    整理参考:https://blog.csdn.net/qq_35472206/article/details/1260495741、在线安装:安装jenkins后,初次启动的时候安装插件安装推荐的插件,或者选择插件安装 2、在线安......
  • docker离线安装
    //下载静态包//https://download.docker.com/linux/static/stable///解压tgz包到docker文件夹tar-xzvfdocker.tgz//将docker文件复制到/usr/bin下sudocpdocker/*/us......
  • 红帽系统离线更新yum源
    1、文件目录结构[root@dg1rhel-7-server-rpms]#tree-L2.├──9d69672f86f4d058e1c2e7fd690c3e5fbf7a46e3-updateinfo.xml.gz├──c76c2299-12f3-4f9c-b7bd-03b......
  • centos7离线部署ntp服务,实现内网服务器时间(转载)
    1、简介NTP(NetworkTimeProtocol,网络时间协议)是用来使计算机时间同步的一种协议。它可以使计算机对时钟源做同步化,提供高精准度的时间校正。通过搭建ntp服务,可以为内网......
  • pip-离线安装第三方包
    第三方包的离线安装搜索到相应的安装包然后点击downloadfiles下载sourcedistribution源码文件其实源码文件和whl包都是可以离线安装的,可能还会联网下载......
  • 离线安装 .Net Framework 3.5
    .NetFramework3.5虽然已经年代久远,但一些老项目或老应用都对它有依赖。在线安装非常方便,通过添加删除程序或离线安装包都可以自动化完成,但有些项目中服务器没有外网环......