Pre Merge pull request !514 from AprilWind/dev-ws

This commit is contained in:
AprilWind 2024-04-11 01:24:44 +00:00 committed by Gitee
commit cf7d3d9e35
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
9 changed files with 131 additions and 25 deletions

View File

@ -18,7 +18,7 @@ import org.dromara.common.core.domain.model.SocialLoginBody;
import org.dromara.common.core.utils.*;
import org.dromara.common.encrypt.annotation.ApiEncrypt;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.satoken.utils.TokenUtils;
import org.dromara.common.social.config.properties.SocialLoginConfigProperties;
import org.dromara.common.social.config.properties.SocialProperties;
import org.dromara.common.social.utils.SocialUtils;
@ -95,11 +95,11 @@ public class AuthController {
// 登录
LoginVo loginVo = IAuthStrategy.login(body, client, grantType);
Long userId = LoginHelper.getUserId();
String tokenId = TokenUtils.getTokenId();
scheduledExecutorService.schedule(() -> {
WebSocketMessageDto dto = new WebSocketMessageDto();
dto.setMessage("欢迎登录RuoYi-Vue-Plus后台管理系统");
dto.setSessionKeys(List.of(userId));
dto.setSessionKeys(List.of(tokenId));
WebSocketUtils.publishMessage(dto);
}, 3, TimeUnit.SECONDS);
return R.ok(loginVo);
@ -198,7 +198,7 @@ public class AuthController {
}
// 根据域名进行筛选
List<TenantListVo> list = StreamUtils.filter(voList, vo ->
StringUtils.equals(vo.getDomain(), host));
StringUtils.equals(vo.getDomain(), host));
// 返回对象
LoginTenantVo vo = new LoginTenantVo();
vo.setVoList(CollUtil.isNotEmpty(list) ? list : voList);

View File

@ -0,0 +1,88 @@
package org.dromara.common.satoken.utils;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.dromara.common.core.enums.DeviceType;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* token工具类
*
* @author 21001
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class TokenUtils {
/**
* 会话idloginId前缀
*/
public static final String SYS_USER = "sys_user:";
/**
* 获取当前登录用户的token
*/
public static String getTokenId() {
return StpUtil.getTokenInfo().getTokenValue();
}
/**
* 获取当前用户的 token 集合
*/
public static List<String> getTokenIds() {
return StpUtil.getTokenValueListByLoginId(SYS_USER + LoginHelper.getUserId());
}
/**
* 获取当前用户 指定设备类型端的 token 集合
*/
public static List<String> getTokenIds(DeviceType device) {
return StpUtil.getTokenValueListByLoginId(SYS_USER + LoginHelper.getUserId(), device.getDevice());
}
/**
* 获取指定账号 userId token 集合
*/
public static List<String> getTokenIds(Long userId) {
return StpUtil.getTokenValueListByLoginId(SYS_USER + userId);
}
/**
* 获取账号 userId 指定设备类型端的 token 集合
*/
public static List<String> getTokenIds(Long userId, DeviceType device) {
return StpUtil.getTokenValueListByLoginId(SYS_USER + userId, device.getDevice());
}
/**
* 获取指定账号 userIds token 集合
*/
public static List<String> getTokenUserIds(Set<Long> userIds) {
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
return userIds.stream()
.flatMap(userId -> StpUtil.getTokenValueListByLoginId(SYS_USER + userId)
.stream())
.collect(Collectors.toList());
}
/**
* 获取账号 userIds 指定设备类型端的 token 集合
*/
public static List<String> getTokenUserIds(Set<Long> userIds, DeviceType device) {
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
return userIds.stream()
.flatMap(userId -> StpUtil.getTokenValueListByLoginId(SYS_USER + userId, device.getDevice())
.stream())
.collect(Collectors.toList());
}
}

View File

