WebSocket实现群聊功能、房间隔离

  • 引用WebSocket相关依赖
 		<dependency>
            <groupId>javax.websocket</groupId>
            <artifactId>javax.websocket-api</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>4.3.30.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-messaging</artifactId>
            <version>4.3.30.RELEASE</version>
        </dependency>
  • 后端代码实现,很简单分为消息封装和消息处理
package com.risen.brain.websocket;

import com.alibaba.fastjson.JSONObject;
import com.risen.brain.websocket.entity.Message;
import com.risen.brain.websocket.entity.MessageData;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Administrator
 */
@ServerEndpoint("/public/xzdnTaskSocket/{platform}/{groupId}/{selfId}")
@Component
public class MessageWebSocket {

    private static Map<String, MessageWebSocket> userMap = new ConcurrentHashMap<>();
    private static Map<String, Set<MessageWebSocket>> roomMap = new ConcurrentHashMap<>();
    private Session session;
    private String selfId;


    //建立连接成功调用
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "platform") String platform, @PathParam(value = "groupId") String groupId, @PathParam(value = "selfId") String selfId) {
        this.session = session;
        this.selfId = selfId;
        userMap.put(selfId, this);
        if (!roomMap.containsKey(groupId)) {
            Set<MessageWebSocket> set = new HashSet<>();
            set.add(userMap.get(selfId));
            roomMap.put(groupId, set);
        } else {
            roomMap.get(groupId).add(this);
        }
        MessageData messageData = new MessageData();
        messageData.setSelfId(selfId);
        messageData.setGroupId(groupId);
        messageData.setPlatform(platform);
        messageData.setType("meta");
        messageData.setDetailType("online");
        System.out.println(selfId + "加入了群聊!");

        Message dataMessage = new Message(selfId + "加入了群聊!");
        messageData.setMessages(Arrays.asList(dataMessage));
        sendMessageTo(messageData, groupId, selfId);

    }

    //关闭连接时调用
    @OnClose
    public void onClose(@PathParam(value = "selfId") String selfId, @PathParam("groupId") String groupId) {
        if (roomMap.containsKey(groupId)) {
            Set<MessageWebSocket> set = roomMap.get(groupId);
            for (MessageWebSocket item : set) {
                if (item.selfId.equals(selfId)) {
                    set.remove(item);
                }
            }
        }
    }

    //收到客户端信息
    @OnMessage
    public void onMessage(String message, @PathParam(value = "platform") String platform, @PathParam(value = "selfId") String selfId, @PathParam("groupId") String groupId) {
        MessageData messageData = new MessageData();
        List<Message> objects = new ArrayList<>();
        Message mg = new Message();
        mg.setData(message);
        mg.setType("text");
        objects.add(mg);
        messageData.setMessages(objects);
        messageData.setPlatform(platform);
        sendMessageTo(messageData, groupId, selfId);
        //根据bean名称获取对象,可以对消息进行记录
        //IXzdnInvestigateCityService xzdnInvestigateCityService1 = SpringUtil.getBean("xzdnInvestigateCityService");
        //XzdnInvestigateCity city = new XzdnInvestigateCity();
        //List<Map> groupCityCount = xzdnInvestigateCityService1.findGroupCityCount(city);
        System.out.println("2222");
        /*TableDynaModel tableDynaModel = tableDynaDao.newDynaModel("xzdn_task_message_info");
        tableDynaModel.set("xzdnMessageId", messageData.getId());
        tableDynaModel.set("xzdnMessagePlatform", messageData.getPlatform());
        tableDynaModel.set("xzdnMessageSelfid", messageData.getSelfId());
        tableDynaModel.set("xzdnMessageSelfname", messageData.getSelfName());
        tableDynaModel.set("xzdnMessageSelfdeptid", messageData.getSelfDeptId());
        tableDynaModel.set("xzdnMessageSelfdeptname", messageData.getSelfDeptName());
        tableDynaModel.set("xzdnMessageTime", messageData.getTime());
        tableDynaModel.set("xzdnMessageType", messageData.getType());
        tableDynaModel.set("xzdnMessageDetailtype", messageData.getDetailType());
        tableDynaModel.set("xzdnMessageMessagetype", messageData.getMessageType());
        tableDynaModel.set("xzdnMessageGroupid", messageData.getGroupId());
        tableDynaModel.set("xzdnMessageMessages", JSONObject.toJSONString(messageData.getMessages()));
        tableDynaDao.save(tableDynaModel);*/
    }

    //错误时调用
    @OnError
    public void onError(Session session, Throwable throwable) {
        System.out.println("发生错误");
        throwable.printStackTrace();
    }

    /**
     * 群聊
     *
     * @param message 消息
     * @param groupId 房间号
     * @param selfId  发送人
     */
    public static void sendMessageTo(MessageData message, String groupId, String selfId) {
        message.setGroupId(groupId);
        message.setSelfId(selfId);
        if (roomMap.containsKey(groupId)) {
            for (MessageWebSocket item : roomMap.get(groupId)) {
                //if (!item.selfId.equals(selfId)) {
                    item.session.getAsyncRemote().sendText(JSONObject.toJSONString(message));
               // }
            }
        }
    }

    /**
     * 私聊
     *
     * @param message  消息
     * @param toSelfId 接收人
     */
    public void sendUserTo(String message, String toSelfId) {
        if (userMap.containsKey(toSelfId)) {
            userMap.get(toSelfId).session.getAsyncRemote().sendText(message);
        }
    }
}

  • 消息封装,里面包含房间信息,用户信息、消息
