太讚了,居然用SpringBoot打造一款網頁版的IM,進行聊天...

程序員的成長之路
互聯網/程序員/技術/資料共享 
關注


閱讀本文大概須要 6.5 分鐘。javascript

做者:蚩尤後裔
來源:https://blog.csdn.net/wangmx1993328/article/details/84582904

# 傳統 Tomcat 開發 WebSocket 回顧

WebSocket 的出現是基於 Web 應用的實時性須要而產生的,在淘寶、京東等網頁客服、網頁賣家聊天等需求上應用普遍。對於前端網頁可使用 H5 開發 WebSocket 客戶端,也可使用 SockJS 庫開發 WebSocket 客戶端。

對於Java 開發者而言,後臺 WebSocket 服務端開發一般有如下經常使用的選擇:
  • Tomcat7 之後開始支持 websocket 協議css

  • Spring4 之後開始支持 WebSockethtml

  • Netty3 之後支持開發 WebSocket前端


Tomcat8 以下所示,自身已經支持 WebSocket 服務端開發,它的 lib 目錄下有本身實現 WebSocket 協議的開發包,若是是傳統的 Java Web 項目,則只須要將 tomcat-websocket.jar、websocket-api.jar 導入應用中便可進行代碼開發。


Tomcat 自身也提供了 WebSocket 開發的示例,在 webapps/exampls下,一共提供了 4 個示例,能夠啓動 Tomcat 進行訪問測試以及學習:


對於傳統 Java Web 導包式應用開發,這裏再也不過多進行說明,它的基本流程是:

1)新建 Java Web 應用後,導入 Tomcat 服務器 lib 目錄下的 websocket-api.jar 、tomcat-websocket.jar開發包,前者是瀏覽器 webSocket 規範的接口,後者是 Tomcat 對它的實現。

2)建立後臺 webSocket 服務端類,標識 @ServerEndpoint( javax.websocket.server.ServerEndpoint)註解,表示當前類是 webSocket 服務終端,同時在裏面實現客戶端鏈接創建、發送消息、接收消息等通訊業務。

3)本身實現 javax.websocket.server.ServerApplicationConfig 接口,掃描整個應用全部的 @ServerEndpoint 服務終端。

# SpringBoot 整合 Tomcat  WebSocket

本文的重點是 SpringBoot 項目如何使用 Tomcat 的 webSocket 服務端開發; 本文環境:springboot 2.1.0 ,使用內置的 Tomcat 服務器。


Spring boot 建立的 web 應用,web 啓動模塊已經依賴了 tomcat-websocket 模塊,因此不須要再重複導入,可是必須導入 Spring boot 的 websocket 啓動模塊 spring-boot-starter-websocket。

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

@ServerEndpoint 建立 websocket 服務終端

一、建立後臺 webSocket 服務端類,標識 @ServerEndpoint( javax.websocket.server.ServerEndpoint)註解,表示當前類是 webSocket 服務終端,同時在裏面實現客戶端鏈接創建、發送消息、接收消息等通訊業務。

二、這與傳統導包式開發 Tomcat WebSocket 服務端是同樣的,區別就是:傳統方式 @ServerEndpoint 類上不須要加 @Component 交由 Spring 管理,而如今須要加上 @Component 將此組件交由 spring 管理。
   
     
   
   
    
    
             
    
    
import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import javax.websocket.*;import javax.websocket.server.ServerEndpoint;import java.io.IOException;import java.util.HashSet;import java.util.Set;/** * Created by Administrator on 2018/11/28 0028. * @ServerEndpoint :標識此類爲 Tomcat 的 websocket 服務終端,/websocket/yy.action 是客戶端鏈接請求的路徑 * @Component :將本類交由 spring IOC 容器管理 */@ServerEndpoint(value = "/websocket/yy.action")@Componentpublic class ServerEnpoint { private static Logger logger = LoggerFactory.getLogger(ServerEnpoint.class); /** * 用 Set 來 存儲 客戶端 鏈接 */ private static Set<Session> sessionSet = new HashSet<>(); /** * 鏈接成功後自動觸發 * * @param session */ @OnOpen public void afterConnectionEstablished(Session session) { /** * session 表示一個鏈接會話,整個鏈接會話過程當中它都是固定的,每一個不一樣的鏈接 session 不一樣 * String queryString = session.getQueryString();//獲取請求地址中的查詢字符串 * Map<String, List<String>> parameterMap = session.getRequestParameterMap();//獲取請求地址中參數 * Map<String, String> stringMap = session.getPathParameters(); * URI uri = session.getRequestURI(); */ sessionSet.add(session); logger.info("新客戶端加入,session id=" + session.getId() + ",當前客戶端格個數爲:" + sessionSet.size()); /** * session.getBasicRemote().sendText(textMessage);同步發送 * session.getAsyncRemote().sendText(textMessage);異步發送 */ session.getAsyncRemote().sendText("我是服務器,你鏈接成功!"); } /** * 鏈接斷開後自動觸發,鏈接斷開後,應該清楚掉 session 集合中的值 * * @param session */ @OnClose public void afterConnectionClosed(Session session) { sessionSet.remove(session); logger.info("客戶端斷開,session id=" + session.getId() + ",當前客戶端格個數爲:" + sessionSet.size()); } /** * 收到客戶端消息後自動觸發 * * @param session * @param textMessage :客戶端傳來的文本消息 */ @OnMessage public void handleMessage(Session session, String textMessage) { try { logger.info("接收到客戶端信息,session id=" + session.getId() + ":" + textMessage); /** * 原樣回覆文本消息 * getBasicRemote:同步發送 * session.getAsyncRemote().sendText(textMessage);異步發送 * */ session.getBasicRemote().sendText(textMessage); } catch (IOException e) { e.printStackTrace(); } } /** * 消息傳輸錯誤後 * * @param session * @param throwable */ @OnError public void handleTransportError(Session session, Throwable throwable) { System.out.println("shake client And server handleTransportError,session.getId()=" + session.getId() + " -- " + throwable.getMessage()); logger.error("與客戶端 session id=" + session.getId() + " 通訊錯誤..."); }}

