1. 程式人生 > >SpringBoot學習-(十二)SpringBoot中建立WebSocket連線

SpringBoot學習-(十二)SpringBoot中建立WebSocket連線

WebSocket握手圖解:

這裡寫圖片描述

建立連線的步驟:

  • pom檔案中新增依賴
  • 建立握手攔截器
  • 建立WebSocket處理類
  • 配置WebSocket
  • 前端頁面訪問

專案目錄結構:
這裡寫圖片描述

1.pom檔案中新增依賴

<!-- springboot websocket -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency
>

2.建立握手攔截器

用於進行握手之前和握手之後的操作
一般用於握手之前將使用者資訊交給WebSocketSession管理
之後可以在WebSocket處理類中獲取使用者資訊

package com.ahut.websocket;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import
org.springframework.http.server.ServletServerHttpRequest; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.HandshakeInterceptor; /** * * @ClassName: MyWebSocketInterceptor * @Description: 建立握手 此類用來獲取登入使用者資訊並交由websocket管理 * @author cheng * @date
2017年9月26日 上午10:31:30 */
/** * HandshakeInterceptor WebSocket握手請求的攔截器. 檢查握手請求和響應, 對WebSocketHandler傳遞屬性 */ public class MyWebSocketInterceptor implements HandshakeInterceptor { private Logger logger = LoggerFactory.getLogger(this.getClass()); /** * 在握手之前執行該方法, 繼續握手返回true, 中斷握手返回false. 通過attributes引數設定WebSocketSession的屬性 */ @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { logger.info("xxx使用者建立連線。。。"); if (request instanceof ServletServerHttpRequest) { String userId = ((ServletServerHttpRequest) request).getServletRequest().getParameter("userId"); attributes.put("userId", userId); logger.info("使用者唯一標識:" + userId); } return true; } /** * 在握手之後執行該方法. 無論是否握手成功都指明瞭響應狀態碼和相應頭. */ @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { } }

3.建立WebSocket處理類

處理類的層級關係:
這裡寫圖片描述

package com.ahut.websocket;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

/**
 * 
 * @ClassName: WebSocketPushHandler
 * @Description: 建立處理器
 * @author cheng
 * @date 2017年9月26日 上午10:36:17
 */
public class WebSocketPushHandler extends TextWebSocketHandler {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private static final List<WebSocketSession> userList = new ArrayList<>();

    /**
     * 使用者進入系統監聽
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        logger.info("xxx使用者進入系統。。。");
        logger.info("使用者資訊:" + session.getAttributes());
        Map<String, Object> map = session.getAttributes();
        for (String key : map.keySet()) {
            logger.info("key:" + key + " and value:" + map.get(key));
        }
        userList.add(session);
    }

    /**
     * 處理使用者請求
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        logger.info("系統處理xxx使用者的請求資訊。。。");
    }

    /**
     * 使用者退出後的處理
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        if (session.isOpen()) {
            session.close();
        }
        userList.remove(session);
        logger.info("xxx使用者退出系統。。。");
    }

    /**
     * 自定義函式 
     * 給所有的線上使用者傳送訊息
     */
    public void sendMessagesToUsers(TextMessage message) {
        for (WebSocketSession user : userList) {
            try {
                // isOpen()線上就傳送
                if (user.isOpen()) {
                    user.sendMessage(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
                logger.error(e.getLocalizedMessage());
            }
        }
    }

    /**
     * 自定義函式 
     * 傳送訊息給指定的線上使用者
     */
    public void sendMessageToUser(String userId, TextMessage message) {
        for (WebSocketSession user : userList) {
            if (user.getAttributes().get("userId").equals(userId)) {
                try {
                    // isOpen()線上就傳送
                    if (user.isOpen()) {
                        user.sendMessage(message);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    logger.error(e.getLocalizedMessage());
                }
            }
        }
    }

}

4.配置WebSocket

package com.ahut.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.HandshakeInterceptor;

import com.ahut.websocket.MyWebSocketInterceptor;
import com.ahut.websocket.WebSocketPushHandler;

/**
 * 
 * @ClassName: WebSocketConfig
 * @Description: websocket配置類
 * @author cheng
 * @date 2017年9月26日 上午10:45:45
 */
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    /**
     * 註冊WebSocket處理類
     */
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(createWebSocketPushHandler(), "/webSocketServer")
                .addInterceptors(createHhandshakeInterceptor()).setAllowedOrigins("*");
        registry.addHandler(createWebSocketPushHandler(), "/sockjs/webSocketServer")
                .addInterceptors(createHhandshakeInterceptor()).withSockJS();
    }

    /**
     * 
     * @Title: createHhandshakeInterceptor
     * @Description: 握手攔截器
     * @return
     */
    @Bean
    public HandshakeInterceptor createHhandshakeInterceptor() {
        return new MyWebSocketInterceptor();
    }

    /**
     * 
     * @Title: createWebSocketPushHandler
     * @Description: 處理類
     * @return
     */
    @Bean
    public WebSocketHandler createWebSocketPushHandler() {
        return new WebSocketPushHandler();
    }

}

5.前端頁面訪問

<!DOCTYPE html>
<html>
<head>
<title>Java後端WebSocket的Tomcat實現</title>
</head>
 <body>
      Welcome<br/><input id="text" type="text"/>
      <button onclick="send()">傳送訊息</button>
     <hr/>
     <button onclick="closeWebSocket()">關閉WebSocket連線</button>
     <hr/>
     <div id="message"></div>
 </body>

 <script type="text/javascript">
     var websocket = null;
     //判斷當前瀏覽器是否支援WebSocket
    if ('WebSocket' in window) {
        websocket = new WebSocket("ws://localhost:8080/webSocketServer?userId=wrwefesdfwetrwe324324");
    }
     else {
         alert('當前瀏覽器 Not support websocket')
     }

     //連線發生錯誤的回撥方法
     websocket.onerror = function () {
         setMessageInnerHTML("WebSocket連線發生錯誤");
     };

     //連線成功建立的回撥方法
     websocket.onopen = function () {
         setMessageInnerHTML("WebSocket連線成功");
     }

     //接收到訊息的回撥方法
     websocket.onmessage = function (event) {
         setMessageInnerHTML(event.data);
     }

     //連線關閉的回撥方法
     websocket.onclose = function () {
         setMessageInnerHTML("WebSocket連線關閉");
     }

     //監聽視窗關閉事件,當視窗關閉時,主動去關閉websocket連線,防止連線還沒斷開就關閉視窗,server端會拋異常。
     window.onbeforeunload = function () {
         closeWebSocket();
     }

     //將訊息顯示在網頁上
     function setMessageInnerHTML(innerHTML) {
         document.getElementById('message').innerHTML += innerHTML + '<br/>';
     }

     //關閉WebSocket連線
     function closeWebSocket() {
         websocket.close();
     }

     //傳送訊息
     function send() {
         var message = document.getElementById('text').value;
         websocket.send(message);
     }
 </script>
 </html>

開啟頁面後臺日誌列印結果:

這裡寫圖片描述