SpringBoot+WebSocket实时监控异常

news2024/11/24 14:26:21

# 写在前面

此异常非彼异常,标题所说的异常是业务上的异常。

最近做了一个需求,消防的设备巡检,如果巡检发现异常,通过手机端提交,后台的实时监控页面实时获取到该设备的信息及位置,然后安排员工去处理。

因为需要服务端主动向客户端发送消息,所以很容易的就想到了用WebSocket来实现这一功能。

WebSocket就不做介绍了,上链接:https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket

前端略微复杂,需要在一张位置分布图上进行鼠标描点定位各个设备和根据不同屏幕大小渲染,本文不做介绍,只是简单地用页面样式进行效果呈现。

绿色代表正常,红色代表异常

预期效果,未接收到请求前----->id为3的提交了异常,id为3的王五变成了红色

# 实现

前端:

直接贴代码

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>实时监控</title>
    </head>
    <style>
        .item {
            display: flex;
            border-bottom: 1px solid #000000;
            justify-content: space-between;
            width: 30%;
            line-height: 50px;
            height: 50px;
        }

        .item span:nth-child(2){
            margin-right: 10px;
            margin-top: 15px;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: #55ff00;
        }
        .nowI{
            background: #ff0000 !important;
        }
</style>
    <body>
        <div id="app">
            <div v-for="item in list" class="item">
                <span>{{item.id}}.{{item.name}}</span>
                <span :class='item.state==-1?"nowI":""'></span>
            </div>
        </div>
    </body>
    <script src="./js/vue.min.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#app",
            data: {
                list: [{
                        id: 1,
                        name: '张三',
                        state: 1
                    },
                    {
                        id: 2,
                        name: '李四',
                        state: 1
                    },
                    {
                        id: 3,
                        name: '王五',
                        state: 1
                    },
                    {
                        id: 4,
                        name: '韩梅梅',
                        state: 1
                    },
                    {
                        id: 5,
                        name: '李磊',
                        state: 1
                    },
                ]
            }
        })

        var webSocket = null;
        if ('WebSocket' in window) {
            //创建WebSocket对象
            webSocket = new WebSocket("ws://localhost:18801/webSocket/" + getUUID());

            //连接成功
            webSocket.onopen = function() {
                console.log("已连接");
                webSocket.send("消息发送测试")
            }
            //接收到消息
            webSocket.onmessage = function(msg) {
                //处理消息
                var serverMsg = msg.data;
                var t_id = parseInt(serverMsg)    //服务端发过来的消息,ID,string需转化为int类型才能比较
                for (var i = 0; i < vm.list.length; i++) {
                    var item = vm.list[i];
                    if(item.id == t_id){
                        item.state = -1;
                        vm.list.splice(i,1,item)
                        break;
                    }
                }
            };

            //关闭事件
            webSocket.onclose = function() {
                console.log("websocket已关闭");
            };
            //发生了错误事件
            webSocket.onerror = function() {
                console.log("websocket发生了错误");
            }
        } else {
            alert("很遗憾,您的浏览器不支持WebSocket!")
        }

        function getUUID() {    //获取唯一的UUID
            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {

                var r = Math.random() * 16 | 0,
                    v = c == 'x' ? r : (r & 0x3 | 0x8);
                return v.toString(16);
            });
        }
</script>
</html>

后端:

项目结构是这样子的,后面的代码关键注释都有,就不重复描述了

1、新建SpringBoot工程,选择web和WebSocket依赖

2、配置application.yml

#端口
server:
  port: 18801

#密码,因为接口不需要权限,所以加了个密码做校验
mySocket:
  myPwd: jae_123

3、WebSocketConfig配置类

@Configuration
public class WebSocketConfig {

    /**
     * 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

4、WebSocketServer类,用来进行服务端和客户端之间的交互

/**
 * @author jae
 * @ServerEndpoint("/webSocket/{uid}") 前端通过此URI与后端建立链接
 */

@ServerEndpoint("/webSocket/{uid}")
@Component
public class WebSocketServer {

    private static Logger log = LoggerFactory.getLogger(WebSocketServer.class);

    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static final AtomicInteger onlineNum = new AtomicInteger(0);

    //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
    private static CopyOnWriteArraySet<Session> sessionPools = new CopyOnWriteArraySet<Session>();

    /**
     * 有客户端连接成功
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "uid") String uid){
        sessionPools.add(session);
        onlineNum.incrementAndGet();
        log.info(uid + "加入webSocket!当前人数为" + onlineNum);
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session) {
        sessionPools.remove(session);
        int cnt = onlineNum.decrementAndGet();
        log.info("有连接关闭,当前连接数为:{}", cnt);
    }

    /**
     * 发送消息
     */
    public void sendMessage(Session session, String message) throws IOException {
        if(session != null){
            synchronized (session) {
                session.getBasicRemote().sendText(message);
            }
        }
    }

