1. 程式人生 > >SSM+WebSocket實現一個簡易網頁版通訊工具

SSM+WebSocket實現一個簡易網頁版通訊工具

編譯環境:jdk1.8 , tomcat8.0+ , IDEA

這裡主要講一下websocket的資訊傳遞,以如何實現多人實時線上聊天為例:

websocket主要的三個類

MyWebSocketConfig主要負責配置websocket的處理器和握手攔截器

MyHandShakeInterceptor 是websocket的攔截器

MyWebSocketHander是websocket的處理器

@Component
@EnableWebSocket
public class MyWebSocketConfig implements WebSocketConfigurer {

    @Autowired
    private MyWebSocketHander myWebSocketHander;

    private static final String LINK_URI = "websocket.do";
    //新增websocket處理器,新增握手攔截器  攔截器先執行 然後到處理器
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
        webSocketHandlerRegistry.addHandler(myWebSocketHander,LINK_URI).addInterceptors(new MyHandShakeInterceptor());
    }
}
/*   private static Map<WebSocketSession,String> map = new HashMap<WebSocketSession, String>();
 * websocket握手攔截器
 * 攔截握手前,握手後的兩個切面
 */
@Component
public class MyHandShakeInterceptor implements HandshakeInterceptor {


    @Override
    public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
        if(serverHttpRequest instanceof ServletServerHttpRequest){
            HttpServletRequest servletRequest = ((ServletServerHttpRequest)serverHttpRequest).getServletRequest();
            User user = (User)servletRequest.getSession().getAttribute("user");
            //這裡給map賦值 相當於websockethandler的afterConnectionEstablished方法裡的WebSocketSession
            //key是session,value是變數
            map.put("ws_user", user);
          
        }
        return true;
    }

    @Override
    public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {
      
    }
}

實時通訊的具體流程:

前端

<% String path = request.getContextPath();%>
<html>
link rel="stylesheet" href="<%=path%>/static/css/bootstrap.min.css"
      type="text/css">
<script src="<%=path%>/static/js/jquery.min.js"></script>
<script src="<%=path%>/static/js/bootstrap.min.js"
        type="text/javascript"></script>
<body>

<div id="container" style="width:500px">

    <div id="header">
        <h1 id="title">chat-room</h1></div>
    <div class="middle">
        <div id="menu">
            <p id="tou">歡迎來到聊天室</p>
        </div>

        <div class="chatter" id="chatter">
            <p id="msg"></p>
        </div>
    </div>
    <div id="content">
        <textarea class="form-control" rows="3" placeholder="我想說....."
                  id="msgContent">
        </textarea>
    </div>

    <div style="background-color: #F8F8F8;">
        <div id="buttons">
            <button id="butSent" type="button" class="btn btn-default"
                    onclick="getConnection()">連線
            </button>
            <button type="button" class="btn btn-default"
                    onclick="sendMsgClose()">斷開
            </button>
            <button type="button" class="btn btn-default" onclick="sendMsg()">
                傳送
            </button>
        </div>
    </div>

    <div id="footer">
        Designed by Annie
    </div>
</div>
</body>
<script>
//開啟連結
    function getConnection() {
        if (websocket == null) {
            websocket = new WebSocket(wsServer);
            websocket.onopen = function (evnt) {
                alert("連結伺服器成功!");
            };
            //從後臺接受資料的函式
            websocket.onmessage = function (evnt) {
                var onlineUser = $("#onlineUser");
                //將收到的資料轉換成物件
                var message = eval("(" + evnt.data + ")");
                //顯示線上人數及線上使用者
                if (message.msgTyp === "notice") {
                    var htmlOnline;
                    $("#onlineNum").text(message.onlineNum);
                    htmlOnline = "<p> " + message.userName + " </p>";
                    //實時更新線上使用者
                    onlineUser.html("");
                    $(onlineUser).append(htmlOnline);
                } else if (message.msgTyp === "msg") {
                    showChat(evnt);
                }
            };
            websocket.onerror = function (evnt) {
                alert("發生錯誤,與伺服器斷開了連結!")
            };
            websocket.onclose = function (evnt) {
                alert("與伺服器斷開了連結!")
            };
        } else {
            alert("連線已存在!")
        }
    }


    function showChat(evnt) {
        var message = eval("(" + evnt.data + ")");
        var msg = $("#msg");
        //msg.html是之前的聊天內容,空一行
        msg.html(msg.html() + "<br/>" + "使用者: " + message.user + " 傳送時間:" +             message.sendDate + "<br/>" + message.sendContent);
    }


  function sendMsg() {
        var msg = $("#msgContent");
        if (websocket == null) {
            alert("連線未開啟!");
            return;
        }
        var message = msg.val();
        //輸入完成後,清空輸入區
        msg.val("");
        if (message == null || message === "") {
            alert("輸入不能為空的哦");
            return;
        }
        //向後臺MyWebSocketHandler中的handerMessage傳送資訊
        //這裡將資訊轉成JSON格式傳送
        websocket.send(JSON.stringify({
            message: message,
            type: "chatMsg"
        }));
    }

    /**
     * 關閉連線
     */
    function closeConnection() {
        if (websocket != null) {
            websocket.close();
            websocket = null;
            alert("已經關閉連線")
        } else {
            alert("未開啟連線")
        }
    }
