工作上遇到一个问题,产品让把网站菜单导出,还得一层一层按照顺序导出,还得兼容以后的菜单拓展,一开始没有头绪。
表结构(为了清晰就不贴sql那种了)
刚开始的思路是直接查没有父级的子节点 分别一层一层往上查,这样就拿到所有父子级,但是这样没法排序。后来经过思考,可以使用继承来解决这个问题
上代码
设置excel表头
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
//设置文件名称
String fileName = "excel/" + contains.getName() + "_" + System.currentTimeMillis() + ".xlsx";
EasyExcel.write(outputStream)
//自动调节列宽
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
.autoCloseStream(Boolean.TRUE)
// 这里放入动态头
.head(getHead(reqEntity)).sheet("菜单路由")
// 放入数据
.doWrite(getData(reqEntity));
代码逻辑
private List<List<String>> getData(WriteExcelReq reqEntity) throws IOException {
List<List<String>> datalist = new ArrayList<>();
// 将演示项目的路由地址添加到数据列表
String urlIdent = "";
OrganizationRes organizationRes = organizationFeign.getOrganizationById(demoOrgId).getData();
if (organizationRes != null && organizationRes.getOrganizationInfo() != null && StringUtil.isNotBlank(organizationRes.getOrganizationInfo().getUrlIdent())){
urlIdent = "https://" + organizationRes.getOrganizationInfo().getUrlIdent() + ".medianos.cn/#";
}
//根据类型查询所有的菜单:1-web 2-小程序 3-大屏权限
Integer type = JSONUtil.parseObj(reqEntity.getParam()).getInt("type");
JSONArray jsonArray = menuCenterFeign.treeAllMenuExcludeButton(type).getData();
List<MenuRes> AllMenus = JSONObject.parseArray(jsonArray.toJSONString(), MenuRes.class);
//创建每一条数据:含有一级菜单、二级菜单、三级菜单
for (MenuRes menuResLevel1 : AllMenus) {
//递归处理当前菜单
generateMenuData(menuResLevel1, new ArrayList<>(), datalist,urlIdent);
}
递归处理获取的菜单树
private void generateMenuData(MenuRes menuRes, List<String> currentList, List<List<String>> dataList,String urlIndent) {
// 添加当前菜单名到当前列表
currentList.add(menuRes.getMenuName());
// 如果当前菜单有子菜单,则递归处理每个子菜单
if (menuRes.getChildren() != null && !menuRes.getChildren().isEmpty()) {
for (MenuRes childMenu : menuRes.getChildren()) {
List<String> newList = new ArrayList<>(currentList);
generateMenuData(childMenu, newList, dataList,urlIndent);
}
} else {
// 如果当前菜单没有子菜单,说明到达叶子节点,将当前列表添加到数据列表
// 将演示项目的路由地址添加到数据列表
if (StringUtil.isNotBlank(urlIndent)){
currentList.add(urlIndent + menuRes.getUrl());
}
dataList.add(currentList);
}
}
public BaseRes<JSONArray> treeAllMenuExcludeButton(Integer type) {
//类型 1web 2小程序 3大屏权限
List<Menu> list = dataMapper.selectList(new QueryWrapper<Menu>().in("menu_type","G","C").eq("type",type));
list = list.stream().sorted(Comparator.comparing(Menu::getOrderNum)).collect(Collectors.toList());
return BaseRes.Success(new JSONArray(!list.isEmpty() ?
TreeUtil.listToTree(JSONArray.parseArray(JSON.toJSONString(list)), "id", "parentId", "children") :
new JSONArray()));
}
排列树方法
package com.open.capacity.common.util;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.util.stream.Collectors;
/**
* Created on 2020/4/3.
*
* @author xienaifa
*/
public class TreeUtil {
/**
* - listToTree
* - <p>方法说明<p>
* - 将JSONArray数组转为树状结构
* - @param arr 需要转化的数据
* - @param id 数据唯一的标识键值
* - @param pid 父id唯一标识键值
* - @param child 子节点键值
* - @return JSONArray
*/
public static JSONArray listToTree(JSONArray arr, String id, String pid, String child) {
JSONArray r = new JSONArray();
JSONObject hash = new JSONObject();
//将数组转为Object的形式,key为数组中的id
if (arr == null || arr.size() == 0) {
return r;
}
for (int i = 0; i < arr.size(); i++) {
JSONObject json = (JSONObject) arr.get(i);
hash.put(json.getString(id), json);
}
//遍历结果集
for (int j = 0; j < arr.size(); j++) {
//单条记录
JSONObject aVal = (JSONObject) arr.get(j);
//在hash中取出key为单条记录中pid的值
JSONObject hashVP = (JSONObject) hash.get(aVal.get(pid).toString());
//如果记录的pid存在,则说明它有父节点,将她添加到孩子节点的集合中
if (hashVP != null) {
//检查是否有child属性
if (hashVP.get(child) != null) {
JSONArray ch = (JSONArray) hashVP.get(child);
ch.add(aVal);
hashVP.put(child, ch);
} else {
JSONArray ch = new JSONArray();
ch.add(aVal);
hashVP.put(child, ch);
}
} else {
r.add(aVal);
}
}
return r;
}
//递归方法
public static JSONArray makeTree(JSONArray jsonArray, Integer parentId) {
//子类
JSONArray children = jsonArray.stream().filter(x -> ((JSONObject) x).getInteger("parentId").equals(parentId)).collect(Collectors.toCollection(JSONArray::new));
//后辈中的非子类
JSONArray successor = jsonArray.stream().filter(x -> !((JSONObject) x).getInteger("parentId").equals(parentId)).collect(Collectors.toCollection(JSONArray::new));
children.forEach(x ->
{
makeTree(successor, ((JSONObject) x).getInteger("id")).forEach(
y -> ((JSONObject) x).put("children", y)
);
}
);
return children;
}
}
这个并不算完善,导出的父级单元格没有合并,只能手动合并。