Spring Boot + Web Socket 打造实时监控异常,写得太好了!

来源:cnblogs.com/jae-tech/p/15409340.html

写在前面

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

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

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

WebSocket就不做介绍了,上链接:

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

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

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

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

Spring Boot + Web Socket 打造实时监控异常,写得太好了!

实现

前端:

直接贴代码

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>&#x5B9E;&#x65F6;&#x76D1;&#x63A7;</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>

            </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 + Web Socket 打造实时监控异常,写得太好了!

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

Spring Boot 基础就不介绍了,推荐下这个实战教程:

https://github.com/javastacks/spring-boot-best-practice

Spring Boot + Web Socket 打造实时监控异常,写得太好了!

2、配置application.yml

#&#x7AEF;&#x53E3;
server:
  port: 18801

#&#x5BC6;&#x7801;&#xFF0C;&#x56E0;&#x4E3A;&#x63A5;&#x53E3;&#x4E0D;&#x9700;&#x8981;&#x6743;&#x9650;&#xFF0C;&#x6240;&#x4EE5;&#x52A0;&#x4E86;&#x4E2A;&#x5BC6;&#x7801;&#x505A;&#x6821;&#x9A8C;
mySocket:
  myPwd: jae_123

3、WebSocketConfig配置类

@Configuration
public class WebSocketConfig {

    /**
     * &#x6CE8;&#x5165;&#x4E00;&#x4E2A;ServerEndpointExporter,&#x8BE5;Bean&#x4F1A;&#x81EA;&#x52A8;&#x6CE8;&#x518C;&#x4F7F;&#x7528;@ServerEndpoint&#x6CE8;&#x89E3;&#x7533;&#x660E;&#x7684;websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

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

/**
 * @author jae
 * @ServerEndpoint("/webSocket/{uid}") &#x524D;&#x7AEF;&#x901A;&#x8FC7;&#x6B64;URI&#x4E0E;&#x540E;&#x7AEF;&#x5EFA;&#x7ACB;&#x94FE;&#x63A5;
 */

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

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

    //&#x9759;&#x6001;&#x53D8;&#x91CF;&#xFF0C;&#x7528;&#x6765;&#x8BB0;&#x5F55;&#x5F53;&#x524D;&#x5728;&#x7EBF;&#x8FDE;&#x63A5;&#x6570;&#x3002;&#x5E94;&#x8BE5;&#x628A;&#x5B83;&#x8BBE;&#x8BA1;&#x6210;&#x7EBF;&#x7A0B;&#x5B89;&#x5168;&#x7684;&#x3002;
    private static final AtomicInteger onlineNum = new AtomicInteger(0);

    //concurrent&#x5305;&#x7684;&#x7EBF;&#x7A0B;&#x5B89;&#x5168;Set&#xFF0C;&#x7528;&#x6765;&#x5B58;&#x653E;&#x6BCF;&#x4E2A;&#x5BA2;&#x6237;&#x7AEF;&#x5BF9;&#x5E94;&#x7684;WebSocketServer&#x5BF9;&#x8C61;&#x3002;
    private static CopyOnWriteArraySet<session> sessionPools = new CopyOnWriteArraySet<session>();

    /**
     * &#x6709;&#x5BA2;&#x6237;&#x7AEF;&#x8FDE;&#x63A5;&#x6210;&#x529F;
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "uid") String uid){
        sessionPools.add(session);
        onlineNum.incrementAndGet();
        log.info(uid + "&#x52A0;&#x5165;webSocket&#xFF01;&#x5F53;&#x524D;&#x4EBA;&#x6570;&#x4E3A;" + onlineNum);
    }

    /**
     * &#x8FDE;&#x63A5;&#x5173;&#x95ED;&#x8C03;&#x7528;&#x7684;&#x65B9;&#x6CD5;
     */
    @OnClose
    public void onClose(Session session) {
        sessionPools.remove(session);
        int cnt = onlineNum.decrementAndGet();
        log.info("&#x6709;&#x8FDE;&#x63A5;&#x5173;&#x95ED;&#xFF0C;&#x5F53;&#x524D;&#x8FDE;&#x63A5;&#x6570;&#x4E3A;&#xFF1A;{}", cnt);
    }

