Go项目实战之无限级结构树形数据格式(易扩展方式)【goshop开源项目 | 20220430更新】
goshop开源项目的更新
备注:前面项目中用到的代码已经分享到
GitHub
中去了,并且以后所有项目中会出现的代码都会提交上去,欢迎查阅。
地址
goshop
感兴趣的可以点个star
哦~goshop开源项目的更新
今天咱们做一个无限级结构树形数据格式
:
-
做一个菜单列表形式的一个树形结构,以满足后续的功能业务开发,类似于下图的功能
-
做成方便扩展的方式
接下来咱们就来实现以上的问题和功能:
- 先修改一下分页获取全部数据的方法
findAll
,将之前[]Roles
改为[]*Roles
,如果这里不明白的话,请看之前的的文章:
Go项目实战之开发完善分页插件(易扩展方式)-------【goshop开源项目】【第12次更新】
// 根据检索条件,获取记录行,并获取总记录条数func (Roles) FindAll(DB *gorm.DB, params map[string]interface{}) ([]*Roles, int64) { var GoodResult []*Roles page := params["page"].(string) // 对返回的interface类型进行转换成字符串 pageSize := params["pageSize"].(string) // 对返回的interface类型进行转换成字符串 // 这里使用了过滤,在下面使用Where条件时过滤掉page,pageSize ParamsFilter := utils.ParamsFilter(params, "page,pageSize") // 通过 Scopes 引用加载 分页类中返回的 DB指针 DB.Scopes(Paginate.Paginate(page, pageSize)).Where(ParamsFilter).Order("created_at desc").Find(&Result) // 这里时查询全部数据,用于返回总记录条数 TotalCount := DB.Find(&Goods{}) return Result, TotalCount.RowsAffected}// 这是过滤的封装,一起贴出来了func ParamsFilter(params map[string]interface{}, isFilterStr string) map[string]interface{} { var data = make(map[string]interface{}) for key, value := range params { if find := strings.Contains(isFilterStr, key); !find { data[key] = value } } return data}
- 接下来就是重头戏了,将查询出来的
[]*Roles
结构体数据,处理成咱们预想的数据格式
// 对应的数据结构体type Roles struct {ModelName string `json:"name" gorm:"size:100;index;default:'';not null;"` // 角色名称Alias string `json:"alias" grom:"size:255;index;default:'';not nill;"` // 别名ParentID uint`json:"parent_id" gorm:"size:10;index;default:0;not null;"` // 父级IDSort uint`json:"sort" gorm:"size:1;index;default:0;"` // 排序值Remark string `json:"remark" gorm:"size:255;"`// 备注Status uint`json:"status" gorm:"size:1;index;default:0;"`// 状态(1:启用 2:禁用)Children *RoleTrees `json:"children"` // 这里是最关键的一步}// RoleTrees 二叉树列表type RoleTrees []*Roles// ToTree 转换为树形结构func (Roles) ToTree(data RoleTrees) RoleTrees {// 定义 HashMap 的变量,并初始化TreeData := make(map[uint]*Roles)// 先重组数据:以数据的ID作为外层的key编号,以便下面进行子树的数据组合for _, item := range data {TreeData[item.ID] = item}// 定义 RoleTrees 结构体var TreeDataList RoleTrees// 开始生成树形for _, item := range TreeData {// 如果没有根节点树,则为根节点if item.ParentID == 0 {// 追加到 TreeDataList 结构体中TreeDataList = append(TreeDataList, item)// 跳过该次循环continue}// 通过 上面的 TreeData HashMap的组合,进行判断是否存在根节点// 如果存在根节点,则对应该节点进行处理if p_item, ok := TreeData[item.ParentID]; ok {// 判断当次循环是否存在子节点,如果没有则作为子节点进行组合if p_item.Children == nil {// 写入子节点children := RoleTrees{item}// 插入到 当次结构体的子节点字段中,以指针的方式p_item.Children = &children// 跳过当前循环continue}// 以指针地址的形式进行追加到结构体中*p_item.Children = append(*p_item.Children, item)}}return TreeDataList}
- 到这里逻辑代码已经全部完成了,但是如何使用呢? 下面咱们就来说一下如何使用?在
controller
中进行调用:
// 查询数据var roles model.RolesResult, totalCount := roles.FindAll(DB, params)TreeResult := roles.ToTree(Result)