fix: 修复菜单无法加载根节点问题

v1.4.1
Carina 4 years ago
parent 58e197e64f
commit 012473fe5c

@ -0,0 +1,33 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.common.constants;
/**
*
*
* @author Parker
* @date 202131015:50:16
*/
public interface TreeConstants {
/** 是否包含子集 */
String HAS_CHILDREN = "hasChildren";
/** 是否是叶子节点 */
String IS_LEAF = "isLeaf";
}

@ -17,13 +17,19 @@ package org.opsli.core.base.controller;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.base.result.ResultVo;
@ -32,6 +38,7 @@ import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.annotation.RequiresPermissionsCus;
import org.opsli.common.annotation.hotdata.EnableHotData;
import org.opsli.common.constants.CacheConstants;
import org.opsli.common.constants.TreeConstants;
import org.opsli.common.enums.ExcelOperate;
import org.opsli.common.exception.ServiceException;
import org.opsli.common.exception.TokenException;
@ -40,6 +47,7 @@ import org.opsli.common.utils.OutputStreamUtil;
import org.opsli.common.utils.WrapperUtil;
import org.opsli.core.autoconfigure.properties.GlobalProperties;
import org.opsli.core.base.entity.BaseEntity;
import org.opsli.core.base.entity.HasChildren;
import org.opsli.core.base.service.interfaces.CrudServiceInterface;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.msg.CoreMsg;
@ -60,9 +68,8 @@ import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.*;
import java.util.function.Function;
/**
* Service CRUD
@ -353,6 +360,67 @@ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWra
}
}
/**
*
* @param treeNodes
*/
protected List<Tree<Object>> handleTreeHasChildren(List<Tree<Object>> treeNodes,
Function<Set<String>, List<HasChildren>> callback) {
if(CollUtil.isEmpty(treeNodes) || callback == null){
return treeNodes;
}
Set<String> parentIds = Sets.newHashSet();
for (Tree<Object> treeNode : treeNodes) {
parentIds.add(Convert.toStr(treeNode.getId()));
}
// 数据排查是否存在下级
List<HasChildren> hasChildrenList = callback.apply(parentIds);
if(CollUtil.isEmpty(hasChildrenList)){
hasChildrenList = ListUtil.empty();
}
// 字典
Map<String, Boolean> hasChildrenDict = Maps.newHashMap();
for (HasChildren hasChildren : hasChildrenList) {
if (hasChildren.getCount() != null && hasChildren.getCount() > 0) {
hasChildrenDict.put(hasChildren.getParentId(), true);
}
}
// 处理节点
this.handleTreeHasChildren(treeNodes, hasChildrenDict);
return treeNodes;
}
/**
*
* @param treeNodes
* @param hasChildrenDict
*/
private void handleTreeHasChildren(List<Tree<Object>> treeNodes,
Map<String, Boolean> hasChildrenDict){
for (Tree<Object> treeNode : treeNodes) {
Boolean tmpFlag = hasChildrenDict.get(Convert.toStr(treeNode.getId()));
if (tmpFlag != null && tmpFlag) {
treeNode.putExtra(TreeConstants.IS_LEAF, false);
treeNode.putExtra(TreeConstants.HAS_CHILDREN, true);
}else {
treeNode.putExtra(TreeConstants.IS_LEAF, true);
treeNode.putExtra(TreeConstants.HAS_CHILDREN, false);
}
// 如果不为空 则继续递归处理
if(CollUtil.isNotEmpty(treeNode.getChildren())){
handleTreeHasChildren(treeNode.getChildren(), hasChildrenDict);
}
}
}
// =================================================
@PostConstruct