    /**
     * &#x53D1;&#x9001;&#x6D88;&#x606F;
     */
    public void sendMessage(Session session, String message) throws IOException {
        if(session != null){
            synchronized (session) {
                session.getBasicRemote().sendText(message);
            }
        }
    }

    /**
     * &#x7FA4;&#x53D1;&#x6D88;&#x606F;
     */
    public void broadCastInfo(String message) throws IOException {
        for (Session session : sessionPools) {
            if(session.isOpen()){
                sendMessage(session, message);
            }
        }
    }

    /**
     * &#x53D1;&#x751F;&#x9519;&#x8BEF;
     */
    @OnError
    public void onError(Session session, Throwable throwable){
        log.error("&#x53D1;&#x751F;&#x9519;&#x8BEF;");
        throwable.printStackTrace();
    }

}
</session></session>

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

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

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

    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * &#x624B;&#x673A;&#x5BA2;&#x6237;&#x7AEF;&#x8BF7;&#x6C42;&#x63A5;&#x53E3;
     * @param id &#x53D1;&#x751F;&#x5F02;&#x5E38;&#x7684;&#x8BBE;&#x5907;ID
     * @param pwd &#x5BC6;&#x7801;&#xFF08;&#x5B9E;&#x9645;&#x5F00;&#x53D1;&#x8BB0;&#x5F97;&#x52A0;&#x5BC6;&#xFF09;
     * @throws IOException
     */
    @PostMapping(value = "/onReceive")
    public void onReceive(String id,String pwd) throws IOException {
        if(pwd.equals(myPwd)){ //&#x5BC6;&#x7801;&#x6821;&#x9A8C;&#x4E00;&#x81F4;&#xFF08;&#x8FD9;&#x91CC;&#x4E3E;&#x4F8B;&#xFF0C;&#x5B9E;&#x9645;&#x5F00;&#x53D1;&#x8FD8;&#x8981;&#x6709;&#x4E2A;&#x5BC6;&#x7801;&#x52A0;&#x5BC6;&#x7684;&#x6821;&#x9A8C;&#x7684;&#xFF09;&#xFF0C;&#x5219;&#x8FDB;&#x884C;&#x7FA4;&#x53D1;
            webSocketServer.broadCastInfo(id);
        }
    }

}

测试

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

控制台输出,连接成功

Spring Boot + Web Socket 打造实时监控异常,写得太好了!

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

Spring Boot + Web Socket 打造实时监控异常,写得太好了!

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

Spring Boot + Web Socket 打造实时监控异常,写得太好了!

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

Spring Boot + Web Socket 打造实时监控异常,写得太好了!

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

参考:

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

最后

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

不足之处欢迎指出,觉得有用的话就点个推荐吧!

近期热文推荐:

  1. 1,000+ 道 Java面试题及答案整理(2022最新版)

  2. 劲爆!Java 协程要来了。。。

  3. Spring Boot 2.x 教程,太全了!

  4. 别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

  5. 《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!

