[WebSocket长连接]SpringBoot2.0集成WebSocket,实现后台向前端推送信息
感谢作者,支持原创: https://blog.csdn.net/moshowgame/article/details/80275084
什么是WebSocket?
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
为什么需要 WebSocket?
初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HTTP 协议,为什么还需要另一个协议?它能带来什么好处?
- 答案很简单,因为 HTTP 协议有一个缺陷:通信只能由客户端发起,HTTP 协议做不到服务器主动向客户端推送信息。
举例来说,我们想要查询当前的排队情况,只能是页面轮询向服务器发出请求,服务器返回查询结果。轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。因此WebSocket 就是这样发明的。
Maven依赖
1 <!--springboot的高级组件会自动引用基础的组件--> 2 <!--,像spring-boot-starter-websocket就引入了spring-boot-starter-web和spring-boot-starter,--> 3 <!--所以不要重复引入。--> 4 <!--JavaEE标准--> 5 <dependency> 6 <groupId>javax</groupId> 7 <artifactId>javaee-api</artifactId> 8 <scope>provided</scope> 9 </dependency> 10 <!--websocket--> 11 <dependency> 12 <groupId>org.springframework.boot</groupId> 13 <artifactId>spring-boot-starter-websocket</artifactId> 14 </dependency>
WebSocket配置类
1 package com.zr.demo.config; 2 3 import org.springframework.context.annotation.Bean; 4 import org.springframework.context.annotation.Configuration; 5 import org.springframework.web.socket.server.standard.ServerEndpointExporter; 6 7 /** 8 * @Author: Hujh 9 * @Date: 2019/7/16 11:10 10 * @Description: WebSocket配置类 11 */ 12 @Configuration 13 public class WebSocketConfig { 14 15 /*使用@ServerEndpoint创立websocket endpoint*/ 16 @Bean 17 public ServerEndpointExporter serverEndpointExporter() { 18 return new ServerEndpointExporter(); 19 } 20 }
WebSocketServer
因为WebSocket是类似客户端服务端的形式(采用ws协议),那么这里的WebSocketServer其实就相当于一个ws协议的Controller直接@ServerEndpoint("/websocket")@Component启用即可,然后在里面实现@OnOpen,@onClose,@onMessage等方法
1 package com.zr.demo.socket; 2 3 import org.springframework.stereotype.Component; 4 5 import javax.websocket.OnClose; 6 import javax.websocket.OnMessage; 7 import javax.websocket.OnOpen; 8 import javax.websocket.Session; 9 import javax.websocket.server.ServerEndpoint; 10 import java.io.IOException; 11 import java.util.concurrent.CopyOnWriteArraySet; 12 13 /** 14 * @Author: Hujh 15 * @Date: 2019/7/16 11:13 16 * @Description: webSocket实现类 17 */ 18 @ServerEndpoint(value = "/webSocket") 19 @Component 20 public class WebSocket { 21 //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 22 private static int onlineCount = 0; 23 24 //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。 25 private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<WebSocket>(); 26 27 //与某个客户端的连接会话,需要通过它来给客户端发送数据 28 private Session session; 29 30 /** 31 * 连接建立成功调用的方法 32 */ 33 @OnOpen 34 public void onOpen(Session session) { 35 this.session = session; //加入set中 36 webSocketSet.add(this); 37 addOnlineCount(); //在线数加1 38 System.out.println("有新连接加入!当前在线人数为:" + getOnlineCount()); 39 try { 40 sendMessage("连接成功"); 41 } catch (IOException e) { 42 System.out.println("IO异常"); 43 } 44 } 45 46 /** 47 * 连接关闭调用的方法 48 */ 49 @OnClose 50 public void onClose() { 51 webSocketSet.remove(this); //从set中删除 52 subOnlineCount(); //在线数减1 53 System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); 54 } 55 56 /** 57 * 收到客户端消息后调用的方法 58 * @param message 客户端发送过来的消息 59 */ 60 @OnMessage 61 public void onMessage(String message, Session session) { 62 System.out.println("来自客户端的消息:" + message); 63 64 //群发消息 65 for (WebSocket item : webSocketSet) { 66 try { 67 item.sendMessage(message); 68 } catch (IOException e) { 69 e.printStackTrace(); 70 } 71 } 72 } 73 74 /** 75 * 发生错误时调用 76 @OnError 77 */ 78 public void onError(Session session, Throwable error) { 79 System.out.println("发生错误"); 80 error.printStackTrace(); 81 } 82 83 /* 84 * @Title: sendMessage 85 * @Author : Hujh 86 * @Date: 2019/7/17 10:52 87 * @Description : 发送消息 88 * @param : message 89 * @Return : void 90 */ 91 public void sendMessage(String message) throws IOException { 92 this.session.getBasicRemote().sendText(message); 93 //this.session.getAsyncRemote().sendText(message); 94 } 95 96 97 /* 98 * @Title: sendInfo 99 * @Author : Hujh 100 * @Date: 2019/7/17 10:52 101 * @Description : 群发自定义消息 102 * @param : message 103 * @Return : void 104 */ 105 public static void sendInfo(String message) throws IOException { 106 for (WebSocket item : webSocketSet) { 107 try { 108 item.sendMessage(message); 109 } catch (IOException e) { 110 continue; 111 } 112 } 113 } 114 115 /* 116 * @Title: getOnlineCount 117 * @Author : Hujh 118 * @Date: 2019/7/17 10:51 119 * @Description : 获得当前在线人数 120 * @param : 121 * @Return : int 122 */ 123 public static synchronized int getOnlineCount() { 124 return onlineCount; 125 } 126 127 /* 128 * @Title: addOnlineCount 129 * @Author : Hujh 130 * @Date: 2019/7/17 10:51 131 * @Description : 在线人数+1 132 * @param : 133 * @Return : void 134 */ 135 public static synchronized void addOnlineCount() { 136 WebSocket.onlineCount++; 137 } 138 139 /* 140 * @Title: subOnlineCount 141 * @Author : Hujh 142 * @Date: 2019/7/17 10:52 143 * @Description :在线人数-1 144 * @param : 145 * @Return : void 146 */ 147 public static synchronized void subOnlineCount() { 148 WebSocket.onlineCount--; 149 } 150 151 }
消息推送
至于推送新信息,可以再自己的Controller写个方法调用WebSocket.sendInfo();
1 package com.zr.demo.controller; 2 3 import com.zr.demo.socket.WebSocket; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.web.bind.annotation.RequestMapping; 6 import org.springframework.web.bind.annotation.RequestParam; 7 import org.springframework.web.bind.annotation.RestController; 8 9 /** 10 * @Author: Hujh 11 * @Date: 2019/7/19 15:40 12 * @Description: 消息发送控制器 13 */ 14 @RestController 15 public class SendMessageController { 16 17 @Autowired 18 private WebSocket webSocket; 19 20 @RequestMapping("sendInfo") 21 public String sendInfo(@RequestParam String msg) { 22 try { 23 webSocket.sendInfo(msg); 24 } catch (Exception e) { 25 e.printStackTrace(); 26 return "信息发送异常!"; 27 } 28 29 return "发送成功~"; 30 } 31 32 }
页面代码
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>WebSocket</title> 5 </head> 6 7 <body> 8 <div style="width: 800px;height: 100%; margin: 0px auto;"> 9 <span style="color: coral; font-size: 22px;"> Welcome WebSocket</span><br/><br/> 10 <div id="message"> 11 </div> 12 </div> 13 </body> 14 15 <script type="text/javascript"> 16 var websocket = null; 17 //判断当前浏览器是否支持WebSocket 18 if('WebSocket' in window){ 19 websocket = new WebSocket("ws://localhost:8082/webSocket"); 20 }else{ 21 alert('连接失败!!') 22 } 23 24 //连接发生错误的回调方法 25 websocket.onerror = function(){ 26 setMessageInnerHTML("error"); 27 }; 28 29 //连接成功建立的回调方法 30 websocket.onopen = function(event){ 31 setMessageInnerHTML("webSocket 连接成功~"); 32 } 33 34 //接收到消息的回调方法 35 websocket.onmessage = function(event){ 36 setMessageInnerHTML(event.data); 37 } 38 39 //连接关闭的回调方法 40 websocket.onclose = function(){ 41 setMessageInnerHTML("close"); 42 } 43 44 //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接, 45 // 防止连接还没断开就关闭窗口,server端会抛异常。 46 window.onbeforeunload = function(){ 47 websocket.close(); 48 } 49 50 //将消息显示在网页上 51 function setMessageInnerHTML(innerHTML){ 52 document.getElementById('message').innerHTML += innerHTML + '<br/>'; 53 } 54 55 //关闭连接 56 function closeWebSocket(){ 57 websocket.close(); 58 } 59 60 61 </script> 62 </html>
测试效果
1.建立两个连接
2.消息推送
注:本文仅作为个人学习记录,不提供任何参考价值!