java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot WebSocket连接失败

SpringBoot WebSocket连接失败怎么办 常见问题排查

作者:wno704

本文手把手教你如何在SpringBoot项目中集成WebSocket,实现客户端与服务端的长连接和文本消息互发,从依赖引入、服务端Handler编写到SockJS客户端构建,每一步都有详细说明,帮助你快速掌握WebSocket通信的核心配置和代码实现

一、前言

本节简单介绍下如何在Spring Boot引入WebSocket,实现简单的客户端与服务端建立长连接并互发送文本消息。

二、框架搭建

2.1 依赖引入

        <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>

2.2 构建服务端

新建handler包,然后在该包下新建MyStringWebSocketHandler继承TextWebSocketHandler:

@Component
@Slf4j
public class MyStringWebSocketHandler extends TextWebSocketHandler {
    @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的四个方法:

此外,因为我们的目的是实现和客户端的通信,并且内容为文本内容,所以我们继承的是TextWebSocketHandler;

如果传输的是二进制内容,则可以继承BinaryWebSocketHandler,更多信息可以自行查看WebSocketHandler的子类。

2.3 配置类

接着新建config包,然后在该包下新建WebSocketServerConfigure配置类:

@Configuration
@EnableWebSocket
public class WebSocketServerConfigure implements WebSocketConfigurer {

    @Autowired
    private MyStringWebSocketHandler myStringWebSocketHandler;

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

}

@EnableWebSocket用于开启WebSocket相关功能,我们注入了上面创建的MyStringWebSocketHandler,并将其注册到了WebSocketHandlerRegistry。

上面代码的含义是,当客户端通过/connecturl和服务端连接通信时,使用MyStringWebSocketHandler处理会话。

withSockJS的含义是,通信的客户端是通过SockJS实现的,下面会介绍到。

三、构建客户端

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="external nofollow"  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对象包含几个常用的实用方法:

上面的JS较为简单,其他逻辑自己看看吧。

四、通信测试

启动项目,浏览器访问:http://localhost:8080/client.html:

五、总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文