From e6f887294d2862c878e92b9d9d1d1c245891c00b Mon Sep 17 00:00:00 2001 From: rays <1615175118@qq.com> Date: Tue, 22 Jun 2021 15:36:20 +0800 Subject: [PATCH] =?UTF-8?q?1.=E4=BF=AE=E5=A4=8D=E6=B6=88=E6=81=AF=E9=80=9A?= =?UTF-8?q?=E7=9F=A5BUG=202.=E6=9B=B4=E6=94=B9WebSocket=E9=80=9A=E4=BF=A1?= =?UTF-8?q?=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kernel/socket/api/SocketOperatorApi.java | 5 +- .../websocket/operator/WebSocketOperator.java | 4 +- .../operator/channel/GettySocketOperator.java | 12 ++- .../websocket/server/WebSocketServer.java | 73 +++++++++---------- .../websocket/session/SessionCenter.java | 13 ++-- kernel-s-message/message-sdk-db/pom.xml | 2 +- .../message/db/MessageDbServiceImpl.java | 22 ++++-- .../kernel/system/api/MenuServiceApi.java | 11 +++ .../menu/service/impl/SysMenuServiceImpl.java | 27 ++++++- .../role/service/impl/SysRoleServiceImpl.java | 23 +++++- 10 files changed, 127 insertions(+), 65 deletions(-) diff --git a/kernel-d-socket/socket-api/src/main/java/cn/stylefeng/roses/kernel/socket/api/SocketOperatorApi.java b/kernel-d-socket/socket-api/src/main/java/cn/stylefeng/roses/kernel/socket/api/SocketOperatorApi.java index 4d73ba413..3c7403775 100644 --- a/kernel-d-socket/socket-api/src/main/java/cn/stylefeng/roses/kernel/socket/api/SocketOperatorApi.java +++ b/kernel-d-socket/socket-api/src/main/java/cn/stylefeng/roses/kernel/socket/api/SocketOperatorApi.java @@ -1,5 +1,6 @@ package cn.stylefeng.roses.kernel.socket.api; +import cn.stylefeng.roses.kernel.socket.api.exception.SocketException; import cn.stylefeng.roses.kernel.socket.api.message.SocketMsgCallbackInterface; /** @@ -21,7 +22,7 @@ public interface SocketOperatorApi { * @author majianguo * @date 2021/6/11 下午2:19 **/ - void sendMsgOfUserSessionBySessionId(String msgType, String sessionId, Object msg); + void sendMsgOfUserSessionBySessionId(String msgType, String sessionId, Object msg) throws SocketException; /** * 发送消息到指定用户的所有会话 @@ -34,7 +35,7 @@ public interface SocketOperatorApi { * @author majianguo * @date 2021/6/2 上午9:35 **/ - void sendMsgOfUserSession(String msgType, String userId, Object msg); + void sendMsgOfUserSession(String msgType, String userId, Object msg) throws SocketException; /** * 发送消息到所有会话 diff --git a/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/operator/WebSocketOperator.java b/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/operator/WebSocketOperator.java index 282f46194..c298bc0e1 100644 --- a/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/operator/WebSocketOperator.java +++ b/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/operator/WebSocketOperator.java @@ -25,7 +25,7 @@ import java.util.List; public class WebSocketOperator implements SocketOperatorApi { @Override - public void sendMsgOfUserSessionBySessionId(String msgType, String sessionId, Object msg) { + public void sendMsgOfUserSessionBySessionId(String msgType, String sessionId, Object msg) throws SocketException { SocketSession session = SessionCenter.getSessionBySessionId(sessionId); if (ObjectUtil.isEmpty(session)) { throw new SocketException(SocketExceptionEnum.SESSION_NOT_EXIST); @@ -37,7 +37,7 @@ public class WebSocketOperator implements SocketOperatorApi { } @Override - public void sendMsgOfUserSession(String msgType, String userId, Object msg) { + public void sendMsgOfUserSession(String msgType, String userId, Object msg) throws SocketException { // 根据用户ID获取会话 List> socketSessionList = SessionCenter.getSessionByUserIdAndMsgType(userId); if (ObjectUtil.isEmpty(socketSessionList)) { diff --git a/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/operator/channel/GettySocketOperator.java b/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/operator/channel/GettySocketOperator.java index e66decd53..6c07d8841 100644 --- a/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/operator/channel/GettySocketOperator.java +++ b/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/operator/channel/GettySocketOperator.java @@ -26,7 +26,9 @@ public class GettySocketOperator implements GettyChannelExpandInterFace { @Override public void writeAndFlush(Object obj) { try { - socketChannel.getBasicRemote().sendText(JSON.toJSONString(obj)); + if (socketChannel.isOpen()) { + socketChannel.getBasicRemote().sendText(JSON.toJSONString(obj)); + } } catch (IOException e) { e.printStackTrace(); } @@ -34,13 +36,17 @@ public class GettySocketOperator implements GettyChannelExpandInterFace { @Override public void writeToChannel(Object obj) { - socketChannel.getAsyncRemote().sendText(JSON.toJSONString(obj)); + if (socketChannel.isOpen()) { + socketChannel.getAsyncRemote().sendText(JSON.toJSONString(obj)); + } } @Override public void close() { try { - socketChannel.close(); + if (socketChannel.isOpen()) { + socketChannel.close(); + } } catch (IOException e) { e.printStackTrace(); } diff --git a/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/server/WebSocketServer.java b/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/server/WebSocketServer.java index e3c6c0c2b..80b14ce3c 100644 --- a/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/server/WebSocketServer.java +++ b/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/server/WebSocketServer.java @@ -40,6 +40,31 @@ public class WebSocketServer { **/ @OnOpen public void onOpen(Session session, @PathParam("userId") String userId) { + // 操作api包装 + GettySocketOperator gettySocketOperator = new GettySocketOperator(session); + + // 回复消息 + WebSocketMessageDTO replyMsg = new WebSocketMessageDTO(); + replyMsg.setServerMsgType(ServerMessageTypeEnum.SYS_REPLY_MSG_TYPE.getCode()); + replyMsg.setToUserId(userId); + + try { + // 设置回复内容 + replyMsg.setData(session.getId()); + + // 创建会话对象 + SocketSession socketSession = new SocketSession<>(); + socketSession.setSessionId(session.getId()); + socketSession.setUserId(userId); + socketSession.setSocketOperatorApi(gettySocketOperator); + socketSession.setConnectionTime(System.currentTimeMillis()); + + // 维护会话 + SessionCenter.addSocketSession(socketSession); + } finally { + // 回复消息 + gettySocketOperator.writeAndFlush(replyMsg); + } } /** @@ -68,13 +93,16 @@ public class WebSocketServer { // 转换为Java对象 WebSocketMessageDTO WebSocketMessageDTO = JSON.parseObject(message, WebSocketMessageDTO.class); + // 维护通道是否已初始化 + SocketSession socketSession = SessionCenter.getSessionBySessionId(socketChannel.getId()); + // 心跳包 - if (ClientMessageTypeEnum.USER_HEART.getCode().equals(WebSocketMessageDTO.getClientMsgType())) { + if (ObjectUtil.isNotEmpty(socketSession) && ClientMessageTypeEnum.USER_HEART.getCode().equals(WebSocketMessageDTO.getClientMsgType())) { // 更新会话最后活跃时间 - SocketSession session = SessionCenter.getSessionBySessionId(socketChannel.getId()); - if (ObjectUtil.isNotEmpty(session)) { - session.setLastActiveTime(System.currentTimeMillis()); + if (ObjectUtil.isNotEmpty(socketSession)) { + socketSession.setLastActiveTime(System.currentTimeMillis()); } + return; } // 用户ID为空不处理直接跳过 @@ -82,40 +110,6 @@ public class WebSocketServer { return; } - // 维护通道是否已初始化 - SocketSession socketSession = SessionCenter.getSessionBySessionId(socketChannel.getId()); - if (ObjectUtil.isEmpty(socketSession) && ClientMessageTypeEnum.USER_CONNECTION_AUTHENTICATION.getCode().equals(WebSocketMessageDTO.getClientMsgType())) { - // 操作api包装 - GettySocketOperator gettySocketOperator = new GettySocketOperator(socketChannel); - - // 回复消息 - WebSocketMessageDTO replyMsg = new WebSocketMessageDTO(); - replyMsg.setServerMsgType(ServerMessageTypeEnum.SYS_REPLY_MSG_TYPE.getCode()); - replyMsg.setToUserId(WebSocketMessageDTO.getFormUserId()); - - try { - // 校验token是否合法 - JwtContext.me().validateTokenWithException(WebSocketMessageDTO.getData().toString()); - - // 设置回复内容 - replyMsg.setData(socketChannel.getId()); - - // 创建会话对象 - socketSession = new SocketSession<>(); - socketSession.setSessionId(socketChannel.getId()); - socketSession.setUserId(WebSocketMessageDTO.getFormUserId()); - socketSession.setSocketOperatorApi(gettySocketOperator); - socketSession.setConnectionTime(System.currentTimeMillis()); - - // 维护会话 - SessionCenter.addSocketSession(socketSession); - } finally { - // 回复消息 - gettySocketOperator.writeAndFlush(replyMsg); - } - return; - } - // 会话建立成功执行业务逻辑 if (ObjectUtil.isNotEmpty(socketSession)) { @@ -143,7 +137,6 @@ public class WebSocketServer { **/ @OnError public void onError(Session session, Throwable error) { - log.error("发生错误"); - error.printStackTrace(); + log.error("session 发生错误:" + session.getId()); } } diff --git a/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/session/SessionCenter.java b/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/session/SessionCenter.java index 97d93d04a..7c6fbdad2 100644 --- a/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/session/SessionCenter.java +++ b/kernel-d-socket/socket-business-websocket/src/main/java/cn/stylefeng/roses/kernel/socket/business/websocket/session/SessionCenter.java @@ -4,8 +4,7 @@ import cn.hutool.core.util.ObjectUtil; import cn.stylefeng.roses.kernel.socket.api.session.pojo.SocketSession; import cn.stylefeng.roses.kernel.socket.business.websocket.operator.channel.GettySocketOperator; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -102,9 +101,13 @@ public class SessionCenter { * @date 2021/6/1 下午3:25 **/ public static void closed(String sessionId) { - for (List> values : socketSessionMap.values()) { - if (ObjectUtil.isNotEmpty(values)) { - values.removeIf(item -> item.getSessionId().equals(sessionId)); + Set>>> entrySet = socketSessionMap.entrySet(); + Iterator>>> iterator = entrySet.iterator(); + while (iterator.hasNext()) { + Map.Entry>> next = iterator.next(); + List> value = next.getValue(); + if (ObjectUtil.isNotEmpty(value)) { + value.removeIf(gettySocketOperatorSocketSession -> gettySocketOperatorSocketSession.getSessionId().equals(sessionId)); } } } diff --git a/kernel-s-message/message-sdk-db/pom.xml b/kernel-s-message/message-sdk-db/pom.xml index 0c481a444..50bc4327b 100644 --- a/kernel-s-message/message-sdk-db/pom.xml +++ b/kernel-s-message/message-sdk-db/pom.xml @@ -40,7 +40,7 @@ cn.stylefeng.roses - socket-sdk-websocket + socket-api ${roses.version} diff --git a/kernel-s-message/message-sdk-db/src/main/java/cn/stylefeng/roses/kernel/message/db/MessageDbServiceImpl.java b/kernel-s-message/message-sdk-db/src/main/java/cn/stylefeng/roses/kernel/message/db/MessageDbServiceImpl.java index 2618d793e..1d78fffc7 100644 --- a/kernel-s-message/message-sdk-db/src/main/java/cn/stylefeng/roses/kernel/message/db/MessageDbServiceImpl.java +++ b/kernel-s-message/message-sdk-db/src/main/java/cn/stylefeng/roses/kernel/message/db/MessageDbServiceImpl.java @@ -43,6 +43,7 @@ import cn.stylefeng.roses.kernel.message.db.service.SysMessageService; import cn.stylefeng.roses.kernel.rule.enums.YesOrNotEnum; import cn.stylefeng.roses.kernel.socket.api.SocketOperatorApi; import cn.stylefeng.roses.kernel.socket.api.enums.ServerMessageTypeEnum; +import cn.stylefeng.roses.kernel.socket.api.exception.SocketException; import cn.stylefeng.roses.kernel.system.api.UserServiceApi; import cn.stylefeng.roses.kernel.system.api.pojo.user.request.SysUserRequest; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; @@ -98,23 +99,28 @@ public class MessageDbServiceImpl implements MessageApi { } Set userIdSet = new HashSet<>(userIds); - SysMessage sysMessage = new SysMessage(); - BeanUtil.copyProperties(messageSendRequest, sysMessage); - // 初始化默认值 - sysMessage.setReadFlag(MessageReadFlagEnum.UNREAD.getCode()); - sysMessage.setSendUserId(loginUser.getUserId()); - userIdSet.forEach(userId -> { + for (Long userId : userIdSet) { // 判断用户是否存在 if (userServiceApi.userExist(userId)) { + SysMessage sysMessage = new SysMessage(); + BeanUtil.copyProperties(messageSendRequest, sysMessage); + // 初始化默认值 + sysMessage.setReadFlag(MessageReadFlagEnum.UNREAD.getCode()); + sysMessage.setSendUserId(loginUser.getUserId()); sysMessage.setReceiveUserId(userId); sendMsgList.add(sysMessage); } - }); + } sysMessageService.saveBatch(sendMsgList); // 给用户发送通知 for (SysMessage item : sendMsgList) { - socketOperatorApi.sendMsgOfUserSession(ServerMessageTypeEnum.SYS_NOTICE_MSG_TYPE.getCode(), item.getReceiveUserId().toString(), item); + try { + socketOperatorApi.sendMsgOfUserSession(ServerMessageTypeEnum.SYS_NOTICE_MSG_TYPE.getCode(), item.getReceiveUserId().toString(), item); + } catch (SocketException socketException) { + // 该用户不在线 + + } } } diff --git a/kernel-s-system/system-api/src/main/java/cn/stylefeng/roses/kernel/system/api/MenuServiceApi.java b/kernel-s-system/system-api/src/main/java/cn/stylefeng/roses/kernel/system/api/MenuServiceApi.java index 10465d09b..48ef971ee 100644 --- a/kernel-s-system/system-api/src/main/java/cn/stylefeng/roses/kernel/system/api/MenuServiceApi.java +++ b/kernel-s-system/system-api/src/main/java/cn/stylefeng/roses/kernel/system/api/MenuServiceApi.java @@ -25,6 +25,7 @@ package cn.stylefeng.roses.kernel.system.api; import java.util.List; +import java.util.Set; /** * 菜单api @@ -52,4 +53,14 @@ public interface MenuServiceApi { */ List getUserAppCodeList(); + /** + * 获取菜单所有的父级菜单ID + * + * @param menuIds 菜单列表 + * @return {@link java.util.Set} + * @author majianguo + * @date 2021/6/22 上午10:11 + **/ + Set getMenuAllParentMenuId(Set menuIds); + } diff --git a/kernel-s-system/system-business-menu/src/main/java/cn/stylefeng/roses/kernel/system/modular/menu/service/impl/SysMenuServiceImpl.java b/kernel-s-system/system-business-menu/src/main/java/cn/stylefeng/roses/kernel/system/modular/menu/service/impl/SysMenuServiceImpl.java index a5f7992ef..e79654497 100644 --- a/kernel-s-system/system-business-menu/src/main/java/cn/stylefeng/roses/kernel/system/modular/menu/service/impl/SysMenuServiceImpl.java +++ b/kernel-s-system/system-business-menu/src/main/java/cn/stylefeng/roses/kernel/system/modular/menu/service/impl/SysMenuServiceImpl.java @@ -32,6 +32,7 @@ import cn.stylefeng.roses.kernel.auth.api.context.LoginContext; import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser; import cn.stylefeng.roses.kernel.auth.api.pojo.login.basic.SimpleRoleInfo; import cn.stylefeng.roses.kernel.db.api.DbOperatorApi; +import cn.stylefeng.roses.kernel.rule.constants.RuleConstants; import cn.stylefeng.roses.kernel.rule.constants.SymbolConstant; import cn.stylefeng.roses.kernel.rule.constants.TreeConstants; import cn.stylefeng.roses.kernel.rule.enums.StatusEnum; @@ -407,9 +408,7 @@ public class SysMenuServiceImpl extends ServiceImpl impl // 菜单查询条件 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysMenu::getStatusFlag, StatusEnum.ENABLE.getCode()) - .eq(SysMenu::getDelFlag, YesOrNotEnum.N.getCode()) - .orderByAsc(SysMenu::getMenuSort); + queryWrapper.eq(SysMenu::getStatusFlag, StatusEnum.ENABLE.getCode()).eq(SysMenu::getDelFlag, YesOrNotEnum.N.getCode()).orderByAsc(SysMenu::getMenuSort); // 如果应用编码不为空,则拼接应用编码 if (StrUtil.isNotBlank(appCode)) { @@ -463,6 +462,28 @@ public class SysMenuServiceImpl extends ServiceImpl impl return list.stream().map(SysMenu::getAppCode).collect(Collectors.toList()); } + @Override + public Set getMenuAllParentMenuId(Set menuIds) { + Set parentMenuIds = new HashSet<>(); + + // 查询所有菜单信息 + List sysMenus = this.listByIds(menuIds); + if (ObjectUtil.isEmpty(sysMenus)) { + return parentMenuIds; + } + + // 获取所有父菜单ID + for (SysMenu sysMenu : sysMenus) { + String menuPids = sysMenu.getMenuPids().replaceAll("\\[", "").replaceAll("\\]", ""); + String[] ids = menuPids.split(SymbolConstant.COMMA); + for (String id : ids) { + parentMenuIds.add(Long.parseLong(id)); + } + } + + return parentMenuIds; + } + /** * 获取系统菜单 * diff --git a/kernel-s-system/system-business-role/src/main/java/cn/stylefeng/roses/kernel/system/modular/role/service/impl/SysRoleServiceImpl.java b/kernel-s-system/system-business-role/src/main/java/cn/stylefeng/roses/kernel/system/modular/role/service/impl/SysRoleServiceImpl.java index c8b36c021..8b1efcb1d 100644 --- a/kernel-s-system/system-business-role/src/main/java/cn/stylefeng/roses/kernel/system/modular/role/service/impl/SysRoleServiceImpl.java +++ b/kernel-s-system/system-business-role/src/main/java/cn/stylefeng/roses/kernel/system/modular/role/service/impl/SysRoleServiceImpl.java @@ -40,6 +40,7 @@ import cn.stylefeng.roses.kernel.rule.enums.StatusEnum; import cn.stylefeng.roses.kernel.rule.enums.YesOrNotEnum; import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException; import cn.stylefeng.roses.kernel.rule.pojo.dict.SimpleDict; +import cn.stylefeng.roses.kernel.system.api.MenuServiceApi; import cn.stylefeng.roses.kernel.system.api.UserServiceApi; import cn.stylefeng.roses.kernel.system.api.constants.SystemConstants; import cn.stylefeng.roses.kernel.system.api.exception.SystemModularException; @@ -62,6 +63,7 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -91,6 +93,9 @@ public class SysRoleServiceImpl extends ServiceImpl impl @Resource private SysRoleMenuButtonService sysRoleMenuButtonService; + @Resource + private MenuServiceApi menuServiceApi; + @Override public void add(SysRoleRequest sysRoleRequest) { @@ -219,9 +224,25 @@ public class SysRoleServiceImpl extends ServiceImpl impl List menuIdList = sysRoleMenuButtonRequest.getGrantMenuIdList(); if (ObjectUtil.isNotEmpty(menuIdList)) { List sysRoleMenus = new ArrayList<>(); + + // 角色ID + Long roleId = sysRoleMenuButtonRequest.getRoleId(); + + // 查询菜单的所有父菜单 + Set allParentMenuId = menuServiceApi.getMenuAllParentMenuId(new HashSet<>(menuIdList)); + + // 处理所有父菜单 + for (Long menuId : allParentMenuId) { + SysRoleMenu item = new SysRoleMenu(); + item.setRoleId(roleId); + item.setMenuId(menuId); + sysRoleMenus.add(item); + } + + // 处理菜单本身 for (Long menuId : menuIdList) { SysRoleMenu item = new SysRoleMenu(); - item.setRoleId(sysRoleMenuButtonRequest.getRoleId()); + item.setRoleId(roleId); item.setMenuId(menuId); sysRoleMenus.add(item); }