1. 程式人生 > 程式設計 >SpringBoot整合websocket

SpringBoot整合websocket

什麼是WebSocket?

WebSocket 是 HTML5 開始提供的一種在單個 TCP 連線上進行全雙工通訊的協議。

WebSocket 使得客戶端和伺服器之間的資料交換變得更加簡單,允許服務端主動向客戶端推送資料。在 WebSocket API 中,瀏覽器和伺服器只需要完成一次握手,兩者之間就直接可以建立永續性的連線,並進行雙向資料傳輸。

在 WebSocket API 中,瀏覽器和伺服器只需要做一個握手的動作,然後,瀏覽器和伺服器之間就形成了一條快速通道。兩者之間就直接可以資料互相傳送。

話不多說,馬上進入乾貨時刻。

maven依賴

SpringBoot2.0對WebSocket的支援簡直太棒了,直接就有包可以引入

<dependency>  
     <groupId>org.springframework.boot</groupId>  
     <artifactId>spring-boot-starter-websocket</artifactId>  
</dependency> 
複製程式碼

WebSocketConfig

啟用WebSocket的支援也是很簡單,幾句程式碼搞定

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * 開啟WebSocket支援
 * @author zhengkai
 */
@Configuration  
public class WebSocketConfig {  
    @Bean  
    public ServerEndpointExporter serverEndpointExporter
() { return new ServerEndpointExporter(); } } 複製程式碼

WebSocketServer

因為WebSocket是類似客戶端服務端的形式(採用ws協議),那麼這裡的WebSocketServer其實就相當於一個ws協議的Controller直接@ServerEndpoint("/websocket")、@Component啟用即可,然後在裡面實現@OnOpen,@onClose,@onMessage等方法

import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import lombok.extern.slf4j.Slf4j;


@ServerEndpoint("/websocket/{sid}"
) @Component public class WebSocketServer { static Log log=LogFactory.get(WebSocketServer.class); //靜態變數,用來記錄當前線上連線數。應該把它設計成執行緒安全的。 private static int onlineCount = 0; //concurrent包的執行緒安全Set,用來存放每個客戶端對應的MyWebSocket物件。 private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>(); //與某個客戶端的連線會話,需要通過它來給客戶端傳送資料 private Session session; //接收sid private String sid=""; /** * 連線建立成功呼叫的方法*/ @OnOpen public void onOpen(Session session,@PathParam("sid") String sid) { this.session = session; webSocketSet.add(this); //加入set中 addOnlineCount(); //線上數加1 log.info("有新視窗開始監聽:"+sid+",當前線上人數為" + getOnlineCount()); this.sid=sid; try { sendMessage("連線成功"); } catch (IOException e) { log.error("websocket IO異常"); } } /** * 連線關閉呼叫的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); //從set中刪除 subOnlineCount(); //線上數減1 log.info("有一連線關閉!當前線上人數為" + getOnlineCount()); } /** * 收到客戶端訊息後呼叫的方法 * * @param message 客戶端傳送過來的訊息*/ @OnMessage public void onMessage(String message,Session session) { log.info("收到來自視窗"+sid+"的資訊:"+message); //群發訊息 for (WebSocketServer item : webSocketSet) { try { item.sendMessage(message); } catch (IOException e) { e.printStackTrace(); } } } /** * * @param session * @param error */ @OnError public void onError(Session session,Throwable error) { log.error("發生錯誤"); error.printStackTrace(); } /** * 實現伺服器主動推送 */ public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); } /** * 群發自定義訊息 * */ public static void sendInfo(String message,@PathParam("sid") String sid) throws IOException { log.info("推送訊息到視窗"+sid+",推送內容:"+message); for (WebSocketServer item : webSocketSet) { try { //這裡可以設定只推送給這個sid的,為null則全部推送 if(sid==null) { item.sendMessage(message); }else if(item.sid.equals(sid)){ item.sendMessage(message); } } catch (IOException e) { continue; } } } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketServer.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketServer.onlineCount--; } } 複製程式碼

訊息推送

至於推送新資訊,可以再自己的Controller寫個方法調WebSocketServer.sendInfo();即可

@Controller
@RequestMapping("/checkcenter")
public class CheckCenterController {

	//頁面請求
	@GetMapping("/socket/{cid}")
	public ModelAndView socket(@PathVariable String cid) {
		ModelAndView mav=new ModelAndView("/socket");
		mav.addObject("cid",cid);
		return mav;
	}
	//推送資料介面
	@ResponseBody
	@RequestMapping("/socket/push/{cid}")
	public ApiReturnObject pushToWeb(@PathVariable String cid,String message) {  
		try {
			WebSocketServer.sendInfo(message,cid);
		} catch (IOException e) {
			e.printStackTrace();
			return ApiReturnUtil.error(cid+"#"+e.getMessage());
		}  
		return ApiReturnUtil.success(cid);
	} 
} 

複製程式碼

前端頁面

在頁面用js程式碼呼叫socket,當然,太古老的瀏覽器是不行的,一般新的瀏覽器或者谷歌瀏覽器是沒問題的。

<!DOCTYPE HTML>
<html>
   <head>
   <meta charset="utf-8">
   <title>菜鳥教程(runoob.com)</title>
    
      <script type="text/javascript">
         function WebSocketTest()
         {
            if ("WebSocket" in window)
            {
               alert("您的瀏覽器支援 WebSocket!");
               
               // 開啟一個 web socket
               var ws = new WebSocket("ws://127.0.0.1:8080/websocket/1212");
                
               ws.onopen = function()
               {
                  // Web Socket 已連線上,使用 send() 方法傳送資料
                  ws.send("傳送資料");
                  alert("資料傳送中...");
               };
                
               ws.onmessage = function (evt) 
               { 
                  var received_msg = evt.data;
                  alert(received_msg)
                  alert("資料已接收...");
               };
                
               ws.onclose = function()
               { 
                  // 關閉 websocket
                  alert("連線已關閉..."); 
               };
            }
            
            else
            {
               // 瀏覽器不支援 WebSocket
               alert("您的瀏覽器不支援 WebSocket!");
            }
         }
      </script>
        
   </head>
   <body>
   
      <div id="sse">
         <a href="javascript:WebSocketTest()">執行 WebSocket</a>
      </div>
      
   </body>
</html>
複製程式碼

執行

1、啟動springboot專案。

2、直接開啟頁面test.html,點選連結

3、服務端傳送訊息:

http://localhost:8080/checkcenter/socket/push/1212?message=xxxx
複製程式碼