1. 添加WebSocket依赖
在ruoyi-framework/pom.xml中添加Spring Boot WebSocket的依赖:
<!-- SpringBoot Websocket -->
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.在ruoyi-framework中创建一个WebSocketConfig配置类,如下所示:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** 开启WebSocket支持*/
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}
3、在ruoyi-framework中创建一个WebSocketServer控制器类,用于处理WebSocket连接和消息
这个类主要用于使用创建连接、监听消息和发送消息等
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.concurrent.CopyOnWriteArraySet;// @ServerEndpoint 声明并创建了webSocket端点, 并且指明了请求路径
// id 为客户端请求时携带的参数, 用于服务端区分客户端使用
@ServerEndpoint("/ws/{sid}")
@Component
public class WebSocketServer {// 日志对象private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);// 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。private static int onlineCount = 0;// concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();// private static ConcurrentHashMap<String,WebSocketServer> websocketList = new ConcurrentHashMap<>();// 与某个客户端的连接会话,需要通过它来给客户端发送数据private Session session;// 接收sidprivate String sid = "";/** 客户端创建连接时触发* */@OnOpenpublic void onOpen(Session session, @PathParam("sid") String sid) {this.session = session;webSocketSet.add(this); // 加入set中addOnlineCount(); // 在线数加1log.info("有新窗口开始监听:" + sid + ", 当前在线人数为" + getOnlineCount());this.sid = sid;try {sendMessage("连接成功");} catch (IOException e) {log.error("websocket IO异常");}}/*** 客户端连接关闭时触发**/@OnClosepublic void onClose() {webSocketSet.remove(this); // 从set中删除subOnlineCount(); // 在线数减1log.info("有一连接关闭!当前在线人数为" + getOnlineCount());}/*** 接收到客户端消息时触发*/@OnMessagepublic void onMessage(String message, Session session) {log.info("收到来自窗口" + sid + "的信息:" + message);// 群发消息for (WebSocketServer item : webSocketSet) {try {item.sendMessage(message);} catch (IOException e) {e.printStackTrace();}}}/*** 连接发生异常时候触发*/@OnErrorpublic void onError(Session session, Throwable error) {log.error("发生错误");error.printStackTrace();}/*** 实现服务器主动推送(向浏览器发消息)*/public void sendMessage(String message) throws IOException {log.info("服务器消息推送:"+message);this.session.getBasicRemote().sendText(message);}/*** 发送消息到所有客户端* 指定sid则向指定客户端发消息* 不指定sid则向所有客户端发送消息* */public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {log.info("推送消息到窗口" + sid + ",推送内容:" + message);for (WebSocketServer item : webSocketSet) {try {// 这里可以设定只推送给这个sid的,为null则全部推送if (sid == null) {item.sendMessage(message);} else if (item.sid.equals(sid)) {item.sendMessage(message);}} catch (IOException e) {continue;}}}public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {WebSocketServer.onlineCount++;}public static synchronized void subOnlineCount() {WebSocketServer.onlineCount--;}public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {return webSocketSet;}}
4、前端页面的配置
<template><!-- 包含音频播放功能的包装元素 --><div id="wrap" v-show="false"> <!-- v-show="false" 隐藏此元素 --><!-- 音频播放控件 --><audio v-if="false" src="@/api/audio/preview.mp3" id="audio" preload="auto" muted autoplay type="audio/mp3" controls="controls"><span id="audioId">播放音乐</span></audio></div>
</template><script>
export default {// 【1】组件创建时初始化 WebSocket 连接created() {this.initWebSocket();},// 【2】组件销毁时关闭 WebSocket 连接destroyed() {this.websock.close(); //离开路由之后断开websocket连接},// 【3】方法methods: {// 3.1初始化 WebSocket连接initWebSocket() {const wsuri = "ws://localhost:8080/ws/123214"; // WebSocket 服务器的 URIif (typeof WebSocket === "undefined") { // 检查浏览器是否支持 WebSocketconsole.log("您的浏览器不支持WebSocket");} else {console.log(wsuri);// 创建 WebSocket 连接this.websock = new WebSocket(wsuri); // 设置 WebSocket 各种事件处理函数this.websock.onmessage = this.websocketonmessage; // 接收到消息时调用this.websock.onopen = this.websocketonopen; // 连接成功时调用this.websock.onerror = this.websocketonerror; // 连接错误时调用this.websock.onclose = this.websocketclose; // 连接关闭时调用}},// 3.2连接建立之后执行send方法发送数据websocketonopen() {let actions = { "test": "我已在线" }; // 创建一个消息对象this.websocketsend(JSON.stringify(actions)); // 发送 JSON 格式的消息},// 3.3连接建立失败重连websocketonerror() {this.initWebSocket(); // 重新初始化 WebSocket 连接},// 3.4数据接收websocketonmessage(e) {this.$modal.msg(e.data); // 显示接收到的消息console.log(e.data); // 打印接收到的消息var audio = document.querySelector("audio"); // 获取音频元素 用这种标签名称获取的方式就不会报错了audio.currentTime = 0; // 从头开始播放audio.muted = false; // 取消静音audio.play(); // 音频播放// const redata = JSON.parse(e.data); // 可用于解析 JSON 格式的消息(如果需要)},// 3.5向服务器发送数据websocketsend(Data) {this.websock.send(Data); // 使用 WebSocket 连接发送数据},// 3.6WebSocket 连接关闭时调用websocketclose(e) {console.log('断开连接', e); // 打印连接断开的信息}}
}
</script>
audio是因为业务场景需要引入的,主要是对与来订单提醒的提示音,然后可以在websocketonmessage()接受数据和进行处理
5、SecurityConfig设置匿名访问
这个主要是方便我们测试
整体结构(仅供参考)