按照菜单顺序导出为excel

39 阅读3分钟

工作上遇到一个问题,产品让把网站菜单导出,还得一层一层按照顺序导出,还得兼容以后的菜单拓展,一开始没有头绪。

image.png

表结构(为了清晰就不贴sql那种了)

image.png 刚开始的思路是直接查没有父级的子节点 分别一层一层往上查,这样就拿到所有父子级,但是这样没法排序。后来经过思考,可以使用继承来解决这个问题 上代码

设置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;
    }

}

这个并不算完善,导出的父级单元格没有合并,只能手动合并。