@ -6,10 +6,12 @@ package org.dromara.common.websocket.constant;
* @author zendwang
*/
public interface WebSocketConstants {
/**
* websocketSession中的参数的key
*/
String LOGIN_USER_KEY = "loginUser";
String TOKEN_ID_KEY = "tokenId";
/**
* 订阅的频道

View File

@ -18,9 +18,9 @@ public class WebSocketMessageDto implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 需要推送到的session key 列表
* 需要推送到的session key 列表 一般为用户tokenId
*/
private List<Long> sessionKeys;
private List<String> sessionKeys;
/**
* 需要发送的消息

View File

@ -2,6 +2,7 @@ package org.dromara.common.websocket.handler;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.satoken.utils.TokenUtils;
import org.dromara.common.websocket.dto.WebSocketMessageDto;
import org.dromara.common.websocket.holder.WebSocketSessionHolder;
import org.dromara.common.websocket.utils.WebSocketUtils;
@ -11,6 +12,7 @@ import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import java.util.List;
import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY;
import static org.dromara.common.websocket.constant.WebSocketConstants.TOKEN_ID_KEY;
/**
* WebSocketHandler 实现类
@ -26,7 +28,8 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) {
LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
WebSocketSessionHolder.addSession(loginUser.getUserId(), session);
String tokenId = (String) session.getAttributes().get(TOKEN_ID_KEY);
WebSocketSessionHolder.addSession(tokenId, session);
log.info("[connect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType());
}
@ -40,9 +43,9 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
List<Long> userIds = List.of(loginUser.getUserId());
List<String> tokenIds = TokenUtils.getTokenIds(loginUser.getUserId());
WebSocketMessageDto webSocketMessageDto = new WebSocketMessageDto();
webSocketMessageDto.setSessionKeys(userIds);
webSocketMessageDto.setSessionKeys(tokenIds);
webSocketMessageDto.setMessage(message.getPayload());
WebSocketUtils.publishMessage(webSocketMessageDto);
}
@ -85,7 +88,8 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
WebSocketSessionHolder.removeSession(loginUser.getUserId());
String tokenId = (String) session.getAttributes().get(TOKEN_ID_KEY);
WebSocketSessionHolder.removeSession(tokenId);
log.info("[disconnect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType());
}

View File

@ -16,27 +16,31 @@ import java.util.concurrent.ConcurrentHashMap;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class WebSocketSessionHolder {
private static final Map<Long, WebSocketSession> USER_SESSION_MAP = new ConcurrentHashMap<>();
private static final Map<String, WebSocketSession> USER_SESSION_MAP = new ConcurrentHashMap<>();
public static void addSession(Long sessionKey, WebSocketSession session) {
/**
* @param sessionKey session主键 一般为用户tokenId
* @param session 会话
*/
public static void addSession(String sessionKey, WebSocketSession session) {
USER_SESSION_MAP.put(sessionKey, session);
}
public static void removeSession(Long sessionKey) {
public static void removeSession(String sessionKey) {
if (USER_SESSION_MAP.containsKey(sessionKey)) {
USER_SESSION_MAP.remove(sessionKey);
}
}
public static WebSocketSession getSessions(Long sessionKey) {
public static WebSocketSession getSessions(String sessionKey) {
return USER_SESSION_MAP.get(sessionKey);
}
public static Set<Long> getSessionsAll() {
public static Set<String> getSessionsAll() {
return USER_SESSION_MAP.keySet();
}
public static Boolean existSession(Long sessionKey) {
public static Boolean existSession(String sessionKey) {
return USER_SESSION_MAP.containsKey(sessionKey);
}
}

View File

@ -1,8 +1,9 @@
package org.dromara.common.websocket.interceptor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.satoken.utils.LoginHelper;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.satoken.utils.TokenUtils;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.socket.WebSocketHandler;
@ -11,6 +12,7 @@ import org.springframework.web.socket.server.HandshakeInterceptor;
import java.util.Map;
import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY;
import static org.dromara.common.websocket.constant.WebSocketConstants.TOKEN_ID_KEY;
/**
* WebSocket握手请求的拦截器
@ -32,7 +34,9 @@ public class PlusWebSocketInterceptor implements HandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) {
LoginUser loginUser = LoginHelper.getLoginUser();
String tokenId = TokenUtils.getTokenId();
attributes.put(LOGIN_USER_KEY, loginUser);
attributes.put(TOKEN_ID_KEY, tokenId);
return true;
}

View File

@ -31,10 +31,10 @@ public class WebSocketUtils {
/**
* 发送消息
*
* @param sessionKey session主键 一般为用户id
* @param sessionKey session主键 一般为用户tokenId
* @param message 消息文本
*/
public static void sendMessage(Long sessionKey, String message) {
public static void sendMessage(String sessionKey, String message) {
WebSocketSession session = WebSocketSessionHolder.getSessions(sessionKey);
sendMessage(session, message);
}
@ -54,9 +54,9 @@ public class WebSocketUtils {
* @param webSocketMessage 消息对象
*/
public static void publishMessage(WebSocketMessageDto webSocketMessage) {
List<Long> unsentSessionKeys = new ArrayList<>();
List<String> unsentSessionKeys = new ArrayList<>();
// 当前服务内session,直接发送消息
for (Long sessionKey : webSocketMessage.getSessionKeys()) {
for (String sessionKey : webSocketMessage.getSessionKeys()) {
if (WebSocketSessionHolder.existSession(sessionKey)) {
WebSocketUtils.sendMessage(sessionKey, webSocketMessage.getMessage());
continue;

View File

@ -12,6 +12,7 @@ import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.reflect.ReflectUtils;
import org.dromara.common.mail.utils.MailUtils;
import org.dromara.common.satoken.utils.TokenUtils;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.websocket.dto.WebSocketMessageDto;
import org.dromara.common.websocket.utils.WebSocketUtils;
@ -23,10 +24,13 @@ import org.dromara.workflow.common.enums.MessageTypeEnum;
import org.dromara.workflow.common.enums.TaskStatusEnum;
import org.dromara.workflow.domain.ActHiProcinst;
import org.dromara.workflow.domain.ActHiTaskinst;
import org.dromara.workflow.domain.vo.*;
import org.dromara.workflow.domain.vo.MultiInstanceVo;
import org.dromara.workflow.domain.vo.ParticipantVo;
import org.dromara.workflow.domain.vo.ProcessInstanceVo;
import org.dromara.workflow.flowable.cmd.UpdateHiTaskInstCmd;
import org.dromara.workflow.mapper.ActHiTaskinstMapper;
import org.dromara.workflow.service.*;
import org.dromara.workflow.service.IActHiProcinstService;
import org.dromara.workflow.service.IWorkflowUserService;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.common.engine.api.delegate.Expression;
@ -41,7 +45,7 @@ import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import java.util.*;
import static org.dromara.workflow.common.constant.FlowConstant.*;
import static org.dromara.workflow.common.constant.FlowConstant.PROCESS_INSTANCE_VO;
/**
* 工作流工具
@ -324,7 +328,7 @@ public class WorkflowUtils {
switch (messageTypeEnum) {
case SYSTEM_MESSAGE:
WebSocketMessageDto dto = new WebSocketMessageDto();
dto.setSessionKeys(new ArrayList<>(userIds));
dto.setSessionKeys(TokenUtils.getTokenUserIds(userIds));
dto.setMessage(message);
WebSocketUtils.publishMessage(dto);
break;