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.
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 WebSocketConfigregisters a ServerEndpointExporter bean so that endpoints annotated with @ServerEndpoint are automatically detected.
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
} WebSocketServerhandles 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);
}
} WebSocketControllerexposes 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.
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
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
