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<S_menu> {
|
|
private MenuServiceImpl menuService;
|
|
public void setMenuService(MenuServiceImpl menuService) {
|
this.menuService = menuService;
|
}
|
|
@Override
|
protected int loadDataToCache(Cache cache) {
|
List<S_menu> 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<S_menu> 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<SystemMenu> getMenuList(List<String> roleIdList, int menuScope){
|
if(StringUtils.isEmptyList(roleIdList)){
|
// 没有给定角色集合,说明是管理员,显示所有菜单数据
|
return this.toSystemMenuList(this.getCacheMenuList(true, menuScope));
|
}
|
// 根据角色权限加载不同菜单集合
|
List<SystemMenu> menuList = new ArrayList<>(32);
|
List<String> 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<SystemMenu> addParentMenu2Collection(List<SystemMenu> menuList, String menuId){
|
// List<SystemMenu> 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<SystemMenu> toSystemMenuList(List<S_menu> srcMenuList){
|
List<SystemMenu> 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<S_menu> getCacheMenuList(boolean containButton, int menuScope){
|
List<S_menu> data = new ArrayList<>();
|
S_menu menu = null;
|
for(Iterator<Cachable> 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<SystemMenu> getChildPerms(List<SystemMenu> list, String parentId) {
|
List<SystemMenu> returnList = new ArrayList<>();
|
for (Iterator<SystemMenu> 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<SystemMenu> list, SystemMenu t) {
|
// 得到子节点列表
|
List<SystemMenu> childList = getChildList(list, t);
|
t.setChildren(childList);
|
for (SystemMenu tChild : childList) {
|
if (hasChild(list, tChild)) {
|
recursionFn(list, tChild);
|
}
|
}
|
}
|
|
/**
|
* 得到子节点列表
|
*/
|
private List<SystemMenu> getChildList(List<SystemMenu> list, SystemMenu t) {
|
List<SystemMenu> tlist = new ArrayList<>();
|
Iterator<SystemMenu> 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<SystemMenu> list, SystemMenu t) {
|
return getChildList(list, t).size() > 0;
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~ 以下为用户登录菜单展示使用,2022-11-12
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
/**
|
* 返回菜单权限标识字符串集合,该方法若依前端使用。<p></p>
|
* 后续会去掉前端对权限点的依赖。
|
* @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<String> getPermissionSet(List<String> menuIdList, boolean showAll, int menuScope){
|
if(StringUtils.isEmptyList(menuIdList) && !showAll){
|
return new HashSet<>();
|
}
|
List<String> permsList = new ArrayList<>(64);
|
// List<S_menu> menuAll = this.getCacheMenuList(true, MenuUtils.MENU_SCOPE_PLATFORM);
|
List<S_menu> 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<String> 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<SystemMenu> getMenuTreeAll(List<String> 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<SystemMenu> getMenuTree(List<String> menuIdList, boolean containButton, boolean showAll, int menuScope){
|
List<SystemMenu> menuGroupList = new ArrayList<>(32);
|
if(StringUtils.isEmptyList(menuIdList) && !showAll){
|
// 2023-03-22 给定为空菜单id,并且不允许显示所有,返回空菜单树。
|
return getChildPerms(menuGroupList, "0");
|
}
|
// List<S_menu> menuAll = this.getCacheMenuList(false);
|
List<S_menu> 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<RouterVo> buildMenus(List<SystemMenu> menus) {
|
List<RouterVo> routers = new LinkedList<RouterVo>();
|
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<SystemMenu> 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<RouterVo> childrenList = new ArrayList<RouterVo>();
|
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<RouterVo> childrenList = new ArrayList<RouterVo>();
|
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权限配置实用。<p></p>
|
* 该方法会有重复数据,例如:多个角色具有相同的URL,由业务去除重复。<p></p>
|
* list[0] = role_id, list[1] = url <p></p>
|
* 因为Map对象相同key会覆盖value,所以换成List集合返回。
|
* @return
|
* @date 2022-11-02
|
*/
|
public List<String[]> getAllRoleMenuMap(){
|
List<String[]> result = new ArrayList<>();
|
List<Map<String, Object>> list = this.menuService.queryRolesPermList();
|
if(StringUtils.isEmptyList(list)){
|
return result;
|
}
|
|
String perms = null;
|
String menuId = null;
|
S_menu menu = null;
|
|
for(Map<String, Object> 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<String> 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<String> getAllMenuUrlList(){
|
List<String> urlList = new ArrayList<>(32);
|
S_menu menu = null;
|
String perms = null;
|
for(Iterator<Cachable> 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;
|
}
|
}
|