diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/entity/BaseMenu.java b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/BaseMenu.java new file mode 100644 index 00000000..f731be0c --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/BaseMenu.java @@ -0,0 +1,40 @@ +package com.czg.account.entity; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import lombok.Data; + +/** + * @author Administrator + */ +@Data +public class BaseMenu { + @Id(keyType = KeyType.Auto) + private Long menuId; + + /** + * 图标 + */ + private String icon; + + /** + * 组件 + */ + private String component; + /** + * 链接地址 + */ + private String path; + + /** + * 包含的接口 + */ + private String apiInfo; + + + /** + * 组件名称 + */ + private String name; + +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/entity/CashMenu.java b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/CashMenu.java index 180547a1..358ec938 100644 --- a/cash-common/cash-common-service/src/main/java/com/czg/account/entity/CashMenu.java +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/CashMenu.java @@ -7,10 +7,7 @@ import java.io.Serializable; import java.io.Serial; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; +import lombok.*; /** * 实体类。 @@ -18,26 +15,14 @@ import lombok.NoArgsConstructor; * @author zs * @since 2025-05-26 */ +@EqualsAndHashCode(callSuper = true) @Data @Builder -@NoArgsConstructor -@AllArgsConstructor @Table("sys_cash_menu") -public class CashMenu implements Serializable { +public class CashMenu extends BaseMenu implements Serializable { @Serial private static final long serialVersionUID = 1L; - @Id(keyType = KeyType.Auto) - private Long menuId; - - private String name; - - private String component; - - private String path; - - private String icon; - private String apiInfo; } diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/entity/SysMenu.java b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/SysMenu.java index 55063c0a..b1af3406 100644 --- a/cash-common/cash-common-service/src/main/java/com/czg/account/entity/SysMenu.java +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/SysMenu.java @@ -6,6 +6,7 @@ import com.mybatisflex.annotation.KeyType; import com.mybatisflex.annotation.Table; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import java.io.Serial; @@ -18,21 +19,16 @@ import java.time.LocalDateTime; * @author Administrator * @since 2025-02-10 */ +@EqualsAndHashCode(callSuper = true) @Data - @NoArgsConstructor @AllArgsConstructor @Table("sys_menu") -public class SysMenu implements Serializable { +public class SysMenu extends BaseMenu implements Serializable{ @Serial private static final long serialVersionUID = 1L; - /** - * ID - */ - @Id(keyType = KeyType.Auto) - private Long menuId; /** * 上级菜单ID @@ -54,30 +50,13 @@ public class SysMenu implements Serializable { */ private String title; - /** - * 组件名称 - */ - private String name; - /** - * 组件 - */ - private String component; /** * 排序 */ private Integer menuSort; - /** - * 图标 - */ - private String icon; - - /** - * 链接地址 - */ - private String path; /** * 是否外链 @@ -139,10 +118,7 @@ public class SysMenu implements Serializable { * 小程序组件 */ private String miniComponent; - /** - * 包含的接口 - */ - private String apiInfo; + /** * 接口地址 */ diff --git a/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/SysRoleServiceImpl.java b/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/SysRoleServiceImpl.java index aff8a7a1..f84d86eb 100644 --- a/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/SysRoleServiceImpl.java +++ b/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/SysRoleServiceImpl.java @@ -9,10 +9,7 @@ import com.czg.account.dto.menu.MenuApiInfoItemDTO; import com.czg.account.dto.role.RoleAddDTO; import com.czg.account.dto.role.RoleEditDTO; import com.czg.account.dto.role.RolePermissionDTO; -import com.czg.account.entity.CashMenu; -import com.czg.account.entity.SysMenu; -import com.czg.account.entity.SysRole; -import com.czg.account.entity.SysRolesMenus; +import com.czg.account.entity.*; import com.czg.account.service.CashMenuService; import com.czg.account.service.SysMenuService; import com.czg.account.service.SysRoleService; @@ -28,7 +25,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import static com.mybatisflex.core.query.QueryMethods.column; @@ -125,83 +124,82 @@ public class SysRoleServiceImpl extends ServiceImpl imp if (role == null) { throw new ApiNotPrintException("角色不存在"); } + return sysRolesMenusService.queryChain().eq(SysRolesMenus::getRoleId, id).eq(SysRolesMenus::getType, type).list().stream().map(SysRolesMenus::getMenuId).toList(); } public boolean addMenu(Long roleId, List menuIds, boolean isAdmin) { - ArrayList apiPathList = new ArrayList<>(); + List> tasks = new ArrayList<>(); + List apiPathList = Collections.synchronizedList(new ArrayList<>()); + List rolesMenus = Collections.synchronizedList(new ArrayList<>()); - ArrayList rolesMenus = new ArrayList<>(); + // Step 1: 获取菜单列表并校验 + List menuList; if (isAdmin) { List sysMenuList = sysMenuService.queryChain().in(SysMenu::getMenuId, menuIds).list(); - if (sysMenuList.size() != menuIds.size()) { - throw new ApiNotPrintException("菜单id包含错误id"); - } - - sysMenuList.forEach(item -> { - if (StrUtil.isNotBlank(item.getApiInfo())) { - List itemDTOS = JSONArray.parseArray(item.getApiInfo()).toJavaList(MenuApiInfoItemDTO.class); - if (!itemDTOS.isEmpty()) { - apiPathList.addAll(itemDTOS); - } - } - }); - - for (SysMenu sysMenu : sysMenuList) { - long count = sysRolesMenusService.count(new QueryWrapper().eq(SysRolesMenus::getMenuId, sysMenu.getMenuId()) - .eq(SysRolesMenus::getRoleId, roleId) - .eq(SysRolesMenus::getType, isAdmin ? 0 : 1)); - if (count == 0) { - rolesMenus.add(new SysRolesMenus(sysMenu.getMenuId(), roleId, isAdmin ? 0 : 1)); - } - } - }else { - List list = cashMenuService.queryChain().in(CashMenu::getMenuId, menuIds).list(); - if (list.size() != menuIds.size()) { - throw new ApiNotPrintException("菜单id包含错误id"); - } - - list.forEach(item -> { - if (StrUtil.isNotBlank(item.getApiInfo())) { - List itemDTOS = JSONArray.parseArray(item.getApiInfo()).toJavaList(MenuApiInfoItemDTO.class); - if (!itemDTOS.isEmpty()) { - apiPathList.addAll(itemDTOS); - } - } - }); - - for (CashMenu sysMenu : list) { - long count = sysRolesMenusService.count(new QueryWrapper().eq(SysRolesMenus::getMenuId, sysMenu.getMenuId()) - .eq(SysRolesMenus::getRoleId, roleId) - .eq(SysRolesMenus::getType, isAdmin ? 0 : 1)); - if (count == 0) { - rolesMenus.add(new SysRolesMenus(sysMenu.getMenuId(), roleId, isAdmin ? 0 : 1)); - } - } + if (sysMenuList.size() != menuIds.size()) throw new ApiNotPrintException("菜单id包含错误id"); + menuList = sysMenuList; + } else { + List cashMenuList = cashMenuService.queryChain().in(CashMenu::getMenuId, menuIds).list(); + if (cashMenuList.size() != menuIds.size()) throw new ApiNotPrintException("菜单id包含错误id"); + menuList = cashMenuList; } + int type = isAdmin ? 0 : 1; + // Step 2: 并发处理 apiInfo 解析和绑定判断 + for (BaseMenu menu : menuList) { + tasks.add(CompletableFuture.runAsync(() -> { + // 解析 apiInfo + if (StrUtil.isNotBlank(menu.getApiInfo())) { + List itemDTOS = JSONArray.parseArray(menu.getApiInfo()).toJavaList(MenuApiInfoItemDTO.class); + if (!itemDTOS.isEmpty()) { + apiPathList.addAll(itemDTOS); + } + } + + // 检查是否已绑定 + long count = sysRolesMenusService.count(new QueryWrapper() + .eq("menu_id", menu.getMenuId()) + .eq("role_id", roleId) + .eq("type", type)); + if (count == 0) { + rolesMenus.add(new SysRolesMenus(menu.getMenuId(), roleId, type)); + } + })); + } + + // 等待上述任务完成 + CompletableFuture.allOf(tasks.toArray(new CompletableFuture[0])).join(); + + // Step 3: 并发处理 apiPath 匹配菜单 if (!apiPathList.isEmpty()) { - String string = buildLikeSql(apiPathList, "url"); + String likeSql = buildLikeSql(apiPathList, "url"); QueryWrapper wrapper = new QueryWrapper(); - wrapper.where(string); - List sysMenus = sysMenuService.list(wrapper); - if (!sysMenus.isEmpty()) { - for (SysMenu sysMenu : sysMenus) { - long count = sysRolesMenusService.count(new QueryWrapper().eq(SysRolesMenus::getMenuId, sysMenu.getMenuId()) - .eq(SysRolesMenus::getRoleId, roleId) - .eq(SysRolesMenus::getType, isAdmin ? 0 : 1)); - if (count == 0) { - rolesMenus.add(new SysRolesMenus(sysMenu.getMenuId(), roleId, isAdmin ? 0 : 1)); - } - } - } - } + wrapper.where(likeSql); + List matchedMenus = sysMenuService.list(wrapper); + List> matchTasks = new ArrayList<>(); + + for (SysMenu matched : matchedMenus) { + matchTasks.add(CompletableFuture.runAsync(() -> { + long count = sysRolesMenusService.count(new QueryWrapper() + .eq("menu_id", matched.getMenuId()) + .eq("role_id", roleId) + .eq("type", type)); + if (count == 0) { + rolesMenus.add(new SysRolesMenus(matched.getMenuId(), roleId, type)); + } + })); + } + + CompletableFuture.allOf(matchTasks.toArray(new CompletableFuture[0])).join(); + } return rolesMenus.isEmpty() || sysRolesMenusService.saveBatch(rolesMenus); } + @Override @Transactional(rollbackFor = Exception.class) public Boolean editPermission(long userId, RolePermissionDTO rolePermissionDTO) {