Websocket实现发送在线-离线消息

package com.cloudpan.common.websocket;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cloudpan.common.RedisCache;
import com.cloudpan.entity.pojo.SysUserMessage;
import com.cloudpan.service.SysUserMessageService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;


@ServerEndpoint("/im/{userId}")
@Component
@Slf4j
@Data
public class WebSocketIMServer {

    private static SysUserMessageService messageService;
    //用来存储在线用户的信息
    private static RedisCache redisCache;

    private static Integer onlineCount = 0;
    private static Map<String, Session> clients = new ConcurrentHashMap();
    private Session session;
    private String userId;

    @Autowired
    public void setSysUserMessageService(RedisCache redisCache){
        WebSocketIMServer.redisCache = redisCache;
    }

    @Autowired
    public void setRedisCache(SysUserMessageService messageService){
        WebSocketIMServer.messageService = messageService;
    }

    @OnOpen
    public void onOpen(@PathParam("userId") String userId, Session session) {
        this.userId = userId;
        this.session = session;
        WebSocketIMServer.onlineCount++;
        clients.put(userId, session);
        //用户上线 判断有无 离线消息 有 发送离线消息
        OffMsgSend(userId);

        log.info("【websocket消息】连接成功, 总数:{},{}", clients.size(),clients);
        //在redis中存储在线用户的key
        Set<String> onlines = clients.keySet();
        redisCache.setCacheSet("onlines",onlines);

        log.info("当前在线的用户为:{}",onlines);
    }

    //用户每次连接,判断是否存在离线消息,从数据库获取
    public void OffMsgSend(String key){
        LambdaQueryWrapper<SysUserMessage> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUserMessage::getToId,key)
                .eq(SysUserMessage::getOffMsg,"1");
        List<SysUserMessage> list = messageService.list(queryWrapper);
        if (CollectionUtil.isNotEmpty(list)){
            // 不为空 则 发送离线消息
            for (SysUserMessage sysUserMessage : list) {
                JSONObject object = JSON.parseObject(sysUserMessage.getTextMessage());
                String fromId = object.getString("fromId");
                String toId = object.getString("toId");
                String textMessage = object.getString("textMessage");
                sendUser(textMessage,toId);
            }
            list.forEach(ele -> {
                ele.setOffMsg("0");
            });
            //更新为不是离线消息
            messageService.updateBatchById(list);

        }

    }

    @OnClose
    public void onClose() {
        Session session = clients.get(userId);
        if (!ObjectUtils.isEmpty(session)){
            clients.remove(userId);
            WebSocketIMServer.onlineCount--;

            //更新redis中的在线人数信息
            redisCache.deleteObject("onlines");
            Set<String> newOnelines= clients.keySet();
            redisCache.setCacheSet("onlines",newOnelines);
            log.info("【websocket消息】连接断开, 总数:{}", clients.size());
        }

    }

    @OnMessage
    public void onMessage(String message) {
        log.info("【Websocket消息】收到客户端发来的消息:{}", message);
        //将前端传来的数据进行转型
        JSONObject object = JSON.parseObject(message);
        //获取所有数据
        String fromId = object.getString("fromId");
        String toId = object.getString("toId");
        //String textMessage = object.getString("textMessage");

        Session toUser = clients.get(toId);

        SysUserMessage sysUserMessage = new SysUserMessage();
        sysUserMessage.setFromId(fromId);
        sysUserMessage.setToId(toId);
        sysUserMessage.setTextMessage(message);
        if (toUser != null){
            sendUser(message,toId);
            try {
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
            messageService.save(sysUserMessage);

        }else {
            //不在线情况 需要给发送消息者发送一份
            try {
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
            sysUserMessage.setOffMsg("1");
            //离线消息
            messageService.save(sysUserMessage);
        }

    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        throwable.printStackTrace();
        log.error("WebSocket发生错误:" + throwable.getMessage());
    }

    //群发
    public void sendAllUser(String message) {
        // 向所有连接websocket的客户端发送消息
        for (Session item : clients.values()) {
            item.getAsyncRemote().sendText(message);
        }
        log.info("【发送消息】:", userId + "向" + clients.size() + "人发送消息:" + message);
    }

    //私发
    public void sendUser(String message,String toUserId) {
        //获取待发送的用户
        Session user = clients.get(toUserId);
        try {
            user.getBasicRemote().sendText(message);
            log.info(userId +  "消息发送拉,{}",message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: websocket离线连接工具是一种用于在断网状态下维持websocket连接的工具。由于websocket是基于HTTP协议的,只能在有网络连接的情况下才能建立和保持连接。然而,在现实生活中,我们经常会遇到网络中断的情况,例如网络断电、信号不稳定等,这就导致websocket连接无法维持。 离线连接工具通过使用局域网或者本地网络等其他连接方式,实现了在断网状态下继续保持websocket连接的功能。当网络恢复后,离线连接工具会自动将离线期间产生的数据发送给服务器,保证数据的完整性。 离线连接工具通常由客户端和服务器端两部分组成。客户端负责维护本地网络连接,以及将离线期间的数据缓存下来。而服务器端则负责接收客户端发送离线数据,并进行处理和存储。 使用离线连接工具可以有效解决断网导致websocket连接中断的问题,提升用户体验。例如在即时通讯或者实时数据推送等应用场景中,即使用户在断网状态下,也能够保证消息的可靠传输,避免数据丢失。 总而言之,websocket离线连接工具是一种用于在断网状态下保持websocket连接并确保数据传输的工具,通过借助本地网络或局域网等方式,实现离线期间数据的缓存和传输,提升用户体验和数据的可靠性。 ### 回答2: WebSocket离线连接工具是一种用于维持和管理WebSocket连接的工具,可以在网络出现异常或者连接断开的情况下,保持WebSocket连接的稳定性和持续性。 使用WebSocket离线连接工具,可以实现WebSocket连接的自动重连和断线恢复功能。当网络连接中断或WebSocket连接断开时,离线连接工具可以自动触发重连,尝试重新建立WebSocket连接。这样可以避免应用程序因网络异常导致的连接中断、数据丢失或者用户体验的下降。 通过WebSocket离线连接工具,可以实现断线恢复功能。当网络连接恢复或者WebSocket连接重新建立成功后,离线连接工具可以协助应用程序重新与服务端建立起有效的数据传输通道,并恢复中断前的通信状态。这样,应用程序可以继续进行数据传输或者业务操作,而不需要手动重新连接。 WebSocket离线连接工具通常还提供了一些附加的功能,如心跳检测、状态监测和异常处理等。通过定期发送心跳包,离线连接工具可以检测和保持连接的活跃状态,防止因长时间没有数据传输而导致的连接断开。同时,离线连接工具也可以监测连接的状态,包括网络状态、连接成功与否等,以便及时采取相应的措施。当发生异常情况时,离线连接工具可以提供相关的错误处理和通知机制,帮助开发者快速排查和解决问题。 总而言之,WebSocket离线连接工具是一个在网络不稳定环境下,帮助应用程序维持和管理WebSocket连接的工具。它通过实现自动重连和断线恢复功能,提供了更稳定和持续的连接体验,同时也提供了额外的监测和处理功能,帮助开发者更好地处理异常情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值