如何实现发送离线消息的功能

思路总结

服务器端思路:

先在接受客户端消息的逻辑块中,先判断接受方是否在线,将其拆分为两种情况,如果对方在线,那么由服务器将消息转发给接收方,如果对方不在线,那么将其加入到一个key为用户id,value为一个消息集合(ArrayList)的离线集合(ConcurrentHashMap)中,当用户登录时判断该用户的id是否存在于该集合的key中,如果存在,那么通过id,获取到对应的消息集合(ArrayList),通过用户id获取到对应的socket,将消息集合发送到客户端

客户端思路:

在客户端的线程中,对接受的object对象使用instance of判断其运行类型,如果为message对象,则进行之前的逻辑,如果为ArrayList对象,则遍历其中所有的message对象,取出内容并打印。

服务器端的新增代码

编写一个OffLineMessageService类 用来处理离线消息####

package qqserver.service;import CommonServerClient.Message;
import org.junit.Test;
import sun.net.util.IPAddressUtil;import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;/*** @author 晓宇* @version 1.0* @Time: 2022/7/14  10:31*/
@SuppressWarnings({"all"})
public class OffLineMessageService {//key->getterId value->contentsprivate static ConcurrentHashMap<String, ArrayList> offlineMap=new ConcurrentHashMap();public static ConcurrentHashMap<String, ArrayList> getOfflineMap() {return offlineMap;}public static void setOfflineMap(ConcurrentHashMap<String, ArrayList> offlineMap) {OffLineMessageService.offlineMap = offlineMap;}@Testpublic void test(){HashMap<String, String> ssHashMap = new HashMap<>();ssHashMap.put("string","hello");System.out.println(ssHashMap.containsKey("string"));}//将离线消息存入到集合中//编写getter不在线 并将离线消息添加到offlineMappublic static void addOfflineMap(Message message){//如果getter不存在 那么创建一个ArrayList 并将message放入if(!offlineMap.containsKey(message.getGetter())){ArrayList<Message> messages = new ArrayList<>();messages.add(message);offlineMap.put(message.getGetter(),messages);}else {ArrayList arrayList = offlineMap.get(message.getGetter());arrayList.add(message);      }System.out.println("离线消息已经存放在offlineMap中");}//编写方法判断user是否存在于offlineMap中 如果存在 就获取对应getter的socket 将ArrayList中的所有内容发送public static void sendOfflineMessage(String userId,ConcurrentHashMap offlineMap){if (offlineMap.containsKey(userId)){try {ArrayList<Message> arrayList = (ArrayList<Message>) offlineMap.get(userId);OutputStream os = ManageClientThread.getServerConnectClientThread(userId).getSocket().getOutputStream();ObjectOutputStream oos = new ObjectOutputStream(os);//将message集合发送到客户端oos.writeObject(arrayList);System.out.println("发送成功");} catch (IOException e) {e.printStackTrace();}}else System.out.println("发送失败");}//编写方法判断getter是否在线public static boolean isOnline(String getterId){HashMap<String, ServerConnectClientThread> hm = ManageClientThread.getHm();return hm.containsKey(getterId);}//将离线消息从offlineMap删除public static void deleteOfflineMessage(String getterId){ArrayList remove = offlineMap.remove(getterId);System.out.println("删除消息成功"+remove);}}

在接受客户端消息时 判断接收方是否在线 并将离线消息加入到集合中

if(message.getMesType().equals(MessageType.MESSAGE_COMM_MES)){//写一个方法 判断getter是否在线 不在线的话 将message对象存入到集合中if (!OffLineMessageService.isOnline(message.getGetter())){System.out.println("该用户不在线 将在登录后接受到消息");OffLineMessageService.addOfflineMap(message);}else {//根据message获取getterId 在得到对应的线程ServerConnectClientThread serverConnectClientThread = ManageClientThread.getServerConnectClientThread(message.getGetter());OutputStream outputStream = serverConnectClientThread.getSocket().getOutputStream();ObjectOutputStream oos = new ObjectOutputStream(outputStream);oos.writeObject(message);}

用户登录成功后调用方法发送离线消息

if(checkUser(u.getUserId(),u.getPassword())){//验证通过message.setMesType(MessageType.MESSAGE_LOGIN_SUCCEED);//将message对象回复oos.writeObject(message);//创建一个线程,和客户端保持通讯,该线程持有socket对象ServerConnectClientThread serverConnectClientThread = new ServerConnectClientThread(socket, u.getUserId());serverConnectClientThread.start();//把该线程对象放入到集合中进行管理ManageClientThread.addClientThread(u.getUserId(),serverConnectClientThread);ConcurrentHashMap<String, ArrayList> offlineMap = OffLineMessageService.getOfflineMap();//发送离线消息OffLineMessageService.sendOfflineMessage(u.getUserId(),offlineMap);OffLineMessageService.deleteOfflineMessage(u.getUserId());}
else {System.out.println("用户 id=" + u.getUserId() + " pwd=" + u.getPassword() + " 验证失败");message.setMesType(MessageType.MESSAGE_LOGIN_FAIL);oos.writeObject(message);//关闭socketsocket.close();}

客户端新增代码

@Override
public void run() {//因为需要在后台和服务器通讯,因此做成while循环while (true){try {System.out.println("客户端线程等待读取服务器端发送的消息");ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());//处理读入的对象Object o = ois.readObject();//如果服务器没有发送objec对象,线程会阻塞在这里if (o instanceof ArrayList){ArrayList<Message> messageArrayList=(ArrayList<Message>)o;System.out.println("以下是您的离线消息:⬇");for (Message message : messageArrayList) {System.out.println(message.getSender()+": "+message.getContent()+" time:");}}else{Message message=(Message)o;//判断message类型 然后做相应的业务处理//如果读取到的式服务得到的返回在线用户列表if (message.getMesType().equals(MessageType.MESSAGE_RET_ONLINE_FRIEND)){//取出在线列表信息,并显示String[] onlineUsers = message.getContent().split(" ");System.out.println("========当前在线用户列表========");for (int i = 0; i <onlineUsers.length ; i++) {System.out.println("用户:"+onlineUsers[i]);}}else if (message.getMesType().equals(MessageType.MESSAGE_COMM_MES)){//普通的聊天消息//把服务端转化的消息显示到控制台即可System.out.println("\n"+message.getSender()+"对"+message.getGetter()+"说"+message.getContent());} else if (message.getMesType().equals(MessageType.MESSAGE_TO_ALL_MES)) {//显示在客户端的控制台System.out.println("\n"+message.getSender()+"对大家说"+message.getContent());}else if (message.getMesType().equals(MessageType.MESSAGE_FILE_MES)){System.out.println("\n"+message.getSender()+"给"+message.getGetter()+"发送文件"+message.getSrc()+"到我的点啊弄目录"+message.getDest());//取出message的字节数组 通过文件输出流写出到磁盘FileOutputStream fileOutputStream = new FileOutputStream(message.getDest());fileOutputStream.write(message.getFileBytes());fileOutputStream.close();System.out.println("\n保存文件成功");}else {System.out.println("是其他类型的message");}}} catch (Exception e) {e.printStackTrace();}}
}

第一篇文章 记录学习过程哈 兄弟们都加油

韩顺平老师多用户即时通讯系统功能扩展:发送离线消息相关推荐

  1. 韩顺平30天javaQQ通信作业扩展-完成离线提醒及接收接收

    我这里只显示需要添加的代码,其余代码与韩老师写的一样. 这里用户1发短信给用户2 大体思路:1.在服务器接收用户1输入信息ObjectInputStream的时候有两个分支(if-else), 第一, ...

  2. 韩顺平老师《一周学会Linux》视频笔记

    前言: 这个教学视频使用的软件环境是: Red Hat Linux(Kernel 2.4.20-8)红帽Linux系统[release 9 shrike],在虚拟机中运行 1.成为一个Linux专家的 ...

  3. Java学习(java基础)-韩顺平老师

    一.简单介绍 1.jdk.jre 2.Java代码规范 a.类.方法的注释,要以javadoc的方式来写 /** *@author:楠小弟 *@version:1.0 */ public class ...

  4. Java基础易忘重点内容笔记【附B站韩顺平老师课程链接】

    B站课程链接:https://www.bilibili.com/video/BV1fh411y7R8?spm_id_from=333.999.0.0 1. 文档注释 用于对Java方法的注释,可据此生 ...

  5. 传智播客韩顺平老师PHP入门到精通视频免费下载

    传智播客韩顺平老师PHP入门到精通视频免费下载--留下邮箱Lz发送 视频介绍: PHP,是英文超级文本预处理语言Hypertext Preprocessor的缩写.PHP 是一种 HTML 内嵌式的语 ...

  6. 韩顺平老师讲解13个自学编程的坑

    文章目录 前言 内容 误区一 不注重基础,什么技术火就学什么 误区二 总是纠结学最好的编程语言 误区三 喜欢看不喜欢动手 误区四 没有认识到,听懂和能使用时两回事 误区五 很少做笔记,也不去画思维导图 ...

  7. 韩顺平老师坦克大战项目总结

    韩顺平老师讲的坦克大战项目,用代码进行了复现,有几个自己的总结 1 有个别功能没有实现,EnemyTank中敌人坦克向四周移动功能没有实现,只是实现了随机转向,但一直停在原地不动,没有找到bug所在. ...

  8. Java坦克大战 跟学韩顺平老师视频开发

    这里写目录标题 TankBigWarGame 介绍 界面展示 项目架构 安装教程 游戏说明 项目涉及技术功能 游戏结束判断 项目不足与优化空间 相关代码展示 主方法Main 绘图界面 MyPanelF ...

  9. Java集合深入剖析【韩顺平老师版】

    Java集合知识体系[思维导图] 1.集合体系 1.1.为什么使用集合? 1.数组的不足 长度固定,不能更改 存储的必须是同一类型的元素(基本类型或引用类型) 增加.删除元素比较麻烦 2.集合的优势 ...

  10. 韩顺平老师讲诉如何学习PHP

    有很多网友发来邮件询问各种问题,有深有浅, 有难有易.因为很多时间需要上课,没有一一回答,这里给大家道个歉,这里我举例出了几封网友的来信: 发件人:Chen Ma 发送时间: 2012-09-18 1 ...

最新文章

  1. BT项目的运作之一项目建设方案与BT总包方的选择
  2. ssl单向tomcat配置webservice访问方法
  3. MySQL中存在索引但不能索引的经典场景(笔记)
  4. uniapp 封装网络请求
  5. 框架学习八:二维码(Zxing)
  6. Java 位运算符 深入理解
  7. 获取当前位置信息-ios
  8. java 边界_Java泛型中的上下边界的理解
  9. 二分排序法(折半排序)
  10. android studio打包h5打包,AndroidStudio将html5打包成apk
  11. __init__在python中的用法_如何打“我爱你”的摩斯密码
  12. 计算机财务基础知识,财务部计算机基础知识培训.ppt
  13. php模板开发教程,discuz模板开发教程系列教程整理
  14. 在Android中加入GOOGLE统计系统
  15. 基于色彩调和的专题图自动生成系统
  16. Cocoa与Cocoa Touch区别
  17. linux下搜狗输入法wps无法使用,搜狗输入法能在WPS下使用,但其他地方不能输入...
  18. 弗洛伊德、荣格、阿德勒
  19. STM32学习心得三十四:外部SRAM原理及实验代码解读
  20. 一阶电路实验报告心得_电路实训心得体会

热门文章

  1. 在Linux命令行中操作PDF
  2. beego golang bootstrap-table做月度考勤(打卡、签到)统计表
  3. Wireshark菜单栏介绍
  4. 关于无线网卡驱动更新后无法使用(错误代码43)的问题
  5. HTML超链接基本属性
  6. UE4打包工程失败问题记录
  7. python存根文件_python中的函数存根
  8. manjaro开启热点设置密码WPA/WPA2后iphone连不上
  9. Python入门篇(下)
  10. 关于删除/卸载win10自带IE 11浏览器后恢复问题