365bet手机版

工作日志,Excel导入树结构数据

工作日志,Excel导入树结构数据

目录1. 前言2. 需求分析2.1 需求难点2.2 解决难点2.3 表格设计3. 功能实现3.1 一个分枝3.2 一个分枝多个树叶3.3 多个分枝多个树叶4. 代码事例4.1 目录实体结构4.2 Excel导入代码

1. 前言

最近做了一个比较有趣的需求。需要把树结构的目录通过Excel的方式导入到系统中,并且该目录层级可以是多级且不确定的。这可能是一个常见又不太常见的需求,一般目录都是在界面上操作创建,或者是系统初始化生成。很少在系统使用一段时间后还有导入新目录的需求。

2. 需求分析

2.1 需求难点

这个需求最大的难点就是如何找到父级节点。包括

1)如何让一个Excel表格实现不确定目录层级功能?

2)如何让子个节点能正确找到其父级节点?

3)如何在遍历完一个分枝后,还能从根节点继续遍历另外一个分枝?

2.2 解决难点

1)我们可以将目录层级作为用户输入项,由用户决定该数据处于第几层目录。解决目录层级不确定的需求。

2)我们可以用树节点深度遍历的思想,遍历一个个节点,使其找到其父节点。

3)我们同样可以用深度遍历的思想再结合先进后出操作,重新找回之前的根节点。

2.3 表格设计

我们可以用Level作为目录所在层级,一级目录的Level就是1,同理N级目录的Level就是N。且数据从上至下可以形成一个完整树分枝。

表格设计如下:

分类名称

级别Level

其他字段

A栋

1

A栋-1楼

2

B栋

1

B栋-1楼

2

B栋-1楼-A区

3

B栋-2楼

2

B栋-2楼-A区

3

B栋-2楼-B区

3

从表格中,我们应该可以得出以下结论:

1)A栋和B栋属于一级目录

2)A栋有一个子目录,A栋-1楼

3)B栋有两个子目录,分别是:B栋-1楼、B栋-2楼

4)B栋-1楼有一个子目录,B栋-1楼-A区

5)B栋-2楼有两个子目录,分别是:B栋-2楼-A区、B栋-2楼-B区

3. 功能实现

我们对需求做了简单的分析,现在就用代码来实现。从易到难,从一个分枝再到多个分枝来实现。

3.1 一个分枝

一个分枝的Level排序应该是:1-2-3-N

这种情况是最简单的,孤零零的一条直线。其父节点就是当前节点的上一个元素。

伪代码如下:

var categoryPathStack = mutableListOf()

for (i in sheet.firstRowNum..sheet.lastRowNum) {

val categoryName = row.getCell(0).stringCellValue

val categoryLevel = row.getCell(1).stringCellValue.toInt()

var parentCategory: EquipmentCategory? = null

if (categoryLevel > 1) {

parentCategory = categoryPathStack.last()

}

// todo save or update

categoryPathStack.add(equipmentCategory)

}

3.2 一个分枝多个树叶

一个分支多个树叶的Level排序应该是:1-2-3-3-3-3

这种情况稍微复杂了一点,如果只是获取当前节点的上一个元素是很难找到其父级节点的。我们需要把同一层的兄弟节点都剔除掉。

伪代码如下:

var categoryPathStack = mutableListOf()

for (i in sheet.firstRowNum..sheet.lastRowNum) {

val categoryName = row.getCell(0).stringCellValue

val categoryLevel = row.getCell(1).stringCellValue.toInt()

var parentCategory: EquipmentCategory? = null

// 将集合中大于或等于当前层级的数据剔除掉

while (categoryPathStack.isNotEmpty() && categoryPathStack.last().level >= categoryLevel) {

categoryPathStack = categoryPathStack.subList(0, categoryPathStack.size-1).toMutableList()

}

if (categoryLevel > 1) {

parentCategory = categoryPathStack.last()

}

// todo save or update

categoryPathStack.add(equipmentCategory)

}

3.3 多个分枝多个树叶

多个分支多个树叶的Level排序应该是:1-2-3-3-3-3-2-3-1-2-3

这种场景依然可以用一个分支多个树叶的代码实现,而后面来的1就像一个分割线,将前面先进来的数据隔离开。

4. 代码事例

4.1 目录实体结构

目录实体添加临时字段level方便逻辑判断。字段code是方便后期通过code作为StartingWith的查询条件,从而减少递归查询所有子级目录带来的性能损耗。code的生成规则是:父节点code拼接当前节点id,

class Category: AuditModel() {

var name: String? = null

var description: String? = null

var isLeaf: Boolean = true

var parentId: String? = null

@Column(columnDefinition = "TEXT")

var code: String? = null

@Transient

var level: Int = 0

}

4.2 Excel导入代码

以下只是删减过后的代码,具体业务场景会有具体的逻辑代码。

@Transactional

fun importCategoryData(file: MultipartFile, request: HttpServletRequest): OperateStatus {

// fileUtil.getExcelWorkbook 只是简单封装的读取excel方法

val work = fileUtil.getExcelWorkbook(file.inputStream, file.originalFilename!!)

// todo 清空旧数据

val sheet: Sheet = work.getSheetAt(0)

var categoryPathStack = mutableListOf()

for (i in sheet.firstRowNum..sheet.lastRowNum) {

val row = sheet.getRow(i)

if (row == null || row.rowNum == 0) {

continue

}

// todo 数据校验

val categoryName = row.getCell(0).stringCellValue

val categoryLevel = row.getCell(1).stringCellValue.toInt()

var parentCategory: Category? = null

while (categoryPathStack.isNotEmpty() && categoryPathStack.last().level >= categoryLevel) {

categoryPathStack = categoryPathStack.subList(0, categoryPathStack.size-1).toMutableList()

}

if (categoryLevel > 1) {

parentCategory = categoryPathStack.last()

}

var category = Category()

category.name = categoryName

category.parentId = parentCategory?.id

category = categoryRepository.save(category)

if (parentCategory == null) {

category.code = category.id

} else {

category.code = "${parentCategory.code}-${category.id}"

category.isLeaf = true

parentCategory.isLeaf = false

categoryRepository.save(parentCategory)

}

categoryRepository.save(category)

category.level = categoryLevel

categoryPathStack.add(category)

}

work.close()

return OperateStatus("Import Category Success")

}

文章到这里就结束了,感谢观看。ITDragon博客

相关推荐

双醚芴(BPEF)市场规模现状及行业发展前景分析
365体育官网贴吧

双醚芴(BPEF)市场规模现状及行业发展前景分析

📅 2025-10-15 👁️ 6390
CSS 图像占位符
365bet手机版

CSS 图像占位符

📅 2025-08-30 👁️ 2145
佳能1dx2相机画质怎么样
365彩票官方正版下载

佳能1dx2相机画质怎么样

📅 2025-11-20 👁️ 1189
2025跑男片酬一览表 跑男2025最新一期片酬
365bet手机版

2025跑男片酬一览表 跑男2025最新一期片酬

📅 2025-08-03 👁️ 3220