专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

SpringBoot + WebSocket 实时监控异常,简单高效,牛逼了!

哎,兄弟们,今天我得聊聊一个能让你感到“高效到飞起”的技术——WebSocket。你们平时肯定都知道,WebSocket可比普通的HTTP请求要牛逼多了,尤其是当我们谈到实时通讯的时候。咱最近做了个需求,消防设备巡检。听着是不是很高大上?其实,需求也挺简单的。就是设备有问题了,巡检人员通过手机端一提交,后台的实时监控页面就得马上反应,能看到这个设备的位置和状态,方便后台快速安排处理。

本来想了好多办法,但服务端得主动给客户端发消息,不是个小问题。这一想,WebSocket自然就蹦出来了。给大家普及一下:WebSocket 就是那种可以持续连接的技术,客户端和服务端保持实时通信,非常适合这种需求。其实 WebSocket 没啥好说的,反正我直接给大家上链接:
WebSocket 官方文档

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

前端的部分稍微有点复杂,要在一张位置分布图上做鼠标定位设备,同时要适配不同屏幕尺寸的显示,不过我这里不多说,咱只是简单展示下效果。

绿色代表正常,红色代表异常
来来来,看看效果。先看下面的图,设备 ID 为 3 的王五设备,提交异常前,还是绿色。等到接收到请求后,ID 为 3 的设备就变成红色,提示异常状态了。

img_1

实现过程

前端:

好了,废话少说,代码最重要。首先,咱把前端的核心代码贴出来,啥都不做,就直接贴上去,看看效果。代码中用了 Vue.js 来管理数据和渲染界面。

<!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;
        }
        .itemspan: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>

后端:

接下来,给大家看看后端的配置。首先,你得创建一个 Spring Boot 项目,然后把 WebSocket 相关的依赖加上。后端代码的实现也是简单直接,不需要太复杂的操作。下面这个项目结构,给大家有个大致了解,后续的代码都带注释,省得你看了懵逼。

img_2

1. 新建 Spring Boot 工程

你得选择 Web 和 WebSocket 相关的依赖,基础配置就这些,别的有空再讲。

img_3

2. 配置 application.yml

# 端口配置
server:
  port: 18801

# 密码配置,实际开发时最好加个加密校验
mySocket:
  myPwd: jae_123

3. WebSocket 配置类

@Configuration
public class WebSocketConfig {
    /**
     * 注入 ServerEndpointExporter,自动注册 WebSocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

4. WebSocket 服务端处理类

/**
 * @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);
    // 线程安全的 Set 存储每个客户端的 WebSocket 会话
    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 类 用于接口测试

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 会自动连接。控制台应该会显示连接成功的信息。

img_4

2. 未提交异常时:

此时,所有设备都显示为正常状态,绿色。

img_5

3. 提交异常:

使用 Postman 或其他接口测试工具提交一个异常请求。注意,设备 ID 为 3 的状态应该发生变化。

img_6

4. 异常状态展示:

提交请求后,设备 ID 为 3 的设备状态变为异常,页面显示红色,提醒有问题。

img_7

总结

WebSocket 实时监控,简单高效又方便,特别适合这种需要实时更新状态的场景。只要后端能主动推送消息,前端就能立马反应,解决了许多传统 HTTP 轮询的问题。你看,这种方案不仅高效,而且简单,关键是实现起来也不复杂。如果你项目中也有类似的需求,可以借鉴一下这个实现方法。

当然,如果你在实现过程中遇到什么问题,随时可以联系我。觉得这篇文章有帮助的话,不要忘了点个赞哦!

未经允许不得转载:搜云库 » SpringBoot + WebSocket 实时监控异常,简单高效,牛逼了!

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们