簡單的websocket demo

aliyeye發表於2021-01-16

使用websocket有兩種方式:1是使用sockjs,2是使用h5的標準。使用Html5標準自然更方便簡單,所以記錄的是配合h5的使用方法。

  1. pom

    <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
  2. 使用@ServerEndpoint創立websocket endpoint
      首先要注入ServerEndpointExporter,這個bean會自動註冊使用了@ServerEndpoint註解宣告的Websocket endpoint。要注意,如果使用獨立的servlet容器,而不是直接使用springboot的內建容器,就不要注入ServerEndpointExporter,因為它將由容器自己提供和管理。

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

    接下來就是寫websocket的具體實現類,直接上程式碼:

    @Component
    @ServerEndpoint("/websocket")
    public class MyWebSocket {
     //與某個客戶端的連線會話,需要透過它來給客戶端傳送資料
     private Session session;
     //concurrent包的執行緒安全Set,用來存放每個客戶端對應的MyWebSocket物件。
     private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();
    
     @OnOpen
     public void onOpen(Session session){
         this.session = session;
         webSocketSet.add(this);
         System.out.println("建立連線:第"+webSocketSet.size());
     }
    
     @OnClose
     public void onClose(){
         webSocketSet.remove(this);
         System.out.println("關閉連線");
     }
    
     @OnMessage
     public void onMessage(String message){
         System.out.println("接受客戶端訊息:"+message);
     }
    
     /**
      * 群發訊息
      */
     public void sendMessage(String message){
         for (MyWebSocket myWebSocket : webSocketSet){
             try {
                 myWebSocket.session.getBasicRemote().sendText(message);
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
     }
     //單發訊息可以在群發的基礎上改造
    }

    使用springboot的唯一區別是要@Component宣告下,而使用獨立容器是由容器自己管理websocket的,但在springboot中連容器都是spring管理的。
    雖然@Component預設是單例模式的,但springboot還是會為每個websocket連線初始化一個bean,所以可以用一個靜態set儲存起來。

  3. 前端程式碼

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
     <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;" name="viewport" />
     <meta http-equiv="X-UA-Compatible" content="ie=edge">
     <title>主頁</title>
    </head>
    <body>
    <script type="text/javascript" th:inline="javascript">
     var websocket = null;
     if('WebSocket' in window){
         //127.0.0.1:8080 是的專案請求地址 websocket是對應@ServerEndpoint("/websocket")裡的值 合起來就是請求websocket地址
         websocket = new WebSocket('ws://127.0.0.1:8080/websocket');
     }else{
         alert("該瀏覽器不支援websocket!")
     }
     websocket.onopen = function (event) {
         console.log("建立連線");
     }
     websocket.onclose = function (event) {
         console.log("關閉連線");
     }
     websocket.onmessage = function (event) {
         console.log("接受訊息:"+event.data);
         //模擬傳送資訊給服務端
         websocket.send("我已經接受到資訊啦!")
     }
     websocket.onerror = function (event) {
         console.log("出現了錯誤")
     }
     window.onbeforeunload = function () {
         websocket.onclose();
     }
    </script>
    </body>
    </html>
  4. 測試方法

    @RestController
    @RequestMapping("/testWebSocketSend")
    public class TestWebSocketSendController {
     @Autowired
     private MyWebSocket myWebSocket;
     @GetMapping("send")
     public String send(@RequestParam("message") String message){
         //todo 其他業務
         //websocket服務
         myWebSocket.sendMessage(message);
         return "成功";
     }
    }

    開啟主頁面 127.0.0.1:8080/index.html
    建立連線
    瀏覽器請求127.0.0.1:8080/testWebSocketSend/se... 我之前寫的controller地址
    接受服務端發來的訊息
    服務端接受客戶端的訊息列印
    服務端接受客戶端的訊息

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章