golang无限层级菜单,子菜单Children 数据递归处理和gorm数据获取示例

6 篇文章 0 订阅

golang中处理带层级的菜单时我们可以有多重方法, 对于数据量大的,我们可以使用pid先通过sql查询不同层级的菜单,然后在拼接为我们需要的菜单,  不过这样做的话对于数据库的压力会大一些,一般不推荐使用因为数据库的资源是比较宝贵的。 我们一般采用先把相关的数据都一次性拉出来后再使用递归的方式对数据进行二次处理,这样可大大的减轻数据库的压力。

带层级子菜单Children菜单数据 gorm获取和递归处理示例

gorm菜单表实体模型定义

// model.SysMenu 菜单表gorm实体模型定义 示例
type SysMenu struct {
	ID        uint           `gorm:"primaryKey"`
	Pid    int64     `gorm:"column:pid;type:bigint(20);comment:父菜单ID" json:"pid"`  // 父菜单ID
	Name   string    `gorm:"column:name;type:varchar(50);not null;comment:菜单名称" json:"name"`  // 菜单名称
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt gorm.DeletedAt `gorm:"index"`
}

// TableName SysMenu's table name
func (*SysMenu) TableName() string {
	return "sys_menu"
}

展现给用户的的带子菜单的层级菜单模型定义

// 这个是我们返回前端的带层级的菜单对象
type SysMenuExtend struct {
	model.SysMenu // 继承model.SysMenu实体模型
	Children   []*SysMenuExtend `gorm:"-" json:"children,omitempty"` // 子菜单 注意如果我们需要直接使用SysMenuExtend通过gorm从数据库中获取数据集,这这里必须使用gorm:"-"忽略这个字段,否则读取数据会报错
}

层级菜单gorm数据获取和递归处理示例


var MenuSvc = &menuSvc{}

type menuSvc struct {
}
// 根据用户ID读取菜单数据
func (s *menuSvc) GetMenusByUid(c *ginx.XContext, uid int32, router ...bool) ([]*model.SysMenuExtend, error) {

	//从数据库中读取
	list, err := s.getMenusListByUid(c, uid)
	if err != nil {
		return nil, err
	}
	result := s.handleMenusExtend(c, list, 0)

	return result, nil
}

// 根据用户id获取用户的全部菜单
func (s *menuSvc) getMenusListByUid(c *ginx.XContext, uid int32) ([]*model.SysMenuExtend, error) {
	var list []*model.SysMenuExtend
    // gorm可直接通过Table方法获取表对象,这里 m表示给表起别名
	m := global.Db.Table("sys_menu m")
	m = m.Select("distinct m.id, m.pid, m.name, ifnull(m.perms,'') as perms")
	m = m.Joins("LEFT JOIN sys_role_menu rm on rm.menu_id = m.id")
	m = m.Joins("LEFT JOIN sys_user_role ur on ur.role_id = rm.role_id ")
	m = m.Where("ur.uid = ? ", uid)
	m = m.Order("m.pid asc")
	if err := m.Find(&list).Error; err != nil {
		return nil, myerror.New("读取数据失败")
	}
	return list, nil
}

// 带层级菜单 gorm子菜单Children 数据递归处理和获取
// 这里的 menus是所有的menu数据, pid为父级ID,
func (s *menuSvc) handleMenusExtend(c *ginx.XContext, menus []*SysMenuExtend, pid int64) []*SysMenuExtend {
	var result []*SysMenuExtend
	for _, menu := range menus {
		if menu.Pid == pid {
			s.recursionFn(c, menus, menu) // 调用递归方法递归处理
			result = append(result, menu)
		}
	}
	return result
}

// 递归处理
func (s *menuSvc) recursionFn(c *ginx.XContext, menus []*SysMenuExtend, entity *SysMenuExtend) {
	childMenus := s.getChildList(c, menus, entity)
	entity.Children = childMenus
	for _, childMenu := range childMenus {
		if s.hasChild(c, menus, childMenu) {
			for _, menu := range childMenus {
				s.recursionFn(c, menus, menu)
			}
		}
	}
}

// 获取子级列表
func (s *menuSvc) getChildList(c *ginx.XContext, menus []*SysMenuExtend, sysMenuExtend *SysMenuExtend) []*SysMenuExtend {

	var tlist []*SysMenuExtend
	for _, menu := range menus {
		if menu.Pid == sysMenuExtend.ID {
			tlist = append(tlist, menu)
		}
	}
	return tlist
}

// 判断是是否还有子级
func (s *menuSvc) hasChild(c *ginx.XContext, menus []*SysMenuExtend, entity *SysMenuExtend) bool {
	return len(s.getChildList(c, menus, entity)) > 0
}

上面的 global.Db 这个是你自己定义的gorm全局数据库的链接对象*gorm.DB

总结

我们通过递归处理方法来对菜单进行二次处理,这样避免了多次查询数据库,这样可大大提高我们网站的性能。通过使用递归函数,我们可以处理无限层级的菜单, 如果是直接查询数据库方式的话无限层级的菜单,每层你就要查询一次数据库这个很容易数据库就挂掉。

 

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值