perf: 菜单 变更上级菜单、更换当前Label 对下级所有子节点产生同步操作

pull/9/head
Carina 4 years ago
parent dc461ae7f7
commit 7871ac0363

@ -16,6 +16,7 @@
package org.opsli.api.wrapper.system.menu;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -40,6 +41,11 @@ public class MenuModel extends ApiWrapper {
@ValidatorLenMax(20)
private String parentId;
/** 父级主键 ID集合 */
@ApiModelProperty(value = "父级主键")
@ExcelIgnore
private String parentIds;
/** 权限编号 */
@ApiModelProperty(value = "权限编号")
@ExcelIgnore

@ -36,6 +36,8 @@ public enum SystemMsg implements BaseMsg {
*/
EXCEPTION_MENU_PERMISSIONS_UNIQUE(20050,"权限重复,该权限编号已存在"),
EXCEPTION_MENU_HANDLE_SELF(20051,"不可操作自身"),
EXCEPTION_MENU_NULL(20052,"未找到菜单"),
/**
*

@ -36,6 +36,9 @@ public class SysMenu extends BaseEntity {
/** 父级主键 */
private String parentId;
/** 父级主键 集合 */
private String parentIds;
/** 权限编号 */
private String permissions;

@ -97,6 +97,7 @@ public enum MenuFactory {
menu.setUrl(subModuleName);
menu.setType(DictType.MENU_MENU.getValue());
menu.setSortNo(1);
menu.setLabel(DictType.MENU_LABEL_SYSTEM.getValue());
menu.setComponent("views/modules/"+model.getModuleName()+"/"+model.getSubModuleName()+"/index");
return menu;

@ -17,13 +17,17 @@ package org.opsli.modulars.system.menu.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.wrapper.system.menu.MenuFullModel;
import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.constants.MenuConstants;
import org.opsli.common.constants.MyBatisConstants;
import org.opsli.common.constants.TreeConstants;
import org.opsli.common.enums.DictType;
import org.opsli.common.exception.ServiceException;
import org.opsli.common.utils.FieldUtil;
@ -33,6 +37,7 @@ import org.opsli.core.msg.CoreMsg;
import org.opsli.core.persistence.querybuilder.GenQueryBuilder;
import org.opsli.core.persistence.querybuilder.QueryBuilder;
import org.opsli.core.utils.MenuUtil;
import org.opsli.core.utils.TreeBuildUtil;
import org.opsli.core.utils.UserUtil;
import org.opsli.modulars.system.SystemMsg;
import org.opsli.modulars.system.menu.entity.SysMenu;
@ -45,6 +50,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@ -87,6 +93,9 @@ public class MenuServiceImpl extends CrudServiceImpl<MenuMapper, SysMenu, MenuMo
return null;
}
// 先清空 parentIds 防止数据出现异常问题
model.setParentIds(null);
// 如果上级ID 为空 则默认为 0
if(StringUtils.isEmpty(model.getParentId())){
model.setParentId(MenuConstants.GEN_ID);
@ -96,35 +105,13 @@ public class MenuServiceImpl extends CrudServiceImpl<MenuMapper, SysMenu, MenuMo
// 如果根结点为0 且 为菜单类型 判断首位是否为 / 如果没有则自动加 /
if(MenuConstants.GEN_ID.equals(model.getParentId())){
if(StringUtils.isNotEmpty(model.getUrl())){
char firstChar = '/';
char first = model.getUrl().charAt(0);
if(firstChar != first){
model.setUrl("/"+model.getUrl());
}
}
}
// 菜单有变动 直接刷新超级管理员 菜单缓存
UserModel adminUser = UserUtil.getUserByUserName(UserUtil.SUPER_ADMIN);
if(adminUser != null){
// 计数器
int cacheCount = 2;
boolean cacheRet;
cacheRet = UserUtil.refreshUserAllPerms(adminUser.getId());
if(cacheRet){
cacheCount--;
String url = StrUtil.addPrefixIfNot(model.getUrl(), "/");
model.setUrl(url);
}
cacheRet = UserUtil.refreshUserMenus(adminUser.getId());
if(cacheRet){
cacheCount--;
}
// 判断删除状态
if(cacheCount != 0){
// 删除缓存失败
throw new ServiceException(CoreMsg.CACHE_DEL_EXCEPTION);
}
}
// 刷新缓存
clearCache(Collections.singletonList(model));
return super.insert(model);
}
@ -136,6 +123,9 @@ public class MenuServiceImpl extends CrudServiceImpl<MenuMapper, SysMenu, MenuMo
return null;
}
// 先清空 parentIds 防止数据出现异常问题
model.setParentIds(null);
// 如果开启 隐藏功能
if(DictType.NO_YES_YES.getValue().equals(model.getHidden())){
// 需要判断是否直接隐藏掉 菜单管理功能 (防止直接隐藏掉后 无法管理菜单)
@ -145,27 +135,108 @@ public class MenuServiceImpl extends CrudServiceImpl<MenuMapper, SysMenu, MenuMo
}
}
// 原数据
MenuModel sourceModel = this.get(model);
if(null == sourceModel){
// 未找到菜单
throw new ServiceException(SystemMsg.EXCEPTION_MENU_NULL);
}
MenuModel oldParentModel = getParentMenuModel(sourceModel.getParentId());
MenuModel newParentModel = getParentMenuModel(model.getParentId());
// 去除 两边的[,] 然后拼接 parentIds
String ordParentIds = unWrap(
StrUtil.join(",",
oldParentModel.getParentIds(), oldParentModel.getId(), sourceModel.getId()), ',');
String newParentIds = unWrap(
StrUtil.join(",",
newParentModel.getParentIds(), newParentModel.getId(), model.getId()), ',');
// 判断 上级是否发生变更 如果发生变更 则当前菜单 继承上级菜单的 label
if(!sourceModel.getParentId().equals(model.getParentId())){
model.setParentIds(newParentIds);
model.setLabel(newParentModel.getLabel());
// 查询所有受影响的子集菜单 批量修改子类的parentIds
QueryWrapper<SysMenu> findChildWrapper = new QueryWrapper<>();
findChildWrapper.likeRight("parent_ids", ordParentIds);
List<SysMenu> menuList = this.list(findChildWrapper);
// 循环变更 parentIds
for (SysMenu sysMenu : menuList) {
String parentIds = sysMenu.getParentIds();
if(StringUtils.isBlank(parentIds)){
parentIds = newParentIds;
}else {
parentIds = StrUtil.replace(parentIds, ordParentIds, newParentIds);
}
sysMenu.setParentIds(parentIds);
// 内部修改 防止版本行锁出现问题
sysMenu.setVersion(null);
}
this.saveOrUpdateBatch(menuList);
}
// 如果 原始标签 与 当前标签发送变更 则逐级变更子类标签
if(!sourceModel.getLabel().equals(model.getLabel())){
// 查询所有受影响的子集菜单
QueryWrapper<SysMenu> findChildWrapper = new QueryWrapper<>();
findChildWrapper.likeRight("parent_ids", newParentIds);
List<MenuModel> menuList = super.transformTs2Ms(this.list(findChildWrapper));
// 刷新缓存
this.clearCache(menuList);
// 修改所有子集 label
UpdateWrapper<SysMenu> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("label", model.getLabel());
updateWrapper.likeRight("parent_ids", newParentIds);
this.update(updateWrapper);
}
// 容错处理
// 如果根结点为0 且 为菜单类型 判断首位是否为 / 如果没有则自动加 /
if(MenuConstants.GEN_ID.equals(model.getParentId())){
if(StringUtils.isNotEmpty(model.getUrl())){
char firstChar = '/';
char first = model.getUrl().charAt(0);
if(firstChar != first){
model.setUrl("/"+model.getUrl());
}
String url = StrUtil.addPrefixIfNot(model.getUrl(), "/");
model.setUrl(url);
}
}
MenuModel menuModel = super.update(model);
if(menuModel != null){
// 清除缓存
this.clearCache(model);
// 刷新缓存
this.clearCache(Collections.singletonList(model));
}
return menuModel;
}
/**
* model
* @param parentId ID
* @return MenuModel
*/
private MenuModel getParentMenuModel(String parentId) {
// 父类菜单
MenuModel parentModel;
if(TreeBuildUtil.DEF_PARENT_ID.equals(parentId)){
parentModel = new MenuModel();
parentModel.setId(TreeBuildUtil.DEF_PARENT_ID);
parentModel.setParentId("");
parentModel.setParentIds("");
parentModel.setLabel(DictType.MENU_LABEL_SYSTEM.getValue());
}else {
parentModel = this.get(parentId);
if(null == parentModel){
// 未找到菜单
throw new ServiceException(SystemMsg.EXCEPTION_MENU_NULL);
}
}
return parentModel;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void saveMenuByFull(MenuFullModel menuFullModel) {
@ -184,6 +255,7 @@ public class MenuServiceImpl extends CrudServiceImpl<MenuMapper, SysMenu, MenuMo
genMenu.setUrl(menuFullModel.getSubModuleName()+"Gen");
genMenu.setType(DictType.MENU_MENU.getValue());
genMenu.setComponent("Layout");
genMenu.setLabel(DictType.MENU_LABEL_SYSTEM.getValue());
genMenu.setRedirect(menuFullModel.getSubModuleName());
genMenu.setSortNo(1);
MenuModel genMenuModel = this.insert(genMenu);
@ -221,7 +293,7 @@ public class MenuServiceImpl extends CrudServiceImpl<MenuMapper, SysMenu, MenuMo
}
// 清除缓存
this.clearCache(menuModel);
this.clearCache(Collections.singletonList(menuModel));
// 删除子数据
this.deleteByParentId(id);
@ -251,7 +323,7 @@ public class MenuServiceImpl extends CrudServiceImpl<MenuMapper, SysMenu, MenuMo
}
// 清除缓存
this.clearCache(menuModel);
this.clearCache(Collections.singletonList(menuModel));
// 先删子数据
this.deleteByParentId(menuModel.getId());
@ -329,7 +401,7 @@ public class MenuServiceImpl extends CrudServiceImpl<MenuMapper, SysMenu, MenuMo
// ============
/**
*
*
* @param model model
* @return Integer
*/
@ -358,62 +430,62 @@ public class MenuServiceImpl extends CrudServiceImpl<MenuMapper, SysMenu, MenuMo
/**
*
* @param menuModel
* @param menuModelList
*/
private void clearCache(MenuModel menuModel){
private void clearCache(List<MenuModel> menuModelList){
if(CollUtil.isEmpty(menuModelList)){
return;
}
boolean cacheRet;
// 计数器
int cacheCount = 1;
int cacheCount = menuModelList.size();
// 菜单ID
List<String> menuIdList = Lists.newArrayListWithCapacity(menuModelList.size());
for (MenuModel menuModel : menuModelList) {
menuIdList.add(menuModel.getId());
// 先清除缓存
// 清空编号缓存
cacheRet = MenuUtil.refreshMenu(menuModel);
if(cacheRet){
cacheCount--;
}
// 清空该菜单下 用户缓存
List<String> userIdList = iUserRoleRefService.getUserIdListByMenuId(menuModel.getId());
if(CollUtil.isNotEmpty(userIdList)){
for (String userId : userIdList) {
cacheCount += 6;
// 清空当期用户缓存角色、权限、菜单
cacheRet = UserUtil.refreshUserRoles(userId);
if(cacheRet){
cacheCount--;
}
cacheRet = UserUtil.refreshUserAllPerms(userId);
// 菜单有变动 直接刷新超级管理员 菜单缓存
UserModel adminUser = UserUtil.getUserByUserName(UserUtil.SUPER_ADMIN);
if(adminUser != null){
cacheCount += 2;
cacheRet = UserUtil.refreshUserAllPerms(adminUser.getId());
if(cacheRet){
cacheCount--;
}
cacheRet = UserUtil.refreshUserMenus(userId);
cacheRet = UserUtil.refreshUserMenus(adminUser.getId());
if(cacheRet){
cacheCount--;
}
cacheRet = UserUtil.refreshUserOrgs(userId);
if(cacheRet){
cacheCount--;
}
cacheRet = UserUtil.refreshUserDefRole(userId);
// 刷新用户缓存
// 清空该菜单下 用户缓存
List<String> userIdList = iUserRoleRefService.getUserIdListByMenuIdList(menuIdList);
if(CollUtil.isNotEmpty(userIdList)){
for (String userId : userIdList) {
cacheCount += 3;
// 清空当期用户缓存角色、权限、菜单
cacheRet = UserUtil.refreshUserRoles(userId);
if(cacheRet){
cacheCount--;
}
cacheRet = UserUtil.refreshUserDefOrg(userId);
cacheRet = UserUtil.refreshUserAllPerms(userId);
if(cacheRet){
cacheCount--;
}
}
}
// 菜单有变动 直接刷新超级管理员 菜单缓存
UserModel adminUser = UserUtil.getUserByUserName(UserUtil.SUPER_ADMIN);
if(adminUser != null){
cacheCount += 2;
cacheRet = UserUtil.refreshUserAllPerms(adminUser.getId());
cacheRet = UserUtil.refreshUserMenus(userId);
if(cacheRet){
cacheCount--;
}
cacheRet = UserUtil.refreshUserMenus(adminUser.getId());
if(cacheRet){
cacheCount--;
}
}
@ -423,6 +495,27 @@ public class MenuServiceImpl extends CrudServiceImpl<MenuMapper, SysMenu, MenuMo
throw new ServiceException(CoreMsg.CACHE_DEL_EXCEPTION);
}
}
/**
*
*
* @param str
* @param prefix
* @return
* @since 4.0.1
*/
public static String unWrap(CharSequence str, char prefix) {
if (StrUtil.isEmpty(str)) {
return StrUtil.str(str);
}
if (str.charAt(0) == prefix) {
return StrUtil.subSuf(str, 1);
}
return str.toString();
}
}

@ -77,6 +77,14 @@ public interface UserRoleRefMapper extends BaseMapper<SysUserRoleRef> {
*/
List<String> getUserIdList(@Param(Constants.WRAPPER) Wrapper<?> wrapper);
/**
* Id
*
* @param wrapper wrapper
* @return List
*/
List<String> getUserIdListByMenu(@Param(Constants.WRAPPER) Wrapper<?> wrapper);
/**
* ID Id
* @param menuId ID

@ -106,6 +106,16 @@
${ew.customSqlSegment}
</select>
<select id="getUserIdListByMenu" resultType="String">
select
b.user_id
from
sys_role_menu_ref a
join sys_user_role_ref b on b.role_id = a.role_id
join sys_menu menu on menu.id = a.menu_id
${ew.customSqlSegment}
</select>
<select id="getUserIdListByMenuId" resultType="String">
select
b.user_id

@ -89,10 +89,17 @@ public interface IUserRoleRefService {
/**
* ID Id
* @param roleId ID
* @param menuId ID
* @return List
*/
List<String> getUserIdListByMenuId(String menuId);
/**
* ID Id
* @param menuIdList ID
* @return List
*/
List<String> getUserIdListByMenuId(String roleId);
List<String> getUserIdListByMenuIdList(List<String> menuIdList);
/**
* ID ID

@ -229,8 +229,31 @@ public class UserRoleRefServiceImpl extends ServiceImpl<UserRoleRefMapper, SysUs
}
@Override
public List<String> getUserIdListByMenuId(String roleId) {
List<String> users = mapper.getUserIdListByMenuId(roleId);
public List<String> getUserIdListByMenuId(String menuId) {
QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
queryWrapper
.eq("menu.deleted", DictType.NO_YES_NO.getValue())
.notIn("menu.parent_id", -1)
.eq("a.menu_id", menuId);
List<String> users = mapper.getUserIdListByMenu(queryWrapper);
if(CollUtil.isEmpty(users)){
return ListUtil.empty();
}
// 去重
return ListDistinctUtil.distinct(users);
}
@Override
public List<String> getUserIdListByMenuIdList(List<String> menuIdList) {
QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
queryWrapper
.eq("menu.deleted", DictType.NO_YES_NO.getValue())
.notIn("menu.parent_id", -1)
.in("a.menu_id", menuIdList);
List<String> users = mapper.getUserIdListByMenu(queryWrapper);
if(CollUtil.isEmpty(users)){
return ListUtil.empty();
}

Loading…
Cancel
Save