在一次项目开发中,使用到了Netty网络应用框架,以及MQTT进行消息数据的收发,这其中须要后台来将获取到的消息主动推送给前端,因而就使用到了MQTT,特此记录一下。javascript
WebSocket协议是基于TCP的一种新的网络协议。它实现了客户端与服务器全双工通讯,学过计算机网络都知道,既然是全双工,就说明了服务器能够主动发送信息给客户端。html
这与咱们的推送技术或者是多人在线聊天的功能不谋而合。前端
为何不使用HTTP 协议呢?java
这是由于HTTP是单工通讯,通讯只能由客户端发起,客户端请求一下,服务器处理一下,这就太麻烦了。因而websocket应运而生。jquery
下面咱们就直接开始使用Springboot开始整合。如下案例都在我本身的电脑上测试成功,你能够根据本身的功能进行修改便可。git
个人项目结构以下:github
Maven依赖:web
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
启用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 { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
Spring Boot 最新教程推荐看这个:https://github.com/javastacks...spring
由于WebSocket是相似客户端服务端的形式(采用ws协议),那么这里的WebSocketServer其实就至关于一个ws协议的Controller
下面是具体业务代码:
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; //接收sid private String sid = ""; /** * 链接创建成功调用的方法 */ @OnOpen public void onOpen(Session session, @PathParam("sid") String sid) { this.session = session; webSocketSet.add(this); //加入set中 this.sid = sid; addOnlineCount(); //在线数加1 try { sendMessage("conn_success"); log.info("有新窗口开始监听:" + sid + ",当前在线人数为:" + getOnlineCount()); } catch (IOException e) { log.error("websocket IO Exception"); } } /** * 链接关闭调用的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); //从set中删除 subOnlineCount(); //在线数减1 //断开链接状况下,更新主板占用状况为释放 log.info("释放的sid为:"+sid); //这里写你 释放的时候,要处理的业务 log.info("有一链接关闭!当前在线人数为" + getOnlineCount()); } /** * 收到客户端消息后调用的方法 * @ Param message 客户端发送过来的消息 */ @OnMessage public 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 */ @OnError public 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; } }
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; } }
<!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; //判断当前浏览器是否支持WebSocket if('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>
后台:
若是有链接请求
前台显示:
这中间我遇到一个问题,就是说WebSocket启动的时候优先于spring容器,从而致使在WebSocketServer中调用业务Service会报空指针异常
因此须要在WebSocketServer中将所须要用到的service给静态初始化一下:
如图所示:
还须要作以下配置:
原文连接:https://blog.csdn.net/MacWx/a...
版权声明:本文为CSDN博主「大树先生.」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处连接及本声明。
近期热文推荐:
1.600+ 道 Java面试题及答案整理(2021最新版)
2.终于靠开源项目弄到 IntelliJ IDEA 激活码了,真香!
3.阿里 Mock 工具正式开源,干掉市面上全部 Mock 工具!
4.Spring Cloud 2020.0.0 正式发布,全新颠覆性版本!
以为不错,别忘了随手点赞+转发哦!