作者 | 大树先生

来源 | https://blog.csdn.net/MacWx/article/details/111319558

前言

在一次项目开发中,使用到了Netty网络应用框架,以及MQTT进行消息数据的收发,这其中需要后台来将获取到的消息主动推送给前端,于是就使用到了MQTT,特此记录一下。

一、什么是websocket?

WebSocket协议是基于TCP的一种新的网络协议。它实现了客户端与服务器全双工通信,学过计算机网络都知道,既然是全双工,就说明了服务器可以主动发送信息给客户端。这与我们的推送技术或者是多人在线聊天的功能不谋而合。

百度网盘再次回收免费空间!21日前赶紧登录下!网友评:想钱想疯了?

为什么不使用HTTP 协议呢?这是因为HTTP是单工通信,通信只能由客户端发起,客户端请求一下,服务器处理一下,这就太麻烦了。于是websocket应运而生。

从 HTTP 到 HTTP/3 的发展简史

下面我们就直接开始使用Springboot开始整合。以下案例都在我自己的电脑上测试成功,你可以根据自己的功能进行修改即可。我的项目结构如下:

二、使用步骤

1.添加依赖

Maven依赖:

 <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-websocket</artifactId>  </dependency>

2.启用Springboot对WebSocket的支持

启用WebSocket的支持也是很简单,几句代码搞定:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/*** @ Auther: 马超伟* @ Date: 2020/06/16/14:35* @ Description: 开启WebSocket支持*/
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

3.核心配置:WebSocketServer

因为WebSocket是类似客户端服务端的形式(采用ws协议),那么这里的WebSocketServer其实就相当于一个ws协议的Controller

  • @ ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端, 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端

  • 新建一个ConcurrentHashMap webSocketMap 用于接收当前userId的WebSocket,方便传递之间对userId进行推送消息。

下面是具体业务代码:

package cc.mrbird.febs.external.webScoket;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;/*** Created with IntelliJ IDEA.* @ Auther: 马超伟* @ Date: 2020/06/16/14:35* @ Description:* @ ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端*/
@Component
@Slf4j
@Service
@ServerEndpoint("/api/websocket/{sid}")
public class WebSocketServer {//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。private static int onlineCount = 0;//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();//与某个客户端的连接会话,需要通过它来给客户端发送数据private Session session;//接收sidprivate String sid = "";/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("sid") String sid) {this.session = session;webSocketSet.add(this);     //加入set中this.sid = sid;addOnlineCount();           //在线数加1try {sendMessage("conn_success");log.info("有新窗口开始监听:" + sid + ",当前在线人数为:" + getOnlineCount());} catch (IOException e) {log.error("websocket IO Exception");}}/*** 连接关闭调用的方法*/@OnClosepublic void onClose() {webSocketSet.remove(this);  //从set中删除subOnlineCount();           //在线数减1//断开连接情况下,更新主板占用情况为释放log.info("释放的sid为:"+sid);//这里写你 释放的时候,要处理的业务log.info("有一连接关闭!当前在线人数为" + getOnlineCount());}/*** 收到客户端消息后调用的方法* @ Param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session) {log.info("收到来自窗口" + sid + "的信息:" + message);//群发消息for (WebSocketServer item : webSocketSet) {try {item.sendMessage(message);} catch (IOException e) {e.printStackTrace();}}}/*** @ Param session* @ Param error*/@OnErrorpublic void onError(Session session, Throwable error) {log.error("发生错误");error.printStackTrace();}/*** 实现服务器主动推送*/public void sendMessage(String message) throws IOException {this.session.getBasicRemote().sendText(message);}/*** 群发自定义消息*/public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {log.info("推送消息到窗口" + sid + ",推送内容:" + message);for (WebSocketServer item : webSocketSet) {try {//这里可以设定只推送给这个sid的,为null则全部推送if (sid == null) {
//                    item.sendMessage(message);} else if (item.sid.equals(sid)) {item.sendMessage(message);}} catch (IOException e) {continue;}}}public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {WebSocketServer.onlineCount++;}public static synchronized void subOnlineCount() {WebSocketServer.onlineCount--;}public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {return webSocketSet;}
}

