后端开发

XYGo Admin 2026-04-22 162 次阅读

路由注册、API/Controller/Logic开发规范

入口文件 module.go

module.go 是扩展的入口,在 init() 中完成路由注册和系统集成。

普通模式(纯后台管理)

大多数扩展只需要后台管理接口,使用单个 AdminAuth 路由组即可:

go 复制代码
package shop



import (

    "xygo/internal/addon"

    "xygo/internal/middleware"

    "xygo/addons/shop/controller"



    // 空导入:触发 queues、crons 子包的 init() 注册

    _ "xygo/addons/shop/queues"

    _ "xygo/addons/shop/crons"



    "github.com/gogf/gf/v2/net/ghttp"

)



func init() {

    addon.Register(addon.Module{

        Name: "shop",

        Mount: func(s *ghttp.Server) {

            s.Group("/", func(group *ghttp.RouterGroup) {

                group.Middleware(

                    middleware.CORS,

                    middleware.ResponseHandler,

                )

                group.Group("/", func(ag *ghttp.RouterGroup) {

                    ag.Middleware(middleware.AdminAuth, middleware.DemoGuard)

                    ag.Bind(controller.NewV1())

                })

            })

        },

    })

}

注意queues/crons/ 是独立子包,必须通过空导入 _ "xygo/addons/shop/queues" 来触发它们的 init()。WebSocket 事件因为只是一行注册调用,通常直接写在 module.go 里即可。

系统启动时,addon.MountAll(s) 会自动调用所有已注册扩展的 Mount 函数挂载路由。

双控制器模式(含独立前台)

如果扩展同时提供平台管理端独立用户端(如租户管理端、供应商端),需要使用双控制器模式:

go 复制代码
package tenant



import (

    "xygo/addons/tenant/controller"

    "xygo/internal/addon"

    "xygo/internal/middleware"



    "github.com/gogf/gf/v2/net/ghttp"

)



func init() {

    addon.Register(addon.Module{

        Name:  "tenant",

        Mount: mountRoutes,

    })

}



func mountRoutes(s *ghttp.Server) {

    // 路由组 1:平台管理端 — 复用核心 AdminAuth

    s.Group("/", func(group *ghttp.RouterGroup) {

        group.Middleware(middleware.CORS, middleware.ResponseHandler)

        group.Group("/", func(ag *ghttp.RouterGroup) {

            ag.Middleware(middleware.AdminAuth, middleware.DemoGuard)

            ag.Bind(controller.NewAdminV1())

        })

    })



    // 路由组 2:扩展自身端 — 使用自定义鉴权

    s.Group("/", func(group *ghttp.RouterGroup) {

        group.Middleware(middleware.CORS, middleware.ResponseHandler)

        group.Middleware(tenantResolve, tenantAdminAuth, middleware.DemoGuard)

        group.Bind(controller.NewV1())

    })

}

两个路由组使用不同的鉴权中间件,绑定不同的控制器 struct,互不干扰。使用脚手架创建时选择「是否有独立前台 → y」即可自动生成此结构。


Controller

普通模式

只需一个 ControllerV1,定义在 controller/controller.go 中:

go 复制代码
package controller



type ControllerV1 struct{}



func NewV1() *ControllerV1 { return &ControllerV1{} }

所有业务方法的 receiver 都是 *ControllerV1

双控制器模式

controller/controller.go 中定义两个 struct:

go 复制代码
package controller



type AdminControllerV1 struct{}   // 平台管理端 — 走 AdminAuth

type ControllerV1 struct{}        // 扩展自身端 — 走自定义鉴权



func NewAdminV1() *AdminControllerV1 { return &AdminControllerV1{} }

func NewV1() *ControllerV1           { return &ControllerV1{} }

文件命名规则:

| 文件名 | Controller Receiver | 路由鉴权 | 示例 |

|--------|---------------------|---------|------|

| admin_*.go | *AdminControllerV1 | 核心 AdminAuth | admin_tenant.go |

| 其他(无 admin_ 前缀) | *ControllerV1 | 扩展自定义鉴权 | user.godept.go |

严格约束admin_*.go 中的方法 receiver 必须是 *AdminControllerV1,不能混用 *ControllerV1,否则会导致接口走错鉴权中间件。


API 定义

api/ 目录下定义请求和响应结构体,使用 GoFrame 的规范路由标签:

go 复制代码
package api



import "github.com/gogf/gf/v2/frame/g"



type ShopOrderListReq struct {

    g.Meta   `path:"/admin/shop/order/list" method:"get" tags:"商城" summary:"订单列表"`

    Page     int    `json:"page" d:"1"`

    PageSize int    `json:"pageSize" d:"20"`

    Status   *int   `json:"status"`

}

type ShopOrderListRes struct {

    g.Meta `mime:"application/json"`

}



type ShopOrderEditReq struct {

    g.Meta `path:"/admin/shop/order/edit" method:"post" tags:"商城" summary:"保存订单"`

    Id     uint64 `json:"id"`

}

type ShopOrderEditRes struct{}



type ShopOrderDeleteReq struct {

    g.Meta `path:"/admin/shop/order/delete" method:"post" tags:"商城" summary:"删除订单"`

    Id     uint64 `json:"id" v:"required"`

}

type ShopOrderDeleteRes struct{}

路由路径规范/admin/{扩展名}/{实体名}/{操作},如 /admin/shop/order/list

Controller 方法

go 复制代码
package controller



import (

    "context"

    api "xygo/addons/shop/api"

    "xygo/addons/shop/service"

)



func (c *ControllerV1) ShopOrderList(ctx context.Context, req *api.ShopOrderListReq) (res *api.ShopOrderListRes, err error) {

    // 调用 service 获取列表

    res = &api.ShopOrderListRes{}

    return

}



func (c *ControllerV1) ShopOrderEdit(ctx context.Context, req *api.ShopOrderEditReq) (res *api.ShopOrderEditRes, err error) {

    return

}



func (c *ControllerV1) ShopOrderDelete(ctx context.Context, req *api.ShopOrderDeleteReq) (res *api.ShopOrderDeleteRes, err error) {

    return

}

Logic

go 复制代码
package logic



import (

    "context"

    api "xygo/addons/shop/api"

)



func OrderList(ctx context.Context, req *api.ShopOrderListReq) (res *api.ShopOrderListRes, err error) {

    // 使用 g.DB() 或 dao 层查询数据库

    // 表名规范:xy_{扩展名}_xxx,如 xy_shop_order

    res = &api.ShopOrderListRes{}

    return

}



func OrderEdit(ctx context.Context, req *api.ShopOrderEditReq) (res *api.ShopOrderEditRes, err error) {

    return

}



func OrderDelete(ctx context.Context, req *api.ShopOrderDeleteReq) (res *api.ShopOrderDeleteRes, err error) {

    return

}