Springboot整合Websocket实现后端向前端主动推送消息案例
16lz
2021-01-22
在手机上相信都有来自服务器的推送消息,比如一些及时的新闻信息,这篇文章主要就是实现这个功能,只演示一个基本的案例。使用的是websocket技术。
一、什么是websocket
WebSocket协议是基于TCP的一种新的网络协议。它实现了客户端与服务器全双工通信,学过计算机网络都知道,既然是全双工,就说明了服务器可以主动发送信息给客户端。这与我们的推送技术或者是多人在线聊天的功能不谋而合。
为什么不使用HTTP 协议呢?这是因为HTTP是单工通信,通信只能由客户端发起,客户端请求一下,服务器处理一下,这就太麻烦了。于是websocket应运而生。
下面我们就直接开始使用Springboot开始整合。以下案例都在我自己的电脑上测试成功,你可以根据自己的功能进行修改即可。
二、整合websocket
1、环境配置
名称 | 版本 |
---|---|
Idea | 2018专业版(已破解) |
Maven | 4.0.0 |
SpringBoot | 2.2.2 |
websocket | 2.1.3 |
jdk | 1.8 |
下面我们新建一个普通的Springboot项目。
2、添加依赖
1 <dependencies>
2 <dependency>
3 <groupId>org.springframework.boot</groupId>
4 <artifactId>spring-boot-starter-web</artifactId>
5 </dependency>
6 <dependency>
7 <groupId>org.springframework.boot</groupId>
8 <artifactId>spring-boot-starter-test</artifactId>
9 <scope>test</scope>
10 </dependency>
11 <dependency>
12 <groupId>org.springframework.boot</groupId>
13 <artifactId>spring-boot-starter-websocket</artifactId>
14 <version>2.1.3.RELEASE</version>
15 </dependency>
16 </dependencies>
3、在application.properties文件修改端口号
一句话:server.port=8081
4、新建config包,创建WebSocketConfig类
1@Configuration
2public class WebSocketConfig {
3 @Bean
4 public ServerEndpointExporter serverEndpointExporter() {
5 return new ServerEndpointExporter();
6 }
7}
5、新建service包,创建WebSocketServer类
1@ServerEndpoint("/websocket/{sid}")
2@Component
3public class WebSocketServer {
4 static Log log= LogFactory.getLog(WebSocketServer.class);
5 //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
6 private static int onlineCount = 0;
7 //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
8 private static CopyOnWriteArraySet<WebSocketServer> webSocketSet
9 = new CopyOnWriteArraySet<WebSocketServer>();
10 //与某个客户端的连接会话,需要通过它来给客户端发送数据
11 private Session session;
12 //接收sid
13 private String sid="";
14 /**
15 * 连接建立成功调用的方法
16 */
17 @OnOpen
18 public void onOpen(Session session,@PathParam("sid") String sid) {
19 this.session = session;
20 webSocketSet.add(this); //加入set中
21 addOnlineCount(); //在线数加1
22 log.info("有新窗口开始监听:"+sid+",当前在线人数为" + getOnlineCount());
23 this.sid=sid;
24 try {
25 sendMessage("连接成功");
26 } catch (IOException e) {
27 log.error("websocket IO异常");
28 }
29 }
30 /**
31 * 连接关闭调用的方法
32 */
33 @OnClose
34 public void onClose() {
35 webSocketSet.remove(this); //从set中删除
36 subOnlineCount(); //在线数减1
37 log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
38 }
39 /**
40 * 收到客户端消息后调用的方法
41 * @param message 客户端发送过来的消息
42 */
43 @OnMessage
44 public void onMessage(String message, Session session) {
45 log.info("收到来自窗口"+sid+"的信息:"+message);
46 //群发消息
47 for (WebSocketServer item : webSocketSet) {
48 try {
49 item.sendMessage(message);
50 } catch (IOException e) {
51 e.printStackTrace();
52 }
53 }
54 }
55 @OnError
56 public void onError(Session session, Throwable error) {
57 log.error("发生错误");
58 error.printStackTrace();
59 }
60 //实现服务器主动推送
61 public void sendMessage(String message) throws IOException {
62 this.session.getBasicRemote().sendText(message);
63 }
64 //群发自定义消息
65 public static void sendInfo(String message,@PathParam("sid") String sid)
66 throws IOException {
67 log.info("推送消息到窗口"+sid+",推送内容:"+message);
68 for (WebSocketServer item : webSocketSet) {
69 try {
70 //这里可以设定只推送给这个sid的,为null则全部推送
71 if(sid==null) {
72 item.sendMessage(message);
73 }else if(item.sid.equals(sid)){
74 item.sendMessage(message);
75 }
76 } catch (IOException e) {
77 continue;
78 }
79 }
80 }
81 public static synchronized int getOnlineCount() {
82 return onlineCount;
83 }
84 public static synchronized void addOnlineCount() {
85 WebSocketServer.onlineCount++;
86 }
87 public static synchronized void subOnlineCount() {
88 WebSocketServer.onlineCount--;
89 }
90}
6、新建controller包,创建Mycontroller类
1@Controller
2public class MyController {
3 //页面请求
4 @GetMapping("/socket/{cid}")
5 public ModelAndView socket(@PathVariable String cid) {
6 ModelAndView mav=new ModelAndView("/socket");
7 mav.addObject("cid", cid);
8 return mav;
9 }
10 //推送数据接口
11 @ResponseBody
12 @RequestMapping("/socket/push/{cid}")
13 public String pushToWeb(@PathVariable String cid,String message) {
14 try {
15 WebSocketServer.sendInfo(message,cid);
16 } catch (IOException e) {
17 e.printStackTrace();
18 return "推送失败";
19 }
20 return "发送成功";
21 }
22}
7、新建一个websocket.html页面
1<html>
2<head>
3 <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
4 <script type="text/javascript">
5 var socket;
6 if (typeof (WebSocket) == "undefined") {
7 console.log("您的浏览器不支持WebSocket");
8 } else {
9 console.log("您的浏览器支持WebSocket");
10 //实现化WebSocket对象,指定要连接的服务器地址与端口 建立连接
11 socket = new WebSocket("ws://localhost:8081/websocket/1");
12 //打开事件
13 socket.onopen = function () {
14 console.log("Socket 已打开");
15 socket.send("这是来自客户端的消息" + location.href + new Date());
16 };
17 //获得消息事件
18 socket.onmessage = function (msg) {
19 console.log(msg.data);
20 };
21 //关闭事件
22 socket.onclose = function () {
23 console.log("Socket已关闭");
24 };
25 //发生了错误事件
26 socket.onerror = function () {
27 alert("Socket发生了错误");
28 }
29 }
30 </script>
31</head>
32</html>
现在开发服务器和网页就可以看到效果了。一般情况下Springboot2+Netty+Websocket的组合方式更加的常用一下。这个只是给出了一个基本的案例,你可以根据自己的需求进行更改。
更多相关文章
- 微信公众号自动回复图文消息
- 客户端请求服务器时的状态码讲解
- 推荐一款神仙颜值的 ZooKeeper 客户端工具
- Node.js如何将Ajax成功消息传递给app.js
- 使用Selectize和Ajax时,在Bootstrap模式中显示Rails错误消息
- 当AJAX响应来自PHP文件时,如何显示以消息为中心的加载器图像&防止
- 关于 客户端发现响应内容类型为“text/html; charset=utf-8”,但
- Jquery - 表单验证,为错误消息添加css样式
- HTML5 windows和iframe之间传递消息