注入 ServerEndpointExporter

一、注入 org.springframework.web.socket.server.standard.ServerEndpointExporter,這個 bean 會自動註冊使用了@ServerEndpoint 註解聲明的 Websocket endpoint 。

二、若是使用獨立的 servlet 容器,而不是使用 spring boot 的內置容器,就不要注入ServerEndpointExporter,由於它將由 Tomcat 容器本身提供和管理。

三、由於傳統導包式 Tomcat websocket 開發時,是須要實現 javax.websocket.server.ServerApplicationConfig 接口的,而後由它去掃描整個應用中的 @ServerEndpoint,而如今這一步就由 springboot 的 ServerEndpointExporter 取代了。
   
     
   
   
    
    
             
    
    
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.server.standard.ServerEndpointExporter;/** * Created by Administrator on 2018/11/28 0028. */@Configurationpublic class WebSocketConfig { /** * 建立 ServerEndpointExporter 組件,交由 spring IOC 容器管理, * 它會自動掃描註冊應用中全部的 @ServerEndpoint * * @return */ @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }}

前端 H5 webSocket 客戶端

爲了方便,直接使用 H5 的 webSocket 方式,頁面的 html 與 css 樣式就不作提供了,直接提供客戶端 webSocket 的 js 代碼。
   
     
   
   
    
    
             
    
    
/** * web socket 綁定 */var ws = null;function webSocketBind() { /**主流瀏覽器如今都支持 H5 d的 webSocket 通訊,但建議仍是要判斷*/ if ("WebSocket" in window) { /**建立 web socket 實例 * 若是鏈接失敗,瀏覽器控制檯報錯,鏈接失敗 * 前綴 ws:// 必須正確,yyServer 是應用名稱,websocket/yy.action 是後臺訪問路徑 * 192.168.1.20:websocket 服務器地址 * */ ws = new WebSocket("ws://192.168.1.20/yyServer/websocket/yy.action"); /**onopen:服務器鏈接成功後,自動觸發*/ ws.onopen = function () { /** Web Socket 已鏈接上,使用 send() 方法發送數據*/ //ws.send("connect success..."); console.log("服務器鏈接成功,併發送數據到後臺..."); }; /**服務器發送數據後,自動觸發此方法,客戶端進行獲取數據,使用 evt.data 獲取數據*/ ws.onmessage = function (evt) { var received_msg = evt.data; console.log("接收到服務器數據:" + received_msg); showClientMessage(received_msg); }; /**客戶端與服務器數據傳輸錯誤時觸發*/ ws.onerror = function (evt) { console.log("客戶端 與 服務器 數據傳輸錯誤..."); }; /**web Socket 鏈接關閉時觸發*/ ws.onclose = function () { console.log("web scoket 鏈接關閉..."); }; } else { alert("您的瀏覽器不支持 WebSocket!"); }} /** * 顯示服務器發送的消息 * @param message */let showServerMessage = function (message) { if (message != undefined && message.trim() != "") { /** * 往服務器發送消息 */ ws.send(message.trim()); /** * scrollHeight:div 區域內文檔的高度,只能 DOM 操做,JQuery 沒有提供相應的方法 * @type {string} */ let messageShow = "<div class='messageLine server'><div class='messageContent serverCon'>" + message + "</div><span>:我</span>"; $(".centerTop").append(messageShow + "<br>"); $(".messageArea").val(""); let scrollHeight = $(".centerTop")[0].scrollHeight; $(".centerTop").scrollTop(scrollHeight - $(".centerTop").height()); }}; /** * 顯示客戶端的消息 * @param message */let showClientMessage = function (message) { if (message != undefined && message.trim() != "") { /** * scrollHeight:div 區域內文檔的高度,只能 DOM 操做,JQuery 沒有提供相應的方法 * @type {string} */ let messageShow = "<div class='messageLine client'><span>服務器:</span><div class='messageContent clientCon'>" + message + "</div>"; $(".centerTop").append(messageShow + "<br>"); $(".messageArea").val(""); let scrollHeight = $(".centerTop")[0].scrollHeight; $(".centerTop").scrollTop(scrollHeight - $(".centerTop").height()); }}; $(function () { /**初始化後清空消息發送區域*/ $(".messageArea").val(""); /** * 爲 消息 發送按鈕綁定事件 */ $(".sendButton").click(function () { let message = $(".messageArea").val(); showServerMessage(message); }); /** * 綁定鍵盤敲擊事件 —— 用於按 回車鍵 發送消息 */ $(window).keydown(function (event) { if (event.keyCode === 13) { let message = $(".messageArea").val(); showServerMessage(message); } }); /** * 綁定 webSocket,鏈接 服務器 */ webSocketBind();});

# websocket 通訊測試

<END>

推薦閱讀:
java

知乎高贊:爲何像王者榮耀這樣的遊戲Server不肯意使用微服務?
程序員

ELK太笨重了?想放棄?快試試日誌系統新貴Loki吧!
web

5T技術資源大放送!包括但不限於:C/C++,Linux,Python,Java,PHP,人工智能,單片機,樹莓派,等等。在公衆號內回覆「2048」,便可免費獲取!!

微信掃描二維碼,關注個人公衆號spring

寫留言

朕已閱 api

本文分享自微信公衆號 - 程序員的成長之路(cxydczzl)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。瀏覽器

相關文章
相關標籤/搜索