1. 修改 MenuDO 的字段,menuId 改成 id,menuName 改成 name
2. 添加 Menu 的创建、修改、删除接口
This commit is contained in:
@@ -12,7 +12,6 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMe
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO;
|
||||
import cn.iocoder.dashboard.modules.system.enums.permission.MenuIdEnum;
|
||||
import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum;
|
||||
import cn.iocoder.dashboard.modules.system.enums.user.UserStatus;
|
||||
import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService;
|
||||
@@ -38,7 +37,10 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
|
||||
@@ -243,36 +245,12 @@ public class SysAuthServiceImpl implements SysAuthService {
|
||||
|
||||
@Override
|
||||
public List<SysAuthMenuRespVO> listMenus(Long userId, Set<Long> roleIds) {
|
||||
// 获得用户拥有的菜单列表
|
||||
List<SysMenuDO> menuList = permissionService.listRoleMenusFromCache(roleIds,
|
||||
SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()),
|
||||
SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus()));
|
||||
SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型
|
||||
SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
|
||||
// 转换成 Tree 结构返回
|
||||
return buildRouterTree(menuList);
|
||||
}
|
||||
|
||||
private static List<SysAuthMenuRespVO> buildRouterTree(List<SysMenuDO> menuList) {
|
||||
// 排序,保证菜单的有序性
|
||||
menuList.sort(Comparator.comparing(SysMenuDO::getSort));
|
||||
// 构建菜单树
|
||||
// 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。
|
||||
Map<Long, SysAuthMenuRespVO> treeNodeMap = new LinkedHashMap<>();
|
||||
menuList.forEach(menu -> treeNodeMap.put(menu.getMenuId(), SysAuthConvert.INSTANCE.convertTreeNode(menu)));
|
||||
// 处理父子关系
|
||||
treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(MenuIdEnum.ROOT.getId())).forEach((childNode) -> {
|
||||
// 获得父节点
|
||||
SysAuthMenuRespVO parentNode = treeNodeMap.get(childNode.getParentId());
|
||||
if (parentNode == null) {
|
||||
log.error("[buildRouterTree][resource({}) 找不到父资源({})]", childNode.getMenuId(), childNode.getParentId());
|
||||
return;
|
||||
}
|
||||
// 将自己添加到父节点中
|
||||
if (parentNode.getChildren() == null) {
|
||||
parentNode.setChildren(new ArrayList<>());
|
||||
}
|
||||
parentNode.getChildren().add(childNode);
|
||||
});
|
||||
// 获得到所有的根节点
|
||||
return CollectionUtils.filterList(treeNodeMap.values(), node -> MenuIdEnum.ROOT.getId().equals(node.getParentId()));
|
||||
return SysAuthConvert.INSTANCE.buildMenuTree(menuList);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public class SysDictDataServiceImpl implements SysDictDataService {
|
||||
|
||||
private static final Comparator<SysDictDataDO> COMPARATOR_TYPE_AND_SORT = Comparator
|
||||
.comparing(SysDictDataDO::getDictType)
|
||||
.thenComparingInt(SysDictDataDO::getDictSort);
|
||||
.thenComparingInt(SysDictDataDO::getSort);
|
||||
|
||||
@Resource
|
||||
private SysDictDataMapper dictDataMapper;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package cn.iocoder.dashboard.modules.system.service.permission;
|
||||
|
||||
import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuCreateReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuListReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuRespVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuUpdateReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -9,6 +11,8 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* 菜单 Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface SysMenuService {
|
||||
|
||||
@@ -49,4 +53,34 @@ public interface SysMenuService {
|
||||
List<SysMenuDO> listMenusFromCache(Collection<Long> menuIds, Collection<Integer> menuTypes,
|
||||
Collection<Integer> menusStatuses);
|
||||
|
||||
/*
|
||||
* 创建菜单
|
||||
*
|
||||
* @param reqVO 菜单信息
|
||||
* @return 创建出来的菜单编号
|
||||
*/
|
||||
Long createMenu(SysMenuCreateReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 更新菜单
|
||||
*
|
||||
* @param reqVO 菜单信息
|
||||
*/
|
||||
void updateMenu(SysMenuUpdateReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 删除菜单
|
||||
*
|
||||
* @param id 菜单编号
|
||||
*/
|
||||
void deleteMenu(Long id);
|
||||
|
||||
/**
|
||||
* 获得菜单
|
||||
*
|
||||
* @param id 菜单编号
|
||||
* @return 菜单
|
||||
*/
|
||||
SysMenuDO getMenu(Long id);
|
||||
|
||||
}
|
||||
|
||||
@@ -48,4 +48,11 @@ public interface SysPermissionService {
|
||||
*/
|
||||
Long getDeptRoleId(Long deptId);
|
||||
|
||||
/**
|
||||
* 删除授予给角色的菜单们
|
||||
*
|
||||
* @param menuId 菜单编号
|
||||
*/
|
||||
void deleteRolesMenuByMenuId(Long menuId);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
package cn.iocoder.dashboard.modules.system.service.permission.impl;
|
||||
|
||||
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuCreateReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuListReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuRespVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuUpdateReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.convert.permission.SysMenuConvert;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysMenuMapper;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO;
|
||||
import cn.iocoder.dashboard.modules.system.enums.permission.MenuIdEnum;
|
||||
import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum;
|
||||
import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService;
|
||||
import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService;
|
||||
import cn.iocoder.dashboard.util.collection.CollectionUtils;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
@@ -21,8 +27,12 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 菜单 Service 实现
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
@@ -46,6 +56,8 @@ public class SysMenuServiceImpl implements SysMenuService {
|
||||
|
||||
@Resource
|
||||
private SysMenuMapper menuMapper;
|
||||
@Resource
|
||||
private SysPermissionService permissionService;
|
||||
|
||||
/**
|
||||
* 初始化 {@link #menuCache} 和 {@link #permMenuCache} 缓存
|
||||
@@ -57,7 +69,7 @@ public class SysMenuServiceImpl implements SysMenuService {
|
||||
ImmutableMap.Builder<Long, SysMenuDO> menuCacheBuilder = ImmutableMap.builder();
|
||||
ImmutableMultimap.Builder<String, SysMenuDO> permMenuCacheBuilder = ImmutableMultimap.builder();
|
||||
menuList.forEach(menuDO -> {
|
||||
menuCacheBuilder.put(menuDO.getMenuId(), menuDO);
|
||||
menuCacheBuilder.put(menuDO.getId(), menuDO);
|
||||
permMenuCacheBuilder.put(menuDO.getPermission(), menuDO);
|
||||
});
|
||||
menuCache = menuCacheBuilder.build();
|
||||
@@ -79,7 +91,7 @@ public class SysMenuServiceImpl implements SysMenuService {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 创建新数组,避免缓存被修改
|
||||
return menuCache.values().stream().filter(menu -> menuTypes.contains(menu.getMenuType())
|
||||
return menuCache.values().stream().filter(menu -> menuTypes.contains(menu.getType())
|
||||
&& menusStatuses.contains(menu.getStatus()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
@@ -91,10 +103,186 @@ public class SysMenuServiceImpl implements SysMenuService {
|
||||
if (CollectionUtils.isAnyEmpty(menuIds, menuTypes, menusStatuses)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return menuCache.values().stream().filter(menu -> menuIds.contains(menu.getMenuId())
|
||||
&& menuTypes.contains(menu.getMenuType())
|
||||
return menuCache.values().stream().filter(menu -> menuIds.contains(menu.getId())
|
||||
&& menuTypes.contains(menu.getType())
|
||||
&& menusStatuses.contains(menu.getStatus()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long createMenu(SysMenuCreateReqVO reqVO) {
|
||||
// 校验父菜单存在
|
||||
checkParentResource(reqVO.getParentId(), null);
|
||||
// 校验菜单(自己)
|
||||
checkResource(reqVO.getParentId(), reqVO.getName(), null);
|
||||
// 插入数据库
|
||||
SysMenuDO menu = SysMenuConvert.INSTANCE.convert(reqVO);
|
||||
initMenuProperty(menu);
|
||||
menuMapper.insert(menu);
|
||||
// 返回
|
||||
return menu.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMenu(SysMenuUpdateReqVO reqVO) {
|
||||
// 校验更新的菜单是否存在
|
||||
if (menuMapper.selectById(reqVO.getId()) == null) {
|
||||
throw ServiceExceptionUtil.exception(MENU_NOT_EXISTS);
|
||||
}
|
||||
// 校验父菜单存在
|
||||
checkParentResource(reqVO.getParentId(), reqVO.getId());
|
||||
// 校验菜单(自己)
|
||||
checkResource(reqVO.getParentId(), reqVO.getName(), reqVO.getId());
|
||||
// 更新到数据库
|
||||
SysMenuDO updateObject = SysMenuConvert.INSTANCE.convert(reqVO);
|
||||
initMenuProperty(updateObject);
|
||||
menuMapper.updateById(updateObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除菜单
|
||||
*
|
||||
* @param menuId 菜单编号
|
||||
*/
|
||||
public void deleteMenu(Long menuId) {
|
||||
// 校验更新的菜单是否存在
|
||||
if (menuMapper.selectById(menuId) == null) {
|
||||
throw ServiceExceptionUtil.exception(MENU_NOT_EXISTS);
|
||||
}
|
||||
// 校验是否还有子菜单
|
||||
if (menuMapper.selectCountByParentId(menuId) > 0) {
|
||||
throw ServiceExceptionUtil.exception(MENU_EXISTS_CHILDREN);
|
||||
}
|
||||
// 校验删除的菜单是否存在
|
||||
if (menuMapper.selectById(menuId) == null) {
|
||||
throw ServiceExceptionUtil.exception(MENU_NOT_EXISTS);
|
||||
}
|
||||
// 标记删除
|
||||
menuMapper.deleteById(menuId);
|
||||
// 删除授予给角色的权限
|
||||
permissionService.deleteRolesMenuByMenuId(menuId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysMenuDO getMenu(Long id) {
|
||||
return menuMapper.selectById(id);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 获得菜单列表
|
||||
// *
|
||||
// * @param menuIds 菜单编号列表
|
||||
// * @return 菜单列表
|
||||
// */
|
||||
// public List<ResourceBO> listResources(List<Integer> menuIds) {
|
||||
// List<ResourceDO> menuDOs = menuMapper.selectBatchIds(menuIds);
|
||||
// return ResourceConvert.INSTANCE.convertList(menuDOs);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 获得菜单全列表
|
||||
// *
|
||||
// * @return 菜单全列表
|
||||
// */
|
||||
// public List<ResourceBO> listResources() {
|
||||
// List<ResourceDO> menuDOs = menuMapper.selectList(null);
|
||||
// return ResourceConvert.INSTANCE.convertList(menuDOs);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 获得指定类型的菜单列表
|
||||
// *
|
||||
// * @param type 菜单类型,允许空
|
||||
// * @return 菜单列表
|
||||
// */
|
||||
// public List<ResourceBO> listResourcesByType(Integer type) {
|
||||
// List<ResourceDO> menuDOs = menuMapper.selectListByType(type);
|
||||
// return ResourceConvert.INSTANCE.convertList(menuDOs);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 获得角色拥有的菜单列表
|
||||
// *
|
||||
// * @param roleIds 角色编号
|
||||
// * @param type 菜单类型,允许空
|
||||
// * @return 菜单列表
|
||||
// */
|
||||
// public List<ResourceBO> listRoleResourcesByType(Collection<Integer> roleIds, Integer type) {
|
||||
// List<RoleResourceDO> roleResourceDOs = roleResourceMapper.selectListByRoleIds(roleIds);
|
||||
// if (CollectionUtils.isEmpty(roleResourceDOs)) {
|
||||
// return Collections.emptyList();
|
||||
// }
|
||||
// List<ResourceDO> menuDOs = menuMapper.selectListByIdsAndType(
|
||||
// CollectionUtils.convertSet(roleResourceDOs, RoleResourceDO::getResourceId), type);
|
||||
// return ResourceConvert.INSTANCE.convertList(menuDOs);
|
||||
// }
|
||||
//
|
||||
/**
|
||||
* 校验父菜单是否合法
|
||||
*
|
||||
* 1. 不能设置自己为父菜单
|
||||
* 2. 父菜单不存在
|
||||
* 3. 父菜单必须是 {@link MenuTypeEnum#MENU} 菜单类型
|
||||
*
|
||||
* @param parentId 父菜单编号
|
||||
* @param childId 当前菜单编号
|
||||
*/
|
||||
private void checkParentResource(Long parentId, Long childId) {
|
||||
if (parentId == null || MenuIdEnum.ROOT.getId().equals(parentId)) {
|
||||
return;
|
||||
}
|
||||
// 不能设置自己为父菜单
|
||||
if (parentId.equals(childId)) {
|
||||
throw ServiceExceptionUtil.exception(MENU_PARENT_ERROR);
|
||||
}
|
||||
SysMenuDO menu = menuMapper.selectById(parentId);
|
||||
// 父菜单不存在
|
||||
if (menu == null) {
|
||||
throw ServiceExceptionUtil.exception(MENU_PARENT_NOT_EXISTS);
|
||||
}
|
||||
// 父菜单必须是目录类型
|
||||
if (!MenuTypeEnum.DIR.getType().equals(menu.getType())) {
|
||||
throw ServiceExceptionUtil.exception(MENU_PARENT_NOT_MENU);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验菜单是否合法
|
||||
*
|
||||
* 1. 校验相同父菜单编号下,是否存在相同的菜单名
|
||||
*
|
||||
* @param name 菜单名字
|
||||
* @param parentId 父菜单编号
|
||||
* @param id 菜单编号
|
||||
*/
|
||||
private void checkResource(Long parentId, String name, Long id) {
|
||||
SysMenuDO menu = menuMapper.selectByParentIdAndName(parentId, name);
|
||||
if (menu == null) {
|
||||
return;
|
||||
}
|
||||
// 如果 menuId 为空,说明不用比较是否为相同 menuId 的菜单
|
||||
if (id == null) {
|
||||
throw ServiceExceptionUtil.exception(MENU_NAME_DUPLICATE);
|
||||
}
|
||||
if (!menu.getId().equals(id)) {
|
||||
throw ServiceExceptionUtil.exception(MENU_NAME_DUPLICATE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化菜单的通用属性。
|
||||
*
|
||||
* 例如说,只有目录或者菜单类型的菜单,才设置 icon
|
||||
*
|
||||
* @param menu 菜单
|
||||
*/
|
||||
private void initMenuProperty(SysMenuDO menu) {
|
||||
// 菜单为按钮类型时,无需 component、icon、path 属性,进行置空
|
||||
if (MenuTypeEnum.BUTTON.getType().equals(menu.getType())) {
|
||||
menu.setComponent("");
|
||||
menu.setIcon("");
|
||||
menu.setPath("");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -107,4 +107,9 @@ public class SysPermissionServiceImpl implements SysPermissionService {
|
||||
return roleDept != null ? roleDept.getRoleId() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRolesMenuByMenuId(Long menuId) {
|
||||
// TODO 实现我
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user