    /**
     * 群发消息
     */
    public void broadCastInfo(String message) throws IOException {
        for (Session session : sessionPools) {
            if(session.isOpen()){
                sendMessage(session, message);
            }
        }
    }

    /**
     * 发生错误
     */
    @OnError
    public void onError(Session session, Throwable throwable){
        log.error("发生错误");
        throwable.printStackTrace();
    }

}

5、WebSocketController类,用于进行接口测试

@RestController
@RequestMapping("/open/socket")
public class WebSocketController {

    @Value("${mySocket.myPwd}")
    public String myPwd;

    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 手机客户端请求接口
     * @param id    发生异常的设备ID
     * @param pwd   密码(实际开发记得加密)
     * @throws IOException
     */
    @PostMapping(value = "/onReceive")
    public void onReceive(String id,String pwd) throws IOException {
        if(pwd.equals(myPwd)){  //密码校验一致(这里举例,实际开发还要有个密码加密的校验的),则进行群发
            webSocketServer.broadCastInfo(id);
        }
    }

}

# 测试

1、打开前端页面,进行WebSocket连接

控制台输出,连接成功

2、因为是模拟数据,所以全部显示正常,没有异常提交时的页面呈现

3、接下来,我们用接口测试工具Postman提交一个异常

注意id为3的这个数据的状态变化

我们可以看到,id为3的王五状态已经变成异常的了,实时通讯成功。

参考:https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket

# 最后

工作中有这方面关于实时监控的需求,可以参考一下哦。

不足之处欢迎指出,觉得有用的话就点个赞河再看吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/403727.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2.9.1 Packet Tracer - Basic Switch and End Device Configuration(作业)

Packet Tracer - 交换机和终端设备的基本 配置地址分配表目标使用命令行界面 (CLI)&#xff0c;在两台思科互联网络 操作系统 (IOS) 交换机上配置主机名和 IP 地址。使用思科 IOS 命令指定或限制对设备 配置的访问。使用 IOS 命令来保存当前的运行配置。配置两台主机设备的 IP …

JavaScript Boolean(布尔)对象

Boolean&#xff08;布尔&#xff09;对象用于将非布尔值转换为布尔值&#xff08;true 或者 false&#xff09;&#xff0c;是三种包装对象&#xff1a;Number、String和Boolean中最简单的一种&#xff0c;它没有大量的实例属性和方法。在线实例检查布尔值检查布尔对象是 true…

大数据-玩转数据-mysql规范

整体图谱 正文部分 一、数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字&#xff08;如果表名中包含关键字查询时&#xff0c;需要将其用单引号括起来&#xff09; 数据库对象的命名要能做到见名识意&#xff…

【算法时间复杂度】学习记录

最近开算法课&#xff0c;开几篇文章记录一下算法的学习过程。 关于算法的重要性 学习计算机当程序员的话&#xff0c;在编程过程中是绕不开算法这个大矿山的&#xff0c;需要我们慢慢挖掘宝藏。 算法&#xff08;Algorithm&#xff09;是指用来操作数据、解决程序问题的一组…

信创和去O大潮下,Oracle OCP(1z0-082 1z0-083)的含金量有多少?(文末附录像)

我自己就考了挺多Oracle的认证&#xff0c;下面是从Oracle的certview网站&#xff08;网址是certview加上点oracle点com&#xff09;上面查询到的姚远老师自己的Oracle证书。 目前国内强调自主可控&#xff0c;推信创和去Oracle数据库&#xff0c;很多想考Oracle OCP认证的学员…

Spring框架源码分析一

如何看源码&#xff08;方法论&#xff09;不要忽略源码中的注释使用翻译工具先梳理脉络&#xff0c;然后梳理细节即总分总&#xff0c;先总体过一遍&#xff0c;再看细节&#xff0c;再做一个总结大胆猜测&#xff08;8分靠猜&#xff09;&#xff0c;小心验证&#xff0c;再调…

ChatGPT真神奇,但是也真焦虑

ChatGPT火爆ChatGPT的火爆程度不用说也知道。就目前来说&#xff0c;已经开始冲击各行业了&#xff0c;比如客服、智能助手、语言学习、自然语言处理等等等。。ChatGPT冲击冲击最高的可能就是中间这个段位的了。高段位无法取代&#xff0c;但是低段位&#xff0c;通过使用ChatG…

Linux - 第7节 - 进程间通信

1.进程间通信介绍 进程间通信目的&#xff1a; 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程 。​​​​​​​ 资源共享&#xff1a;多个进程之间共享同样的资源。 ​​​​​​​ 通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息&#xff0c;通…

数据结构-用栈实现队列

前言&#xff1a; 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a; void push(int x) 将元素 x 推到队列的末尾 int pop() 从队列的开头移除并返回元素 int…

双通道5.2GSPS(或单通道10.4GSPS)射频采样FMC+模块

概述 FMC140是一款具有缓冲模拟输入的低功耗、12位、双通道&#xff08;5.2GSPS/通道&#xff09;、单通道10.4GSPS、射频采样ADC模块&#xff0c;该板卡为FMC标准&#xff0c;符合VITA57.1规范&#xff0c;该模块可以作为一个理想的IO单元耦合至FPGA前端&#xff0c;8通道的JE…

socket编程-UDP各函数及其用法

socket编程-UDP socket主要类型 流套接字&#xff08;SOCK_STREAM&#xff09; 流套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复送&#xff0c;并按顺序接收。流套接字之所以能够实现可靠的数据服务&#xff0c;原因在于其使用了传输…

电商API分享:获得淘宝商品评论、商品评论问答列表 分页显示 代码展示

item_review-获得淘宝商品评论item_question_answer-淘宝评论问答列表接口请求示例<?php// 请求示例 url 默认请求参数已经URL编码处理 // 本示例代码未加密secret参数明文传输&#xff0c;若要加密请参考&#xff1a;https://open.qq1635608656.cn/help/demo/sdk/demo-sig…

关于IDEA系列行号左侧空白处太宽的缩短

IntelliJ IDEA行号左侧空白处太宽&#xff0c;缩短的方法修改之前打开设置File–Settings–Editor–General–Gutter Icons&#xff08;可以在Settings左上角搜索框直接搜Gutter Icons&#xff09;将对号去掉就好了 &#xff0c;但是这些符号今后不会显示 &#xff0c;最重要的…

【数据结构】单链表中,如何实现 将链表中所有结点的链接方向“原地”逆转

一.实现一个单链表&#xff08;无头单向不循环&#xff09; 我们首先实现一个无头单向不循环单链表。 写出基本的增删查改功能&#xff0c;以及其它的一些功能&#xff08;可忽略&#xff09;。 #include<stdio.h> #include<assert.h> #include<stdlib.h>…

ros使用详解

文章目录ros概述ros使用winbox登录ros关机重启ros修改路由器名ros恢复出厂设置ros修改管理员账号密码及限制登录IPros备份还原ros使用pppor拨号ros的nat&#xff0c;也叫伪装ros静态ARP绑定ros端口映射ros配置静态路由ros概述 软路由是指利用台式机或服务器的供应商配合一定软…

mos管驱动与米勒平台介绍、消除

mos驱动设计 1.选择适当的驱动芯片 为了控制MOSFET&#xff0c;需要使用专门的驱动芯片。选择合适的芯片需要考虑MOSFET的电压和电流需求。常见的驱动芯片包括IR2110、IR2184、MIC4424等。 2.设计电路 在驱动电路中&#xff0c;需要加入一些电路元件来保证MOSFET的顺畅工作…

爱国者一体机电脑蓝屏怎么U盘重装系统教学?

爱国者一体机电脑蓝屏怎么U盘重装系统教学&#xff1f;有用户使用的爱国者一体机电脑开机了之后突然变成了蓝屏的了。而且无法继续使用了&#xff0c;那么遇到这样的蓝屏问题怎么去进行系统的重装呢&#xff1f;一起来看看以下的U盘重装系统教学吧。 准备工作&#xff1a; 1、U…

es6动态模块import()

目录 一、语法说明 二、适用场合 三、注意点 四、示例代码 五、效果 一、语法说明 import命令会被 JavaScript 引擎静态分析&#xff0c;先于模块内的其他语句执行&#xff08;import命令叫做“连接” binding 其实更合适&#xff09;。 // 报错 if (x 2) {import MyMod…

网络安全工程师在面试安全岗位时,哪些内容是加分项?

金三银四已经来了&#xff0c;很多小伙伴都在困惑&#xff0c;面试网络安全工程师的时候&#xff0c;有哪些技能是加分项呢&#xff1f;接下来&#xff0c;我简单说说&#xff01; 去年我在微博上贴了一些在面试安全工作时会加分的内容&#xff0c;如下&#xff1a; 1. wooyu…

MySQL、HBase、ElasticSearch三者对比

1、概念介绍 MySQL&#xff1a;关系型数据库&#xff0c;主要面向OLTP&#xff0c;支持事务&#xff0c;支持二级索引&#xff0c;支持sql&#xff0c;支持主从、Group Replication架构模型&#xff08;本文全部以Innodb为例&#xff0c;不涉及别的存储引擎&#xff09;。 HBas…