{"id":7411,"date":"2022-09-22T09:48:30","date_gmt":"2022-09-22T01:48:30","guid":{"rendered":"http:\/\/123.57.164.21\/?p=7411"},"modified":"2022-09-22T09:48:30","modified_gmt":"2022-09-22T01:48:30","slug":"spring%e9%9b%86%e6%88%90websocket%e8%af%a6%e8%a7%a3","status":"publish","type":"post","link":"https:\/\/92it.top\/?p=7411","title":{"rendered":"Spring\u96c6\u6210webSocket\u8be6\u89e3"},"content":{"rendered":"\n<p><strong>\u8e29\u5751\u603b\u7ed3<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>\u56e0\u4e3a\u4e4b\u524d\u4ece\u6765\u6ca1\u6709\u63a5\u89e6\u8fc7\uff0c\u6240\u4ee5\u7f51\u4e0a\u627e\u4e86\u5f88\u591a\u6559\u7a0b\u6700\u540e\u53d1\u73b0\u90fd\u4e0d\u600e\u4e48\u5b8c\u6574\uff0c\u5927\u591a\u6570\u90fd\u662f\u76f4\u63a5\u5168\u76d8\u7167\u6284\u300aSpring Boot\u300b\u4e00\u4e66\u4e2d\u7684\u76f8\u5173\u793a\u4f8b\uff0c\u6ca1\u6709\u505a\u4efb\u4f55\u4fee\u6539\uff0c\u6ca1\u6709\u8bf4\u660e\u4e3a\u4ec0\u4e48\u4e00\u5b9a\u8981\u7528spring security\uff0c\u800c\u4e0b\u9762\u7684\u6559\u7a0b\u81ea\u5df1\u4e5f\u662f\u8e29\u4e86\u4e0d\u5c11\u5751\uff0c\u5982\u524d\u540e\u5206\u79bb\u4e2dsession\u4e00\u76f4\u83b7\u53d6\u4e0d\u5230\uff0c\u5bfc\u81f4\u65e0\u6cd5\u94fe\u63a5\u4e0a\uff0cuid\u4e0d\u53ef\u4e3a\u4e2d\u6587\uff0cwebsocket\u81ea\u5e26\u534f\u8bae\u548c\u670d\u52a1\uff0c\u5bfc\u81f4\u524d\u540e\u7aef\u5206\u79bb\u4e00\u76f4\u62a5\u8de8\u57df\u7684\u9519\u8bef\u7b49\u7b49\u3002\u5f53\u7136websocket\u4e00\u4e9b\u89e3\u91ca\u5728\u8fd9\u8fb9\u5c31\u4e0d\u591a\u8bf4\u4e86\uff0c\u76f8\u4fe1\u4f60\u5df2\u7ecf\u770b\u4e86\u5f88\u591a\u6559\u7a0b\u4e86\uff0c\u6211\u4eec\u5c31\u76f4\u63a5\u4e0a\u914d\u7f6e\u6559\u7a0b<\/p>\n\n\n\n<p><strong>\u524d\u7aef\u914d\u7f6e<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>\u524d\u7aef\u914d\u7f6e\u76f8\u5bf9\u6bd4\u8f83\u7b80\u5355\uff0c\u4e3b\u8981\u5c31\u662fwebsocket\u670d\u52a1\u7684\u6ce8\u518c\uff0c\u6d88\u606f\u7684\u53d1\u9001\u548c\u63a5\u6536\u3002\u6bd4\u8f83\u5173\u952e\u7684\u70b9\uff1auid\u7684\u5b9a\u4e49\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u7528\u6237\u7684\u7279\u6b8a\u6807\u5fd7\uff0c\u4e00\u822c\u7528id\u6216\u8005\u751f\u6210\u7684uuid\uff0c\u540e\u53f0\u4e3aLong\uff0c\u4e0d\u53ef\u5e26\u6709\u4e2d\u6587\uff0c\u5e76\u4e14\u8fd9\u4e9b\u503c\u5982\u679c\u4ecesession\u4e2d\u83b7\u53d6\uff0c\u9700\u8981\u6ce8\u610f\u524d\u540e\u7aef\u5206\u79bb\u5e26\u6765\u7684session\uff0c\u5426\u5219\u4f1a\u62a5\u9519,\u8fd9\u4e9b\u53c2\u6570\u4e3b\u8981\u5bf9\u5e94\u7740\u540e\u53f0\u7684message\u7c7b\uff0c\u7528\u4e8e\u4fe1\u606f\u7684\u53d1\u9001\n    let from = '';\n    let fromName = '';\n    let to = 5521;\n    let host = window.location.host;\n    let webSocket = \"\";\n    \/\/ \u4e0d\u540c\u7684\u6d4f\u89c8\u5668\u5bf9websocket\u7684\u652f\u6301\u4e0d\u540c\n    if ('WebSocket' in window) {\n    \/\/ \u6700\u5173\u952e\u7684\u70b9\uff0cws\u5fc5\u987b\u52a0\u4e0a\uff0c\u4e0d\u53ef\u7528http\uff0c\u56e0\u4e3a\u4e24\u8005\u7684\u534f\u8bae\u662f\u4e0d\u540c\u7684\uff0cwebsocket\u6709\u81ea\u5e26\u7684\u8bf7\u6c42\u534f\u8bae\uff0cuid\u662f\u4e3a\u4e86\u5c06\u7528\u6237\u7684id\u6ce8\u518c\u5230websocket\u7684\u670d\u52a1\u4e2d\n        webSocket = new WebSocket(\"ws:\/\/127.0.0.1:8090\/ws?uid=\" + from);\n    } else if ('MozWebSocket' in window) {\n        webSocket = new MozWebSocket(\"ws:\/\/\" + host + \"\/ws\" + from);\n    } else {\n        webSocket = new SockJS(\"ws:\/\/\" + host + \"\/ws\/sockjs\" + from);\n    }\n    \/\/ \u94fe\u63a5\uff0c\u9519\u8bef\uff0c\u5173\u95ed\uff0c\u6536\u5230\u6d88\u606f\u76f8\u5173\u7684\u56de\u6389\u51fd\u6570\n    webSocket.onopen = function (event) {\n        console.log(\"WebSocket:\u5df2\u8fde\u63a5\");\n    };\n    webSocket.onerror = function (event) {\n        console.log(\"WebSocket:\u53d1\u751f\u9519\u8bef \");\n        console.log(event);\n    };\n    webSocket.onclose = function (event) {\n        console.log(\"WebSocket:\u5df2\u5173\u95ed\");\n        console.log(event);\n    };\n    webSocket.onmessage = function (event) {\n    \/\/ \u63a5\u6536\u5230\u7684\u6d88\u606f\u7684\u5bf9\u8c61\n        let data = JSON.parse(event.data);\n    };\n    \/\/ \u53d1\u9001\u6d88\u606f\u7684\u5b9e\u4f8b\n    function sendMsg() {\n        let data = {};\n        data[\"from\"] = from;\n        data[\"fromName\"] = fromName;\n        data[\"to\"] = to;\n        data[\"text\"] = \"\u6211\u53d1\u7ed9\u4f60\u4e00\u6761\u4fe1\u606f\";\n        webSocket.send(JSON.stringify(data));\n    }\n<\/pre>\n\n\n\n<p><strong>\u540e\u7aef\u914d\u7f6e<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<ul><li>\u5148\u6dfb\u52a0maven\u76f8\u5173\u4f9d\u8d56<\/li><\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\u5148\u6dfb\u52a0maven\u76f8\u5173\u4f9d\u8d56\n       &lt;dependency>\n            &lt;groupId>org.springframework.boot&lt;\/groupId>\n            &lt;artifactId>spring-boot-starter-websocket&lt;\/artifactId>\n        &lt;\/dependency>\n        &lt;dependency>\n            &lt;groupId>com.google.code.gson&lt;\/groupId>\n            &lt;artifactId>gson&lt;\/artifactId>\n            &lt;version>2.2.2&lt;\/version>\n        &lt;\/dependency><\/pre>\n\n\n\n<ul><li>\u6ce8\u518cwebsocket\u670d\u52a1\uff08\u524d\u7aef\u94fe\u63a5\u7684url\u5730\u5740\uff09<\/li><\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import javax.annotation.Resource;\n\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;\nimport org.springframework.web.socket.config.annotation.EnableWebSocket;\nimport org.springframework.web.socket.config.annotation.WebSocketConfigurer;\nimport org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;\n\n \/**\n * \u63cf\u8ff0:\n * WebScoket\u914d\u7f6e\u5904\u7406\u5668\n *\n * @author Msater Zg\n * @create 2018-01-24 10:49\n *\/\n@Component\n@EnableWebSocket\npublic class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {\n    \/**\n     * \u540e\u53f0\u5199\u597d\u670d\u52a1\uff0c\u9879\u76ee\u542f\u52a8\u7684\u65f6\u5019\uff0c\u6ce8\u518c\u597d\u8fd9\u4e24\u4e2a\u670d\u52a1\uff0c\u4ee5\u4f9b\u524d\u53f0\u8c03\u7528\n     *\/\n    @Resource\n    MyWebSocketHandler handler;\n\n    @Override\n    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {\n        \/\/ \u94fe\u63a5\u7684\u65f6\u5019\uff0cwebsocket\u4f1a\u81ea\u5df1\u589e\u52a0\u540c\u6e90\u68c0\u6d4b\u7684\u529f\u80fd\uff0c\u9700\u8981\u5355\u72ec\u914d\u7f6e\u662f\u5426\u5141\u8bb8\u8de8\u57df\uff0c\u6211\u914d\u7f6e*\u4ee3\u8868\u5141\u8bb8\u6240\u6709\u7684ip\u8fdb\u884c\u8c03\u7528\u3002\n        registry.addHandler(handler, \"\/ws\").addInterceptors(new HandShake()).setAllowedOrigins(\"*\");\n        registry.addHandler(handler, \"\/ws\/sockjs\").addInterceptors(new HandShake()).setAllowedOrigins(\"*\").withSockJS();\n    }\n}\n<\/pre>\n\n\n\n<ul><li>\u63e1\u624b\u4e4b\u524d\u7684\u914d\u7f6e\uff08\u9700\u8981\u5c06\u7528\u6237\u76f8\u5173uid\u6ce8\u518c\u5230WebSocketSession\u4e2d\uff0c\u800c\u8fd9\u4e2auid\u4f60\u53ef\u4ee5\u7528token\uff0csession\u7b49\u7b49\u6765\u4ee3\u66ff\uff0c\u56e0\u4e3a\u662f\u524d\u7aef\u5206\u79bb\uff0c\u6240\u4ee5\u6211\u76f4\u63a5\u7528\u4e86\u7528\u6237\u7684id\uff09<\/li><\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import java.util.Map;\nimport javax.servlet.http.HttpSession;\n\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\nimport org.springframework.http.server.ServletServerHttpRequest;\nimport org.springframework.web.socket.WebSocketHandler;\nimport org.springframework.web.socket.server.HandshakeInterceptor;\n\n \/**\n * \u63cf\u8ff0:\n * Socket\u5efa\u7acb\u8fde\u63a5\uff08\u63e1\u624b\uff09\u548c\u65ad\u5f00\n *\n * @author Msater Zg\n * @create 2018-01-24 10:49\n *\/\npublic class HandShake implements HandshakeInterceptor {\n    @Override\n    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,\n                                   Map&lt;String, Object> attributes) throws Exception {\n        \/**\n         * websocket\u7cfb\u7edf\u542f\u52a8\u8fde\u63a5\u7a0b\u5e8f\uff0c\u542f\u52a8\u7684\u65f6\u5019\u5c31\u4f1a\u628a\u4ed6\u7684session\u503c\u4f20\u8fc7\u6765\uff0c\u653e\u5165\u5230websocketsession\uff08websocket\u7684\u4e00\u4e2a\u5185\u7f6e\u670d\u52a1\u5668\uff09\u91cc\u9762\n         *\/\n        ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;\n        Long uid = Long.parseLong(servletRequest.getServletRequest().getParameter(\"uid\"));\n        if (uid != 0) {\n            attributes.put(\"uid\", uid);\n        } else {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,\n                               Exception exception) {\n    }\n}\n<\/pre>\n\n\n\n<ul><li>\u6d88\u606f\u63a8\u9001\u7684\u76f8\u5173\u7684\u540e\u53f0\u7684\u65b9\u6cd5<\/li><\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import java.io.IOException;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.socket.CloseStatus;\nimport org.springframework.web.socket.TextMessage;\nimport org.springframework.web.socket.WebSocketHandler;\nimport org.springframework.web.socket.WebSocketMessage;\nimport org.springframework.web.socket.WebSocketSession;\n\n  \/**\n * \u63cf\u8ff0:\n * Socket\u5904\u7406\u5668(\u5305\u62ec\u53d1\u9001\u4fe1\u606f\uff0c\u63a5\u6536\u4fe1\u606f\uff0c\u4fe1\u606f\u9519\u8bef\u7b49\u65b9\u6cd5\u3002)\n *\n * @author Msater Zg\n * @create 2018-01-24 10:49\n *\/\n@Component\npublic class MyWebSocketHandler implements WebSocketHandler {\n    \/**\n     * \u6700\u91cd\u8981\u7684websocket\u5904\u7406\u7a0b\u5e8f\uff08\u5305\u62ec\u53d1\u9001\u4fe1\u606f\uff0c\u63a5\u6536\u4fe1\u606f\uff0c\u4fe1\u606f\u9519\u8bef\u7b49\u65b9\u6cd5\u3002\uff09\n     *\/\n\n    \/**\n     * \u5148\u6ce8\u518c\u4e00\u4e2awebsocket\u670d\u52a1\u5668\uff0c\u5c06\u8fde\u63a5\u4e0a\u7684\u6240\u6709\u7528\u6237\u653e\u8fdb\u53bb\n     *\/\n    public static final Map&lt;Long, WebSocketSession> USER_SOCKET_SESSION_MAP;\n\n    static {\n        USER_SOCKET_SESSION_MAP = new HashMap&lt;Long, WebSocketSession>();\n    }\n\n    \/**\n     * \u524d\u53f0\u8fde\u63a5\u5e76\u4e14\u6ce8\u518c\u4e86\u8d26\u6237\n     *\/\n    @Override\n    public void afterConnectionEstablished(WebSocketSession session) throws Exception {\n        Long uid = (Long) session.getAttributes().get(\"uid\");\n        if (USER_SOCKET_SESSION_MAP.get(uid) == null) {\n            USER_SOCKET_SESSION_MAP.put(uid, session);\n        }\n    }\n\n    @Override\n    public void handleMessage(WebSocketSession session, WebSocketMessage&lt;?> message) throws Exception {\n        if (message.getPayloadLength() == 0) {\n            return;\n        }\n        NotificationMessage msg = new Gson().fromJson(message.getPayload().toString(), NotificationMessage.class);\n        msg.setDate(new Date());\n        sendMessageToUser(msg.getTo(), new TextMessage(new GsonBuilder().setDateFormat(\"yyyy-MM-dd HH:mm:ss\").create().toJson(msg)));\n    }\n\n    \/**\n     * \u6d88\u606f\u4f20\u8f93\u9519\u8bef\u5904\u7406\uff0c\u5982\u679c\u51fa\u73b0\u9519\u8bef\u76f4\u63a5\u65ad\u5f00\u8fde\u63a5\n     *\/\n    @Override\n    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {\n        if (session.isOpen()) {\n            session.close();\n        }\n        removeWebSocketUser(session);\n    }\n\n    \/**\n     * \u5173\u95ed\u8fde\u63a5\u540e\n     *\/\n    @Override\n    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {\n        System.out.println(\"Websocket:\" + session.getId() + \"\u5df2\u7ecf\u5173\u95ed\");\n        removeWebSocketUser(session);\n    }\n\n    @Override\n    public boolean supportsPartialMessages() {\n        return false;\n    }\n\n    \/**\n     * \u7ed9\u6240\u6709\u5728\u7ebf\u7528\u6237\u53d1\u9001\u6d88\u606f\n     *\n     * @param message\n     * @throws IOException\n     *\/\n    public void broadcast(final TextMessage message) throws IOException {\n        Iterator&lt;Entry&lt;Long, WebSocketSession>> it = USER_SOCKET_SESSION_MAP.entrySet().iterator();\n        \/\/ \u591a\u7ebf\u7a0b\u7fa4\u53d1\uff08\u7ed9\u6240\u6709\u5728\u7ebf\u7684\u7528\u6237\u53d1\u9001\u6d88\u606f\uff09  \u5148\u5224\u65ad\u662f\u5426\u91cc\u9762\u6709\u7528\u6237\uff08\uff09\u7136\u540e\u5faa\u73af\u53d1\u6d88\u606f\n        \/*\u540e\u53f0\u8c03\u7528sendMessage\u65b9\u6cd5\u7684\u65f6\u5019\uff0c\u524d\u53f0\u4f1a\u89e6\u53d1onmessage*\/\n        while (it.hasNext()) {\n            final Entry&lt;Long, WebSocketSession> entry = it.next();\n            if (entry.getValue().isOpen()) {\n                new Thread(new Runnable() {\n                    @Override\n                    public void run() {\n                        try {\n                            if (entry.getValue().isOpen()) {\n                                entry.getValue().sendMessage(message);\n                            }\n                        } catch (IOException e) {\n                            e.printStackTrace();\n                        }\n                    }\n                }).start();\n            }\n        }\n    }\n\n    \/**\n     * \u5355\u4e2a\u7528\u6237\u53d1\u6d88\u606f\n     *\n     * @param message\n     * @throws IOException\n     *\/\n    public void sendMessageToUser(Long uid, TextMessage message) throws IOException {\n        \/\/\u6839\u636e\u4f20\u8fc7\u6765\u7684\u8d26\u53f7\uff0c\u5728websocketseesion\u7684\u670d\u52a1\u5668\u91cc\u9762\u627e\uff0c\u63a5\u6536\u8005\u6ce8\u518c\u7684\u8d26\u53f7\n        WebSocketSession session = USER_SOCKET_SESSION_MAP.get(uid);\n        if (session != null &amp;&amp; session.isOpen()) {\n            session.sendMessage(message);\n        }\n    }\n\n    public void removeWebSocketUser(WebSocketSession session) {\n        Iterator&lt;Entry&lt;Long, WebSocketSession>> it = USER_SOCKET_SESSION_MAP.entrySet().iterator();\n        \/\/ \u79fb\u9664Socket\u4f1a\u8bdd\n        while (it.hasNext()) {\n            Entry&lt;Long, WebSocketSession> entry = it.next();\n            if (entry.getValue().getId().equals(session.getId())) {\n                USER_SOCKET_SESSION_MAP.remove(entry.getKey());\n                break;\n            }\n        }\n    }\n}\n<\/pre>\n\n\n\n<ul><li>\u6d88\u606f\u7c7b\uff08\u53ef\u6839\u636e\u4e0d\u540c\u7684\u9700\u6c42\u8fdb\u884c\u4fee\u6539\uff09<\/li><\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import java.util.Date;\n\/**\n * \u63cf\u8ff0:\n * \u6d88\u606f\u7c7b\n *\n * @author Msater Zg\n * @create 2018-02-24 10:49\n *\/\npublic class NotificationMessage {\n    \/**\n     * \u53d1\u9001\u8005\u8d26\u53f7\n     *\/\n    public Long from;\n    \/**\n     * \u53d1\u9001\u8005\u540d\u79f0\n     *\/\n    public String fromName;\n    \/**\n     * \u63a5\u6536\u8005\u8d26\u53f7\n     *\/\n    public Long to;\n    \/**\n     * \u53d1\u9001\u7684\u5185\u5bb9\n     *\/\n    public String text;\n    \/**\n     * \u53d1\u9001\u7684\u65e5\u671f\n     *\/\n    public Date date;\n\n    public Long getFrom() {\n        return from;\n    }\n\n    public void setFrom(Long from) {\n        this.from = from;\n    }\n\n    public Long getTo() {\n        return to;\n    }\n\n    public void setTo(Long to) {\n        this.to = to;\n    }\n\n    public String getText() {\n        return text;\n    }\n\n    public void setText(String text) {\n        this.text = text;\n    }\n\n    public String getFromName() {\n        return fromName;\n    }\n\n    public void setFromName(String fromName) {\n        this.fromName = fromName;\n    }\n\n    public Date getDate() {\n        return date;\n    }\n\n    public void setDate(Date date) {\n        this.date = date;\n    }\n}\n<\/pre>\n\n\n\n<p><strong>\u540e\u7eed<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>\u5927\u81f4\u539f\u7406\u5c31\u662f\u540e\u53f0\u542f\u52a8websocket\u670d\u52a1\uff0c\u524d\u7aef\u7528\u6237\u6ce8\u518c\u5e76\u5728websocket\u81ea\u5e26session\u670d\u52a1\u4e2d\u653e\u8fd9\u513f\u503c\uff0c\u800c\u540e\u7eed\u7684\u6d88\u606f\u53d1\u9001\uff0c\u5c31\u662f\u7ed9websocketsession\u4e2d\u7684\u7528\u6237\u53d1\u9001\u6d88\u606f\uff0c\u7136\u540e\u524d\u7aef\u8fdb\u884c\u54cd\u5e94\uff0c\u4ee5\u4e0a\u90fd\u662f\u81ea\u5df1\u4e00\u4e9b\u770b\u6cd5\uff0c\u6709\u4ec0\u4e48\u95ee\u9898\u8fd8\u5e0c\u671b\u6307\u51fa<\/p>\n\n\n\n<p>\u6700\u540e\u9644\u4e0a\u81ea\u5df1\u5c01\u88c5\u7684starter\u6e90\u7801git\u5730\u5740\uff08\u6b22\u8fcestar\uff09\uff1a<a rel=\"noreferrer noopener\" href=\"https:\/\/link.zhihu.com\/?target=https%3A\/\/github.com\/zg091418\/websocketspringbootstarter\" target=\"_blank\">https:\/\/github.com\/zg091418\/websocketspringbootstarter<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u8e29\u5751\u603b\u7ed3 \u56e0\u4e3a\u4e4b\u524d\u4ece\u6765\u6ca1\u6709\u63a5\u89e6\u8fc7\uff0c\u6240\u4ee5\u7f51\u4e0a\u627e\u4e86\u5f88\u591a\u6559\u7a0b\u6700\u540e\u53d1\u73b0\u90fd\u4e0d\u600e\u4e48\u5b8c\u6574\uff0c\u5927\u591a\u6570\u90fd\u662f\u76f4\u63a5\u5168\u76d8\u7167\u6284\u300aSprin [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26,27],"tags":[],"_links":{"self":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/7411"}],"collection":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7411"}],"version-history":[{"count":1,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/7411\/revisions"}],"predecessor-version":[{"id":7412,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/7411\/revisions\/7412"}],"wp:attachment":[{"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7411"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7411"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7411"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}