(一)案例背景
如上图所示,该功能是依托于ZTree开发的一个权限分配系统。其中用户组和菜单组是相关联的,点击用户组,相关联的菜单树中的节点就被勾选上。菜单树中的节点分为两种:Menu节点(菜单节点)和Action节点(动作节点),例:“内容管理”就是Menu节点,“广告管理”就是Action节点。现在,想开发一个功能:删除Action节点。
(二)问题分析
因为“用户组”是和Action节点是相关联的,所以:
第一步:得先删除“用户组”和Action节点的关联关系;
第二步:再删除Action节点;
第三步:若Action节点删除以后,其父节点菜单及其父节点菜单的父节点菜单下若再无下辖的Action节点,则需要删除“用户组”和Menu节点的关联关系。
关于最后一点,我需要详细说明下。由于ZTree的特性,我们在勾选Action节点时,其父节点和父节点的父节点也会被勾选上,如下图:
这样,我们在为“超级管理员组”分配Action节点(1节点)时,同时还建立了“超级管理员组”与“内容管理”、“测试菜单1”和“测试菜单2”的“用户组”和Menu节点的关联关系。当我们删除了Action节点(1节点)时,此时“超级管理员组”与“内容管理”、“测试菜单1”和“测试菜单2”的关联关系还是存在的,就变成了这样:
这样显然是违背我们想要得到的效果的,我们想要的效果是:当删除了Action节点(1节点)时,“内容管理”、“测试菜单1”和“测试菜单2”不应该被勾选上,因为这些菜单节点下已经没有Action节点与“超级管理员组”有关系了。所以我们需要进行第三步:若Action节点删除以后,其父节点菜单及其父节点菜单的父节点菜单下若再无下辖的Action节点,则需要删除“用户组”和Menu节点的关联关系。
(三)解决办法
解决的核心思想就是:迭代!!具体见代码:
@Override
public ResultDto removeActionWithId(Integer id) {
Action action = new Action();
action.setId(id);
action = getAction(action);
if (action == null){
return new ResultDto(PageCodeEnum.ACTION_NOT_EXISTS);
}
//删除Action的关联关系与Action
removeRelationshipWithAction(action);
return new ResultDto(PageCodeEnum.DELETE_SUCCESS);
}
/**
* 删除Action节点的关联关系(group/action)
* 重难点:
* 若菜单及其所有子菜单均无下辖的Action节点,则清除该父节点与用户组之间的关联关系(group/menu),
* 若父菜单及其所下辖的其他子菜单均无下辖的Action节点,则清除该父菜单与用户组之间的关联关系(group/menu)
*/
private void removeRelationshipWithAction(Action action){
//删除Action节点的关联关系(group/action)
groupActionService.deleteGroupActionByActionId(action.getId());
//留着
Integer menuId = action.getMenuId();
//删除Action
deleteAction(action);
//若删除该action以后,父节点菜单及其所有子节点菜单均无其他下辖的Action节点,则清除该父节点与用户组之间的关联关系(group/menu)
removeGroupMenuIfMenuEmpty(menuId);
}
/**
* 若菜单及其所有子菜单均无下辖的Action节点,则清除该父节点与用户组之间的关联关系(group/menu),
* 若父菜单及其所下辖的其他子菜单均无下辖的Action节点,则清除该父菜单与用户组之间的关联关系(group/menu)
* @param menuId 菜单id
*/
private void removeGroupMenuIfMenuEmpty(Integer menuId) {
Menu menu = new Menu();
menu.setId(menuId);
if (CollectionUtils.isNotEmpty(menuService.getMenu(menu))){
menu = menuService.getMenu(menu).get(0);
//若菜单及其所有子菜单均无下辖的Action节点,则清除该父节点与用户组之间的关联关系(group/menu)
removeGroupMenuIfSelfEmpty(menu);
//清除父节点
Menu parentMenu = new Menu();
parentMenu.setId(menu.getParentId());
if (CollectionUtils.isNotEmpty(menuService.getMenu(parentMenu))){
//若父菜单及其所下辖的其他子菜单均无下辖的Action节点,则清除该父菜单与用户组之间的关联关系(group/menu)
removeGroupMenuIfMenuEmpty(menuService.getMenu(parentMenu).get(0).getId());
}
}
}
/**
* 若删除该action以后,父节点菜单无其他下辖的Action节点或下辖的所有子菜单,无Action节点,则清除该父节点与用户组
* 之间的关联关系(group/menu)
* @param menu Action节点所属的菜单节点
* 重难点:所有子菜单无Action节点
*/
private void removeGroupMenuIfSelfEmpty(Menu menu) {
//自身及所有子菜单均无Action节点
if (isAllActionListEmpty(menu)){
//删除与用户组之间的关联关系(group/menu)
groupMenuService.deleteGroupMenuByMenuId(menu.getId());
}
}
/**
* 菜单节点本身及其所下辖的所有子菜单节均无Action
* @param menu 菜单节点
* @return true:无 false:有
*/
private boolean isAllActionListEmpty(Menu menu) {
//下辖actionList不为空
if (CollectionUtils.isNotEmpty(menu.getActionList())){
return false;
}
//以该菜单节点为父节点的菜单节点actionList不为空
Menu childMenu = new Menu();
childMenu.setParentId(menu.getId());
List<Menu> childMenuList = menuService.getMenu(childMenu);
if (CollectionUtils.isNotEmpty(childMenuList)){
for (Menu tempMenu : childMenuList){
isAllActionListEmpty(tempMenu);
}
}
return true;
}