websocket+springboot+vue+element ui完成數據表格的數據實時更新(指定秒數更新)

java部分:vue

import org.springframework.stereotype.Component;

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.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @description:TODO
 * @author:xing.Li
 * @date:2019/8/26 10:02
 */
@Component
@ServerEndpoint("/websocket/{code}")
//此註解至關於設置訪問URL
public class WebSocket {

    private Session session;

    private static CopyOnWriteArraySet<WebSocket> webSockets =new CopyOnWriteArraySet<>();
    private static Map<String,Session> sessionPool = new HashMap<String,Session>();

    @OnOpen
    public void onOpen(Session session, @PathParam(value="code")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);
        /*在發送數據以前先確認 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();
            }
        }
    }
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * @description:TODO
 * @author:xing.Li
 * @date:2019/8/25 17:44
 */
@Configuration
public class WebSocketConfig {//打包部署到tomcat中須要刪除此文件
    /**
     * 注入ServerEndpointExporter,
     * 這個bean會自動註冊使用了@ServerEndpoint註解聲明的Websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}
此處爲springboot自動執行代碼
@Scheduled(fixedRate = 5 * 1000)//多少秒執行一次
@Async//異步執行
public void computerTableOnline() {
    if (Constants.WEBSOCKET) {
        R r = computerListService.queryList(Constants.COMPUTER_GROUP);
        if ("0".equals(r.get("code").toString()) && r.get("ComputerList") != null) {
            List<ComputerList> computerList = (List<ComputerList>) r.get("ComputerList");
            String str = JSON.toJSONString(computerList); // List轉json
            webSocket.sendOneMessage("computer", str);//websocket推送數據
        }
    }
}

最終要的固然是jar包了java

<!--websocket-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
    <version>1.5.3.RELEASE</version>
    <type>pom</type>
</dependency>

js部分:web

data(){} 中spring

created() { // 頁面建立生命週期函數
    this.initWebSocket()
},
destroyed: function () { // 離開頁面生命週期函數
    this.websocketclose();
},

methods中json

initWebSocket: function () {
    // WebSocket與普通的請求所用協議有所不一樣,ws等同於http,wss等同於https   key你自定義的key
    var host = window.location.host;
    this.websock = new WebSocket("ws://" + host + "/websocket/key");
    this.websock.onopen = this.websocketonopen;
    this.websock.onerror = this.websocketonerror;
    this.websock.onmessage = this.websocketonmessage;
    this.websock.onclose = this.websocketclose;
},
websocketonopen: function () {
    console.log("WebSocket鏈接成功");
    console.log("WebSocket正在發送實時數據.......");
},
websocketonerror: function (e) {
    console.log("WebSocket鏈接發生錯誤");
},
websocketonmessage: function (e) {
       JSON.parse(e.data); //這個是收到後端主動推送的值
    }
},
websocketclose: function (e) {
    console.log("WebSocket鏈接斷開");
}

實現思路:經過websocket長鏈接從後端主動推送數據,利用vue的雙向綁定實現數據同步後端

注:由於數據的改變也會刷新表格上覆選框的選中狀態,本人思路爲,element ui中有選中複選框的值得集合,判斷複選框裏面有沒有值,有值的話就是在操做數據,這時中止websocket的鏈接,操做完成後,複選框值所在集合也就沒有值了,這時再開啓websocket鏈接,這樣也有問題,可是算是實現了吧。。。。緩存

在此記錄方便之後觀看tomcat

固然上面的部分代碼是忘記那位博主的了,時間過久找不到連接了,就不放原文連接了springboot

----------------------------------------------------------------------------------------------------------------------------------------------------------------websocket

更新:

最近打包發現了個問題,websocket放在tomcat中運行會報錯,具體緣由忘了。。好像是說在tomcat8以上會替代spring管理bean因此刪除WebSocketConfig這個配置bean的文件就能夠正常運行了

----------------------------------------------------------------------------------------------------------------------------------------------------------------

更新:

需求又變了,說是讓選中也能夠進行實時刷新,又網上找了下,發現大佬寫法:http://www.javashuo.com/article/p-risyvwhh-dn.html

其實element ui 官網就有寫法,仍是要多看看文檔-0.0-

官網是說

代碼爲

<!-- stripe--啓用馬紋線   border--啓用邊框  highlight-current-row--啓用單選 sortable--啓用排序-->
<el-table ref="multipleTable" :data="tables.slice((currentPage-1)*pagesize,currentPage*pagesize)"
          stripe border highlight-current-row tooltip-effect="dark"
          style="width: 100%;font-size: 13px"
          :cell-style="{padding:'0px'}"
          @row-click="rowClick"
          :row-style="rowStyle"
          :row-class-name="rowClassName"
          @selection-change="handleSelectionChange"
          :row-key="getRowKeys">
    <el-table-column sortable :reserve-selection="true" type="selection" width="55"></el-table-column>
    <el-table-column sortable prop="test" label="test" show-overflow-tooltip></el-table-column>
    <el-table-column sortable prop="test" label="test" show-overflow-tooltip></el-table-column>
    <el-table-column sortable prop="test" label="test" show-overflow-tooltip></el-table-column>
    <el-table-column sortable prop="test" label="testtest" show-overflow-tooltip></el-table-column>
    <el-table-column sortable prop="test" label="test" show-overflow-tooltip></el-table-column>
</el-table>

須要加入代碼已加粗加下劃線 這個不能直接reserve-selection="true"這樣寫

會報錯Invalid prop: type check failed for prop "reserveSelection". Expected Boolean, got String with value "true".

錯誤大體爲須要一個boolean類型的參數,可是傳入爲String類型的須要加上   :reserve-selection="true"

還有要返回一個當前行標識

// 指定返回的行
getRowKeys(row){
    return row.id;
},

----------------------------------------------------------------------------------------------------------------------------------------------------------------

再更新,忽然發現一個問題,由於element ui 中

@selection-change="handleSelectionChange"

是獲取複選框選中的行的全部值,當我選中時就會緩存進頁面聲明的集合或者對象中,若是這時websocket更新了tabledata中的值,這時緩存的值就成了舊數據,這樣確定是不行的,那怎麼辦,看到這個大佬的博客,先貼出來  https://blog.csdn.net/qq_36537108/article/details/89261394  上面是這樣說的   利用vue的ref屬性和element中的 複選框屬性

type="selection"

在按鈕點擊的時候獲取當前複選框選中的值,這時點擊按鈕時就是當前的新數據這樣就避免了出現舊數據

懶得打,複製過來吧,注意這個selection就是複選框呀

而後選中的是這樣寫的

this.$refs.multipleTable.selection

個人代碼是這個邏輯,由於只有一個頁面會用到實時刷新,因此其餘頁面就不用改了,而後就是在點擊事件的開始就讓

下面這個就是element ui 官網給出的選中複選框的那個@selection-change="handleSelectionChange"

注意這個 self 是  var self = this;
handleSelectionChange(val) {
    this.multipleSelection = val
},
self.multipleSelection = this.$refs.multipleTable.selection;

直接替換掉舊的數據而後代碼就不用有大改動

相關文章
相關標籤/搜索