VUE使用websocket

在之前搭建好的项目的基础上新版security demo(二)前端-CSDN博客

目录

一、代码改造

1、后端改造

2、VUE使用websocket

3、测试

二、按用户推送

1、完整代码如下

1.1、前端

1.2、后端:

2、测试


一、代码改造

1、后端改造

(1)把websocket相关代码复制到web项目:

(2)添加白名单

web-socket端口无需token验证,SecurityWebConfig添加白名单

 @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers("/param/**", "/user-websocket-endpoint/**","/menu-websocket-endpoint/**");
    }
2、VUE使用websocket
<template>
  <div>this is user manage</div>
</template>
<script>
export default {
  data() {
    return {
      socket: null,
      message: '',
      inputMessage: ''
    };
  },
  mounted() {
    // Create a new WebSocket connection
    this.socket = new WebSocket("ws://localhost:2222/securityDemo/user-websocket-endpoint");
    
    // Set up event listeners
    this.socket.onopen = (event) => {
      console.log('WebSocket connection opened.');
      this.socket.send("Hello Server! This is menu client");
    };
    
    this.socket.onmessage = (event) => {
      this.message = event.data;
    };
    
    this.socket.onerror = (error) => {
      console.error('WebSocket Error:', error);
    };
    
    this.socket.onclose = (event) => {
      console.log('WebSocket connection closed.');
    };
  },
  methods: {
    sendMessage() {
      if (this.socket && this.inputMessage) {
        this.socket.send(this.inputMessage);
        this.inputMessage = ''; // Clear the input field after sending
      }
    }
  },
  // beforeDestroy() {
  //   // Close the WebSocket connection when the component is destroyed
  //   if (this.socket) {
  //     this.socket.close();
  //   }
  // }
};
</script>

menumanage.vue代码和这个类似。

3、测试

分别启动前后端,打开浏览器

(1)查看消息收发

切换到菜单管理:

再次切换到user页面,会断开之前的连接重新建立连接,因为vue每次进入页面都会执行mounted。

idea控制台打印:

(2)postman调用user发送消息接口

浏览器接收成功:

postman调用menu发送消息接口:

浏览器接收成功:

二、按用户推送

上面的demo,所有的客户端都会接收到消息,现在希望推送给某个user。则需要建立WebSocketSession和userId的关系,

(1)前端在open建立连接时发送userId;

<!DOCTYPE html>
<html>
<head>
    <title>WebSocket Client</title>
</head>
<body>
    <script>
        const userId = "user123"; // Replace with dynamic user ID

        const socket = new WebSocket(`ws://localhost:8080/websocket-endpoint`);

        socket.onopen = function(event) {
            console.log("WebSocket connection opened.");
            socket.send(JSON.stringify({ type: "REGISTER", userId: userId }));
        };

        socket.onmessage = function(event) {
            const message = event.data;
            console.log("Message from server: " + message);
        };

        socket.onclose = function(event) {
            console.log("WebSocket connection closed.");
        };

        socket.onerror = function(error) {
            console.error("WebSocket Error: " + error);
        };
    </script>
</body>
</html>

(2)后端WebSocketHandler存储userId和WebSocketSession的映射关系

import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import org.springframework.web.socket.CloseStatus;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Component
public class UserWebSocketHandler extends TextWebSocketHandler {

    private final ConcurrentMap<String, WebSocketSession> userSessions = new ConcurrentHashMap<>();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String userId = getUserIdFromSession(session);
        if (userId != null) {
            userSessions.put(userId, session);
            System.out.println("WebSocket connection established for userId: " + userId);
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String userId = getUserIdFromSession(session);
        if (userId != null) {
            userSessions.remove(userId);
            System.out.println("WebSocket connection closed for userId: " + userId);
        }
    }

    public void sendMessageToUser(String userId, String message) throws IOException {
        WebSocketSession session = userSessions.get(userId);
        if (session != null && session.isOpen()) {
            session.sendMessage(new TextMessage(message));
        }
    }

    private String getUserIdFromSession(WebSocketSession session) {
        // Assuming userId is stored as a session attribute
        return (String) session.getAttributes().get("userId");
    }
}

(3)发送消息时根据userId检索目标WebSocketSession。

1、完整代码如下
1.1、前端
<template>
  <div>this is user manage:{{this.userAccount}}</div>
