共计 7658 个字符,预计需要花费 20 分钟才能阅读完成。
在之前搭建好的项目的基础上新版 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
this is user manage
menumanage.vue 代码和这个类似。
3、测试
分别启动前后端,打开浏览器
(1)查看消息收发
切换到菜单管理:
再次切换到 user 页面,会断开之前的连接重新建立连接,因为 vue 每次进入页面都会执行 mounted。
idea 控制台打印:
(2)postman 调用 user 发送消息接口
浏览器接收成功:
postman 调用 menu 发送消息接口:
浏览器接收成功:
二、按用户推送
上面的 demo,所有的客户端都会接收到消息,现在希望推送给某个 user。则需要建立 WebSocketSession 和 userId 的关系,
(1)前端在 open 建立连接时发送 userId;
WebSocket Client
(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 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、前端
this is user manage:{{this.userAccount}}
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 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 的没有接收到:
原文地址: VUE 使用 websocket