4.测试Controller

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;import java.io.IOException;
import java.util.HashMap;
import java.util.Map;/*** Created with IntelliJ IDEA.** @ Auther: 马超伟* @ Date: 2020/06/16/14:38* @ Description:*/
@Controller("web_Scoket_system")
@RequestMapping("/api/socket")
public class SystemController {//页面请求@GetMapping("/index/{userId}")public ModelAndView socket(@PathVariable String userId) {ModelAndView mav = new ModelAndView("/socket1");mav.addObject("userId", userId);return mav;}//推送数据接口@ResponseBody@RequestMapping("/socket/push/{cid}")public Map pushToWeb(@PathVariable String cid, String message) {Map<String,Object> result = new HashMap<>();try {WebSocketServer.sendInfo(message, cid);result.put("code", cid);result.put("msg", message);} catch (IOException e) {e.printStackTrace();}return result;}
}

5.测试页面index.html

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Java后端WebSocket的Tomcat实现</title><script type="text/javascript" src="js/jquery.min.js"></script></head><body><div id="main" style="width: 1200px;height:800px;"></div>Welcome<br/><input id="text" type="text" /><button onclick="send()">发送消息</button><hr/><button onclick="closeWebSocket()">关闭WebSocket连接</button><hr/><div id="message"></div></body><script type="text/javascript">var websocket = null;//判断当前浏览器是否支持WebSocketif('WebSocket' in window) {//改成你的地址websocket = new WebSocket("ws://192.168.100.196:8082/api/websocket/100");} else {alert('当前浏览器 Not support websocket')}//连接发生错误的回调方法websocket.onerror = function() {setMessageInnerHTML("WebSocket连接发生错误");};//连接成功建立的回调方法websocket.onopen = function() {setMessageInnerHTML("WebSocket连接成功");}var U01data, Uidata, Usdata//接收到消息的回调方法websocket.onmessage = function(event) {console.log(event);setMessageInnerHTML(event);setechart()}//连接关闭的回调方法websocket.onclose = function() {setMessageInnerHTML("WebSocket连接关闭");}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function() {closeWebSocket();}//将消息显示在网页上function setMessageInnerHTML(innerHTML) {document.getElementById('message').innerHTML += innerHTML + '<br/>';}//关闭WebSocket连接function closeWebSocket() {websocket.close();}//发送消息function send() {var message = document.getElementById('text').value;websocket.send('{"msg":"' + message + '"}');setMessageInnerHTML(message + "
");}</script></html>

6.结果展示

后台:如果有连接请求

他总在逆风翻盘,绝地反击!最不爱钱却成了最有钱的人...

前台显示:

开发文件上传功能稍不注意就会引发安全漏洞

总结

这中间我遇到一个问题,就是说WebSocket启动的时候优先于spring容器,从而导致在WebSocketServer中调用业务Service会报空指针异常

所以需要在WebSocketServer中将所需要用到的service给静态初始化一下:如图所示:

IDEA不能一个窗口管理多个项目?那是你不会用!

还需要做如下配置:

往期推荐

百度网盘再次回收免费空间!21日前赶紧登录下!网友评:想钱想疯了?

从 HTTP 到 HTTP/3 的发展简史

他总在逆风翻盘,绝地反击!最不爱钱却成了最有钱的人...

开发文件上传功能稍不注意就会引发安全漏洞

IDEA不能一个窗口管理多个项目?那是你不会用!

Nacos 惊爆安全漏洞,可绕过身份验证(附修复建议)

