# ws-onlinechat **Repository Path**: imoder/ws-onlinechat ## Basic Information - **Project Name**: ws-onlinechat - **Description**: 基于SSM框架的WebSocket网页实时聊天界面实现简易版! - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: http://39.99.136.11/onlinechat/ - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 0 - **Created**: 2021-01-27 - **Last Updated**: 2022-01-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # WebSocket # 0 demo演示 ## 0.0 目的 > 学习学习学习 > 前端页面用了我N多的时间还是如此丑,,,,,,,,,,,ヽ(•ω•。)ノ > 只是为了展示最基本功能,因此bug多多 ## 0.1 项目演示 > http://39.99.136.11/onlinechat/ > > 网页打开,该服务器将于21年3月到期。 ## 0.2 项目源代码 > https://gitee.com/imoder/ws-onlinechat ## 0.3 前端页面展示 - 首先进行登录,==name无所谓,密码123456== ![](readme.assets/Snipaste_2021-01-28_19-11-50.png) - 实时聊天界面(有点粗糙,以后再改改?想多了( ̄︶ ̄)↗) ![](readme.assets/Snipaste_2021-01-28_19-24-56.png) ![](readme.assets/2021-01-28_192558.png) ![](readme.assets/2021-01-28_192651.png) # 1 WebSocket技术介绍 ## 1.1 WebSocket? - WebSocket是HTML5开始提供的一种在单个TCP连接上进行==全双工通讯的**协议**==。WebSocket使得客户端和服务器之间的数据交换变得更加简单,==允许服务端主动向客户端推送数据==。在 WebSocket API 中浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接并进行双向数据传输。 - 网站为了实现推送技术,所用的技术都是==Ajax轮询==,轮询是在特定的的时间间隔,浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器,这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。HTML5 定义的WebSocket 协议能更好的节省服务器资源和带宽,并且能够更==**实时地进行通讯**==; ## 1.2 与HTTP协议的区别与联系 - WebSocket是独立的、创建在TCP上的协议,**但是Websocket的握手(handshanking)是通过HTTP/1.1协议的101状态码进行的**; - 数据格式更加的轻量化,性能开销小,客户端与服务端进行数据交换时,服务端到客户端的数据包头只有2到10字节,客户端到服务端需要加上另外4字节的掩码,而HTTP每次都需要携带完整头部。 - 更好的二进制支持,可以发送文本,和二进制数据,没有同源限制,客户端可以与任意服务器通信; - 协议标识符是ws(或wss),请求的地址就是后端支持websocket的API; - 地址格式:ws://localhost:3000/websocket; ![image-20210128194934941](readme.assets/image-20210128194934941.png) ## 1.3 WebSocket API | 属性 | 描述 | | --------------------- | ------------------------------------------------------------ | | Socket.readyState | 只读属性 **readyState** 表示连接状态: 0 - 表示连接尚未建立。 1 - 表示连接已建立,可以进行通信。 2 - 表示连接正在进行关闭。 3 - 表示连接已经关闭或者连接不能打开。 | | Socket.bufferedAmount | 只读属性 **bufferedAmount** 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。 | | 事件 | 事件处理程序 | 描述 | | ------- | ---------------- | -------------------------- | | open | Socket.onopen | 连接建立时触发 | | message | Socket.onmessage | 客户端接收服务端数据时触发 | | error | Socket.onerror | 通信发生错误时触发 | | close | Socket.onclose | 连接关闭时触发 | | 方法 | 描述 | | -------------- | ---------------- | | Socket.send() | 使用连接发送数据 | | Socket.close() | 关闭连接 | - 参考:https://developer.mozilla.org/zh-cn/docs/web/api/websocket ## 1.4 典型的WebSocket请求格式 - Websocket 使用和HTTP相同的TCP端口,可以绕过大多数防火墙的限制。默认情况下Websocket协议使用80端口,运行在TLS之上时默认使用443端口。 - 一个典型的Websocket握手请求如下: ```http //client GET / HTTP/1.1 Upgrade: websocket Connection: Upgrade Host: example.com Origin: http://example.com Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ== Sec-WebSocket-Version: 13 ``` ```html //server HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s= Sec-WebSocket-Location: ws://example.com/ ``` > Connection:Upgrade表示客户端希望连接升级。 > > Upgrade:Websocket表示希望升级到Websocket协议。 > > Sec-WebSocket-Key是随机字符串,用它加上特殊字符串 “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,然后计算SHA-1摘要,之后进行BASE-64编码,将结果做为 “Sec-WebSocket-Accept” 头的值返回给客户端。如此操作可以尽量避免普通 HTTP请求被误认为 Websocket 协议。 > > Sec-WebSocket-Version表示支持的 Websocket 版本,RFC6455 要求使用的版本是 13,之前草案的版本均应当弃用。 ## 1.5 主流服务器对WebSocket协议的支持 ```properties php - http://code.google.com/p/phpwebsocket/ jetty - http://jetty.codehaus.org/jetty/(version 7+) netty - http://www.jboss.org/netty ruby - http://github.com/gimite/web-socket-ruby Tomcat - http://tomcat.apache.org/(7.0.27+,建议用tomcat8+) node.js - https://github.com/Worlize/WebSocket-Node node.js - http://socket.io nginx - http://nginx.com/ mojolicious - http://mojolicio.us/ python - https://github.com/abourget/gevent-socketio Django - https://github.com/stephenmcd/django-socketio erlang - https://github.com/ninenines/cowboy.git ``` ## 1.6 参考链接 >https://baike.baidu.com/item/WebSocket/1953845?fr=aladdin > >https://www.runoob.com/html/html5-websocket.html > >https://developer.mozilla.org/zh-cn/docs/web/api/websocket > >https://developer.mozilla.org/zh-CN/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications > >http://tomcat.apache.org/ > >https://www.zhihu.com/question/20215561 # 2 基于SSM的WebScoket的配置 ## 2.1 项目结构 - 需要说明的是,由于只是做技术演示,所以只展示了最基本的基于WebSocket的实时通信功能,其他的功能并没有完善(有时间再填坑(づ ̄3 ̄)づ╭❤~),所以有些文件目录看起来有些多余。 ![image-20210127230655464](readme.assets/image-20210127230655464.png) ## 2.2 项目逻辑说明 - 都在酒里了。 ## 2.3 配置 - **后端配置** - ==WebSockketConfig==配置文件:目的是为了使SSM框架开启WebScoket支持,并注册相应的请求句柄(路径); - 前端的请求路径是: ```properties ws://localhost:80/onlinechat/websocket ``` ![image-20210127231202684](readme.assets/image-20210127231202684.png) - ==WebSocketHandShakeInterceptor==拦截器:目的是为了拦截WebSocket请求;并在spring的配置文件中加入该拦截器配置。 - some talk 见注释。 ![image-20210127231658725](readme.assets/image-20210127231658725.png) ![image-20210127231936490](readme.assets/image-20210127231936490.png) - ==OnlineChatWebScoketHandler==控制器文件:这个就是后台处理WebSocket请求的主要文件了,相当于SSM中的一个Controller; - 通过重写下面的几个方法来实现连接、消息、关闭和异常处理的基本功能; ```java public class OnlineChatWebScoketHandle implements WebSocketHandler { @Override public void afterConnectionEstablished(WebSocketSession session) { //onopen handler } @Override public void handleMessage(WebSocketSession session, WebSocketMessage msg) { //opmessage hanlder } @Override public void handleTransportError(WebSocketSession session, Throwable exc) { //onerror handler } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus cs){ //onclose handler } @Override public boolean supportsPartialMessages() { return false; } } ``` - **前端配置** - 前端主要是获取一个指定格式的webscoket,通过对应的方法来监听相应的事件并进行有关的页面处理; ```js //websocket!!! function webSocket(userSelf) { /*Consider browser compatibility*/ /*Maybe you can use *sockJS* instead for this!*/ if ('WebSocket' in window) { ws = new WebSocket("ws://localhost:80/onlinechat/websocket"); } else if ('MozWebSocket' in window) { ws = new MozWebSocket("ws://localhost:8080/onlinechat/websocket"); } else { console.warn("当前浏览器不支持websocket original API!"); ws = new SockJS("ws://localhost:8080/onlinechat/sockjs/websocket"); } ws.onopen = function (evt) { //此处处理webscoket连接时的信息,因此可以拿到所有和连接有关的信息 //不再作相应的处理 console.log(evt.target); }; ws.onmessage = function (evt) {}; ws.onclose = function (evt) {}; ws.onerror = function (evt) {}; ws.onclose = function (evt) {} } ``` - 有用的参考 > https://blog.csdn.net/ouyang111222/article/details/50545411 >https://blog.csdn.net/zxwu_1993/article/details/81034087 # 4 tips - Jq找到父元素下包含某一指定class的子元素: ```js $("#onlineuser-list").children(".active"); ``` - Jq实时对话框始终保持滚动条在最下边: ```js $("#msg-box").scrollTop($("#msg-box")[0].scrollHeight) ``` - Map中删除指定value的项: ```java map.keySet().removeIf(next -> Objects.equals(map.get(next), "ccc")); ``` # 5 bug时间 ## 5.1后端无法接受来自Ajax的页面请求 > 可能是使用的Jquery库有问题,比如说本应用使用了Bootstrap前端模板库,默认导入的Jquery库是: ```properties