基于WebSocket的网页在线多用户多房间群聊

1、上一篇文章写了单聊和单房间群聊的实现,实际运用中当然不可能只能创建一个房间,这一篇文章就介绍多房间的实现。
2、界面展示
![$7GQ4{A5)6{{GQ}W5I%QNO.png

![THG[@N]LYO6O{3N(]N]CBAW.png](https://upload-images.jianshu.io/upload_images/14217092-b83c80670ff462fe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![ZQ7D0}M$A4WZD8})I@01`K.png

3、代码结构


NK1`PSBSZRJON)JZS8~_SU3.png

4、复制上一篇测试成功后的项目复制粘贴,修改项目名称。
WebSocketConfig代码与上一篇不变,controller代码我直接删除了,请自行按需求编写。
修改WebSocketServer代码如下:

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * writer: holien
 * Time: 2017-08-01 13:00
 * Intent: webSocket服务器
 */
@Slf4j
@ServerEndpoint("/webSocket/chat/{roomName}/{username}")
@Component
public class WebSocketServer {

    // 使用map来收集session,key为roomName,value为同一个房间的用户集合
    // concurrentMap的key不存在时报错,不是返回null
    private static final Map<String, Set<Session>> rooms = new ConcurrentHashMap();
    private static final Map<String, String> userNameList = new ConcurrentHashMap();

    @OnOpen
    public void connect(@PathParam("roomName") String roomName,@PathParam("username") String username, Session session) throws Exception {
        System.out.println("连接成功");
        // 将session按照房间名来存储,将各个房间的用户隔离
        if (!rooms.containsKey(roomName)) {
            // 创建房间不存在时,创建房间
            Set<Session> room = new HashSet<Session>();
            // 添加用户
            room.add(session);
            rooms.put(roomName, room);
        } else {
            // 房间已存在,直接添加用户到相应的房间
            rooms.get(roomName).add(session);
        }
        System.err.println("username:"+username);
        System.out.println("a client has connected!");
    }

    @OnClose
    public void disConnect(@PathParam("roomName") String roomName,@PathParam("userName") String userName, Session session) {
        rooms.get(roomName).remove(session);
        System.out.println("a client has disconnected!");
    }

    @OnMessage
    public void receiveMsg(@PathParam("roomName") String roomName,@PathParam("username") String username,
                           String msg, Session session) throws Exception {
        // 此处应该有html过滤
        msg = username + ":" + msg;
        System.out.println(msg);
        // 接收到信息后进行广播
        broadcast(roomName, msg);
    }

    // 按照房间名进行广播
    public static void broadcast(String roomName, String msg) throws Exception {
        for (Session session : rooms.get(roomName)) {
            System.out.println("session:"+session.getBasicRemote());
            session.getBasicRemote().sendText(msg);
        }
    }
}

5、修改chat.html页面代码如下:

<!DOCTYPE html><html lang="en">
<head>
    <meta charset="UTF-8">
    <title>网络聊天室</title>
</head>
<style type="text/css">
    .talk_con {
        width: 600px;
        height: 510px;
        border: 1px solid #666;
        margin: 50px auto 0;
        background: #f9f9f9;
    }

    .talk_show {
        width: 580px;
        height: 420px;
        border: 1px solid #666;
        background: #fff;
        margin: 10px auto 0;
        overflow: auto;
    }

    .talk_input {
        width: 580px;
        margin: 10px auto 0;
    }

    .whotalk {
        width: 80px;
        height: 30px;
        float: left;
        outline: none;
    }

    .talk_word {
        width: 500px;
        height: 26px;
        padding: 0px;
        float: left;
        margin-left: 0px;
        outline: none;
        text-indent: 10px;
    }

    .talk_sub {
        width: 56px;
        height: 30px;
        float: left;
        margin-left: 10px;
    }

    .atalk {
        margin: 10px;
    }

    .atalk span {
        display: inline-block;
        background: #0181cc;
        border-radius: 10px;
        color: #fff;
        padding: 5px 10px;
    }

    .btalk {
        margin: 10px;
        text-align: right;
    }

    .btalk span {
        display: inline-block;
        background: #ef8201;
        border-radius: 10px;
        color: #fff;
        padding: 5px 10px;
    }
</style>
<style type="text/css">
    .msg_board {
        width: 322px;
        height: 100px;
        border: solid 1px darkcyan;
        padding: 5px;
        overflow-y: scroll;
    // 文字长度大于div宽度时换行显示
    word-break: break-all;
    }
    /*set srcoll start*/
    ::-webkit-scrollbar
    {
        width: 10px;
        height: 10px;
        background-color: #D6F2FD;
    }
    ::-webkit-scrollbar-track
    {
        -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
        /*border-radius: 5px;*/
        background-color: #D6F2FD;
    }
    ::-webkit-scrollbar-thumb
    {
        height: 20px;
        /*border-radius: 10px;*/
        -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
        background-color: #89D7F7;
    }
    /*set srcoll end*/
</style>
<body>
<div class="talk_con">
    <div style="margin-top: 10px">
        &nbsp;&nbsp;<label>房间名</label>
        <input id="input_roomName" size="10" maxlength="10">
        <label>用户名</label>
        <input id="username" size="10" maxlength="10">
        <input type="button"  value="进入聊天室" onclick="initWebSocket()" />
        <input type="button" value="退出聊天室" onclick="closeWs()" /><br>
    </div>
    <div class="talk_show" id="words">
        <!--<div class="atalk"><span id="asay">A说:吃饭了吗?</span></div>
        <div class="btalk"><span id="bsay">B说:还没呢,你呢?</span></div>-->
    </div>
    <div class="talk_input">
        <!--<select class="whotalk" id="who">
            <option value="0">A说:</option>
            <option value="1">B说:</option>
        </select>-->
        <input type="text" class="talk_word" id="input_msg">
        <input type="button" value="发送" class="talk_sub" onclick="send_msg()">
    </div>
</div>
<!--<div class="msg_board"></div>-->
<!--<input id=s"input_msg" size="43" maxlength="40">-->
<!--<input type="button" value="发送" onclick="send_msg()" />-->
</body>
<script type="text/javascript">
    var webSocket;
    function send_msg() {
        if (webSocket != null) {
            var input_msg = document.getElementById("input_msg").value.trim();
            if (input_msg == "") {
                return;
            }
            webSocket.send(input_msg);
            // 清除input框里的信息
            document.getElementById("input_msg").value = "";
        } else {
            alert("您已掉线,请重新进入聊天室...");
        }
    };

    function closeWs() {
        webSocket.close();
    };

    function initWebSocket() {
        var roomName = document.getElementById("input_roomName").value;
        // 房间名不能为空
        if (roomName == null || roomName == "") {
            alert("请输入房间名");
            return;
        }
        var username = document.getElementById("username").value.trim();
        if (username == "" || username==null) {
            alert("用户名不能为空")
            return;
        }
        if ("WebSocket" in window){
            // alert("您的浏览器支持 WebSocket!");
            if (webSocket == null) {
                var url = "ws://localhost:8080/webSocket/chat/" + roomName+"/"+username;
                // 打开一个 web socket
                webSocket = new WebSocket(url);
            } else {
                alert("您已进入聊天室...");
            }

            webSocket.onopen = function () {
                alert("已进入聊天室,畅聊吧...");
            };

            webSocket.onmessage = function (evt) {
                var Words = document.getElementById("words");
                //得到返回的数据
                var received_msg = evt.data;
                var userName = document.getElementById("username").value;
                if (received_msg.split(":")[0] == userName ){
                    var str = '<div class="btalk"><span id="bsay">' + received_msg + '</span></div>';
                } else
                    var str = '<div class="atalk"><span id="asay">' + received_msg + '</span></div>';
                Words.innerHTML = Words.innerHTML + str;
                Words.scrollTop = Words.scrollHeight;
            };
            webSocket.onclose = function () {
                // 关闭 websocket,清空信息板
                alert("连接已关闭...");
                webSocket = null;
                document.getElementsByClassName("msg_board")[0].innerHTML = "";
            };
        }
        else {
            // 浏览器不支持 WebSocket
            alert("您的浏览器不支持 WebSocket!");
        }
    }
</script>
</html>

5、接下来测试代码是否能运行成功。主要修改就只是server的代码处理,前端页面只是负责展示返回的消息,这次我找了个好一点的页面,css之类的代码没必要深究。重点将server的代码与上一篇的对比,看懂了就会理解websocket转发的代码逻辑。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容

  • 1、现在通过QQ、微信聊天已经非常普遍了,我们常用的网站中联系商家等也是链接到QQ中,一般不会自己去开发聊天模块,...
    Lobo_asd阅读 1,598评论 0 0
  • # 一、框架概述 # 课程概述 1. laravel 4天(之前TP框架还是很大的区别)(国外框架) 2. 在线教...
    关进一阅读 371评论 0 0
  • 本章节主要介绍jenkins的使用 在前一章节中已经介绍可jenkins安装步骤,不了解的可以参考前文:[jenk...
    haishuiaa阅读 3,241评论 0 3
  • 关键词:小龙虾 西瓜 夏威夷 耳机 雪地靴 在五一这个炎热的午后,GYY与队友们正在进行一场激烈的篮球比赛,因天气...
    梁木纯阅读 180评论 0 1
  • 一下子放下可能是很难,如果坚持下来肯定也不容易,但我总觉得我每发一次文,对你的情分就能少一分,对你的执念能淡一分,...
    Lucilfer阅读 186评论 0 0