怎么使用Spring Boot+Vue实现Socket通知推送
Spring Boot端
第一步,引入依赖
首先我们需要引入WebSocket所需的依赖,以及处理输出格式的依赖
com.alibaba fastjson 1.2.73 org.springframework.boot spring-boot-starter-websocket
第二步,创建WebSocket配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @author: tjp
* @create: 2023-04-03 09:58
* @Description: WebSocket配置
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}第三步,创建WebSocket服务
这一步我们通过userId作为标识符,区分系统中对应的用户,后续也可基于此,进行其他的操作步骤。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.excel.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author: tjp
* @create: 2023-04-03 13:55
* @Description: WebSocket服务
*/
@ServerEndpoint("/websocket/{userId}")
@Slf4j
@Component
public class WebSocketServer {
/**
* 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
*/
private static int onlineCount = 0;
/**
* concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
*/
private static ConcurrentHashMap webSocketMap = new ConcurrentHashMap<>();
/**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
private Session session;
/**
* 接收userId
*/
private String userId = "";
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
this.session = session;
this.userId = userId;
if (webSocketMap.containsKey(userId)) {
webSocketMap.remove(userId);
//加入set中
} else {
webSocketMap.put(userId, this);
//加入set中
addOnlineCount();
//在线数加1
}
log.info("用户连接:" + userId + ",当前在线人数为:" + getOnlineCount());
try {
HashMap 第四步,创建Controller进行发送测试
获取当前在线人数
import com.......WebSocketServer;
@ApiOperation(value = "获取当前在线人数")
@GetMapping("/getOnlineCount")
public Integer getOnlineCount() {
return WebSocketServer.getOnlineCount();
}通过接口,向前端用户推送消息
import com.......WebSocketServer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
* @author: tjp
* @create: 2023-04-03 13:57
* @Description: 测试
*/
@RestController
@RequestMapping("/news")
public class NewsController {
@GetMapping("/send")
public String send() {
try {
WebSocketServer.sendInfo("这是websocket发送过来的消息!", "需要推送的用户的编号");
} catch (IOException e) {
throw new RuntimeException(e);
}
return "发送消息成功";
}
}Vue端
第一步,创建连接工具类
创建工具类websocket.js,这里的userId就是用来作为标识符的userId
/**
* @author: tjp
* @create: 2023-04-03 11:22
* @Description: Socket客户端
*/
export class WebSocketClient {
constructor(userId) {
this.userId = userId;
this.websocket = null;
this.timeout = 10000; // 心跳超时时间,单位ms
this.timeoutObj = null; // 心跳定时器
this.serverTimeoutObj = null; // 服务器超时定时器
this.lockReconnect = false; // 避免重复连接
this.timeoutnum = null; // 重连延迟定时器
}
// 初始化WebSocket连接
initWebSocket() {
let wsUrl = `ws://127.0.0.1:8080/websocket/${this.userId}`;
this.websocket = new WebSocket(wsUrl);
this.websocket.onopen = this.websocketonopen.bind(this);
this.websocket.onerror = this.websocketonerror.bind(this);
this.websocket.onmessage = this.setOnmessageMessage.bind(this);
this.websocket.onclose = this.websocketclose.bind(this);
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = this.websocketclose.bind(this);
}
// 启动心跳
start() {
console.log('start');
// 清除延时器
this.timeoutObj && clearTimeout(this.timeoutObj);
this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
/*// 向服务器发送心跳消息
let actions = { "test": "12345" };
this.websocket && this.websocket.readyState == 1 && this.websocket.send(JSON.stringify(actions));
// 启动心跳定时器
this.timeoutObj = setTimeout(() => {
this.start();
// 定义一个延时器等待服务器响应,若超时,则关闭连接,重新请求server建立socket连接
this.serverTimeoutObj = setTimeout(() => {
this.websocket.close();
}, this.timeout)
}, this.timeout)*/
}
// 重置心跳
reset() {
// 清除时间
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
// 重启心跳
this.start();
}
// 重新连接
reconnect() {
if (this.lockReconnect) return;
this.lockReconnect = true;
// 没连接上会一直重连,设置延迟避免请求过多
this.timeoutnum && clearTimeout(this.timeoutnum);
this.timeoutnum = setTimeout(() => {
this.initWebSocket();
this.lockReconnect = false;
}, 5000)
}
// 处理收到的消息
async setOnmessageMessage(event) {
console.log(event.data, '获得消息');
// 重置心跳
// this.reset();
// 自定义全局监听事件
window.dispatchEvent(new CustomEvent('onmessageWS', {
detail: {
data: event.data
}
}))
// //发现消息进入 开始处理前端触发逻辑
// if (event.data === 'success' || event.data === 'heartBath') return
}
// WebSocket连接成功回调
websocketonopen() {
// 开启心跳
this.start();
console.log("WebSocket连接成功!!!" + new Date() + "----" + this.websocket.readyState);
clearInterval(this.otimer);//停止
}
// WebSocket连接错误回调
websocketonerror(e) {
console.log("WebSocket连接发生错误" + e);
}
// WebSocket连接关闭回调
websocketclose(e) {
this.websocket.close();
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
console.log("websocketcloe关闭连接")
}
// 关闭WebSocket连接
closeWebSocket() {
this.websocket.close();
console.log("closeWebSocket关闭连接")
}
// 监听窗口关闭事件
onbeforeunload() {
this.closeWebSocket();
}
}第二步,建立连接
在任意你想建立连接的页面中建立Socket连接
比如,在用户点击登录按钮之后
在这里可以使用原型,创建连接对象,并启动连接

第三步,监听服务器发送过来的消息
在你想监听的页面,使用监听器进行监听
这个时候,你就可以通过后端的接口进行发送了
搞个测试


第四步,关闭连接
搞个按钮
