花了20分鐘,給女朋友們寫了一個web版群聊程式

Java識堂發表於2020-01-14

WebSocket詳解

在這裡插入圖片描述

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

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

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

原來為了實現推送,很多公司用的是Ajax 輪詢,即按照特定的時間間隔,由瀏覽器對伺服器發出HTTP請求,然後由伺服器返回最新的資料給客戶端的瀏覽器。這種傳統的模式帶來很明顯的缺點,即瀏覽器需要不斷的向伺服器發出請求,然而HTTP請求可能包含較長的頭部,其中真正有效的資料可能只是很小的一部分,顯然這樣會浪費很多的頻寬等資源。而websocket就可以解決這些問題。

在Spring Boot中使用WebSocket

1.pom檔案增加依賴

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

2.增加配置

@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

3.Java程式碼

@Component
@ServerEndpoint("/websocket")
public class WebSocketServerController {

    // 收到訊息呼叫的方法
    @OnMessage
    public void onMessage(String message) {
        System.out.println("收到的訊息為 " + message);
    }

    // 建立連線呼叫的方法
    @OnOpen
    public void onOpen() {
        System.out.println("Client connected");
    }

    // 關閉連線呼叫的方法
    @OnClose
    public void onClose() {
        System.out.println("Connection closed");
    }

    // 傳輸訊息錯誤呼叫的方法
    @OnError
    public void OnError(Throwable error) {
        System.out.println("Connection error");
    }
}

4.前端程式碼

<!DOCTYPE html>
<html>
<head>
<title>Testing websockets</title>
</head>
<body>
  <div>
	<textarea rows="3" cols="20" id="content"></textarea>
	<br>
    <input type="submit" value="Start" onclick="start()" />
  </div>
  <div id="messages"></div>
  <script type="text/javascript">
    var webSocket = 
      new WebSocket('ws://localhost:8080/websocket');

    webSocket.onerror = function(event) {
      onError(event)
    };

    webSocket.onopen = function(event) {
      onOpen(event)
    };

    webSocket.onmessage = function(event) {
      onMessage(event)
    };
	
	webSocket.onclose = function(event) {
      onClose(event)
    };
	

    function onMessage(event) {
      document.getElementById('messages').innerHTML 
        += '<br />' + event.data;
    }

    function onOpen(event) {
      document.getElementById('messages').innerHTML 
        = 'Connection established';
    }

    function onError(event) {
      alert(event);
    }
	
	function onClose(event) {
      alert(event);
    }

    function start() {
	  var text = document.getElementById('content').value;
      webSocket.send(text);
    }
  </script>
</body>
</html>

所以你看websocket其實很簡單,前後端各寫4個事件方法就行了(當然你也可以省略一些方法)

1.建立連線
2.收到訊息
3.傳輸訊息失敗
4.關閉連線

事件和具體會話關聯

如果事件想和具體會話關聯,方法上只要加Session引數就行(4種事件型別的方法上都可加)

舉個例子,直接將使用者傳送給服務端的話再返回給客戶端

// 收到訊息呼叫的方法
@OnMessage
public void onMessage(Session session, String message) {
	try {
		session.getBasicRemote().sendText(message);
	} catch (IOException e) {
		e.printStackTrace();
	}
}

在這裡插入圖片描述
傳遞引數

方法上加@PathParam引數即可

@Component
@ServerEndpoint("/websocket/{sid}")
public class WebSocketServerController
@OnOpen
public void onOpen(@PathParam("sid") String sid) {
	System.out.println("Client connected");
}

實現一個線上群聊

後端介面

@Slf4j
@Component
@ServerEndpoint("/groupChat/{sid}/{username}")
public class GroupChatController {

    // 儲存 組id->組成員 的對映關係
    private static ConcurrentHashMap<String, List<Session>> groupMemberInfoMap = new ConcurrentHashMap<>();

    // 收到訊息呼叫的方法,群成員傳送訊息
    @OnMessage
    public void onMessage(@PathParam("sid") String sid,
                          @PathParam("username") String username, String message) {
        List<Session> sessionList = groupMemberInfoMap.get(sid);
        // 先一個群組內的成員傳送訊息
        sessionList.forEach(item -> {
            try {
                String text = username + ": " + message;
                item.getBasicRemote().sendText(text);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    // 建立連線呼叫的方法,群成員加入
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        List<Session> sessionList = groupMemberInfoMap.get(sid);
        if (sessionList == null) {
            sessionList = new ArrayList<>();
            groupMemberInfoMap.put(sid,sessionList);
        }
        sessionList.add(session);
        log.info("Connection connected");
        log.info("sid: {}, sessionList size: {}", sid, sessionList.size());
    }

    // 關閉連線呼叫的方法,群成員退出
    @OnClose
    public void onClose(Session session, @PathParam("sid") String sid) {
        List<Session> sessionList = groupMemberInfoMap.get(sid);
        sessionList.remove(session);
        log.info("Connection closed");
        log.info("sid: {}, sessionList size: {}", sid, sessionList.size());
    }

    // 傳輸訊息錯誤呼叫的方法
    @OnError
    public void OnError(Throwable error) {
        log.info("Connection error");
    }
}

前端程式碼很簡單,放github了
地址為:https://github.com/erlieStar/spring-boot-websocket

下面來看效果
在這裡插入圖片描述
注意先連線,後傳送
在這裡插入圖片描述
線上開房地址:
http://www.javashitang.com:8090/

歡迎關注

在這裡插入圖片描述

參考部落格

好文
[1]https://blog.csdn.net/moshowgame/article/details/80275084
[2]https://www.jianshu.com/p/d79bf8174196
[3]https://www.byteslounge.com/tutorials/java-ee-html5-websocket-example
一個群聊程式
[4]https://blog.csdn.net/moshowgame/article/details/80275084

相關文章