package com.risen.brain.websocket.entity;

import lombok.Data;

@Data
public class Message {
    /**
     * 消息类型 text,json,image,audio,video,file,markdown,btn
     */
    private String type;
    /**
     * 内容 媒体类容均为文件id/url/详情json
     */
    private String data;

    public Message() {

    }

    public Message(String data) {
        this.data = data;
        this.type = "text";
    }
}

package com.risen.brain.websocket.entity;

import com.risen.brain.utils.SequenceUtils;
import lombok.Data;

import java.math.BigInteger;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 *  * @Author: yxz
 * @Date: 2021/10/18/10:21
 * @Description:
 */
@Data
public class MessageData {
    /**
     * 事件唯一标识符
     */
    private BigInteger id;

    /**
     * 实现平台名称,协议名称 web,dd
     */
    private String platform;
    /**
     * 消息发送人 id
     */
    private String selfId;
    /**
     * 消息发送人
     */
    private String selfName;
    /**
     * 消息发送人部门id
     */
    private String selfDeptId;
    /**
     * 消息发送人部门
     */
    private String selfDeptName;
    /**
     * 事件发生时间(Unix 时间戳),单位:秒
     */
    private Long time;
    /**
     * 事件类型,必须是 meta、message、notice、request 中的一个,分别表示元事件、消息事件、通知事件和请求事件
     */
    private String type;

    /**
     * 事件详细类型
     * meta: online,heartbeat 分别表示 首次连接,心跳包
     * message:
     * notice: remove 删除通知
     * request:
     */
    private String detailType;

    /**
     * 消息类型 1:群消息
     */
    private String messageType;
    /**
     * 群消息时的群id
     */
    private String groupId;

    /**
     * 消息段
     */
    private List<Message> messages;

    public MessageData() {
        this.id = SequenceUtils.nextId();
        this.time = LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
    }
}
  • 前端代码实现,本人不是专业前端,网上随便找个了页面做交互
<!DOCTYPE HTML>
<html>

<head>
    <meta charset="UTF-8">
    <title>My WebSocket</title>
    <style>
        #message {
            margin-top: 40px;
            border: 1px solid gray;
            padding: 20px;
        }
    </style>
</head>

<body>
<button onclick="conectWebSocket()">连接WebSocket</button>
<button onclick="closeWebSocket()">断开连接</button>
<hr />
<br />
消息:<input id="text" type="text" />
<button onclick="send()">发送消息</button>
<div id="message"></div>
</body>
<script type="text/javascript">

    //获取地址栏参数,key:参数名称



    const urlParams = new URLSearchParams(window.location.search);
    //发信息用户
    const user = urlParams.get('user');
    //房间名称
    const type = urlParams.get('group');

    var websocket = null;

    function conectWebSocket() {
        //判断当前浏览器是否支持WebSocket
        if ('WebSocket' in window) {
            websocket = new WebSocket("ws://localhost:8081/xzdn/public/xzdnTaskSocket/web/"+type+"/"+user);
        } else {
            alert('Not support websocket')
        }

        //连接发生错误的回调方法
        websocket.onerror = function () {
            setMessageInnerHTML("error");
        };

        //连接成功建立的回调方法
        websocket.onopen = function (event) {
            setMessageInnerHTML("tips: 连接成功!");
        }

        //接收到消息的回调方法
        websocket.onmessage = function (event) {
            setMessageInnerHTML(event.data);
        }

        //连接关闭的回调方法
        websocket.onclose = function () {
            setMessageInnerHTML("tips: 关闭连接");
        }

        //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
        window.onbeforeunload = function () {
            websocket.close();
        }

    }

    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }


    //关闭连接
    function closeWebSocket() {
        websocket.close();
    }

    //发送消息
    function send() {
        var message = document.getElementById('text').value;
        websocket.send(message,"web",user,type);
    }

</script>

</html>
  • 最终效果

超人发送信息:房间号:加班放假

chao在这里插入图片描述

王亮在房间“加班放假”中,收到了超人信息,并进行回答

在这里插入图片描述

四环单独在“吃喝玩乐”房间并没有收到房间“加班放假”中的消息
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值