diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java index 8345540418..e627ba1f46 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java @@ -62,12 +62,12 @@ public interface MenuService { List getMenuList(MenuListReqVO reqVO); /** - * 获得权限对应的菜单数组 + * 获得权限对应的菜单编号数组 * * @param permission 权限标识 * @return 数组 */ - List getMenuListByPermissionFromCache(String permission); + List getMenuIdListByPermissionFromCache(String permission); /** * 获得菜单 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java index a1cdf01759..c61863b91b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.system.service.permission; import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuUpdateReqVO; @@ -10,9 +11,9 @@ import cn.iocoder.yudao.module.system.dal.mysql.permission.MenuMapper; import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; import cn.iocoder.yudao.module.system.service.tenant.TenantService; -import com.baomidou.dynamic.datasource.annotation.Master; import com.google.common.annotations.VisibleForTesting; import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -23,6 +24,7 @@ import java.util.Collection; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO.ID_ROOT; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; @@ -44,6 +46,7 @@ public class MenuServiceImpl implements MenuService { private TenantService tenantService; @Override + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#reqVO.permission") public Long createMenu(MenuCreateReqVO reqVO) { // 校验父菜单存在 validateParentMenu(reqVO.getParentId(), null); @@ -59,6 +62,8 @@ public class MenuServiceImpl implements MenuService { } @Override + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为 permission 如果变更,涉及到新老两个 permission。直接清理,简单有效 public void updateMenu(MenuUpdateReqVO reqVO) { // 校验更新的菜单是否存在 if (menuMapper.selectById(reqVO.getId()) == null) { @@ -77,19 +82,21 @@ public class MenuServiceImpl implements MenuService { @Override @Transactional(rollbackFor = Exception.class) - public void deleteMenu(Long menuId) { + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为此时不知道 id 对应的 permission 是多少。直接清理,简单有效 + public void deleteMenu(Long id) { // 校验是否还有子菜单 - if (menuMapper.selectCountByParentId(menuId) > 0) { + if (menuMapper.selectCountByParentId(id) > 0) { throw exception(MENU_EXISTS_CHILDREN); } // 校验删除的菜单是否存在 - if (menuMapper.selectById(menuId) == null) { + if (menuMapper.selectById(id) == null) { throw exception(MENU_NOT_EXISTS); } // 标记删除 - menuMapper.deleteById(menuId); + menuMapper.deleteById(id); // 删除授予给角色的权限 - permissionService.processMenuDeleted(menuId); + permissionService.processMenuDeleted(id); } @Override @@ -112,8 +119,9 @@ public class MenuServiceImpl implements MenuService { @Override @Cacheable(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#permission") - public List getMenuListByPermissionFromCache(String permission) { - return menuMapper.selectListByPermission(permission); + public List getMenuIdListByPermissionFromCache(String permission) { + List menus = menuMapper.selectListByPermission(permission); + return convertList(menus, MenuDO::getId); } @Override diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java index 0cfed68f6c..3a0359bc2c 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java @@ -7,7 +7,6 @@ import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; -import cn.iocoder.yudao.framework.tenant.core.db.dynamic.TenantDS; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; @@ -206,19 +205,18 @@ public class PermissionServiceImpl implements PermissionService { * @param permission 权限标识 * @return 是否拥有 */ - // TODO 芋艿:要想想咋继续优化 private boolean hasAnyPermission(List roles, String permission) { - List menuList = menuService.getMenuListByPermissionFromCache(permission); + List menuIds = menuService.getMenuIdListByPermissionFromCache(permission); // 采用严格模式,如果权限找不到对应的 Menu 的话,也认为没有权限 - if (CollUtil.isEmpty(menuList)) { + if (CollUtil.isEmpty(menuIds)) { return false; } // 判断是否有权限 Set roleIds = convertSet(roles, RoleDO::getId); - for (MenuDO menu : menuList) { + for (Long menuId : menuIds) { // 拥有该角色的菜单编号数组 - Set menuRoleIds = getSelf().getMenuRoleIdListByMenuIdFromCache(menu.getId()); + Set menuRoleIds = getSelf().getMenuRoleIdListByMenuIdFromCache(menuId); // 如果有交集,说明有权限 if (CollUtil.containsAny(menuRoleIds, roleIds)) { return true; diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImplTest.java index d643c5501d..a0c17b3fbb 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImplTest.java @@ -8,10 +8,7 @@ import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuUp import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; import cn.iocoder.yudao.module.system.dal.mysql.permission.MenuMapper; import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; -import cn.iocoder.yudao.module.system.mq.producer.permission.MenuProducer; import cn.iocoder.yudao.module.system.service.tenant.TenantService; -import com.google.common.collect.LinkedListMultimap; -import com.google.common.collect.Multimap; import org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; @@ -26,8 +23,6 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServic import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO.ID_ROOT; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; -import static java.util.Arrays.asList; -import static java.util.Collections.singletonList; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.ArgumentMatchers.argThat; @@ -46,35 +41,12 @@ public class MenuServiceImplTest extends BaseDbUnitTest { @MockBean private PermissionService permissionService; @MockBean - private MenuProducer menuProducer; - @MockBean private TenantService tenantService; - @Test - public void testInitLocalCache_success() { - MenuDO menuDO1 = randomPojo(MenuDO.class); - menuMapper.insert(menuDO1); - MenuDO menuDO2 = randomPojo(MenuDO.class); - menuMapper.insert(menuDO2); - - // 调用 - menuService.initLocalCache(); - // 校验 menuCache 缓存 - Map menuCache = menuService.getMenuCache(); - assertEquals(2, menuCache.size()); - assertPojoEquals(menuDO1, menuCache.get(menuDO1.getId())); - assertPojoEquals(menuDO2, menuCache.get(menuDO2.getId())); - // 校验 permissionMenuCache 缓存 - Multimap permissionMenuCache = menuService.getPermissionMenuCache(); - assertEquals(2, permissionMenuCache.size()); - assertPojoEquals(menuDO1, permissionMenuCache.get(menuDO1.getPermission())); - assertPojoEquals(menuDO2, permissionMenuCache.get(menuDO2.getPermission())); - } - @Test public void testCreateMenu_success() { // mock 数据(构造父菜单) - MenuDO menuDO = createMenuDO(MenuTypeEnum.MENU, + MenuDO menuDO = buildMenuDO(MenuTypeEnum.MENU, "parent", 0L); menuMapper.insert(menuDO); Long parentId = menuDO.getId(); @@ -89,14 +61,12 @@ public class MenuServiceImplTest extends BaseDbUnitTest { // 校验记录的属性是否正确 MenuDO dbMenu = menuMapper.selectById(menuId); assertPojoEquals(reqVO, dbMenu); - // 校验调用 - verify(menuProducer).sendMenuRefreshMessage(); } @Test public void testUpdateMenu_success() { // mock 数据(构造父子菜单) - MenuDO sonMenuDO = initParentAndSonMenu(); + MenuDO sonMenuDO = createParentAndSonMenu(); Long sonId = sonMenuDO.getId(); // 准备参数 MenuUpdateReqVO reqVO = randomPojo(MenuUpdateReqVO.class, o -> { @@ -111,8 +81,6 @@ public class MenuServiceImplTest extends BaseDbUnitTest { // 校验记录的属性是否正确 MenuDO dbMenu = menuMapper.selectById(sonId); assertPojoEquals(reqVO, dbMenu); - // 校验调用 - verify(menuProducer).sendMenuRefreshMessage(); } @Test @@ -137,7 +105,6 @@ public class MenuServiceImplTest extends BaseDbUnitTest { MenuDO dbMenuDO = menuMapper.selectById(id); assertNull(dbMenuDO); verify(permissionService).processMenuDeleted(id); - verify(menuProducer).sendMenuRefreshMessage(); } @Test @@ -149,7 +116,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest { @Test public void testDeleteMenu_existChildren() { // mock 数据(构造父子菜单) - MenuDO sonMenu = initParentAndSonMenu(); + MenuDO sonMenu = createParentAndSonMenu(); // 准备参数 Long parentId = sonMenu.getParentId(); @@ -218,85 +185,6 @@ public class MenuServiceImplTest extends BaseDbUnitTest { assertPojoEquals(menu100, result.get(0)); } - @Test - public void testListMenusFromCache_withoutId() { - // mock 缓存 - Map menuCache = new HashMap<>(); - // 可被匹配 - MenuDO menuDO = randomPojo(MenuDO.class, o -> o.setId(1L) - .setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus())); - menuCache.put(menuDO.getId(), menuDO); - // 测试 type 不匹配 - menuCache.put(3L, randomPojo(MenuDO.class, o -> o.setId(3L) - .setType(MenuTypeEnum.BUTTON.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus()))); - // 测试 status 不匹配 - menuCache.put(4L, randomPojo(MenuDO.class, o -> o.setId(4L) - .setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.DISABLE.getStatus()))); - menuService.setMenuCache(menuCache); - // 准备参数 - Collection menuTypes = singletonList(MenuTypeEnum.MENU.getType()); - Collection menusStatuses = singletonList(CommonStatusEnum.ENABLE.getStatus()); - - // 调用 - List list = menuService.getMenuListFromCache(menuTypes, menusStatuses); - // 断言 - assertEquals(1, list.size()); - assertPojoEquals(menuDO, list.get(0)); - } - - @Test - public void testListMenusFromCache_withId() { - // mock 缓存 - Map menuCache = new HashMap<>(); - // 可被匹配 - MenuDO menuDO = randomPojo(MenuDO.class, o -> o.setId(1L) - .setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus())); - menuCache.put(menuDO.getId(), menuDO); - // 测试 id 不匹配 - menuCache.put(2L, randomPojo(MenuDO.class, o -> o.setId(2L) - .setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus()))); - // 测试 type 不匹配 - menuCache.put(3L, randomPojo(MenuDO.class, o -> o.setId(3L) - .setType(MenuTypeEnum.BUTTON.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus()))); - // 测试 status 不匹配 - menuCache.put(4L, randomPojo(MenuDO.class, o -> o.setId(4L) - .setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.DISABLE.getStatus()))); - menuService.setMenuCache(menuCache); - // 准备参数 - Collection menuIds = asList(1L, 3L, 4L); - Collection menuTypes = singletonList(MenuTypeEnum.MENU.getType()); - Collection menusStatuses = singletonList(CommonStatusEnum.ENABLE.getStatus()); - - // 调用 - List list = menuService.getMenuListFromCache(menuIds, menuTypes, menusStatuses); - // 断言 - assertEquals(1, list.size()); - assertPojoEquals(menuDO, list.get(0)); - } - - @Test - public void testGetMenuListByPermissionFromCache() { - // mock 缓存 - Multimap permissionMenuCache = LinkedListMultimap.create(); - // 可被匹配 - MenuDO menuDO01 = randomPojo(MenuDO.class, o -> o.setId(1L).setPermission("123")); - permissionMenuCache.put(menuDO01.getPermission(), menuDO01); - MenuDO menuDO02 = randomPojo(MenuDO.class, o -> o.setId(2L).setPermission("123")); - permissionMenuCache.put(menuDO02.getPermission(), menuDO02); - // 不可匹配 - permissionMenuCache.put("456", randomPojo(MenuDO.class, o -> o.setId(3L).setPermission("456"))); - menuService.setPermissionMenuCache(permissionMenuCache); - // 准备参数 - String permission = "123"; - - // 调用 - List list = menuService.getMenuListByPermissionFromCache(permission); - // 断言 - assertEquals(2, list.size()); - assertPojoEquals(menuDO01, list.get(0)); - assertPojoEquals(menuDO02, list.get(1)); - } - @Test public void testGetMenu() { // mock 数据 @@ -314,7 +202,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest { @Test public void testValidateParentMenu_success() { // mock 数据 - MenuDO menuDO = createMenuDO(MenuTypeEnum.MENU, "parent", 0L); + MenuDO menuDO = buildMenuDO(MenuTypeEnum.MENU, "parent", 0L); menuMapper.insert(menuDO); // 准备参数 Long parentId = menuDO.getId(); @@ -340,7 +228,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest { @Test public void testValidateParentMenu_parentTypeError() { // mock 数据 - MenuDO menuDO = createMenuDO(MenuTypeEnum.BUTTON, "parent", 0L); + MenuDO menuDO = buildMenuDO(MenuTypeEnum.BUTTON, "parent", 0L); menuMapper.insert(menuDO); // 准备参数 Long parentId = menuDO.getId(); @@ -353,7 +241,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest { @Test public void testValidateMenu_success() { // mock 父子菜单 - MenuDO sonMenu = initParentAndSonMenu(); + MenuDO sonMenu = createParentAndSonMenu(); // 准备参数 Long parentId = sonMenu.getParentId(); Long otherSonMenuId = randomLongId(); @@ -366,7 +254,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest { @Test public void testValidateMenu_sonMenuNameDuplicate() { // mock 父子菜单 - MenuDO sonMenu = initParentAndSonMenu(); + MenuDO sonMenu = createParentAndSonMenu(); // 准备参数 Long parentId = sonMenu.getParentId(); Long otherSonMenuId = randomLongId(); @@ -380,26 +268,26 @@ public class MenuServiceImplTest extends BaseDbUnitTest { // ====================== 初始化方法 ====================== /** - * 构造父子菜单,返回子菜单 + * 插入父子菜单,返回子菜单 * * @return 子菜单 */ - private MenuDO initParentAndSonMenu() { + private MenuDO createParentAndSonMenu() { // 构造父子菜单 - MenuDO parentMenuDO = createMenuDO(MenuTypeEnum.MENU, "parent", ID_ROOT); + MenuDO parentMenuDO = buildMenuDO(MenuTypeEnum.MENU, "parent", ID_ROOT); menuMapper.insert(parentMenuDO); // 构建子菜单 - MenuDO sonMenuDO = createMenuDO(MenuTypeEnum.MENU, "testSonName", + MenuDO sonMenuDO = buildMenuDO(MenuTypeEnum.MENU, "testSonName", parentMenuDO.getParentId()); menuMapper.insert(sonMenuDO); return sonMenuDO; } - private MenuDO createMenuDO(MenuTypeEnum type, String name, Long parentId) { - return createMenuDO(type, name, parentId, randomCommonStatus()); + private MenuDO buildMenuDO(MenuTypeEnum type, String name, Long parentId) { + return buildMenuDO(type, name, parentId, randomCommonStatus()); } - private MenuDO createMenuDO(MenuTypeEnum type, String name, Long parentId, Integer status) { + private MenuDO buildMenuDO(MenuTypeEnum type, String name, Long parentId, Integer status) { return randomPojo(MenuDO.class, o -> o.setId(null).setName(name).setParentId(parentId) .setType(type.getType()).setStatus(status)); }