Vue+Websocket 带参数使用

Vue+Websocket 带参数使用
在页面初始化的时候就建立Websocket
vue 前台
在这里插入图片描述

1.在data(){定义websocket=null}
2.在methods(){}以下方法

 //打开一个websocket
        webSocket() {
             const wsurl = localhost:端口号 + "/deviceMonitorWebSocket/" + _self.userId +"/"+deviceId;
            _self.websocket = new WebSocket(wsurl);
            _self.websocket.onopen = _self.websocketonopen;
            _self.websocket.onmessage = _self.websocketonmessage;
            _self.websocket.onerror = _self.websocketonerror;
            _self.websocket.onclose = _self.websocketclose;
        },
        //连接建立之后执行send方法发送数据
        websocketonopen() {
            console.log("Connected to WebSocket server.");
        },
        //连接建立失败重连
        websocketonerror() {
            console.log("Connected to WebSocket server error");
        },
        //数据接收
        websocketonmessage(e) {//e为websocket里面的值
            if (e.data != null && e.data != undefined) {
                let tmp_data = JSON.parse(e.data)
                var productInfoList = tmp_data.devicesList;  
                    Vue.set(this, 'productList', productInfoList);//'productList'为你页面上需要websocket的值
            }
        },
        //关闭
        websocketclose(e) {
            console.log('websocket Connection Closed. ');
        },

关掉timerTask

destroyed() {
        _self.websocket.close();
    },
 

java 后台
DeviceMonitorWebSocket类

@Component
//此注解相当于设置访问URL
@ServerEndpoint("/deviceMonitorWebSocket/{id}/{productId}")
public class DeviceMonitorWebSocket {

    private static CopyOnWriteArraySet<DeviceMonitorWebSocket> webSockets = new CopyOnWriteArraySet<DeviceMonitorWebSocket>();
    private static Map<String, Session> sessionPool = new HashMap<String, Session>();
    private Session session;

    @OnOpen
    public void onOpen(Session session, @PathParam(value = "id") String id, @PathParam(value = "productId") String productId) {
        this.session = session;
        webSockets.add(this);
        sessionPool.put(id, session);

        DeviceTask deviceTask = DeviceTask.getInstance(id, productId);
        deviceTask.start();

    }
    
    /**
    *
    * @param session
    * @param error
    */
   @OnError
   public void onError(Session session, Throwable error) {
       error.printStackTrace();
   }

    @OnClose
    public void onClose() {
        webSockets.remove(this);
        DeviceTask.getInstance("", "").destroyed();
    }

    @OnMessage
    public void onMessage(String message) {
        //JSONObject jsonObject =JSONObject.parseObject(message);

    }

