package com.iplatform.base.cache; import com.iplatform.base.Constants; import com.iplatform.base.SecurityConstants; import com.iplatform.base.service.MenuServiceImpl; import com.iplatform.base.util.MenuUtils; import com.iplatform.base.util.menu.MenuOrderNumComparator; import com.iplatform.base.util.menu.ParentMenuComparator; import com.iplatform.base.util.menu.SystemMenu; import com.iplatform.model.po.S_menu; import com.iplatform.model.vo.MetaVo; import com.iplatform.model.vo.RouterVo; import com.walker.cache.AbstractCacheProvider; import com.walker.cache.Cachable; import com.walker.cache.Cache; import com.walker.infrastructure.utils.StringUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; /** * 菜单本地缓存,因为不需要集群环境,因此只有内存模式(没有redis方式) * @author 时克英 * @date 2022-11-01 */ public class MenuCacheProvider extends AbstractCacheProvider { private MenuServiceImpl menuService; public void setMenuService(MenuServiceImpl menuService) { this.menuService = menuService; } @Override protected int loadDataToCache(Cache cache) { List list = this.menuService.selectAll(new S_menu()); if(!StringUtils.isEmptyList(list)){ for(S_menu h : list){ cache.put(h.getMenu_id(), h); } return list.size(); } return 0; } @Override public String getProviderName() { return Constants.CACHE_NAME_MENU; } @Override public Class getProviderType() { return S_menu.class; } /** * 给定的菜单,是否包含子菜单。 * @param menuId 给定菜单ID * @return * @date 2022-12-29 */ public boolean isHasChildren(String menuId){ List menuAll = this.getCacheMenuList(true, MenuUtils.MENU_SCOPE_PLATFORM); for(S_menu menu : menuAll){ if(menu.getParent_id().equals(menuId)){ return true; } } return false; } /** * 返回菜单集合列表(不是树结构),目前该方法在代码生成功能中使用,展示选择生成在哪个菜单模块。 * @param roleIdList * @param menuScope 菜单范围:0 平台(目前也有3),4 独立单位, -1 表示显示所有菜单,>4 表示机构特定菜单,如班主任菜单。 * @return * @date 2022-11-27 * @date 2023-06-05 添加参数 menuScope * @date 2023-10-11 menuScope 参数增加值(-1)可以展示所有菜单,邮政集团模式 * @date 2023-10-24 menuScope 参数增加值(大于4),表示特定人员的特定菜单(如:班主任的菜单) */ public List getMenuList(List roleIdList, int menuScope){ if(StringUtils.isEmptyList(roleIdList)){ // 没有给定角色集合,说明是管理员,显示所有菜单数据 return this.toSystemMenuList(this.getCacheMenuList(true, menuScope)); } // 根据角色权限加载不同菜单集合 List menuList = new ArrayList<>(32); List menuIdList = this.menuService.queryRoleMenuIdList(roleIdList); if(StringUtils.isEmptyList(menuIdList)){ logger.warn("用户没有任何权限,menuIdList = null, roleIdList = {}", roleIdList); return menuList; } S_menu menu = null; for(String menuId : menuIdList){ menu = this.getCacheData(menuId); // 2023-10-11 增加这个if判断,如果是不区分范围,则加载所有菜单 // if(menuScope != MenuUtils.MENU_SCOPE_ALL){ // if(menuScope == MenuUtils.MENU_SCOPE_PLATFORM){ // // 如果要展示菜单范围是:平台,则菜单中 >= 4的分类都不要,这些是顶级机构业务独立菜单。 // if(menu.getType().intValue() >= MenuUtils.MENU_SCOPE_ORG){ // continue; // } // } else if(menuScope == MenuUtils.MENU_SCOPE_ORG){ //// if(menu.getType().intValue() < MenuUtils.MENU_SCOPE_ORG){ // if(menu.getType().intValue() != MenuUtils.MENU_SCOPE_ORG){ // // 如果要展示菜单范围是:顶级机构业务的独立菜单,则平台菜单不显示。2023-06-01 // continue; // } // } else if(menuScope > MenuUtils.MENU_SCOPE_ORG){ // // 对于大于机构菜单的,都属于机构特定菜单,必须与传入范围完全一致,如:班主任菜单等。2023-10-24 // if(menu.getType().intValue() != menuScope){ // continue; // } // } // } if(MenuUtils.menuScopeNotMatch(menuScope, menu)){ continue; } menuList.add(new SystemMenu(menu)); } // 2023-10-13,查找每个菜单上级,如果上级范围类型与下级菜单不一致,也需要加入列表中 for(String menuId : menuIdList){ if(MenuUtils.containMenu(menuList, menuId)){ continue; } menu = this.getCacheData(menuId); menuList.add(new SystemMenu(menu)); } // if(!StringUtils.isEmptyList(menuList)){ // String pid = null; // for(SystemMenu systemMenu : menuList){ // pid = systemMenu.getParent_id(); // if(pid.equals(MenuUtils.MENU_ID_ROOT)){ // continue; // } // if(menuIdList.contains(pid)){ // this.addParentMenu2Collection(menuList, pid); // } // } // } Collections.sort(menuList, new ParentMenuComparator()); Collections.sort(menuList, new MenuOrderNumComparator()); return menuList; } // private List addParentMenu2Collection(List menuList, String menuId){ // List addList = null; // boolean exist = false; // for(SystemMenu menu : menuList){ // if(menu.getMenu_id().equals(menuId)){ // exist = true; // break; // } // } // if(!exist){ // S_menu menu = this.getCacheData(menuId); // if(addList == null){ // addList = new ArrayList<>(8); // } // addList.add(new SystemMenu(menu)); // } // return addList; // } public List toSystemMenuList(List srcMenuList){ List list = new ArrayList<>(32); if(StringUtils.isEmptyList(srcMenuList)){ return list; } for(S_menu menu : srcMenuList){ list.add(new SystemMenu(menu)); } return list; } /** * 获得缓存菜单列表 * @param containButton 是否包含按钮权限菜单 * @param menuScope 菜单范围,对独立顶级机构,可以显示机构设置的分类菜单范围,目前有:0-平台(包含3),4-顶级单位独立菜单 * @return * @date 2023-06-01 */ public List getCacheMenuList(boolean containButton, int menuScope){ List data = new ArrayList<>(); S_menu menu = null; for(Iterator it = this.getCache().getIterator(); it.hasNext();){ menu = (S_menu) it.next().getValue(); // 2023-10-11 增加这个if判断,如果是不区分范围,则加载所有菜单 // if(menuScope != MenuUtils.MENU_SCOPE_ALL){ // if(menuScope == MenuUtils.MENU_SCOPE_PLATFORM){ // // 如果要展示菜单范围是:平台,则菜单中 >= 4的分类都不要,这些是顶级机构业务独立菜单。 // if(menu.getType().intValue() >= MenuUtils.MENU_SCOPE_ORG){ // continue; // } // } else if(menu.getType().intValue() < MenuUtils.MENU_SCOPE_ORG){ // // 如果要展示菜单范围是:顶级机构业务的独立菜单,则平台菜单不显示。2023-06-01 // continue; // } // } // 2023-10-24 if(MenuUtils.menuScopeNotMatch(menuScope, menu)){ continue; } if(menu.getStatus().intValue() == MenuUtils.MENU_STATUS_DISABLED){ // 去掉禁用菜单 continue; } if(menu.getMenu_type().equals(MenuUtils.MENU_TYPE_BUTTON)){ if(containButton){ data.add(menu); } } else { data.add(menu); } } Collections.sort(data, new ParentMenuComparator()); Collections.sort(data, new MenuOrderNumComparator()); return data; } /** * 根据父节点的ID获取所有子节点 * * @param list 分类表 * @param parentId 传入的父节点ID * @return String */ public List getChildPerms(List list, String parentId) { List returnList = new ArrayList<>(); for (Iterator iterator = list.iterator(); iterator.hasNext();) { SystemMenu t = iterator.next(); // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点 if (t.getParent_id().equals(parentId)) { recursionFn(list, t); returnList.add(t); } } return returnList; } /** * 递归列表 * * @param list * @param t */ private void recursionFn(List list, SystemMenu t) { // 得到子节点列表 List childList = getChildList(list, t); t.setChildren(childList); for (SystemMenu tChild : childList) { if (hasChild(list, tChild)) { recursionFn(list, tChild); } } } /** * 得到子节点列表 */ private List getChildList(List list, SystemMenu t) { List tlist = new ArrayList<>(); Iterator it = list.iterator(); while (it.hasNext()) { SystemMenu n = it.next(); if (n.getParent_id().equals(t.getMenu_id())) { tlist.add(n); } } return tlist; } /** * 判断是否有子节点 */ private boolean hasChild(List list, SystemMenu t) { return getChildList(list, t).size() > 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~ 以下为用户登录菜单展示使用,2022-11-12 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * 返回菜单权限标识字符串集合,该方法若依前端使用。

* 后续会去掉前端对权限点的依赖。 * @param menuIdList * @param showAll 是否显示所有权限点 * @param menuScope 菜单范围,对独立顶级机构,可以显示机构设置的分类菜单范围,目前有:0-平台(包含3),4-顶级单位独立菜单 * @return * @date 2022-11-12 * @date 2023-03-20 如果给定菜单id为空,则不返回任何权限点信息。时克英 * @date 2023-06-07 对于独立单位(商户)则会显示所有该单位的菜单权限信息 */ public Set getPermissionSet(List menuIdList, boolean showAll, int menuScope){ if(StringUtils.isEmptyList(menuIdList) && !showAll){ return new HashSet<>(); } List permsList = new ArrayList<>(64); // List menuAll = this.getCacheMenuList(true, MenuUtils.MENU_SCOPE_PLATFORM); List menuAll = this.getCacheMenuList(true, menuScope); if(!StringUtils.isEmptyList(menuAll)){ for(S_menu menu : menuAll){ // 2023-10-11 增加这个if判断,如果是不区分范围,则加载所有菜单 // if(menuScope != MenuUtils.MENU_SCOPE_ALL){ // // // 2023-06-07 // if(menuScope == MenuUtils.MENU_SCOPE_PLATFORM){ // // 如果要展示菜单范围是:平台,则菜单中 >= 4的分类都不要,这些是顶级机构业务独立菜单。 // if(menu.getType().intValue() >= MenuUtils.MENU_SCOPE_ORG){ // continue; // } // } else if(menu.getType().intValue() < MenuUtils.MENU_SCOPE_ORG){ // // 如果要展示菜单范围是:顶级机构业务的独立菜单,则平台菜单不显示。2023-06-01 // continue; // } // } // 2023-10-24 if(MenuUtils.menuScopeNotMatch(menuScope, menu)){ continue; } if(StringUtils.isEmpty(menu.getPerms())){ continue; } if(StringUtils.isEmptyList(menuIdList)){ // 如果没有限制,全部加上 permsList.add(menu.getPerms()); } else if(menuIdList.contains(menu.getMenu_id())){ // 如果限制有,则只添加给定的 permsList.add(menu.getPerms()); } } } Set permsSet = new HashSet<>(); for(String perms : permsList){ if (StringUtils.isNotEmpty(perms)) { permsSet.addAll(Arrays.asList(perms.trim().split(","))); } } return permsSet; } /** * 返回菜单树形结果,列表中包含多个菜单根节点,menuIdList 为空时,允许返回所有的。 * @param menuIdList * @param containButton * @return * @date 2023-03-22 */ public List getMenuTreeAll(List menuIdList, boolean containButton, int menuScope){ return this.getMenuTree(menuIdList, containButton, true, menuScope); } /** * 返回菜单树形结果,列表中包含多个菜单根节点。 * @param menuIdList 指定显示的菜单,如果为空表示不特别限制 * @param containButton 是否包含按钮权限 * @param showAll 当给定'menuIdList'为空时,是否显示所有菜单 * @return * @date 2022-12-18 更新 * @date 2023-03-22 添加参数'showAll' */ public List getMenuTree(List menuIdList, boolean containButton, boolean showAll, int menuScope){ List menuGroupList = new ArrayList<>(32); if(StringUtils.isEmptyList(menuIdList) && !showAll){ // 2023-03-22 给定为空菜单id,并且不允许显示所有,返回空菜单树。 return getChildPerms(menuGroupList, "0"); } // List menuAll = this.getCacheMenuList(false); List menuAll = this.getCacheMenuList(containButton, menuScope); if(!StringUtils.isEmptyList(menuAll)){ for(S_menu menu : menuAll){ if(menuIdList == null){ // 如果没有限制,全部加上 menuGroupList.add(new SystemMenu(menu)); } else if(menuIdList.contains(menu.getMenu_id())){ // 如果限制有,则只添加给定的 menuGroupList.add(new SystemMenu(menu)); } } } return getChildPerms(menuGroupList, "0"); } /** * 构建前端路由所需要的菜单(若依) * * @param menus 菜单列表 * @return 路由列表 */ @Deprecated public List buildMenus(List menus) { List routers = new LinkedList(); for (SystemMenu menu : menus) { RouterVo router = new RouterVo(); router.setHidden(MenuUtils.MENU_INVISIBLE.equals(menu.getVisible())); router.setName(MenuUtils.getRouteName(menu)); router.setPath(MenuUtils.getRouterPath(menu)); router.setComponent(MenuUtils.getComponent(menu)); router.setQuery(menu.getQuery()); router.setMeta(new MetaVo(menu.getMenu_name(), menu.getIcon(), menu.getIs_cache().intValue() == MenuUtils.MENU_CACHE_DISABLE, menu.getPath())); List cMenus = menu.getChildren(); if (!cMenus.isEmpty() && cMenus.size() > 0 && menu.getMenu_type().equals(MenuUtils.MENU_TYPE_FOLDER)) { router.setAlwaysShow(true); router.setRedirect("noRedirect"); router.setChildren(buildMenus(cMenus)); } else if (MenuUtils.isMenuFrame(menu)) { router.setMeta(null); List childrenList = new ArrayList(); RouterVo children = new RouterVo(); children.setPath(menu.getPath()); children.setComponent(menu.getComponent()); children.setName(StringUtils.capitalize(menu.getPath())); children.setMeta(new MetaVo(menu.getMenu_name(), menu.getIcon(), menu.getIs_cache().intValue() == MenuUtils.MENU_CACHE_DISABLE, menu.getPath())); children.setQuery(menu.getQuery()); childrenList.add(children); router.setChildren(childrenList); } else if (menu.getParent_id().equals(MenuUtils.MENU_ID_ROOT) && MenuUtils.isInnerLink(menu)) { router.setMeta(new MetaVo(menu.getMenu_name(), menu.getIcon())); router.setPath("/"); List childrenList = new ArrayList(); RouterVo children = new RouterVo(); String routerPath = MenuUtils.innerLinkReplaceEach(menu.getPath()); children.setPath(routerPath); children.setComponent(MenuUtils.INNER_LINK); children.setName(StringUtils.capitalize(routerPath)); children.setMeta(new MetaVo(menu.getMenu_name(), menu.getIcon(), menu.getPath())); childrenList.add(children); router.setChildren(childrenList); } routers.add(router); } return routers; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~ 以下为系统权限管理使用,2022-11-02 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * 返回系统所有角色与url关联数据,security权限配置实用。

* 该方法会有重复数据,例如:多个角色具有相同的URL,由业务去除重复。

* list[0] = role_id, list[1] = url

* 因为Map对象相同key会覆盖value,所以换成List集合返回。 * @return * @date 2022-11-02 */ public List getAllRoleMenuMap(){ List result = new ArrayList<>(); List> list = this.menuService.queryRolesPermList(); if(StringUtils.isEmptyList(list)){ return result; } String perms = null; String menuId = null; S_menu menu = null; for(Map map : list){ menuId = map.get("menu_id").toString(); menu = this.getCacheData(menuId); if(menu == null){ throw new IllegalArgumentException("缓存中未找到菜单:" + menuId); } perms = menu.getPerms(); if(StringUtils.isEmpty(perms)){ continue; } // result.put(map.get("role_id").toString(), MenuUtils.acquireUrlFromPerms(perms)); result.add(new String[]{map.get("role_id").toString(), MenuUtils.acquireUrlFromPerms(perms)}); } // 2023-06-07 // 商户(顶级机构)特有的菜单,也需要加入到角色中,设置默认三方角色:ROLE_MERCHANT Set merchantPermSet = this.getPermissionSet(null, true, MenuUtils.MENU_SCOPE_ORG); if(merchantPermSet != null){ for(String onePerms : merchantPermSet){ result.add(new String[]{SecurityConstants.ROLE_MERCHANT, MenuUtils.acquireUrlFromPerms(onePerms)}); } logger.debug("添加商户(顶级机构)角色权限:{}", merchantPermSet.size()); } return result; } /** * 返回系统所有菜单包含权限的url集合,即:所有perms存在的菜单。 * @return * @date 2022-11-02 */ public List getAllMenuUrlList(){ List urlList = new ArrayList<>(32); S_menu menu = null; String perms = null; for(Iterator it = this.getCache().getIterator(); it.hasNext();){ menu = (S_menu) it.next().getValue(); perms = menu.getPerms(); if(StringUtils.isEmpty(perms)){ continue; } urlList.add(MenuUtils.acquireUrlFromPerms(perms)); } return urlList; } }