Building Real‑Time Device Monitoring with WebSocket, Vue, and SpringBoot

This tutorial walks through creating a fire‑equipment inspection system where a mobile client reports anomalies and a backend pushes real‑time updates to a monitoring page using WebSocket, with a Vue front‑end and SpringBoot server implementation.

Java Web Project
Java Web Project
Java Web Project
Building Real‑Time Device Monitoring with WebSocket, Vue, and SpringBoot

Problem

Fire‑equipment inspection requires that when a mobile client reports an anomaly, the backend must push the update instantly to a monitoring dashboard.

Solution Overview

WebSocket is used because the server must actively send messages to the client. The MDN WebSocket documentation is referenced.

Frontend Implementation

Vue.js renders a list of devices. Each device shows a colored dot: green for normal, red for abnormal (state = -1).

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8"/>
  <title>实时监控</title>
  <style>
    .item {display:flex;border-bottom:1px solid #000;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>
</head>
<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>
  <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 = 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);
        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(){
      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>
</body>
</html>

Backend Implementation

Spring Boot project with web and WebSocket starters. application.yml sets the server port to 18801 and defines a simple password for request validation.

# application.yml
server:
  port: 18801
mySocket:
  myPwd: jae_123
WebSocketConfig

registers a ServerEndpointExporter bean so that endpoints annotated with @ServerEndpoint are automatically detected.

@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
WebSocketServer

handles client connections, broadcasts messages, and logs events. It uses a thread‑safe CopyOnWriteArraySet<Session> to store active sessions and an AtomicInteger to track online count.

@ServerEndpoint("/webSocket/{uid}")
@Component
public class WebSocketServer {
    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
    private static final AtomicInteger onlineNum = new AtomicInteger(0);
    private static final CopyOnWriteArraySet<Session> sessionPools = new CopyOnWriteArraySet<Session>();

    @OnOpen
    public void onOpen(Session session, @PathParam("uid") String uid) {
        sessionPools.add(session);
        onlineNum.incrementAndGet();
        log.info(uid + " joined, current count " + onlineNum);
    }

    @OnClose
    public void onClose(Session session) {
        sessionPools.remove(session);
        int cnt = onlineNum.decrementAndGet();
        log.info("connection closed, count {}", 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 s : sessionPools) {
            if (s.isOpen()) {
                sendMessage(s, message);
            }
        }
    }

    @OnError
    public void onError(Session session, Throwable t) {
        log.error("WebSocket error", t);
    }
}
WebSocketController

exposes a POST endpoint that mobile clients call to report an abnormal device. It validates the password (hard‑coded for demo) and then broadcasts the device ID to all connected WebSocket clients.

@RestController
@RequestMapping("/open/socket")
public class WebSocketController {
    @Value("${mySocket.myPwd}")
    private String myPwd;

    @Autowired
    private WebSocketServer webSocketServer;

    @PostMapping("/onReceive")
    public void onReceive(String id, String pwd) throws IOException {
        if (pwd.equals(myPwd)) {
            webSocketServer.broadCastInfo(id);
        }
    }
}

Testing Procedure

Open the HTML page in a browser. The console logs “已连接”, confirming the WebSocket connection.

All devices appear green because no anomaly has been reported.

Use Postman (or any HTTP client) to POST to /open/socket/onReceive with parameters id=3 and pwd=jae_123.

The server broadcasts the ID “3”. The client receives the message, parses it to an integer, finds the matching item in vm.list, sets state = -1, and updates the UI. The dot for device 3 turns red, confirming real‑time push.

Images illustrate the connection log, the initial green state, the Postman request, and the red dot after the anomaly.

WebSocket connection log
WebSocket connection log
Initial device status
Initial device status
Postman request
Postman request
Device status after anomaly
Device status after anomaly

Key Points

WebSocket enables server‑push without polling.

Vue.js provides a lightweight UI that reacts to list updates.

Thread‑safe collections ( CopyOnWriteArraySet<Session>) and AtomicInteger ensure correct concurrency handling on the server.

Simple password check demonstrates request validation; in production replace with proper authentication.

The end‑to‑end flow: mobile POST → controller validates → server broadcasts ID → client updates UI.

Reference

https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket
backendfrontendVuereal-time monitoringWebSocketSpringBoot
Java Web Project
Written by

Java Web Project

Focused on Java backend technologies, trending internet tech, and the latest industry developments. The platform serves over 200,000 Java developers, inviting you to learn and exchange ideas together. Check the menu for Java learning resources.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.