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

這種實現需要實時推送數據上來,那一般有兩種方法
方法一:前端寫個定時器,不斷輪詢后台即可。這當然是很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"); } }
