美文网首页SpringBoot
SpringBoot+WebSocket聊天

SpringBoot+WebSocket聊天

作者: HeloWxl | 来源:发表于2020-05-12 23:06 被阅读0次

    先看一下页面效果,有点简单粗暴!哈哈哈哈哈,别介意.
    本文参考:SpringBoot2.0集成WebSocket,实现后台向前端推送信息

    效果图

    新建一个springboot项目

    项目结构

    引入相关依赖

      <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>3.0</version>
            </dependency>
    
            <!--com.alibaba/fastjson-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.62</version>
            </dependency>
    
            <!--websocket依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-websocket</artifactId>
            </dependency>
    
            <!--thymeleaf-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
    
    

    Java代码

    WebSocketConfig

    @Configuration
    public class WebSocketConfig {
        @Bean
        public ServerEndpointExporter serverEndpointExporter(){
            return new ServerEndpointExporter();
        }
    }
    

    PageController

    @RestController
    public class PageController {
        @GetMapping("chat")
        public ModelAndView toChat(){
            return new ModelAndView("/chat");
        }
    }
    

    WebSocketServer

    @ServerEndpoint("/chat/{userName}")
    @Component
    @Slf4j
    public class WebSocketServer {
    
        /**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
        private static int onlineCount = 0;
        /**concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。*/
        private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
        /**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
        private Session session;
    
        /**接收userId*/
        private String userName="";
    
        /**
         * @Description: 连接建立成功调用的方法
         * @params: [session, userId]
         * @return: void
         * @Author: wangxianlin
         * @Date: 2020/5/9 9:13 PM
         */
        @OnOpen
        public void onOpen(Session session,@PathParam("userName") String userName) {
            this.session = session;
            this.userName=userName;
            if(webSocketMap.containsKey(userName)){
                webSocketMap.remove(userName);
                webSocketMap.put(userName,this);
                //加入set中
            }else{
                webSocketMap.put(userName,this);
                //加入set中
                addOnlineCount();
                //在线数加1
            }
    
            log.info("用户连接:"+userName+",当前在线人数为:" + getOnlineCount());
    
            try {
                sendMessage("{\"msg\":\"连接成功\"}");
            } catch (IOException e) {
                log.error("用户:"+userName+",网络异常!!!!!!");
            }
        }
    
        /**
         * @Description: 连接关闭调用的方法
         * @params: []
         * @return: void
         * @Author: wangxianlin
         * @Date: 2020/5/9 9:13 PM
         */
        @OnClose
        public void onClose() {
            if(webSocketMap.containsKey(userName)){
                webSocketMap.remove(userName);
                //从set中删除
                subOnlineCount();
            }
            log.info("用户退出:"+userName+",当前在线人数为:" + getOnlineCount());
        }
    
    
        /**
         * @Description: 收到客户端消息后调用的方法
         * @params: [message, session]
         * @return: void
         * @Author: wangxianlin
         * @Date: 2020/5/9 9:13 PM
         */
        @OnMessage
        public void onMessage(String message, Session session) {
            log.info("用户消息:"+userName+",报文:"+message);
            //可以群发消息
            //消息保存到数据库、redis
            if(StringUtils.isNotBlank(message)){
                try {
                    //解析发送的报文
                    JSONObject jsonObject = JSON.parseObject(message);
                    //追加发送人(防止串改)
                    jsonObject.put("sender",this.userName);
                    String receiver=jsonObject.getString("receiver");
                    //传送给对应toUserId用户的websocket
                    if(StringUtils.isNotBlank(receiver)&&webSocketMap.containsKey(receiver)){
                        webSocketMap.get(receiver).sendMessage(jsonObject.toJSONString());
                    }else{
                        log.error("请求的receiver:"+receiver+"不在该服务器上");
                        //否则不在这个服务器上,发送到mysql或者redis
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    
        /**
         *
         * @param session
         * @param error
         */
        @OnError
        public void onError(Session session, Throwable error) {
            log.error("用户错误:"+this.userName+",原因:"+error.getMessage());
            error.printStackTrace();
        }
    
        /**
         * 实现服务器主动推送
         */
        public void sendMessage(String message) throws IOException {
            this.session.getBasicRemote().sendText(message);
        }
    
        /**
         * @Description: 发送消息
         * @params: [message, userId]
         * @return: void
         * @Author: wangxianlin
         * @Date: 2020/5/9 9:09 PM
         */
        public static void sendInfo(String message,@PathParam("userId") String userId) throws IOException {
            log.info("发送消息到:"+userId+",报文:"+message);
            if(StringUtils.isNotBlank(userId)&&webSocketMap.containsKey(userId)){
                webSocketMap.get(userId).sendMessage(message);
            }else{
                log.error("用户"+userId+",不在线!");
            }
        }
    
        /**
         * @Description: 获取在线人数
         * @params: []
         * @return: int
         * @Author: wangxianlin
         * @Date: 2020/5/9 9:09 PM
         */
        public static synchronized int getOnlineCount() {
            return onlineCount;
        }
    
        /**
         * @Description: 在线人数+1
         * @params: []
         * @return: void
         * @Author: wangxianlin
         * @Date: 2020/5/9 9:09 PM
         */
        public static synchronized void addOnlineCount() {
            WebSocketServer.onlineCount++;
        }
    
        /**
         * @Description: 在线人数-1
         * @params: []
         * @return: void
         * @Author: wangxianlin
         * @Date: 2020/5/9 9:09 PM
         */
        public static synchronized void subOnlineCount() {
            WebSocketServer.onlineCount--;
        }
    }
    
    

    前端HTMl

    <div class="layui-container">
        <div class="layui-row">
            <div class="layui-col-md12">
                <fieldset class="layui-elem-field layui-field-title" style="margin-top: 25px;">
                    <legend style="margin-left: 40%;">简单粗暴的聊天界面</legend>
                </fieldset>
                <div class="grid-demo grid-demo-bg2" style="text-align: center">
                    <form class="layui-form">
                        <div class="layui-form-item">
                            <label class="layui-form-label">接收者</label>
                            <div class="layui-input-block">
                                <input type="text" id="receiver" lay-verify="title" autocomplete="off" class="layui-input">
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <label class="layui-form-label">发送者</label>
                            <div class="layui-input-block">
                                <input type="text" id="sender" autocomplete="off" class="layui-input">
                            </div>
                        </div>
    
                        <div class="layui-form-item layui-form-text">
                            <label class="layui-form-label">消息</label>
                            <div class="layui-input-block">
                                <textarea placeholder="请输入内容" class="layui-textarea" id="msg"></textarea>
                            </div>
                        </div>
                        <div class="layui-col-md12" style="margin-left: 4%">
                            <div class="layui-tab layui-tab-card" style="height: 200px;overflow: auto">
                                <fieldset class="layui-elem-field layui-field-title">
                                    <legend>消息记录</legend>
                                </fieldset>
                                <div id="msgDiv">
    
                                </div>
                            </div>
                        </div>
    
                        <div class="layui-form-item">
                            <div class="layui-input-block">
                                <button type="button" class="layui-btn layui-btn-primary" onclick="establishConnection()">
                                    建立连接
                                </button>
                                <button type="button" class="layui-btn layui-btn-primary" onclick="sendMessage()">发送消息
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
    <script type="text/javascript" th:src="@{/javascript/jquery-2.1.4.js}"></script>
    <!--layui-->
    <script type="text/javascript" th:src="@{/plugins/layui/layui.js}"></script>
    

    JavaScript代码

    var socket;
        if (typeof(WebSocket) == "undefined") {
            console.log("您的浏览器不支持WebSocket");
        } else {
    
            /***建立连接*/
            function establishConnection() {
                var userName = $("#sender").val();
                if (userName == '' || userName == null) {
                    alert("请输入发送者");
                    return;
                }
                //实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接
                var socketUrl = "" + window.location.protocol + "//" + window.location.host + "/chat/" + userName;
                socketUrl = socketUrl.replace("https", "ws").replace("http", "ws");
                if (socket != null) {
                    socket.close();
                    socket = null;
                }
                socket = new WebSocket(socketUrl);
                //打开事件
                socket.onopen = function () {
                    console.log("开始建立链接....")
                };
                //关闭事件
                socket.onclose = function () {
                    console.log("websocket已关闭");
                };
                //发生了错误事件
                socket.onerror = function () {
                    console.log("websocket发生了错误");
                };
                /**
                 * 接收消息
                 * @param msg
                 */
                socket.onmessage = function (msg) {
                    msg = JSON.parse(msg.data);
                    if (msg.msg != '连接成功') {
                        $("#msgDiv").append('<p class="user">用户名:' + msg.sender + '</p><p class="chat">' + msg.msg + '</p>');
                    }
                };
            }
    
            /**
             * 发送消息
             */
            function sendMessage() {
                var msg = $("#msg").val();
                if (msg == '' || msg == null) {
                    alert("消息内容不能为空");
                    return;
                }
                var receiver = $("#receiver").val();
                if (receiver == '' || receiver == null) {
                    alert("接收人不能为空");
                    return;
                }
                var msgObj = {
                    receiver: receiver,
                    msg: msg
                };
                socket.send(JSON.stringify(msgObj));
            }
        }
    

    相关文章

      网友评论

        本文标题:SpringBoot+WebSocket聊天

        本文链接:https://www.haomeiwen.com/subject/aqilnhtx.html