最近项目有个需求,上传一个文件压缩包,解压后根据解压的相对路径生成目录结构返回给前端展示,前端采用 element-ui 的el-tree组件,组件详情查看:el-tree
查阅相关资料发现生成目录树很多都是采用从数据库中读取目录关联结构生成的,但是在实际项目中没有相关的层次关系,需要建立层级结构,那么如何通过目录结构直接生成树状结构呢?
首先看下生成效果:

首先建立节点类:
节点包含节点id,文件名称,文件路径,父节点id,还有孩子节点列表
public class Menu {
/**
* id
*/
public Integer id;
/**
* 名称
*/
public String name;
/**
* 路径
*/
public String path;
/**
* 父id ,根节点为0
*/
public Integer parentId;
/**
* 子节点信息
*/
public List<Menu> childList;
public Menu() {
}
public Menu(Integer id, String name, Integer parentId) {
this.id = id;
this.name = name;
this.parentId = parentId;
}
public Menu(Integer id, String name, Integer parentId, List<Menu> childList) {
this.id = id;
this.name = name;
this.parentId = parentId;
this.childList = childList;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getParentId() {
return parentId;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public void setParentId(Integer parentId) {
this.parentId = parentId;
}
public List<Menu> getChildList() {
return childList;
}
public void setChildList(List<Menu> childList) {
this.childList = childList;
}
}
递归查询子节点:
/**
* 递归查询子节点
*
* @param root 根节点
* @param all 所有节点
* @return 根节点信息
*/
private static List<Menu> getChildrens(Menu root, List<Menu> all) {
List<Menu> children = all.stream().filter(m -> {
return Objects.equals(m.getParentId(), root.getId());
}).map((m) -> {
m.setChildList(getChildrens(m, all));
return m;
}
).collect(Collectors.toList());
return children;
}
生成目录结构:
public static List<Menu> getFilePathTree(List<String> paths) {
Map<String, Integer> map = new LinkedHashMap<>();
Integer id = 1;
for (int i = 0; i < paths.size(); i++) {
String[] path = paths.get(i).split("/");
String p = "";
for (int j = 0; j < path.length; j++) {
p += path[j] + "/";
if (!map.containsKey(p.substring(0, p.length() - 1))) {
map.put(p.substring(0, p.length() - 1), id++);
}
}
}
List<Menu> menus = new ArrayList<>();
for (Map.Entry<String, Integer> entry : map.entrySet()) {
Menu menu = new Menu();
Integer values = entry.getValue();
String[] keys = entry.getKey().split("/");
menu.setId(values);
if (keys.length == 1) {
menu.setParentId(0);
menu.setName(keys[0]);
menu.setPath(keys[0]);
} else {
String path = "";
for (int i = 0; i < keys.length - 1; i++) {
path += keys[i] + "/";
}
menu.setName(keys[keys.length - 1]);
menu.setPath(String.join("/", keys));
path = path.substring(0, path.length() - 1);
menu.setParentId(map.get(path));
}
menus.add(menu);
}
//获取父节点
List<Menu> collect = menus.stream().filter(m -> m.getParentId() == 0).map(
(m) -> {
m.setChildList(getChildrens(m, menus));
return m;
}
).collect(Collectors.toList());
return collect;
}
使用方式:
// 文件目录相对路径列子
private static String[] fileList = new String[]{
"dist/favicon.ico",
"dist/index.html",
"dist/static/css/app.46c00deb.css",
"dist/static/css/chunk-vendors.b80cec6e.css",
"dist/static/css/dashboard.65e4cda8.css",
"dist/static/css/home.c7bb3066.css",
"dist/static/css/login.89e00d4a.css",
"dist/static/css/table.cf6aa91f.css",
"dist/static/fonts/element-icons.535877f5.woff",
"dist/static/fonts/element-icons.732389de.ttf",
"dist/static/img/img.146655c9.jpg",
"dist/static/img/login-bg.e2134055.jpg",
"dist/static/js/app.db875c52.js",
"dist/static/js/chunk-vendors.31d72191.js",
"dist/static/js/dashboard.988c89e7.js",
"dist/static/js/home.482bfd24.js",
"dist/static/js/login.78ac76b0.js",
"dist/static/js/table.eac1b16a.js",
"dist/table.json"
};
public static void main(String args[]) throws IOException {
List<Menu> collect = getFilePathTree(Arrays.asList(fileList));
System.out.println("-------转json输出结果-------");
System.out.println(JSON.toJSON(collect));
}
输出结果:
[{
"path": "dist",
"name": "dist",
"childList": [{
"path": "dist/favicon.ico",
"name": "favicon.ico",
"childList": [],
"id": 2,
"parentId": 1
}, {
"path": "dist/index.html",
"name": "index.html",
"childList": [],
"id": 3,
"parentId": 1
}, {
"path": "dist/static",
"name": "static",
"childList": [{
"path": "dist/static/css",
"name": "css",
"childList": [{
"path": "dist/static/css/app.46c00deb.css",
"name": "app.46c00deb.css",
"childList": [],
"id": 6,
"parentId": 5
}, {
"path": "dist/static/css/chunk-vendors.b80cec6e.css",
"name": "chunk-vendors.b80cec6e.css",
"childList": [],
"id": 7,
"parentId": 5
}, {
"path": "dist/static/css/dashboard.65e4cda8.css",
"name": "dashboard.65e4cda8.css",
"childList": [],
"id": 8,
"parentId": 5
}, {
"path": "dist/static/css/home.c7bb3066.css",
"name": "home.c7bb3066.css",
"childList": [],
"id": 9,
"parentId": 5
}, {
"path": "dist/static/css/login.89e00d4a.css",
"name": "login.89e00d4a.css",
"childList": [],
"id": 10,
"parentId": 5
}, {
"path": "dist/static/css/table.cf6aa91f.css",
"name": "table.cf6aa91f.css",
"childList": [],
"id": 11,
"parentId": 5
}],
"id": 5,
"parentId": 4
}, {
"path": "dist/static/fonts",
"name": "fonts",
"childList": [{
"path": "dist/static/fonts/element-icons.535877f5.woff",
"name": "element-icons.535877f5.woff",
"childList": [],
"id": 13,
"parentId": 12
}, {
"path": "dist/static/fonts/element-icons.732389de.ttf",
"name": "element-icons.732389de.ttf",
"childList": [],
"id": 14,
"parentId": 12
}],
"id": 12,
"parentId": 4
}, {
"path": "dist/static/img",
"name": "img",
"childList": [{
"path": "dist/static/img/img.146655c9.jpg",
"name": "img.146655c9.jpg",
"childList": [],
"id": 16,
"parentId": 15
}, {
"path": "dist/static/img/login-bg.e2134055.jpg",
"name": "login-bg.e2134055.jpg",
"childList": [],
"id": 17,
"parentId": 15
}],
"id": 15,
"parentId": 4
}, {
"path": "dist/static/js",
"name": "js",
"childList": [{
"path": "dist/static/js/app.db875c52.js",
"name": "app.db875c52.js",
"childList": [],
"id": 19,
"parentId": 18
}, {
"path": "dist/static/js/chunk-vendors.31d72191.js",
"name": "chunk-vendors.31d72191.js",
"childList": [],
"id": 20,
"parentId": 18
}, {
"path": "dist/static/js/dashboard.988c89e7.js",
"name": "dashboard.988c89e7.js",
"childList": [],
"id": 21,
"parentId": 18
}, {
"path": "dist/static/js/home.482bfd24.js",
"name": "home.482bfd24.js",
"childList": [],
"id": 22,
"parentId": 18
}, {
"path": "dist/static/js/login.78ac76b0.js",
"name": "login.78ac76b0.js",
"childList": [],
"id": 23,
"parentId": 18
}, {
"path": "dist/static/js/table.eac1b16a.js",
"name": "table.eac1b16a.js",
"childList": [],
"id": 24,
"parentId": 18
}],
"id": 18,
"parentId": 4
}],
"id": 4,
"parentId": 1
}, {
"path": "dist/table.json",
"name": "table.json",
"childList": [],
"id": 25,
"parentId": 1
}],
"id": 1,
"parentId": 0
}]
前端使用:
fileTree就是上面生成的json串
<el-input placeholder="输入关键字进行过滤" v-model="filterText"></el-input>
<div class="custom-tree-container">
<div class="block">
<el-tree
class="filter-tree"
:data="fileTree"
:props="defaultProps"
default-expand-all
:filter-node-method="filterNode"
:expand-on-click-node="false"
ref="tree">
<span class="custom-tree-node" slot-scope="{ node, data }" @mouseenter="mouseenter(data)" @mouseleave="mouseleave(data)">
<span>{{ data.name }}</span>
<el-link v-show="data.del" size="mini" type="primary" @click="deleteAgentFile()" style="float:right;">删除</el-link>
</span>
</el-tree>
</div>
</div>
<script>
export default {
watch: {
filterText(val) {
this.$refs.tree.filter(val);
}
},
methods: {
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
}
},
data() {
return {
filterText: '',
fileTree: [],
defaultProps: {
children: 'childList',
label: 'name'
},
};
}
};
</script>
这样就可以生成相关目录结构树效果了
该博客介绍了如何在Java中通过文件压缩包的解压路径生成目录树结构,用于前端展示。文章提供了一个节点类`Menu`来表示文件或目录,并实现了递归查询子节点的方法`getChildrens`。通过`getFilePathTree`方法将文件路径转换为树结构,最后用Element-UI的`el-tree`组件在前端展示。示例代码展示了具体实现和输出结果。
3126

被折叠的 条评论
为什么被折叠?



