5

day05-离线留言和离线文件 - 一刀一个小西瓜

 1 year ago
source link: https://www.cnblogs.com/liyuelian/p/16726553.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

多用户即时通讯系统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

功能实现完毕


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK