Go语言实现excel导入无限级菜单结构
一、需求
最近有一个需求,要实现一个无限级结构的树型菜单,差不多长下面这个样子
我们知道无限级实现思路都是用一个parent_id将各种层级串联起来,顶级的parent_id为0,例如如下层级的菜单
菜单一
菜单二
菜单三
菜单四
菜单五
菜单六
菜单七
菜单八
在数据库中的存储一般是如下形式
原理就会记录每一个菜单的父级ID(parent_id),通过这样的父级ID会构造出一棵树型结构,层级(level)是为了标明当前菜单是处于哪个层级
问题来了,一般这样的结果要是一条一条插入,再人工用parent_id串起来,太反人类了,低效!
产品会让工程师通过表格导入这样的数据,表格差不多都长如下这个样子
我们需要用过代码来实现生成上面数据库的结果,talk is cheap, show you the code
二、代码实现
func ImportMenus() (res interface{}, err error) {
columns := 5 //支持的无限级菜单数量,想支持多少级写多少
templateFile := "/Users/chenqionghe/Downloads/menus.xlsx" //导入的表格路径
f, err := excelize.OpenFile(templateFile) //读取表格
if err != nil {
return nil, err
}
rows, err := f.GetRows("Sheet1")
if err != nil {
return nil, err
}
var allRowIds = make([][]int, len(rows)) //初始化保存ID的数组,通过下标定位对应菜单生成的ID
for i, _ := range rows {
allRowIds[i] = make([]int, columns)
}
var parentId int
tx := db.DB().Begin()
exception.Block{
Try: func() {
for i, row := range rows {
if i == 0 { //表头跳过
continue
}
//构造无限级菜单
for j := 0; j < columns; j++ {
if row[j] == "" { //空值不操作
continue
}
if j == 0 && row[j] != "" { //顶级按钮父级ID是0
parentId = 0
}
if j > 0 { //非顶级,向前或向上寻找最近的父级ID
if allRowIds[i][j-1] != 0 {
parentId = allRowIds[i][j-1] //向前找ID作为父级ID
} else {
for z := i - 1; z > 0; z-- {
if allRowIds[z][j-1] != 0 {
parentId = allRowIds[z][j-1] //向上找ID作为父级ID
break
}
}
}
}
newData := &model.Menu{Name: row[j], ParentID: parentId, Level: j + 1}
if err = tx.Save(newData).Error; err != nil { //菜单插入数据库
panic(err)
}
allRowIds[i][j] = newData.ID //保存当ID到数组对应数组下标中,供后续菜单作为父级ID使用
}
}
tx.Commit()
err = nil
},
Catch: func(e interface{}) {
tx.Rollback()
err = fmt.Errorf("err: %v", e)
},
}.Do()
return allRowIds, err
}
三、代码测试
简单例子
我们来测试一下导入上面的表格
运行结果如下
可以看到,结果和我们设想的数据库结果完全一样!
复杂例子
好,我们再测试一个更复杂的例子,表格模板如下
导入的结果如下
这样就用Go实现了一个支持无限级菜单的表格导入,以上代码由chenqionghe提供,转载请标明出处,giao~