    /**
     * 此为广播消息
     *
     * @param message
     */
    public void sendAllMessage(String message) {
        for (DeviceMonitorWebSocket webSocket : webSockets) {
            try {
                webSocket.session.getAsyncRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 此为单点消息 (发送文本)
     *
     * @param id
     * @param message
     */
    public void sendTextMessage(String id, String message) {
        Session session = sessionPool.get(id);
        if (session != null) {
            try {
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 此为单点消息 (发送对象)
     *
     * @param id
     * @param message
     */
    public void sendObjMessage(String id, Object message) {
        Session session = sessionPool.get(id);
        if (session != null) {
            try {
//              session.getAsyncRemote().sendObject(message);
            	session.getBasicRemote().sendText(JSONObject.toJSONString(message));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

定时器任务DeviceTask

public class DeviceTask extends TimerTask {
    private DeviceMonitorWebSocket deviceMonitorWebSocket = new DeviceMonitorWebSocket();
    private SysStatusService sysStatusService =(SysStatusService) ApplicationContextUtils.getBeanById("SysStatusService");
    private static DeviceTask deviceTask = null;
    private Timer timer = null;
    private String userId;
    private String productId;
    public DeviceTask() {
    }



    //单例模式,保持这个对象
    public static DeviceTask getInstance(String userId, String productId) {
        if  (deviceTask == null) {
            //当flag == true时,为了解决,timer.cancel()后,重新创建一个timer
            deviceTask= new DeviceTask();

        }
        deviceTask.setUserId(userId);
        deviceTask.setProductId(productId);
        return deviceTask;
    }

    public void start() {
        if (timer == null) {
            timer = new Timer();
        } else {
            //从此计时器的任务队列中移除所有已取消的任务。
           timer.purge();
        }

        // myTimeTask 指定执行的线程 delay 延迟时间 timestamp 指定每格多久再次执行一次( 5min执行一次)
        timer.scheduleAtFixedRate(this,0, 定时的时间);
    }

    //定时执行的方法
    @Override
    public void run() {
       //你需要websocket获取的什么数据
         Map<String,Object> deviceMap =*****Service.方法(productId);
        deviceMonitorWebSocket.sendObjMessage(userId,deviceMap);

    }

    public void destroyed() {
        //终止此计时器,丢弃所有当前已安排的任务。(不但结束当前schedule,连整个Timer的线程(即当前的定时任务)都会结束掉)
        deviceTask.cancel();
        deviceTask=null;
        timer.cancel();
        timer.purge();
        timer=null;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getProductId() {
        return productId;
    }

    public void setProductId(String productId) {
        this.productId = productId;
    }
}

<think>我们正在使用Spring Boot、VueWebSocket实现私聊聊天室功能。私聊功能意味着消息只发送给特定的用户,而不是广播给所有在线用户。 实现思路: 1. 后端Spring Boot使用WebSocket,并维护用户会话(Session)信息,同时需要能够根据用户标识(如用户ID)来定向发送消息。 2. 前端Vue建立WebSocket连接,并在连接建立时发送用户标识(如用户ID)给后端,以便后端将用户ID和Session关联起来。 3. 当用户A想给用户B发私信时,前端将消息和接收者用户ID发送给后端,后端根据接收者用户ID找到对应的WebSocket Session,然后发送消息。 步骤: 后端(Spring Boot): a. 添加WebSocket依赖(已提供)。 b. 配置WebSocket,启用ServerEndpointExporter。 c. 编写WebSocket处理器(或使用@ServerEndpoint注解的端点类),在连接建立时,将用户ID(由前端连接时传入)与Session关联并保存(比如使用ConcurrentHashMap)。 d. 处理客户端发送的消息,消息格式应该包含接收者的用户ID和消息内容。然后根据接收者用户ID查找对应的Session,发送消息。 e. 处理连接关闭事件,从Map中移除对应的Session。 前端(Vue): a. 使用WebSocket API建立连接,并在连接建立后发送一个包含当前用户ID的消息(用于注册)。 b. 实现发送消息的方法,将消息(包含接收者ID和消息内容)通过WebSocket发送给后端。 c. 监听WebSocket的onmessage事件,接收并处理来自服务器的消息(如显示在聊天窗口中)。 注意:用户ID如何获取?通常,在用户登录后,我们可以获取到当前用户的ID。在建立WebSocket连接时,可以将用户ID作为参数传递给后端(例如在URL中:ws://localhost:8080/chat?userId=123),或者在连接建立后立即发送一个注册消息包含用户ID。 下面我们分别实现后端和前端的关键代码。 后端代码示例: 1. 添加依赖(pom.xml): ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 配置WebSocketWebSocketConfig.java): ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration @EnableWebSocket public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } } ``` 3. 编写WebSocket端点(ChatEndpoint.java): ```java import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.ConcurrentHashMap; @ServerEndpoint("/chat/{userId}") // 使用路径参数传递userId public class ChatEndpoint { // 保存用户ID到Session的映射 private static ConcurrentHashMap<String, Session> userSessions = new ConcurrentHashMap<>(); @OnOpen public void onOpen(Session session, @PathParam("userId") String userId) { userSessions.put(userId, session); System.out.println("用户连接: " + userId); } @OnMessage public void onMessage(String message, Session session, @PathParam("userId") String senderId) { // 假设消息格式为:{"to":"receiverId", "content":"hello"} // 这里简单处理,实际应用可能需要解析JSON // 为了简化,我们假设消息是固定格式:接收者ID:消息内容 String[] parts = message.split(":", 2); if (parts.length < 2) { // 格式错误 return; } String receiverId = parts[0]; String content = parts[1]; // 根据接收者ID获取Session Session receiverSession = userSessions.get(receiverId); if (receiverSession != null) { try { // 发送消息,这里可以构造更复杂的消息格式(如JSON) receiverSession.getBasicRemote().sendText(senderId + ":" + content); } catch (IOException e) { e.printStackTrace(); } } else { // 接收者不在线,可以存储离线消息或通知发送者 } } @OnClose public void onClose(Session session, @PathParam("userId") String userId) { userSessions.remove(userId); System.out.println("用户断开: " + userId); } @OnError public void onError(Session session, Throwable throwable, @PathParam("userId") String userId) { System.err.println("用户ID: " + userId + " 发生错误"); throwable.printStackTrace(); } } ``` 注意:上述代码中,我们使用路径参数传递userId,这样在连接建立时就可以知道是哪个用户。同时,消息格式我们约定为“接收者ID:消息内容”,实际项目中建议使用JSON格式。 前端Vue代码示例(假设在某个Vue组件中): ```vue <template> <div> <input type="text" v-model="receiverId" placeholder="接收者ID"> <input type="text" v-model="message" placeholder="消息"> <button @click="sendMessage">发送</button> <div v-for="(msg, index) in messages" :key="index">{{ msg }}</div> </div> </template> <script> export default { data() { return { receiverId: '', message: '', messages: [], socket: null, userId: '当前用户ID' // 这里应该从登录信息中获取 } }, mounted() { // 建立WebSocket连接,将当前用户ID作为路径参数 this.socket = new WebSocket(`ws://localhost:8080/chat/${this.userId}`); this.socket.onopen = () => { console.log('连接已建立'); }; this.socket.onmessage = (event) => { // 接收到消息,格式为 "发送者ID:消息内容" this.messages.push(event.data); }; this.socket.onclose = () => { console.log('连接关闭'); }; }, methods: { sendMessage() { if (this.message.trim() !== '') { // 发送格式:接收者ID:消息内容 const fullMessage = `${this.receiverId}:${this.message}`; this.socket.send(fullMessage); this.message = ''; } } }, beforeDestroy() { // 组件销毁时关闭WebSocket连接 this.socket.close(); } } </script> ``` 以上是一个简单的私聊实现。但是,请注意,实际应用中需要更健壮的消息格式(如JSON),并且需要处理用户认证、离线消息、消息存储等问题。 另外,上述后端代码中,我们使用了一个静态的ConcurrentHashMap来存储用户会话,这在单机环境下可行,但在分布式环境下需要改用Redis等中间件来存储会话信息。 现在,我们根据这个实现,生成相关问题。 §§相关问题§§ 1. 如何确保WebSocket连接的安全性(例如用户认证)? 2. 在分布式环境下,如何实现WebSocket私聊功能? 3. 如何实现离线消息存储和推送? 4. 前端如何处理复杂的消息格式(如JSON)? 5. 如何优化WebSocket消息的传输效率?</think>基于 Spring Boot、VueWebSocket 实现私聊聊天室功能的解决方案如下: ### 一、后端实现(Spring Boot) 1. **添加依赖** ```xml <!-- pom.xml --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. **WebSocket 配置类** ```java @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(chatHandler(), "/chat") .setAllowedOrigins("*"); } @Bean public WebSocketHandler chatHandler() { return new PrivateChatHandler(); } } ``` 3. **消息处理器** ```java public class PrivateChatHandler extends TextWebSocketHandler { // 存储用户会话: <用户ID, Session> private static final Map<String, WebSocketSession> userSessions = new ConcurrentHashMap<>(); @Override public void afterConnectionEstablished(WebSocketSession session) { String userId = getUserIdFromSession(session); // 从请求参数获取用户ID userSessions.put(userId, session); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) { // 消息格式: {"to":"targetUserId", "content":"Hello"} JsonObject msgObj = JsonParser.parseString(message.getPayload()).getAsJsonObject(); String targetUserId = msgObj.get("to").getAsString(); String content = msgObj.get("content").getAsString(); // 私发给目标用户 WebSocketSession targetSession = userSessions.get(targetUserId); if(targetSession != null && targetSession.isOpen()) { targetSession.sendMessage(new TextMessage(content)); } } private String getUserIdFromSession(WebSocketSession session) { // 从URL参数获取: ws://localhost:8080/chat?userId=123 return session.getUri().getQuery().split("=")[1]; } } ``` ### 二、前端实现(Vue 3) 1. **建立 WebSocket 连接** ```vue <script setup> import { ref, onMounted } from 'vue'; const userId = ref('user123'); // 当前用户ID const targetUserId = ref(''); // 聊天对象ID const message = ref(''); const messages = ref([]); let socket = null; onMounted(() => { // 连接WebSocket (携带用户ID) socket = new WebSocket(`ws://localhost:8080/chat?userId=${userId.value}`); socket.onmessage = (event) => { messages.value.push({ sender: targetUserId.value, content: event.data }); }; }); const sendMessage = () => { if (message.value.trim() && targetUserId.value) { const msg = { to: targetUserId.value, content: message.value }; socket.send(JSON.stringify(msg)); messages.value.push({ sender: 'me', content: message.value }); message.value = ''; } }; </script> ``` 2. **聊天界面组件** ```vue <template> <div> <input v-model="targetUserId" placeholder="输入对方ID"> <div v-for="(msg, index) in messages" :key="index"> <strong>{{ msg.sender }}:</strong> {{ msg.content }} </div> <input v-model="message" @keyup.enter="sendMessage"> <button @click="sendMessage">发送</button> </div> </template> ``` ### 三、关键技术点 1. **用户标识管理** - 连接建立时通过 URL 参数传递用户 ID:`ws://host/chat?userId=123` - 后端使用 `ConcurrentHashMap` 存储用户ID和Session的映射 2. **消息路由机制** - 前端发送消息时指定接收方 ID:`{ "to": "targetId", "content": "text" }` - 后端根据目标ID查找对应 Session 发送消息 3. **跨域处理** - 配置 `setAllowedOrigins("*")` 允许跨域(生产环境应指定域名) 4. **异常处理** - 添加 `@OnError` 方法处理 WebSocket 错误 - 前端监听 `onerror` 和 `onclose` 事件 ### 四、部署流程 1. 启动 Spring Boot 服务(默认端口 8080) 2. 部署 Vue 项目(使用 Nginx 或直接运行) 3. 访问页面时携带用户 ID 参数: ``` http://localhost:8080?userId=user1 ``` > **注意事项**: > 1. 生产环境需添加身份认证(如 JWT 验证) > 2. 需要实现离线消息存储(可集成 Redis) > 3. 分布式部署时需使用 STOMP 或消息队列[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值