zoukankan      html  css  js  c++  java
  • SpringBoot快速集成WebSocket实现群聊

    SpringBoot快速集成WebSocket实现群聊

    • 添加pom依赖
    <!-- springboot websocket -->
    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    
    • java
    package cn.pconline.pcloud.admin.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.socket.server.standard.ServerEndpointExporter;
    
    /**
     * @Description WebSocket配置
     * @Author jie.zhao
     * @Date 2020/3/23 18:32
     */
    @Configuration
    public class WebSocketConfig {
        //实例化一个Bean对象
        @Bean
        public ServerEndpointExporter serverEndpointExporter() {
            return new ServerEndpointExporter();
        }
    }
    
    package cn.pconline.pcloud.admin.controller.api;
    
    import cn.pconline.framework.enums.MessageTypeEnum;
    import cn.pconline.pcloud.base.dto.MessageDto;
    import com.alibaba.fastjson.JSON;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import javax.websocket.*;
    import javax.websocket.server.PathParam;
    import javax.websocket.server.ServerEndpoint;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * @Description 群聊websocket
     * @Author jie.zhao
     * @Date 2020/3/23 18:34
     */
    @Component
    @ServerEndpoint("/groupChat/{groupNo}/{name}")
    public class GroupChatWebsocket {
    
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        /**
         * 保存 组id->组成员 的映射关系
         * 之所以使用ConcurrentHashMap因为这个是线程安全的
         */
        private static ConcurrentHashMap<String, List<Session>> groupMemberInfoMap = new ConcurrentHashMap<>();
    
        /**
         * 收到消息调用的方法,群成员发送消息
         *
         * @param groupNo
         * @param name
         * @param message
         */
        @OnMessage
        public void onMessage(@PathParam("groupNo") String groupNo,
                              @PathParam("name") String name, String message) {
            //得到当前群的所有会话,也就是所有用户
            List<Session> sessionList = groupMemberInfoMap.get(groupNo);
            MessageDto dto = new MessageDto();
            dto.setType(MessageTypeEnum.CHAT.getType());
            dto.setOnlineNum(sessionList.size());
            // 遍历Session集合给每个会话发送文本消息
            sessionList.forEach(item -> {
                try {
                    dto.setName(name);
                    dto.setContent(message);
                    item.getBasicRemote().sendText(JSON.toJSONString(dto));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    
        /**
         * 建立连接调用的方法,群成员加入
         *
         * @param session 会话
         * @param groupNo 群id
         */
        @OnOpen
        public void onOpen(Session session, @PathParam("groupNo") String groupNo) {
            //得到当前群的所有会话,也就是所有用户
            List<Session> sessionList = groupMemberInfoMap.get(groupNo);
            if (sessionList == null) {
                sessionList = new ArrayList<>();
                groupMemberInfoMap.put(groupNo, sessionList);
            }
            sessionList.add(session);
            logger.info("连接建立");
            logger.info("直播房间号: {}, 直播在线人数: {}", groupNo, sessionList.size());
            systemOnlineNumMsg(sessionList, sessionList.size());
        }
    
        /**
         * 关闭连接调用的方法,群成员退出
         *
         * @param session
         * @param groupNo
         */
        @OnClose
        public void onClose(Session session, @PathParam("groupNo") String groupNo) {
            List<Session> sessionList = groupMemberInfoMap.get(groupNo);
            sessionList.remove(session);
            logger.info("连接关闭");
            logger.info("直播房间号: {}, 直播在线人数: {}", groupNo, sessionList.size());
            systemOnlineNumMsg(sessionList, sessionList.size());
        }
    
        /**
         * 传输消息错误调用的方法
         *
         * @param error
         */
        @OnError
        public void OnError(Throwable error) {
            logger.info("连接出错:{}", error.getMessage());
        }
    
        /**
         * 在线人数系统通知
         * @param sessionList
         * @param onlineNum
         */
        public void systemOnlineNumMsg(List<Session> sessionList , int onlineNum) {
            // 遍历Session集合给每个会话发送文本消息
            MessageDto dto = new MessageDto();
            dto.setType(MessageTypeEnum.SYSTEM.getType());
            sessionList.forEach(item -> {
                try {
                    dto.setOnlineNum(onlineNum);
                    item.getBasicRemote().sendText(JSON.toJSONString(dto));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }
    
    package cn.pconline.pcloud.admin.controller.api;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    /**
     * @Description 测试
     * @Author jie.zhao
     * @Date 2020/3/23 18:41
     */
    @Controller
    @RequestMapping("/api")
    public class TestChatController {
    
        @RequestMapping("/test")
        public String index(){
            return "api/test";
        }
    }
    
    
    • 测试html
    <!doctype html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>直播互动</title>
    <!--适应移动端-->
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!--css样式-->
    <style> 
    body{ margin:0 auto; 400px; border:1px solid #F00} 
    .box{margin:20px;}
    </style>
    <!--引用jquery库-->
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
    
    </head>
    
    <body>
        <div class="box">
    		 <p>直播房间号</p>
    		 <input type="text" id="groupNo" value="1585023517289" placeholder="请输入房间号"/>
    		 <p>昵称</p>
    		 <input type="text" id="name" value="" placeholder="请输入昵称"/>
    		 <p>聊天内容</p>
    		 <textarea rows="3" cols="20" id="content"  placeholder="请输入聊天内容"></textarea> <br/>
    		 <input type="submit" value="发送" onclick="start()"/>
    		 <p>-----------------------------------------</p>
    		 <div id="messages" style=""></div>
    	 </div>
    
    <script type="text/javascript">
    
        var webSocket = null;
    
        //收到消息
        function onMessage(event) {
            $('#messages').append('<p>'+ event.data+'</p>');
        }
    
        //建立连接
        function onOpen(event) {
    		console.log('连接已经建立'); 
        }
    
        //发生错误
        function onError(event) {
            console.log('发生错误');
            webSocket = null;
        }
    
        //连接关闭
        function onClose(event) {
            console.log('连接关闭');
            webSocket = null;
        }
    
        //连接
        function connect() {
            //获取群号
            var groupNo = $('#groupNo').val();
            //获取昵称
            var name = $('#name').val();
            //验证非法数据
            if (url == '' || name == '') {
                alert('群号和用户名不能为空');
                return;
            }
            //验证是否已经建立连接
            if (webSocket != null) {
                alert('已经建立过连接,如需重新建立连接,请自行更改逻辑,或者重新刷新页面');
                return;
            }
            //创建Websocket连接url
            var url = 'ws://127.0.0.1:8080/cisco/groupChat/' + groupNo + '/' + name;
            //实例化WebSocket
    		try {
    		 webSocket = new WebSocket(url);
    		}catch(err){
    		}
    		//出现错误
            webSocket.onerror = function (event) {
                onError(event)
            };
            //调用创建连接
            webSocket.onopen = function (event) {
                onOpen(event)
            };
            //调用收到消息
            webSocket.onmessage = function (event) {
                onMessage(event)
            };
            //调用关闭连接
            webSocket.onclose = function (event) {
                onClose(event)
            };
        }
    
        //开始发送
        function start() {
            //获取发送的内容
            var text =  $('#content').val(); 
            if (text == '') {
                alert('发送内容不允许为空');
                return;
            }
            if (webSocket == null) {
    			console.log('连接已关闭,正在重新连接'); 
    			connect(); 
            }
            //调用WebSocket发送的方法
            webSocket.send(text);
            //初始化文本域的内容为空
            $('#content').val('')
        }
    	
        //连接检测,重试连接
        function wsCheck() {
            setTimeout(function () {
                if (webSocket == null) {
                    connect();
                    console.log('连接健康监测:'+(webSocket!=null?'ok':'error'));
                }
                wsCheck();
            }, 1000 * 10);
        }
    
    	
    	window.onload = function(){
    	
    		var name = $.cookie('cisco-cookie-name');
    	
    		if(name==null||name==''){
    			name = '游客'+ Date.parse(new Date());
    			$.cookie('cisco-cookie-name', name, { expires: 7 });
    		}
    	
    		$('#name').val(name)
    		connect();
    		wsCheck();
    	}
    	
    </script>
    </body>
    </html>
    
    
  • 相关阅读:
    ASP.NET程序中常用的三十三种代码[1]
    window.showModalDialog使用手册
    ASP函数详解
    ASP.NET程序中常用的三十三种代码[2]
    Session对象的清空
    Css不朽的经典—3D文字特效
    IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
    ASP.NET程序中常用的三十三种代码[3]
    平面设计常用制作尺寸
    Work with a file upload and download controls2
  • 原文地址:https://www.cnblogs.com/cnsyear/p/12635382.html
Copyright © 2011-2022 走看看