SpringBoot集成WebSocket,实现后台向前端推送信息相关推荐

  1. SpringBoot2.0集成WebSocket,实现后台向前端推送信息

    SpringBoot+WebSocket集成 什么是WebSocket? 为什么需要 WebSocket? 前言 maven依赖 WebSocketConfig WebSocketServer 消息推 ...

  2. SpringBoot 集成 WebSocket,实现后台向前端推送信息

    作者 | 大树先生 来源 | https://blog.csdn.net/MacWx/article/details/111319558 前言 在一次项目开发中,使用到了Netty网络应用框架,以及M ...

  3. WebSocket + SpringBoot + VUE实现后端实时向前端推送消息

    一.目的 众所周知,正常来说在前后端通信中,后端往往处于一个被动的状态,对前端的请求作出对应的响应.但有的时候我们会遇到需要后端前前端推送数据的需求,比如消息.邮件等的推送.这个时候,实现的一种方式是 ...

  4. websocket 本地可以服务器断开 springboot linux_SpringBoot+WebSocket实现简单的数据推送...

    问题背景 为什么要要用websocket呢?websocket相对于传统http协议有什么优势呢? http协议有一个缺陷,就是通信只能由客户端发起,服务器返回数据,不能做到服务器主动向客户端推送.这 ...

  5. springboot集成MQTT协议实现消息实时推送(未实现版)

    <!--mqtt依赖包--><dependency><groupId>org.springframework.integration</groupId> ...

  6. SpringBoot 集成 webSocket,实现后台向客户端推送消息

    图文等内容参考链接 SpringBoot2.0集成WebSocket,实现后台向前端推送信息_Moshow郑锴的博客-CSDN博客_springboot websocket WebSocket 简介 ...

  7. SpringBoot+Vue整合WebSocket实现前后端消息推送

    场景 WebSocket HTTP 协议是一种无状态的.无连接的.单向的应用层协议.它采用了请求/响应模型.通信请求只能由客户端发起,服务端对请求做出应答处理. 这种通信模型有一个弊端:HTTP 协议 ...

  8. SpringBoot使用Socket向前端推送消息

    个人资源与分享网站:http://xiaocaoshare.com/ 1.对webSocket理解 WebSocket协议是基于TCP的一种新的网络协议.它实现了浏览器与服务器全双工(full-dup ...

  9. Springboot集成websocket实现消息推送和在线用户统计

    一.HTTP 说到websocket首先要说Http,Http大家都知道是一个网络通信协议,每当客户端浏览器需要访问后台时都会发一个请求,服务器给出响应后该连接就会关闭,请求只能有客户端发起,服务端是 ...

最新文章

  1. 判断一个对象是否是可调用对象
  2. 移动端H5混合开发设置复盘与总结
  3. LibJson数据解析方法
  4. 计算机网络核心知识(下)
  5. oracle实现分段,用Oracle分段空间管理功能改进数据库性能
  6. 单元测试代码:SpringTest+JUnit
  7. 2017前端资源汇总
  8. JSON与XML的选择
  9. java怎么给坦克上图片_Java坦克大战 (七) 之图片版
  10. 算法笔记_面试题_9.解码方法/数字字符串解码成字母的种类
  11. windows搭建FTP
  12. 在Latex中插入FontAwesome图标
  13. VOA Special English Facebook Stock Goes on Sale (中英文对照)
  14. 3D图库框架范围与示例
  15. 什么相片可以两张弄成一张_美图秀秀怎么把两张图片合成一张?美图秀秀两张图片融合方法汇总_图形图像_软件教程_脚本之家...
  16. 自学Java day8 项目-零钱通 从jvav到架构师
  17. 崩坏35.4版本什么时候更新
  18. 马斯克都不懂的 GraphQL,API 网关又能对其如何理解?
  19. Java锁深入理解5——共享锁
  20. android平板电脑手写笔应用,四款最佳手写笔平板推荐

热门文章

  1. fedora 12下查看pdf不显示乱码的方法
  2. 从Java视角理解系统结构(一)CPU上下文切换
  3. mybatis和ibatis的一点区别
  4. 由PostgreSQL的区域与字符集说起
  5. python3 检测端口是否开放
  6. mysql group by 分组查询
  7. tcp时间戳 引起的网站不能访问
  8. netbios 网上基本输入输出系统 简介
  9. mysql update多个字段 逗号 and 的错误例子
  10. linux shell 设置 标准 错误流 输出流 不显示