</script>

</html>

後臺MyWebSocketHander接受資料


@Component
public class MyWebSocketHander implements WebSocketHandler {
   
    private final static List<WebSocketSession> USERS = new ArrayList<>();
    private final static List<User> USER_ONLINE = new ArrayList<>();

    /*
    *在連結建立完後就在前端顯示線上使用者
    */
    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
       USERS.add(webSocketSession);
        //每次有新的連線,就加入到user集合中
        User user = (User) webSocketSession.getAttributes().get("ws_user");
        USER_ONLINE.add(user);

        List<String> userNamelist = new ArrayList<>();
        for (User u : USER_ONLINE) {
            String userName = u.getUserName();
            userNamelist.add(userName);
        }

        //String類的format()方法用於建立格式化的字串以及連線多個字串物件。
        //這裡傳到前端的應該是JSON格式
        String messageFormat = "{onlineNum:\"%d\",userName:\"%s\" , msgTyp " +
                ":\"%s\"}";
        String msg = String.format(messageFormat, USERS.size(), userNamelist,
                "notice");

        TextMessage testMsg = new TextMessage(msg + "");
        //確保每個使用者資訊都能同步到
        for (WebSocketSession wss : USERS) {
            wss.sendMessage(testMsg);
        }
    }

    /**
     * 客戶端傳送伺服器的訊息時的處理函式,在這裡收到訊息之後可以分發訊息
     */
    @Autowired
    private ChatService chatService;

    @Override
    public void handleMessage(WebSocketSession webSocketSession,
                              WebSocketMessage<?> webSocketMessage) throws Exception {

        String messageFormat = null;

        //傳送訊息的時間
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        String sentMsgDate = dateFormat.format(new Date());

        User user = (User) webSocketSession.getAttributes().get("ws_user");

        String msgContent = webSocketMessage.getPayload() + "";

        JSONObject chat = JSON.parseObject(msgContent);
        //訊息的內容
        String msgJSON = chat.get("message").toString();
        //訊息的樣式
        String msgJSONType = chat.get("type").toString();

        String chatMsg = "chatMsg";
 
        if (msgJSONType.equals(chatMsg)) {
            //將訊息儲存到資料庫
            ChatMsg chatMessage = new ChatMsg(user.getId(), sentMsgDate,
                    msgJSON);
            chatService.addMessage(chatMessage);

            messageFormat = "{user:\"%s\",sendDate:\"%s\" ," +
                    "sendContent:\"%s\" , msgTyp :\"%s\"}";
            String message = String.format(messageFormat, user.getUserName(),
                    sentMsgDate, msgJSON , "msg");
            TextMessage toMsg = new TextMessage(message + "");
            //遍歷所有的使用者,發信息,這個要注意哦,要不然不能做到多人同時聊天
            for (WebSocketSession wss : USERS) {
                wss.sendMessage(toMsg);
            }
        }
    }


    @Override
    public void handleTransportError(WebSocketSession webSocketSession,
                                     Throwable throwable) throws Exception {
        USERS.remove(webSocketSession);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession,
                                      CloseStatus closeStatus) throws Exception {
        User userRemove = (User) webSocketSession.getAttributes().get(
                "ws_user");
        USER_ONLINE.remove(userRemove);
        USERS.remove(webSocketSession);
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

}

所以websocket訊息傳送流程大致是

websocket.onopen開啟連結 --> websocket.send()傳送資料 -->後臺的MyWebSocketHander接收資料-->WebSocketSession.sendMessage將訊息傳送給前端 --> 前端websocket.onmessage()接收資料並顯示。

github地址:https://github.com/androidlearner2017/simple-chatroom.git

很簡單的一個demon,裡面有些功能還沒有完全實現,繼續修改中 ing