1. 程式人生 > 資訊 >中芯國際正式委任高永崗為董事長,周子學辭任董事

中芯國際正式委任高永崗為董事長,周子學辭任董事

本節簡單介紹下如何在Spring Boot引入WebSocket,實現簡單的客戶端與服務端建立長連線並互發送文字訊息。

1.框架搭建

新建一個Spring Boot專案,artifactId為spring-boot-websocket-socketjs,專案結構如下圖所示:

專案的pom內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cc.mrbird</groupId>
    <artifactId>spring-boot-websocket-socketjs</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-boot-websocket-socketjs</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

引入了spring-boot-starter-websocket和spring-boot-starter-web依賴。

2.構建服務端

在cc.mrbird.socket目錄下新建handler包,然後在該包下新建MyStringWebSocketHandler繼承TextWebSocketHandler

@Component
public class MyStringWebSocketHandler extends TextWebSocketHandler {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    public void afterConnectionEstablished(WebSocketSession session) {
        log.info("和客戶端建立連線");
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        session.close(CloseStatus.SERVER_ERROR);
        log.error("連線異常", exception);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        super.afterConnectionClosed(session, status);
        log.info("和客戶端斷開連線");
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 獲取到客戶端傳送過來的訊息
        String receiveMessage = message.getPayload();
        log.info(receiveMessage);
        // 傳送訊息給客戶端
        session.sendMessage(new TextMessage(fakeAi(receiveMessage)));
        // 關閉連線
        // session.close(CloseStatus.NORMAL);
    }

    private static String fakeAi(String input) {
        if (input == null || "".equals(input)) {
            return "你說什麼?沒聽清︎";
        }
        return input.replace('你', '我')
                .replace("嗎", "")
                .replace('?', '!')
                .replace('?', '!');
    }
}

該類重寫了父類AbstractWebSocketHandler的四個方法:

  • afterConnectionEstablished,和客戶端連結成功的時候觸發該方法;
  • handleTransportError,和客戶端連線失敗的時候觸發該方法;
  • afterConnectionClosed,和客戶端斷開連線的時候觸發該方法;
  • handleTextMessage,和客戶端建立連線後,處理客戶端傳送的請求。

WebSocketSession物件代表每個客戶端會話,包含許多實用方法:

方法見名知意,就不贅述了。

此外,因為我們的目的是實現和客戶端的通訊,並且內容為文字內容,所以我們繼承的是TextWebSocketHandler

;如果傳輸的是二進位制內容,則可以繼承BinaryWebSocketHandler,更多資訊可以自行檢視WebSocketHandler的子類。

接著在cc.mrbird.socket目錄下新建configure包,然後在該包下新建WebSocketServerConfigure配置類:

@Configuration
@EnableWebSocket
public class WebSocketServerConfigure implements WebSocketConfigurer {

    @Autowired
    private MyStringWebSocketHandler myStringWebSocketHandler;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myStringWebSocketHandler, "/connect").withSockJS();
    }
}

@EnableWebSocket用於開啟WebSocket相關功能,我們注入了上面建立的MyStringWebSocketHandler,並將其註冊到了WebSocketHandlerRegistry

上面程式碼的含義是,當客戶端通過/connecturl和服務端連線通訊時,使用MyStringWebSocketHandler處理會話。withSockJS的含義是,通訊的客戶端是通過SockJS實現的,下面會介紹到。

3.構建客戶端

SockJS是一個JS外掛,用於構建WebSocket,相容性好。

在resources目錄下新建static包,然後在該包下新建client.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket客戶端</title>
    <script src="https://cdn.bootcss.com/sockjs-client/0.3.4/sockjs.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<style>
    .jumbotron {
        width: 100%;
    }

    #text {
        height: 3rem;
        font-size: 1rem;
        line-height: 3rem;
        margin: 1rem;
    }

    .btn {
        margin-right: 5px;
    }

    #connect {
        margin-left: 1rem;
    }

    #log {
        margin: 1rem 0 0 1rem;
    }

</style>
<div class="container">
    <div class="row">
        <div class="jumbotron">
            <input type="text" placeholder="請輸入你想傳輸的內容" id="text" class="col-lg-12"/>
            <input type="button" value="連線" class="btn btn-info" id="connect" onclick="connect()"/>
            <input type="button" value="傳送" class="btn btn-success" id="sent" disabled="disabled" onclick="sent()"/>
            <input type="button" value="斷開" class="btn btn-danger" id="disconnect" disabled="disabled"
                   onclick="disconnect()"/>

            <div id="log">
                <p>聊天記錄:</p>
            </div>
        </div>
    </div>
</div>
<script type="text/javascript">
    let text = document.querySelector('#text');
    let connectBtn = document.querySelector("#connect");
    let sentBtn = document.querySelector("#sent");
    let disconnectBtn = document.querySelector("#disconnect");
    let logDiv = document.querySelector("#log");

    let ws = null;

    function connect() {
        let targetUri = "/connect";
        ws = new SockJS(targetUri);
        ws.onopen = function () {
            setConnected(true);
            log('和服務端連線成功!');
        };
        ws.onmessage = function (event) {
            log('服務端說:' + event.data);
        };
        ws.onclose = function () {
            setConnected(false);
            log('和服務端斷開連線!')
        }
    }

    function sent() {
        if (ws != null) {
            ws.send(text.value);
            log('客戶端說:' + text.value);
        } else {
            log('請先建立連線!')
        }
    }

    function disconnect() {
        if (ws != null) {
            ws.close();
            ws = null;
        }
        setConnected(false);
    }

    function log(value) {
        let content = document.createElement('p');
        content.innerHTML = value;
        logDiv.appendChild(content);
        text.value = '';
    }

    function setConnected(connected) {
        connectBtn.disabled = connected;
        disconnectBtn.disabled = !connected;
        sentBtn.disabled = !connected;
    }
</script>
</body>
</html>

html,css那些都不重要,重要的是我們引入了SockJS庫。在connect()方法中,我們通過new SockJS(/connect)和上面的服務端建立了Socket通訊。SockJS物件包含幾個常用的實用方法:

  • onopen,和服務端講了連線後的回撥方法;
  • onmessage,服務端返回訊息時的回撥方法;
  • onclose,和服務端斷開連線的回撥方法;
  • send,傳送訊息給服務端;
  • close,斷開和服務端的連線。

上面的JS較為簡單,其他邏輯自己看看吧。

4.通訊測試

啟動專案,瀏覽器訪問:http://localhost:8080/client.html:

原始碼連線:https://github.com/wuyouzhuguli/SpringAll/tree/master/76.spring-boot-websocket-socketjs。

FROM:https://mrbird.cc/Spring-Boot%E6%95%B4%E5%90%88WebSocket.html****