zeromemos
最好的学习方法就是输出所学的知识

SpringBoot+WebSocket实现简单在线聊天功能--私信

接着http://www.zeromemos.com/index/article/read.html?id=354

在entity包下创建消息对象socketMsg

package com.zeromemos.entity;

import lombok.Data;

@Data
public class SocketMsg {
    private int type;        //聊天类型0:群聊,1:单聊
    private String fromUser; //发送者
    private String toUser;   //接受者
    private String msg;      //消息
}

调整建立连接的方法(MyWebSocket)

使用一个map对象保存频道号和session之前的关系,这边直接使用链接者的昵称作为key

    //用来记录nickname和该session进行绑定
    private static Map<String,Session> map = new HashMap<String, Session>();

修改连接的方法onOpen(MyWebSocket)

    @OnOpen
    public void onOpen(Session session, @PathParam("nickname") String nickname) {

        this.session = session;
        this.nickname=nickname;
        webSocketSet.add(this); //加入set中
        map.put(nickname, session); //加入map中
        System.out.println("有新连接加入:"+nickname+"!当前在线人数为" + webSocketSet.size());
        this.session.getAsyncRemote().sendText("恭喜" + nickname + "成功连接上WebSocket频道号:" + nickname + "当前在线人数为:"+webSocketSet.size());

    }

修改关闭连接的方法onClose(MyWebSocket),要从map中移除

    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //从set中删除
        map.remove(this.nickname); //从map中删除
        System.out.println("有一连接关闭!当前在线人数为" + webSocketSet.size());
    }

修改消息发送的方法 onMessage(MyWebSocket)

    @OnMessage
    public void onMessage(String message, Session session, @PathParam("nickname") String nickname) {
        System.out.println("来自客户端的消息:" + message);
        ObjectMapper objectMapper = new ObjectMapper();
        SocketMsg socketMsg;

        try {
            //JSON转对象
            socketMsg = objectMapper.readValue(message, SocketMsg.class);

            if (socketMsg.getType() == 1){
                //单聊 需要找到发送者和接受者
                socketMsg.setFromUser(nickname); //发送者
                Session fromSession = map.get(socketMsg.getFromUser()); //map里找发送者
                Session toSession = map.get(socketMsg.getToUser()); //map里找接收者

                if(toSession != null){
                    //发送给发送者
                    fromSession.getAsyncRemote().sendText(nickname+":"+socketMsg.getMsg());
                    //发送给接收者
                    toSession.getAsyncRemote().sendText(nickname+":"+socketMsg.getMsg());
                } else {
                    //发送给发送者
                    fromSession.getAsyncRemote().sendText("系统消息:对方不在线或者您输入的频道号不对");
                }
            } else {
                //否则群发消息
                broadcast(nickname+": "+socketMsg.getMsg());
            }
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        //群发消息
        //broadcast(message);
    }

客户端网页调整

消息:<input id="text" type="text" />
频道号:<input id="toUser" type="text" />
<button onclick="send()">发送消息</button>
    //发送消息
    function send() {
        //获取输入的文本信息进行发送
        var message = document.getElementById('text').value;
        var toUser = document.getElementById('toUser').value;
        var socketMsg = {msg:message,toUser:toUser};
        if(toUser == ''){
            //群聊.
            socketMsg.type = 0;
        }else{
            //单聊.
            socketMsg.type = 1;
        }
        websocket.send(JSON.stringify(socketMsg));
    }

测试,连接三个客户端


群发成功

私信三号成功,二号不会收到消息

三号断开后私信会收到正确的提示


附上修改文件的完整代码

webSocketTest.html

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8">
    <title>My WebSocket</title>
</head>
<body>
昵称:<input type="text" id="nickname"/>
<button onclick="conectWebSocket()">连接WebSocket</button>
<button onclick="closeWebSocket()">断开连接</button>
<hr />
<br />
消息:<input id="text" type="text" />
频道号:<input id="toUser" type="text" />
<button onclick="send()">发送消息</button>
<div id="message"></div>
</body>
<script type="text/javascript">

    var websocket = null;
    function conectWebSocket(){
        var nickname = document.getElementById("nickname").value;
        if(nickname === ""){
            alert("请输入昵称");
            return;
        }
        //判断当前浏览器是否支持WebSocket
        if ('WebSocket'in window) {
            websocket = new WebSocket("ws://localhost:9001/websocket/"+nickname);
        } else {
            alert('Not support websocket')
        }
        //连接发生错误的回调方法
        websocket.onerror = function() {
            setMessageInnerHTML("error");
        };
        //连接成功建立的回调方法
        websocket.onopen = function(event) {
            setMessageInnerHTML("Loc MSG: 成功建立连接");
        }
        //接收到消息的回调方法
        websocket.onmessage = function(event) {
            setMessageInnerHTML(event.data);
        }
        //连接关闭的回调方法
        websocket.onclose = function() {
            setMessageInnerHTML("Loc MSG:关闭连接");
        }
        //监听窗口关闭事件,当窗口关闭时,主动去关闭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;
        var toUser = document.getElementById('toUser').value;
        var socketMsg = {msg:message,toUser:toUser};
        if(toUser == ''){
            //群聊.
            socketMsg.type = 0;
        }else{
            //单聊.
            socketMsg.type = 1;
        }
        websocket.send(JSON.stringify(socketMsg));
    }
</script>
<!--样式-->
<style>
    #message{
        margin-top:40px;
        border:1px solid gray;
        padding:20px;
    }
