文章目录
- 前情描述
- websocket优势
- 效果展示
- spring-boot后端
- html前端代码
- 资源地址
- 结语
前情描述
最近想了解websocket的相关原理,于是写了一个极简版的程序,后端使用springboot集成websocket模块,前端手敲了一个html页面(页面很丑很丑很丑,勿喷勿喷),整个程序仅支持简单的websocket通信。
websocket优势
百度百科对websocket的定义是:WebSocket是一种在单个TCP连接上进行全双工通信的协议。
 websocket的优势:
 1:数据包更小,创建连接后数据包头部较小,减少网络传输的开销,提高了传输效率;
 2:实时性更强,webwocket是全双工协议,服务器和客户端可以同时相互发送数据;
 3:保持连接状态,websocket创建连接之后,会保持服务器和客户端的联系状态,之后通信可以省略部分状态信息。
效果展示
下面是use_one和user_two的聊天记录:
 两个相互发送消息,消息内容会显示在聊天框
 
spring-boot后端
一: 依赖
 在springboot的基础上引入websocket相关依赖
        <!-- websocket -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
二: 重要代码
 1:向springboot容器注入ServerEnpointExporter实例
 该实例是spring集成websocket的重要内容,它可以将标注有@ServerEndpoint的类注册到websocket服务器中,从而让客户端可以正常访问到websocket服务器。
@Configuration
public class WebSocketConfig {
    /**
     * 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
2:创建websocket服务器
 在类上标注@ServerEnpoint(“/url”),需要注意的是不同的url会由不同的实例来维护,然后需要我们实现@OnOpen【开始链接】,@OnClose【结束链接】,@OnMessage【客户端向服务器发送消息】,@OnError【链接发生错误】注解的方法,这些方法参数会带有一个Session,我们可以将session保存起来,当需要向客户端发送信信息可以调用session.getBasicRemote().sendText(message);
@ServerEndpoint("/person/{userId}")
@Component
@Slf4j
public class WebSocketServer {
    private static Map<String, WebSocketServer> SOCKET_MAP = new ConcurrentHashMap<>();
    @Getter
    private Session session;
    @OnOpen
    public void open(Session session, @PathParam("userId") String userId) {
        this.session = session;
        SOCKET_MAP.put(userId, this);
        log.info("用户{}连接成功,当前链接总人数{}", userId, SOCKET_MAP.size());
    }
    @OnClose
    public void close(Session session, @PathParam("userId") String userId) {
        SOCKET_MAP.remove(userId);
        log.info("用户{}断开连接,当前链接总人数{}", userId, SOCKET_MAP.size());
    }
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到用户{}的消息:{}", session.getId(), message);
        ChatEntityStr chatEntity = JSONObject.parseObject(message, ChatEntityStr.class);
        WebSocketServer socketServer = SOCKET_MAP.get(chatEntity.getTo());
        if (null == socketServer) {
            //用户不在线
            log.info("用户{}不在线", chatEntity.getTo());
            return;
        }
        SendHelper.sendToPersonStr(message, socketServer.getSession());
    }
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误:{}", session.getId());
        error.printStackTrace();
    }
}
html前端代码
这里写了两个html,one.html【代表user_one】,two.html【代表user_two】,下面仅展示了one.html,前端代码在项目目录下,one.html和two.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>简易聊天框</title>
    <style type="text/css">
    </style>
</head>
<body>
<div style="flex-direction: column">
    <div>
        <label>
            <textarea rows="3" id="chatMsg" style="height: 500px;width: 500px;resize: none;"></textarea>
        </label>
    </div>
    <div>
        <label>
            <input type="text" style="width: 400px" name="inputMsg" id="inputMsg" onkeyup="inputChange(this.value)">
            <button type="button" onclick="sendMsg()">发送</button>
        </label>
    </div>
</div>
</body>
<script type="application/javascript">
    /**
     * 一般情况下,只需要改动self,other,websocket服务器地址即可使用
     */
    const self = "user_one";
    const other = "user_two";
    const message = {attr: ""};
    const input = document.getElementById("inputMsg");
    const chatMsg = document.getElementById("chatMsg");
    let websocket = {
        send: function (str) {
        }
    };
    window.onload = function () {
        if (!'WebSocket' in window) return;
        webSocketInit();
    };
    //初始化websocket
    function webSocketInit() {
        websocket = new WebSocket("ws://127.0.0.1:7777/person/" + self);
        //成功建立连接
        websocket.onopen = function () {
            linkSuccess(self, self, "链接成功");
        };
        //接收到消息
        websocket.onmessage = function (event) {
            const data = JSON.parse(event.data);
            chatMsg.value = chatMsg.value + data.from + " >>> " + data.message + "\n";
        };
        //连接发生错误
        websocket.onerror = function () {
            alert("WebSocket连接发生错误");
        };
        //连接关闭
        websocket.onclose = function () {
            alert("WebSocket连接关闭");
        };
        //监听窗口关闭事件,当窗口关闭时,主动关闭websocket连接
        window.onbeforeunload = function () {
            websocket.close()
        };
    }
    //对message.attr进行绑定
    Object.defineProperty(message, "attr", {
        configurable: true,
        enumerable: true,
        set: function (newValue) {
            attr = newValue;
            input.value = newValue
        },
        get: function () {
            return attr;
        },
    });
    function inputChange(newValue) {
        message.attr = newValue
        if (event.keyCode === 13 &&
            message.attr !== undefined && message.attr !== null && message.attr.length > 0) {
            sendMsg();
        }
    }
    //发送消息
    function sendMsg() {
        if (message.attr.length <= 0) {
            return
        }
        const msg = {
            from: self,
            to: other,
            createTime: new Date(),
            message: message.attr
        };
        chatMsg.value = chatMsg.value + msg.from + " >>> " + msg.message + "\n";
        websocket.send(JSON.stringify(msg))
        message.attr = ""
    }
    //链接成功
    function linkSuccess(from, to, msg) {
        const successMsg = {
            from: from,
            to: to,
            createTime: new Date(),
            message: msg
        };
        websocket.send(JSON.stringify(successMsg))
    }
</script>
</html>
资源地址
项目地址:https://gitee.com/ryfz-git/springboot-websocket.git
结语
共同学习,共同进步,欢迎交流。



















