当前项目,采用若依开源框架,所以集成按照若依开源框架提供的集成方式
插件相关包和代码实现ruoyi-vue/集成websocket实现实时通信.zip
链接: https://pan.baidu.com/s/13JVC9jm-Dp9PfHdDDylLCQ 提取码: y9jt
一 集成
问题 1:连接失败200
若依架构中SecurityConfig,需要增加匿名访问,在文档2中有体现(读文档不用心的结果)
此时可以正常连接
二 使用
后端代码修改 ,需要增加用户id,记录当前在线的用户(最终发消息是给在线用户发送请求)
import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.Semaphore;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.PathParam;import javax.websocket.server.ServerEndpoint;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;/** * websocket 消息处理 * * @author ruoyi */@Component@ServerEndpoint("/websocket/message/{userId}")public class WebSocketServer {/** * WebSocketServer 日志控制器 */private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class);/** * 默认最多允许同时在线人数100 */public static int socketMaxOnlineCount = 100;private static Semaphore socketSemaphore = new Semaphore(socketMaxOnlineCount);public static Map USER_SESSIONS = new ConcurrentHashMap();/** * 连接建立成功调用的方法 */@OnOpenpublic void onOpen(@PathParam("userId") String userId, Session session) throws Exception {//从登录链接获取用户信息,记录下来USER_SESSIONS.remove(userId);USER_SESSIONS.put(userId, session);//给其他用户发送有新用户登录上来for (Map.Entry it : USER_SESSIONS.entrySet()) {if (!it.getKey().equals(userId)) {it.getValue().getBasicRemote().sendText(userId + "-登录");}}boolean semaphoreFlag = false;// 尝试获取信号量semaphoreFlag = SemaphoreUtils.tryAcquire(socketSemaphore);if (!semaphoreFlag) {// 未获取到信号量LOGGER.error("\n 当前在线人数超过限制数- {}", socketMaxOnlineCount);WebSocketUsers.sendMessageToUserByText(session, "当前在线人数超过限制数:" + socketMaxOnlineCount);session.close();} else {// 添加用户WebSocketUsers.put(session.getId(), session);LOGGER.info("\n 建立连接 - {}", session);LOGGER.info("\n 当前人数 - {}", WebSocketUsers.getUsers().size());WebSocketUsers.sendMessageToUserByText(session, "连接成功");}}/** * 连接关闭时处理 */@OnClosepublic void onClose(Session session) {LOGGER.info("\n 关闭连接 - {}", session);// 移除用户WebSocketUsers.remove(session.getId());// 获取到信号量则需释放SemaphoreUtils.release(socketSemaphore);}/** * 抛出异常时处理 */@OnErrorpublic void onError(Session session, Throwable exception) throws Exception {if (session.isOpen()) {// 关闭连接session.close();}String sessionId = session.getId();LOGGER.info("\n 连接异常 - {}", sessionId);LOGGER.info("\n 异常信息 - {}", exception);// 移出用户WebSocketUsers.remove(sessionId);// 获取到信号量则需释放SemaphoreUtils.release(socketSemaphore);}/** * 服务器接收到客户端消息时调用的方法 */@OnMessagepublic void onMessage(String message, Session session) {String msg = message.replace("111", "222").replace("张三", "李四");WebSocketUsers.sendMessageToUserByText(session, msg);}}
public AjaxResult mediaAccountLoginResult(@RequestBody Map map) throws IOException {String userId = map.get("userId").toString();Session session = WebSocketServer.USER_SESSIONS.get(userId);if (session != null) {session.getBasicRemote().sendText("开始发送消息提醒");}
到此 后端调用完成
前端。主要是当前三种方法(上面地址有完整前端测试代码)
export default {data() {return {url: 'ws://localhost:8099/websocket/message',message: '',text_content: '',ws: null}},methods: {join() {const wsuri = this.urlthis.ws = new WebSocket(wsuri)const self = thisthis.ws.onopen = function(event) {self.text_content = self.text_content + '已经打开连接!' + '\n'}this.ws.onmessage = function(event) {self.text_content = event.data + '\n'}this.ws.onclose = function(event) {self.text_content = self.text_content + '已经关闭连接!' + '\n'}},exit() {if (this.ws) {this.ws.close()this.ws = null}},send() {if (this.ws) {this.ws.send(this.message)} else {alert('未连接到服务器')}}}}
WebSocket ,如果调用过多,可以封装成一个组件,主要是打开当前页面时候调用。所以,在需要WebSocket通信的页面调用当前方法即可
服务器nginx配置
参考:Nginx配置WebSocket – 谢端阳 – 博客园
location / {proxy_pass http://xxx;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "Upgrade";}