• Go语言实现excel导入无限级菜单结构


    一、需求

    最近有一个需求,要实现一个无限级结构的树型菜单,差不多长下面这个样子

    我们知道无限级实现思路都是用一个parent_id将各种层级串联起来,顶级的parent_id为0,例如如下层级的菜单

    菜单一
        菜单二
            菜单三
        菜单四
            菜单五
                菜单六
                菜单7
                      菜单八
    

    在数据库中的存储一般是如下形式

    原理就会记录每一个菜单的父级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
    }
    

    三、代码测试

    先建立对应的数据表,结构如下

    CREATE TABLE `menu` (
      `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '菜单ID',
      `name` varchar(255) NOT NULL COMMENT '菜单名称',
      `parent_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '上级菜单ID',
      `level` tinyint(1) NOT NULL COMMENT '层级',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COMMENT='菜单表';
    

    简单例子

    我们来测试一下导入上面的表格

    运行结果如下

    可以看到,结果和我们设想的数据库结果完全一样!

    复杂例子

    好,我们再测试一个更复杂的例子,表格模板如下

    导入的结果如下

    这样就用Go实现了一个支持无限级菜单的表格导入,以上代码由chenqionghe提供,转载请标明出处,giao~

  • 相关阅读:
    iis管理器的程序应用池中没有Asp.NET v4.0
    Rowlock、UPDLOCK
    转SQLSERVER 会不会自动加锁
    安装IE11必备更新
    阻止表单提交刷新页面的问题
    C#分屏控件用法实例
    Flex内存泄露解决方法和内存释放优化原则
    DataSet.Clear() Method()
    短文件名漏洞修复
    vs2017创建dotnetcore web项目,并部署到centos7上
  • 原文地址:https://www.cnblogs.com/chenqionghe/p/14031142.html
Copyright © 2020-2023  润新知