1. 程式人生 > 實用技巧 >springboot 整合websocket實現訊息推送(nginx、vue)

springboot 整合websocket實現訊息推送(nginx、vue)

最近需要一個動態圖表的功能,如下圖。

這種實現需要實時推送資料上來,那一般有兩種方法

方法一:前端寫個定時器,不斷輪詢後臺即可。這當然是很low的,請求太多很不友好,果斷拋棄

方法二:使用websocket,廢話不多說直接上程式碼

springboot 整合websocket有兩種方法,這裡先記錄原始方法:

新增webSocket外掛

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

WebSocketConfig配置

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
//注意註解
@EnableWebSocket
@Configuration
public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }

然後寫個webSocket工具類

import org.springframework.stereotype.Controller;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArraySet; //注意是controller註解 @Controller @ServerEndpoint("/websocket/{tableId}") public class WebSocket { private Session session; public static CopyOnWriteArraySet<WebSocket> webSockets =new CopyOnWriteArraySet<>(); private static Map<String,Session> sessionPool = new HashMap<String,Session>(); @OnOpen public void onOpen(Session session, @PathParam(value="tableId")String code) { this.session = session; webSockets.add(this); sessionPool.put(code, session); // Constants.WEBSOCKET = true;//定義常量 是否開啟websocket連線 System.out.println("【websocket訊息】有新的連線,總數為:"+webSockets.size()); } @OnClose public void onClose() { webSockets.remove(this); //Constants.WEBSOCKET = false; System.out.println("【websocket訊息】連線斷開,總數為:"+webSockets.size()); } @OnMessage public void onMessage(String message) { System.out.println("【websocket訊息】收到客戶端訊息:"+message); } // 此為廣播訊息 public void sendAllMessage(String message) { for(WebSocket webSocket : webSockets) { System.out.println("【websocket訊息】廣播訊息:"+message); try { webSocket.session.getAsyncRemote().sendText(message); } catch (Exception e) { e.printStackTrace(); } } } // 此為單點訊息 public void sendOneMessage(String code, String message) { Session session = sessionPool.get(code); System.out.println(code); /*在傳送資料之前先確認 session是否已經開啟 使用session.isOpen() 為true 則傳送訊息 * 不然會報錯:The WebSocket session [0] has been closed and no method (apart from close()) may be called on a closed session */ if (session != null && session.isOpen()) { try { session.getAsyncRemote().sendText(message); } catch (Exception e) { e.printStackTrace(); } } } }

簡單的已經可以使用的,注意如果後臺有用shiro許可權框架的注意要開放介面

測試

下面介紹一種線上測試工具 http://ws.douqq.com/

如果專案是前後端分離的,需要nginx進行請求轉發的需要在nginx的配置檔案裡新增如下配置:紅色字型部分

主要是把websocket的請求和http請求區分開

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;
    
     map $http_upgrade $connection_upgrade { 
         default upgrade;
         '' close;
        }

    server {
        listen       888;
        server_name  localhost;

    location ~/websocket/ {
        proxy_pass http://127.0.0.1:8089;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For     
        $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
       }
           
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}    

這個時候介面換成nginx監聽介面即可:

待這些測試完之後在頁面new一個websocket即可,我這裡用的vue



created(){
this.initWebSocket();
},


destroyed(){
this.websocketclose();
},



initWebSocket: function () {
      //debugger;
      // WebSocket與普通的請求所用協議有所不同,ws等同於http,wss等同於https   key你自定義的key
      //var host = window.location.host
      this.websock = new WebSocket("ws://47.106.172.176:888/websocket/123");
      this.websock.onopen = this.websocketonopen;
      this.websock.onerror = this.websocketonerror;
      this.websock.onmessage = this.websocketonmessage;
      this.websock.onclose = this.websocketclose;
      console.log(this.websock);
      //this.websock.send("您好啊");
    },
    websocketonopen: function () {
    },
    websocketonerror: function (e) {
    },
    websocketonmessage: function (e) {//JSON.parse(e.data); //這個是收到後端主動推送的值
    },
    websocketclose: function (e) {
    },

如果想要後端不斷推送資料上來,可以寫個定時任務:

@Component
public class ScheduledTask {
   
    @Autowired
    private WebSocket webSocket;
    //新增定時任務
    //@Scheduled(cron = "0/5 * * * * ?")
    @Scheduled(fixedRate=2000)
    public void sendMessage() {
        System.out.println("定時傳送資料");
        //webSocket.sendAllMessage(JSON.toJSONString("str"));
    //呼叫websocket推送訊息
webSocket.sendOneMessage("1","str"); } }