哎,兄弟们,今天我得聊聊一个能让你感到“高效到飞起”的技术——WebSocket。你们平时肯定都知道,WebSocket可比普通的HTTP请求要牛逼多了,尤其是当我们谈到实时通讯的时候。咱最近做了个需求,消防设备巡检。听着是不是很高大上?其实,需求也挺简单的。就是设备有问题了,巡检人员通过手机端一提交,后台的实时监控页面就得马上反应,能看到这个设备的位置和状态,方便后台快速安排处理。
本来想了好多办法,但服务端得主动给客户端发消息,不是个小问题。这一想,WebSocket自然就蹦出来了。给大家普及一下:WebSocket 就是那种可以持续连接的技术,客户端和服务端保持实时通信,非常适合这种需求。其实 WebSocket 没啥好说的,反正我直接给大家上链接:
WebSocket 官方文档
https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket
前端的部分稍微有点复杂,要在一张位置分布图上做鼠标定位设备,同时要适配不同屏幕尺寸的显示,不过我这里不多说,咱只是简单展示下效果。
绿色代表正常,红色代表异常
来来来,看看效果。先看下面的图,设备 ID 为 3 的王五设备,提交异常前,还是绿色。等到接收到请求后,ID 为 3 的设备就变成红色,提示异常状态了。
实现过程
前端:
好了,废话少说,代码最重要。首先,咱把前端的核心代码贴出来,啥都不做,就直接贴上去,看看效果。代码中用了 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 相关的依赖加上。后端代码的实现也是简单直接,不需要太复杂的操作。下面这个项目结构,给大家有个大致了解,后续的代码都带注释,省得你看了懵逼。
1. 新建 Spring Boot 工程
你得选择 Web 和 WebSocket 相关的依赖,基础配置就这些,别的有空再讲。
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 会自动连接。控制台应该会显示连接成功的信息。
2. 未提交异常时:
此时,所有设备都显示为正常状态,绿色。
3. 提交异常:
使用 Postman 或其他接口测试工具提交一个异常请求。注意,设备 ID 为 3 的状态应该发生变化。
4. 异常状态展示:
提交请求后,设备 ID 为 3 的设备状态变为异常,页面显示红色,提醒有问题。
总结
WebSocket 实时监控,简单高效又方便,特别适合这种需要实时更新状态的场景。只要后端能主动推送消息,前端就能立马反应,解决了许多传统 HTTP 轮询的问题。你看,这种方案不仅高效,而且简单,关键是实现起来也不复杂。如果你项目中也有类似的需求,可以借鉴一下这个实现方法。
当然,如果你在实现过程中遇到什么问题,随时可以联系我。觉得这篇文章有帮助的话,不要忘了点个赞哦!