Original: https://www.cnblogs.com/javastack/p/16671688.html
Author: Java技术栈
Title: Spring Boot + Web Socket 打造实时监控异常,写得太好了!

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/616386/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • [转]Spring Security打造一个简单Login登录页面,实现登录+跳转+注销+角色权限功能,核心代码不到100行!

    原文链接:Spring Security打造一个简单Login登录页面,实现登录+跳转+注销+角色权限功能,核心代码不到100行! posted @2022-07-08 18:31…

    Java 2023年5月29日
    0101
  • 设计模式 21 状态模式

    状态模式(State Pattern)属于 行为型模式 在标准大气压下, 水在 0 ~ 100 度之间时,会呈现 液态;在 0 度以下会变成 固态;100 度以上会变成气态。 物质…

    Java 2023年6月6日
    082
  • 验证码 案例

    import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; impo…

    Java 2023年6月7日
    070
  • springboot2.0集成webSocket

    WebSocket和http的区别? * 1. http协议是用在应用层的协议,他是基于tcp协议的,http协议建立链接也必须要有三次握手才能发送信息。 http链接分为短链接,…

    Java 2023年5月30日
    092
  • SQLServer触发器调用JavaWeb接口

    这几天接到一个需求需要吧不同系统的数据库进行同步,需要我做一个中间平台进行连接,瞬间就想到了触发器调用接口然后通过API进行传递再写入另一个数据库。sqlServer触发器调用Ja…

    Java 2023年6月5日
    077
  • 8000字长文让你彻底了解 Java 8 的 Lambda、函数式接口、Stream 用法和原理

    我是风筝,公众号「古时的风筝」。一个兼具深度与广度的程序员鼓励师,一个本打算写诗却写起了代码的田园码农!文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白…

    Java 2023年5月29日
    091
  • 线程简介

    线程简介以多线程在Windows操作系统中的运行模式为例:Windows操作系统是 多任务操作系统,它以进程为 单位。每个独立执行的程序都被称为 进程( 比如正在运行的QQ是一个进…

    Java 2023年6月9日
    079
  • 初次使用create-react-app

    最近玩了一下React,感觉还挺好玩的,说实话对后端的来说比vue好多了,记得刚学vue的时候是一头雾水; 基础知识暂时后面慢慢说,其实感觉还是挺容易的吧,今天就简单使用一下rea…

    Java 2023年6月6日
    091
  • Hello World(Java)

    1.语言:Java 2.编译器:IntelliJ IDEA 3.第一个程序 public class Hello {public static void main(String[]…

    Java 2023年6月9日
    064
  • java8 lambda list map 便捷操作记录

    1.list的直接forEach List<useraccount> list = new ArrayList<>(); //{}&#x5185;&…

    Java 2023年6月5日
    0132
  • MSSQL中Repalce函数处理长字符串时报异常的解决方案

    阅文时长 | 17.99分钟字数统计 | 28788.8字符主要内容 | 1、引言&背景 2、问题还原 3、解决方案 4、官方解释 5、声明与参考资料『MSSQL中Repa…

    Java 2023年6月5日
    075
  • 【我的面试-01】Web前端开发实习岗-面试题总结

    简单开头 首先技术面试官会根据简历里所写的项目和个人掌握技术栈提问(我不知道已经改过多少次简历了,因为前期投简历是真的是沉在茫茫大海,捞漂流瓶都捞不到的那种) 我的技术栈:(Vue…

    Java 2023年6月5日
    087
  • Java 类方法

    Java 类方法 Java的类方法,也称为成员方法是封装在类中的一个方法,可以理解为一个可以重复使用代码模板。 定义语法 &#x8BBF;&#x95EE;&…

    Java 2023年6月5日
    0130
  • ||运算你真的了解吗?

    或运算介绍 或运算:只要有一个条件为true,即为true。 通过如上逻辑关系图,还有另外一层 隐含的意思: 如果A条件是true,B条件不执行! 如果A条件是false,B条件要…

    Java 2023年6月8日
    072
  • 【工作篇】再次熟悉 SpringMVC 参数绑定

    主要现在项目中使用的参数绑定五花八门的,搞得很头大,例如有些用字符串接收日期,用字符串接受数组等等,完全没有利用好 SpringMVC 的优势,这里自己也总结一下,免得到时又要百度…

    Java 2023年6月5日
    0140
  • Java 自定义Excel数据排序

    通常,我们可以在Excel中对指定列数据执行升序或者降序排序,排序时可依据单元格中的数值、单元格颜色、字体颜色或图标等。在需要自定义排序情况下,我们也可以自行根据排序需要编辑数据排…

    Java 2023年6月7日
    096
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球