gozero实现部门组织树的设计与实践

228 阅读3分钟

为了实现一个获取树状组织结构的接口,首先需要理解数据库表 ms_base_depart 的结构。从表结构来看,部门是以层级的方式存储的,每个部门都有一个 parent_id 字段,表示它的上级部门。因此,可以通过递归查询来构建部门的树状结构。

image.png

步骤

  1. 数据库设计分析
    - parent_id 字段指向上级部门的 id 字段。
    - 通过递归查询所有部门及其子部门,构建树形结构。

  2. GoZero 实现
    - 在 GoZero 中,使用 sqlx 提供的数据库查询方法来获取部门数据。
    - 在构建组织树时,利用递归或迭代的方式,根据 parent_id 进行嵌套构建树状结构。

设计接口

假设我们需要编写一个 RESTful API 接口,该接口通过部门的 org_id 获取部门的树状结构。具体的 API 设计如下:

  • GET /api/departments/tree
    - 请求参数:
    - org_id: 组织 ID(可以用于限定组织的根节点,默认返回全部组织)
    - 返回数据:
    - 返回树状结构的部门信息。

GoZero 实现

以下是用 GoZero 实现获取树状组织树接口的步骤。

1. 数据库查询

首先,我们需要定义一个部门结构体来映射数据库表 ms_base_depart

package model

type Department struct {  
    Id          int    `db:"id"`  
    OrgId       int    `db:"org_id"`  
    ParentId    string `db:"parent_id"`  
    DepartCode  string `db:"depart_code"`  
    DepartName  string `db:"depart_name"`  
    DepartLeader string `db:"depart_leader"`  
    Sort        int    `db:"sort"`  
    Level       int    `db:"level"`  
    Type        int    `db:"type"`  
    Desc        string `db:"desc"`  
    Status      int    `db:"status"`  
    IsDelete    int    `db:"is_delete"`  
    CreateTime  int    `db:"create_time"`  
    UpdateTime  int    `db:"update_time"`  
    DeleteTime  int    `db:"delete_time"`  
}  

接着,我们通过 sqlx 获取部门数据:

package logic

import (  
    "context"  
    "github.com/zeromicro/go-zero/core/stores/sqlx"  
    "ms-base/model"  
)

type DepartmentLogic struct {  
    conn sqlx.SqlConn  
}

// GetDepartmentsTree 获取部门的树状结构  
func (l *DepartmentLogic) GetDepartmentsTree(ctx context.Context, orgId int) ([]model.Department, error) {  
    var departments []model.Department  
    query := "SELECT * FROM ms_base_depart WHERE org_id = ? AND is_delete = 0 AND status = 1 ORDER BY sort"  
    err := l.conn.QueryRows(&departments, query, orgId)  
    if err != nil {  
        return nil, err  
    }

    return departments, nil  
}  

2. 构建树状结构

接下来,我们需要将数据库查询到的部门数据转换为树形结构。我们可以使用递归的方式来完成。

package logic

import (  
    "ms-base/model"  
    "fmt"  
)

type DepartmentNode struct {  
    Department model.Department  
    Children   []*DepartmentNode  
}

// BuildDepartmentTree 构建部门树  
func BuildDepartmentTree(departments []model.Department) []*DepartmentNode {  
    var tree []*DepartmentNode  
    departmentMap := make(map[int][]*DepartmentNode)

    // 将部门信息构建成树的节点  
    for _, dept := range departments {  
        node := &DepartmentNode{Department: dept}  
        departmentMap[dept.ParentId] = append(departmentMap[dept.ParentId], node)  
    }

    // 构建树  
    for _, dept := range departments {  
        if dept.ParentId == "" {  
            tree = append(tree, departmentMap[dept.ParentId]...)  
        } else {  
            parent := departmentMap[dept.ParentId]  
            for _, p := range parent {  
                p.Children = append(p.Children, departmentMap[dept.ParentId]...)  
            }  
        }  
    }

    return tree  
}  

3. 控制器实现

handler 层,调用逻辑层的方法并返回树形结构:

package handler

import (  
    "context"  
    "ms-base/logic"  
    "ms-base/model"  
    "net/http"  
    "github.com/zeromicro/go-zero/rest"  
    "github.com/zeromicro/go-zero/rest/httpx"  
)

type GetDepartmentsTreeResponse struct {  
    Data []*logic.DepartmentNode `json:"data"`  
}

func GetDepartmentsTreeHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {  
    orgId := 1 // 假设从请求中获取 org_id  
    logicLayer := logic.DepartmentLogic{}  
      
    // 获取部门数据  
    departments, err := logicLayer.GetDepartmentsTree(ctx, orgId)  
    if err != nil {  
        httpx.Error(w, err)  
        return  
    }

    // 构建树状结构  
    tree := logic.BuildDepartmentTree(departments)

    // 返回数据  
    response := GetDepartmentsTreeResponse{  
        Data: tree,  
    }  
    httpx.OkJson(w, response)  
}  

4. 路由配置

在 GoZero 中,路由配置通过 routes 方法进行:

package main

import (  
    "ms-base/handler"  
    "github.com/zeromicro/go-zero/rest"  
)

func main() {  
    server := rest.MustNewServer(cfg)  
    defer server.Stop()

    server.AddRoute(rest.Route{  
        Method:  "GET",  
        Path:    "/api/departments/tree",  
        Handler: handler.GetDepartmentsTreeHandler,  
    })

    server.Start()  
}  

总结

在这篇文章中,我们展示了如何使用 GoZero 实现一个获取树状组织结构的接口。通过以下步骤:

  1. 定义数据库模型。
  2. 编写逻辑层获取数据库中的部门数据。
  3. 使用递归或迭代将数据转换为树状结构。
  4. 编写接口响应树状结构数据。

通过以上方法,可以实现高效且易于扩展的树状组织结构查询接口。如果有多个组织或复杂的树状结构需求,还可以进一步优化查询性能或引入缓存机制。