</template>
<script>
export default {
  data() {
    return {
      socket: null,
      message: '',
      inputMessage: ''
    };
  },
computed: {
    userAccount() {
      return this.$store.getters.name;
    }
},
  mounted() {
    // Create a new WebSocket connection
    this.socket = new WebSocket("ws://localhost:2222/securityDemo/user-websocket-endpoint");
    
    // Set up event listeners
    this.socket.onopen = (event) => {
      console.log('WebSocket connection opened.');
       let msg = {"userAccount":this.userAccount}
       this.socket.send(JSON.stringify(msg));
    };
    
    this.socket.onmessage = (event) => {
      this.message = event.data;
    };
    
    this.socket.onerror = (error) => {
      console.error('WebSocket Error:', error);
    };
    
    this.socket.onclose = (event) => {
      console.log('WebSocket connection closed.');
    };
  },
  methods: {
    sendMessage() {
      if (this.socket && this.inputMessage) {
        this.socket.send(this.inputMessage);
        this.inputMessage = ''; // Clear the input field after sending
      }
    }
  },
  // beforeDestroy() {
  //   // Close the WebSocket connection when the component is destroyed
  //   if (this.socket) {
  //     this.socket.close();
  //   }
  // }
};
</script>
1.2、后端:

(1)常量

package com.demo.security.ws.constant;

import lombok.Getter;
import org.springframework.web.socket.WebSocketSession;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class UserSessionConstant {

    @Getter
    private static Map<String,WebSocketSession> sessionMap = new HashMap<>();

    public static void add(String userId,WebSocketSession session) {
        sessionMap.put(userId,session);
    }

    public static void remove(WebSocketSession session) {
        //从map中找到key,再remove key
        //sessionMap.remove(userAccount);
    }
}

(2)ws操作

package com.demo.security.ws;

import com.demo.security.dto.MsgDTO;
import com.demo.security.dto.UserDTO;
import com.demo.security.ws.constant.UserSessionConstant;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

@Component
@Slf4j
public class UserWebSocketHandler extends TextWebSocketHandler {

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //UserSessionConstant.add(session);
        log.info("user有新的连接,sessionId:{}",session.getId());
    }

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 处理接收到的消息
        log.info("user服务端Received message: {}",message.getPayload());
        String payLoad = message.getPayload();
        ObjectMapper objectMapper = new ObjectMapper();
        MsgDTO msgDTO = objectMapper.readValue(payLoad, MsgDTO.class);
        UserSessionConstant.add(msgDTO.getUserAccount(),session);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        UserSessionConstant.remove(session);
        log.info("user连接已断开sessionId:{}",session.getId());
    }

    public void sendMessageToAll(String message) {
        for(WebSocketSession session : UserSessionConstant.getSessionMap().values()) {
            if (session.isOpen()) {
                try {
                    session.sendMessage(new TextMessage(message));
                    log.info("user发送消息给{}成功",session.getId());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void sendMessageToUser(String message,String userAccount) {
        for(String sessionUserAccount : UserSessionConstant.getSessionMap().keySet()){
            if(!userAccount.equals(sessionUserAccount)){
                continue;
            }
            WebSocketSession session = UserSessionConstant.getSessionMap().get(userAccount);
            if (session.isOpen()) {
                try {
                    session.sendMessage(new TextMessage(message));
                    log.info("user发送消息给用户{}成功",userAccount);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

(3)controller接口

package com.demo.security.controller;


import com.demo.security.dto.UserDTO;
import com.demo.security.ws.UserWebSocketHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/userMsg")
public class UserMsgController {

    @Autowired
    private UserWebSocketHandler userWebSocketHandler;

    @RequestMapping("/send")
    public void sendMessage(UserDTO messageDTO) {
        userWebSocketHandler.sendMessageToUser(messageDTO.toString(),messageDTO.getUserAccount());
    }
}
2、测试

(1)

打开两个浏览器,分别登录zs、admin

后端断点可以看到map存储了两条数据:

(2)调用postman接口给zs发送消息:

查看浏览器,zs的账号接收到了消息,admin的没有接收到:

相关推荐
过期的H2O211 小时前
【H2O2|全栈】JS进阶知识(四)Ajax
开发语言·javascript·ajax
生椰拿铁You16 小时前
前端前置——ajax
前端·javascript·ajax
子非鱼9212 天前
【Ajax】原生Ajax与jQuery中的Ajax
xml·ajax·node.js·jquery
蜗牛学苑_武汉3 天前
浏览器中的事件循环
前端·javascript·chrome·ajax·软件工程·html5
awonw3 天前
[java][高级]Filter&Listener&Ajax
java·开发语言·ajax
supercool73 天前
Ajax学习
前端·学习·ajax
samroom4 天前
AJAX学习笔记总结
前端·学习·ajax
中庸之为德也,其至矣乎5 天前
uniapp 图片bug(图片为线上地址,url不变,内容更新)
开发语言·前端·javascript·css·ajax·uni-app
谈谈叭5 天前
Vue3+Data-V实现可视化大屏页面布局
javascript·css·vue.js·ajax·信息可视化·html·html5
盒马盒马7 天前
Ajax:跨域 & JSONP
前端·ajax