</style>
</html>

SocketMsg

package com.zeromemos.entity;

import lombok.Data;

@Data
public class SocketMsg {
    private int type;        //聊天类型0:群聊,1:单聊
    private String fromUser; //发送者
    private String toUser;   //接受者
    private String msg;      //消息
}

MyWebSocket

package com.zeromemos.component;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zeromemos.entity.SocketMsg;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

@ServerEndpoint(value = "/websocket/{nickname}")
@Component
public class MyWebSocket {
    //用来存放每个客户端对应的MyWebSocket对象。
    private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();
    //用来记录nickname和该session进行绑定
    private static Map<String,Session> map = new HashMap<String, Session>();
    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    private String nickname;
    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("nickname") String nickname) {

        this.session = session;
        this.nickname=nickname;
        webSocketSet.add(this); //加入set中
        map.put(nickname, session); //加入map中
        System.out.println("有新连接加入:"+nickname+"!当前在线人数为" + webSocketSet.size());
        this.session.getAsyncRemote().sendText("恭喜" + nickname + "成功连接上WebSocket频道号:" + nickname + "当前在线人数为:"+webSocketSet.size());

    }
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //从set中删除
        map.remove(this.nickname); //从map中删除
        System.out.println("有一连接关闭!当前在线人数为" + webSocketSet.size());
    }
    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("nickname") String nickname) {
        System.out.println("来自客户端的消息:" + message);
        ObjectMapper objectMapper = new ObjectMapper();
        SocketMsg socketMsg;

        try {
            //JSON转对象
            socketMsg = objectMapper.readValue(message, SocketMsg.class);

            if (socketMsg.getType() == 1){
                //单聊 需要找到发送者和接受者
                socketMsg.setFromUser(nickname); //发送者
                Session fromSession = map.get(socketMsg.getFromUser()); //map里找发送者
                Session toSession = map.get(socketMsg.getToUser()); //map里找接收者

                if(toSession != null){
                    //发送给发送者
                    fromSession.getAsyncRemote().sendText(nickname+":"+socketMsg.getMsg());
                    //发送给接收者
                    toSession.getAsyncRemote().sendText(nickname+":"+socketMsg.getMsg());
                } else {
                    //发送给发送者
                    fromSession.getAsyncRemote().sendText("系统消息:对方不在线或者您输入的频道号不对");
                }
            } else {
                //否则群发消息
                broadcast(nickname+": "+socketMsg.getMsg());
            }
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        //群发消息
        //broadcast(message);
    }
    /**
     * 发生错误时调用
     *
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("发生错误");
        error.printStackTrace();
    }
    /**
     * 群发自定义消息
     * */
    public  void broadcast(String message){
        for (MyWebSocket item : webSocketSet) {
            //同步异步说明参考:http://blog.csdn.net/who_is_xiaoming/article/details/53287691
            //this.session.getBasicRemote().sendText(message);
            item.session.getAsyncRemote().sendText("来自客户端的消息-->"+nickname+": " + message);//异步发送消息.
        }
    }
}
评论区

关于我们

本站主要用于记录个人学习笔记,网站开发中,如需以前站内资料请加QQ群272473835索取。注册账号仅提供回帖功能,可不注册!

微信公众号