springboot搭建一個簡單的websocket的實時推送應用


 

說一下實用springboot搭建一個簡單的websocket 的實時推送應用

websocket是什么

WebSocket是一種在單個TCP連接上進行全雙工通信的協議

我們以前用的http協議只能單向的瀏覽器給服務器發請求,然后服務器再去相應返回數據。

websocket呢就是可以服務器主動給瀏覽器發數據

優點

較少的控制開銷

更強的實時性

保持連接狀態

更好的二進制的支持

支持擴展

更換的壓縮效果

pom文件

springboot項目的話只需要下面這個依賴就可以了

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

springboot的項目搭建

這里看我上一篇文章就不在多說了

我們需要去注入ServerEndpointExporter

這是一個檢測類型的bean 檢測帶注釋@ServerEndpoint的bean並注冊它們

稍后我們可以講一下@configuration @bean 和@component @autowired 等注解

  package com.gzh; ​ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; ​ /** * @Configuration * @bean * 表示給spring容器注入bean 他們兩個一般一起使用 * 他們和@component的區別是他們使用了動態代理cglib 所以每次調用都會返回同一個實例 */ @Configuration public class WebSocketConfig { ​ /** * 給spring容器注入這個ServerEndpointExporter對象 * 相當於xml: * <beans> * <bean id="serverEndpointExporter" class="org.springframework.web.socket.server.standard.ServerEndpointExporter"/> * </beans> * * 檢測所有帶有@serverEndpoint注解的bean並注冊他們。 * @return
       */ @Bean public ServerEndpointExporter serverEndpointExporter(){ System.out.println("我被注入了"); return  new ServerEndpointExporter(); } }

下面使我們的websocket類

下面一共寫了五種方法

建立通信

關閉通信

接收消息

發送消息

異常


  package com.gzh; ​ import org.springframework.stereotype.Component; ​ import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet; ​ /** * @Component 將類注入到容器 * @ServerEndpoint 前端通過這個url進行訪問通信 建立連接 */ @ServerEndpoint("/websocket") @Component public class MyWebSocket { ​ //存放websocket 的線程安全的無序的集合
      private  static  CopyOnWriteArraySet<MyWebSocket> websocket = new CopyOnWriteArraySet<MyWebSocket>(); ​ private Session session; ​ public static CopyOnWriteArraySet<MyWebSocket> getWebsocket() { return websocket; } ​ public static void setWebsocket(CopyOnWriteArraySet<MyWebSocket> websocket) { MyWebSocket.websocket = websocket; } ​ public Session getSession() { return session; } ​ public void setSession(Session session) { this.session = session; } ​ /** * 連接建立成功調用的方法 * */ @OnOpen public void onOpen(Session session) { this.session = session; websocket.add(this);     //加入set中 // addOnlineCount(); //在線數加1
           System.out.println("進入onOpen方法"); try { sendMessage("連接已建立成功."); } catch (Exception e) { System.out.println("IO異常"); } } ​ ​ /** * 關閉通信連接 * @param session */ @OnClose public void onClose(Session session){ //關閉連接后將此socket刪除
          websocket.remove(this); System.out.println("進入onClose方法"); } ​ /** * 獲取客戶端發來的信息 */ @OnMessage public void onMessage(String message){ System.out.println("進入onMessage方法; message = " + message); } ​ /** * 給客戶端推送信息 */
      public void sendMessage(String message) throws IOException { System.out.println("進入sendMessage方法"); this.session.getBasicRemote().sendText(message); } ​ /** * 異常方法 */ @OnError public void onError(Session session, Throwable error){ System.out.println("進入error方法"); error.printStackTrace(); } ​ } ​

 

 

這里呢我們稍微分析下這個方法里面的東西

  • 注解@ServerEndpoint

  package javax.websocket.server; ​ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.websocket.Decoder; import javax.websocket.Encoder; import javax.websocket.server.ServerEndpointConfig.Configurator; ​ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface ServerEndpoint { //注釋類應映射到的URI或URI模板(必寫的參數)。
 String value(); //子協議
      String[] subprotocols() default {}; ​ //解碼器 輸入websocket消息 輸出java對象
      Class<? extends Decoder>[] decoders() default {}; ​ //編碼器 輸入java對象 輸出websocket
      Class<? extends Encoder>[] encoders() default {}; ​ //配置器
      Class<? extends Configurator> configurator() default Configurator.class; } ​
  • CopyOnWriteArraySet(看完就知道我們為什么要用它了)

    • java.util.concurrent包下 俗稱 JUC

    • 線程安全的無序的集合,可以將它理解成線程安全的HashSet

    • Set:不可重復,檢索元素效率低下,刪除和插入效率高,

    • List:可重復,和數組類似,List可以動態增長,查找元素效率高,插入刪除元素效率低

  • @onopen @onclose等注解

    • 和前台websocket.onerror等方法相對應

我們的主方法執行服務

這里我們每三秒啟動個線程

package com.gzh; ​ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; ​ /** * @SpringBootApplication 標注一個主程序,說明這是一個springboot應用 */ @SpringBootApplication public class SpringBootMainApplication { ​ //編寫主程序方法
      public static void main(String[] args) { SpringApplication.run(SpringBootMainApplication.class); ​ for (int i = 0; i <= 10 ; i++){ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } MyThread myThread = new MyThread(); Thread thread = new Thread(myThread); thread.start(); } ​ } } ​

 

線程類

在線程的run方法里讓他去發送消息

 
  package com.gzh; ​ import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet; ​ public class MyThread implements Runnable{ ​ @Override public void run() { ​ CopyOnWriteArraySet<MyWebSocket> websocket = MyWebSocket.getWebsocket(); for (MyWebSocket myWebSocket : websocket) { try { myWebSocket.sendMessage("我要發消息了"+ Math.random()); } catch (IOException e) { e.printStackTrace(); } } } } ​

 

html前端

這里我們只需要更改我們的地址路徑就即可

<!DOCTYPE HTML>
  <html>
  <head>
      <title>My WebSocket</title>
  </head>
<body> Welcome<br/>
  <input id="text" type="text" /><button onclick="send()">Send</button>    <button onclick="closeWebSocket()">Close</button>
  <div id="message">
  </div>
  </body>
<script type="text/javascript">
      var websocket = null; ​ //判斷當前瀏覽器是否支持WebSocket ,主要此處要更換為自己的地址
      if('WebSocket' in window){ websocket = new WebSocket("ws://localhost:8080/websocket"); } else{ alert('Not support websocket') } ​ //連接發生錯誤的回調方法
      websocket.onerror = function(){ setMessageInnerHTML("error"); }; ​ //連接成功建立的回調方法
      websocket.onopen = function(event){ setMessageInnerHTML("open"); } ​ //接收到消息的回調方法
      websocket.onmessage = function(event){ setMessageInnerHTML(event.data); } ​ //連接關閉的回調方法
      websocket.onclose = function(){ setMessageInnerHTML("close"); } ​ //監聽窗口關閉事件,當窗口關閉時,主動去關閉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; websocket.send(message); } </script>
  </html>

 

這里說一下我們的路徑 ws 我們一般會看到wss 什么時候用哪個呢?

1.Firefox環境下https不能使用ws連接

2.chrome內核版本號低於50的瀏覽器是不允許https下使用ws鏈接

3.Firefox環境下https下使用wss鏈接需要安裝證書

所以我們可以對這部分瀏覽器做個處理

 let protocol = location.protocol === 'https' 
      ? 'wss://localhost:8888' : 'ws://localhost:8889'; new WebSocket(protocol);
以上就是springboot下實現簡單的websocket的應用

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM