WebSocket简介
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
Websocket优点
Websocket优点
-
更强的实时性。由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少;即使是和Comet等类似的长轮询比较,其也能在短时间内更多次地传递数据。
-
保持连接状态。与HTTP不同的是,Websocket需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。而HTTP请求可能需要在每个请求都携带状态信息(如身份认证等)。
-
更好的二进制支持。Websocket定义了 二进制帧,相对HTTP,可以更轻松地处理二进制内容。
-
可以支持扩展。Websocket定义了扩展,用户可以扩展协议、实现部分自定义的子协议。如部分浏览器支持 压缩等。
下面实现我们的多人聊天室
简单看一下我们的效果
这里就是我们一个简单的效果
再来看一下具体是怎样实现的
1、首先创建我们的maven项目
2、导入我们的pom依赖
下面是我pom依赖的全部代码
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ybf</groupId> <artifactId>liaotianshi2</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- Spring Boot 启动父依赖 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.1.RELEASE</version> </parent> <properties> <!-- 项目设置 : 编码格式 UTF-8 及 springboot 相关版本 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <mybatis-spring-boot>1.2.0</mybatis-spring-boot> <mysql-connector>5.1.39</mysql-connector> <druid>1.0.18</druid> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <!-- Spring Boot Test 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <finalName>liaotianshi</finalName> </build> </project>
3、创建我们的SpringBootWebSocketHandler类
package com.ybf.test; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.WebSocketMessage; import org.springframework.web.socket.WebSocketSession; @Component public class SpringBootWebSocketHandler implements WebSocketHandler { // 存储所有客户端的会话 WebSocketSession,key 使用客户端的唯一标识方便存取 // private static Map<String, WebSocketSession> allWebSocketSession = new HashMap<String, WebSocketSession>(); private static List<WebSocketSession> sessionList = new ArrayList<>(); /** * 与服务器成功建立连接 */ @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { // TODO Auto-generated method stub System.out.println("客户端成功建立连接=>" + session.getId()); sessionList.add(session); } /** * 接受客户端的消息 */ @Override public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception { // 获取客户端的消息 String msg = message.getPayload().toString(); // System.out.println("接受到的客户端消息:" + msg); // 将数据存入会话 回传给客户端 // session.sendMessage(new TextMessage("服务器接收到的消息:" + msg)); sendMsg(msg); } //给所有客户端发信息的方法 private void sendMsg(String msg) throws IOException { for (WebSocketSession session : sessionList) { if(session.isOpen()) { session.sendMessage(new TextMessage(msg)); } } } /** * 通讯异常时 */ @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { // TODO Auto-generated method stub System.out.println("通讯出现异常"); } /** * 当连接关闭时 */ @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { // TODO Auto-generated method stub System.out.println("连接已关闭"); } /** * 是否允许分段发送 */ @Override public boolean supportsPartialMessages() { // 一次性发送 return false; } }
4、再来创建我们的SpringBootWebSocketConfigurer 类
package com.ybf.test; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.validation.MessageCodesResolver; import org.springframework.validation.Validator; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer; import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; @Configuration // 单例模式 bean @EnableWebSocket // 启动 WebSocket 服务器 public class SpringBootWebSocketConfigurer implements WebMvcConfigurer, WebSocketConfigurer { @Autowired private SpringBootWebSocketHandler handler; // @Autowired // private SpringBootHandshakeInterceptor handshakeInterceptor; @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { // -------------------- 允许跨域访问 WebSocket ------------------------ String[] allowsOrigins = { "*" };// 允许连接的域 , 只能以 http 或 https 开头 // 7. 设置 websocket 服务器地址 ws://localhost:8080/SpringBootWebSocket registry.addHandler(handler, "/SpringBootWebSocket").setAllowedOrigins(allowsOrigins); } /** * 这下面的代码是没有什么用的 * 主要是第一个方法 */ @Override public void configurePathMatch(PathMatchConfigurer configurer) { // TODO Auto-generated method stub } @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { // TODO Auto-generated method stub } @Override public void configureAsyncSupport(AsyncSupportConfigurer configurer) { // TODO Auto-generated method stub } @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { // TODO Auto-generated method stub } @Override public void addFormatters(FormatterRegistry registry) { // TODO Auto-generated method stub } @Override public void addInterceptors(InterceptorRegistry registry) { // TODO Auto-generated method stub } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // TODO Auto-generated method stub } @Override public void addCorsMappings(CorsRegistry registry) { // TODO Auto-generated method stub } @Override public void addViewControllers(ViewControllerRegistry registry) { // TODO Auto-generated method stub } @Override public void configureViewResolvers(ViewResolverRegistry registry) { // TODO Auto-generated method stub } @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { // TODO Auto-generated method stub } @Override public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) { // TODO Auto-generated method stub } @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { // TODO Auto-generated method stub } @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { // TODO Auto-generated method stub } @Override public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) { // TODO Auto-generated method stub } @Override public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) { // TODO Auto-generated method stub } @Override public Validator getValidator() { // TODO Auto-generated method stub return null; } @Override public MessageCodesResolver getMessageCodesResolver() { // TODO Auto-generated method stub return null; } }
5、创建我们的前台页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>聊天室</title> <link rel="stylesheet" href="layui/css/layui.css" media="all"> <script src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script> <script> $(document).ready( function() { var urlPrefix = "ws://localhost:8080/SpringBootWebSocket"; var ws = null; // 加入聊天室 $('#bt_join').click(function() { if(ws != null){ alert("用户【"+$('#username').val()+"】已加入连接"); return; } //建立连接 //判断当前浏览器是否支持WebSocket if ('WebSocket' in window) { ws = new WebSocket(urlPrefix); } else { alert('当前浏览器 Not support websocket'); } ws.onopen = function(event) { console.log("与服务器建立连接"); ws.send("您的好友【"+$('#username').val()+"】上线了"); }; // 接收服务端返回给前端的消息 ws.onmessage = function(event) { $('#text_chat_content').append( event.data + "\n"); }; ws.onclose = function() { console.log("与服务器断开连接"); $('#text_chat_content').append( "用户【" + $('#username').val() + "】离开聊天室!" + "\n"); $("#username").val(""); }; }); // 发送消息 $('#bt_send').click(function() { if (ws == null) { alert("该用户不在线"); return; } var msg = $('#in_msg').val(); ws.send("用户【" + $('#username').val() + "】:" + msg); }); // 离开聊天室 $('#bt_left').click(function() { ws.send("用户【" + $('#username').val() + "】离开聊天室!"); $('#in_msg').val(""); ws.close(); }); }) </script> </head> <body> 聊天消息内容: <br /> <textarea id="text_chat_content" readonly="readonly" class="layui-textarea" style="height: 400px; width: 600px;"></textarea> <br /> 输入框: <br /> <div class="layui-input-inline"> <textarea id="in_msg" placeholder="请输入内容" class="layui-textarea" style="height: 100px; width: 500px;"> </textarea> </div> <button type="button" id="bt_send" class="layui-btn layui-btn-radius">发送信息</button> <br /> <br /> <label class="layui-form-mid">用户:</label> <div class="layui-input-inline"> <input type="text" id="username" placeholder="请输入姓名" class="layui-input"> </div> <button type="button" id="bt_join" class="layui-btn layui-btn-radius layui-btn-normal">加入聊天室</button> <button type="button" id="bt_left" class="layui-btn layui-btn-radius layui-btn-normal">离开聊天室</button> </body> </html>
注意:
我这里是加的 layui 效果,当然也可以不加layui效果,这就看自己的意思了
这是 layui 官网地址 https://www.layui.com/ 大家有兴趣可以了解一下
下面就是我的项目框架