@ -25,7 +25,6 @@ import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
@ -41,10 +40,10 @@ import org.opsli.common.annotation.EnableLog;
import org.opsli.common.annotation.RequiresPermissionsCus;
import org.opsli.common.constants.MenuConstants;
import org.opsli.common.constants.MyBatisConstants;
import org.opsli.common.enums.DictType;
import org.opsli.common.utils.FieldUtil;
import org.opsli.common.utils.WrapperUtil;
import org.opsli.core.base.controller.BaseRestController;
import org.opsli.core.base.entity.HasChildren;
import org.opsli.core.general.StartPrint;
import org.opsli.core.persistence.Page;
import org.opsli.core.persistence.querybuilder.GenQueryBuilder;
@ -63,7 +62,6 @@ import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@ -83,10 +81,6 @@ public class MenuRestController extends BaseRestController<SysMenu, MenuModel, I
/** 排序字段 */
private static final String SORT_FIELD = "order";
/** 是否包含子集 */
private static final String HAS_CHILDREN = "hasChildren";
/** 是否是叶子节点 */
private static final String IS_LEAF = "isLeaf";
/** 虚拟总节点 ID */
private static final String VIRTUAL_TOTAL_NODE = "-1";
@ -114,7 +108,8 @@ public class MenuRestController extends BaseRestController<SysMenu, MenuModel, I
// 这里有坑 如果 为 菜单数据 且 组件(Component)地址为空 不会跳转到主页 也不报错
// 修复菜单问题导致无法跳转主页
menuModelList.removeIf(menuModel -> MenuConstants.MENU.equals(menuModel.getType()) &&
menuModelList.removeIf(
menuModel -> MenuConstants.MENU.equals(menuModel.getType()) &&
(StringUtils.isEmpty(menuModel.getComponent()) ||
StringUtils.isEmpty(menuModel.getUrl())
));
@ -142,7 +137,8 @@ public class MenuRestController extends BaseRestController<SysMenu, MenuModel, I
// 这里有坑 如果 为 菜单数据 且 组件(Component)地址为空 不会跳转到主页 也不报错
// 修复菜单问题导致无法跳转主页
menuModelList.removeIf(menuModel -> MenuConstants.MENU.equals(menuModel.getType()) &&
menuModelList.removeIf(
menuModel -> MenuConstants.MENU.equals(menuModel.getType()) &&
(StringUtils.isEmpty(menuModel.getComponent()) ||
StringUtils.isEmpty(menuModel.getUrl())
));
@ -167,14 +163,9 @@ public class MenuRestController extends BaseRestController<SysMenu, MenuModel, I
List<MenuModel> menuModelList;
if(StringUtils.isEmpty(parentId)){
menuModelList = Lists.newArrayList();
parentId = VIRTUAL_TOTAL_NODE;
MenuModel model = new MenuModel();
model.setId(MenuConstants.GEN_ID);
model.setMenuName("根节点");
model.setHidden("0");
model.setSortNo(-1);
model.setType("1");
model.setParentId(parentId);
// 生成根节点菜单
MenuModel model = getGenMenuModel();
parentId = model.getParentId();
menuModelList.add(model);
}else{
// 只查菜单
@ -182,7 +173,7 @@ public class MenuRestController extends BaseRestController<SysMenu, MenuModel, I
QueryWrapper<SysMenu> queryWrapper = queryBuilder.build();
queryWrapper.eq(
FieldUtil.humpToUnderline(MyBatisConstants.FIELD_PARENT_ID), parentId);
queryWrapper.eq("type", "1");
queryWrapper.eq("type", MenuConstants.MENU);
// 如果传入ID 则不包含自身
if(StringUtils.isNotEmpty(id)){
@ -200,7 +191,8 @@ public class MenuRestController extends BaseRestController<SysMenu, MenuModel, I
List<Tree<Object>> treeNodes = getMenuTrees(menuModelList, parentId,1);
// 处理是否包含子集
this.handleTreeIsLeafByChoose(treeNodes);
super.handleTreeHasChildren(treeNodes,
(parentIds)-> IService.hasChildrenByChoose(parentIds));
return ResultVo.success(treeNodes);
}
@ -216,14 +208,9 @@ public class MenuRestController extends BaseRestController<SysMenu, MenuModel, I
List<MenuModel> menuModelList;
if(StringUtils.isEmpty(parentId)){
menuModelList = Lists.newArrayList();
parentId = VIRTUAL_TOTAL_NODE;
MenuModel model = new MenuModel();
model.setId(MenuConstants.GEN_ID);
model.setMenuName("根节点");
model.setHidden("0");
model.setSortNo(-1);
model.setType("1");
model.setParentId(parentId);
// 生成根节点菜单
MenuModel model = getGenMenuModel();
parentId = model.getParentId();
menuModelList.add(model);
}else{
QueryBuilder<SysMenu> queryBuilder = new GenQueryBuilder<>();
@ -238,7 +225,8 @@ public class MenuRestController extends BaseRestController<SysMenu, MenuModel, I
List<Tree<Object>> treeNodes = getMenuTrees(menuModelList, parentId,1);
// 处理是否包含子集
this.handleTreeHasChildren(treeNodes);
super.handleTreeHasChildren(treeNodes,
(parentIds)-> IService.hasChildren(parentIds));
return ResultVo.success(treeNodes);
}
@ -251,11 +239,9 @@ public class MenuRestController extends BaseRestController<SysMenu, MenuModel, I
@RequiresPermissions("system_menu_select")
@Override
public ResultVo<?> findMenuTreePage(HttpServletRequest request) {
QueryBuilder<SysMenu> queryBuilder = new WebQueryBuilder<>(entityClazz,
request.getParameterMap());
// 获得菜单
List<SysMenu> menuList = IService.findList(queryBuilder.build());
List<MenuModel> menuModelList = WrapperUtil.transformInstance(menuList, MenuModel.class);
@ -292,11 +278,8 @@ public class MenuRestController extends BaseRestController<SysMenu, MenuModel, I
public ResultVo<MenuModel> get(MenuModel model) {
if(model != null){
if(StringUtils.equals(MenuConstants.GEN_ID, model.getId())){
model.setMenuName("根节点");
model.setHidden("0");
model.setSortNo(-1);
model.setType("1");
model.setParentId(VIRTUAL_TOTAL_NODE);
// 生成根节点菜单
model = getGenMenuModel();
}else{
// 如果系统内部调用 则直接查数据库
if (model.getIzApi() != null && model.getIzApi()){
@ -589,72 +572,19 @@ public class MenuRestController extends BaseRestController<SysMenu, MenuModel, I
return TreeBuildUtil.INSTANCE.build(beanMapList, treeNodeConfig);
}
/**
*
* @param treeNodes
*/
private void handleTreeHasChildren(List<Tree<Object>> treeNodes) {
if(CollUtil.isEmpty(treeNodes)){
return;
}
Set<String> parentIds = Sets.newHashSet();
for (Tree<Object> treeNode : treeNodes) {
parentIds.add(Convert.toStr(treeNode.getId()));
}
// 数据排查是否存在下级
List<HasChildren> hasChildrenList = IService.hasChildren(parentIds);
if (CollUtil.isNotEmpty(hasChildrenList)) {
Map<String, Boolean> tmp = Maps.newHashMap();
for (HasChildren hasChildren : hasChildrenList) {
if (hasChildren.getCount() != null && hasChildren.getCount() > 0) {
tmp.put(hasChildren.getParentId(), true);
}
}
for (Tree<Object> treeNode : treeNodes) {
Boolean tmpFlag = tmp.get(Convert.toStr(treeNode.getId()));
if (tmpFlag != null && tmpFlag) {
treeNode.putExtra(HAS_CHILDREN, true);
}
}
}
}
/**
*
* @param treeNodes
*
* @return MenuModel
*/
private void handleTreeIsLeafByChoose(List<Tree<Object>> treeNodes) {
if(CollUtil.isEmpty(treeNodes)){
return;
}
Set<String> parentIds = Sets.newHashSet();
for (Tree<Object> treeNode : treeNodes) {
parentIds.add(Convert.toStr(treeNode.getId()));
}
// 数据排查是否存在下级
List<HasChildren> hasChildrenList = IService.hasChildrenByChoose(parentIds);
Map<String, Boolean> tmp = Maps.newHashMap();
for (HasChildren hasChildren : hasChildrenList) {
if (hasChildren.getCount() != null && hasChildren.getCount() > 0) {
tmp.put(hasChildren.getParentId(), false);
}
}
for (Tree<Object> treeNode : treeNodes) {
Boolean tmpFlag = tmp.get(Convert.toStr(treeNode.getId()));
if (tmpFlag == null || tmpFlag) {
treeNode.putExtra(IS_LEAF, true);
}else {
treeNode.putExtra(IS_LEAF, false);
}
}
private MenuModel getGenMenuModel() {
MenuModel model = new MenuModel();
model.setId(MenuConstants.GEN_ID);
model.setMenuName("根菜单");
model.setHidden(DictType.NO_YES_NO.getValue());
model.setSortNo(-1);
model.setType(MenuConstants.MENU);
model.setParentId(VIRTUAL_TOTAL_NODE);
return model;
}
/**

@ -33,9 +33,9 @@ spring:
#primary: master
datasource:
master:
url: jdbc:mysql://127.0.0.1:3306/opsli-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&rewriteBatchedStatements=true&serverTimezone=Asia/Shanghai
username: root
password: 12345678
url: jdbc:mysql://10.0.0.28:3306/opsli-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&rewriteBatchedStatements=true&serverTimezone=Asia/Shanghai
username: opsli-boot
password: asRtHGtxSZYGEtmJ
driver-class-name: com.mysql.cj.jdbc.Driver
# 多数据源配置
#slave-datasource:

Loading…
Cancel
Save