gin/router
2024-07-22 14:31:55 +08:00
..
define.go 完成基础路由注册, 遗留 : form表单, any数据类型解析失败 2024-07-21 18:49:44 +08:00
meta.go 支持解析路由前缀 2024-07-20 23:39:25 +08:00
README.md add readme 2024-07-22 14:31:55 +08:00
register_test.go add readme 2024-07-22 14:31:55 +08:00
register.go add readme 2024-07-22 14:31:55 +08:00

路由包使用说明

基础说明

为什么要二次封装

二次封装的想法来源于 web框架GoFrame。gf框架本身内置集成了大量组件, 对于轻量应用开发, 相比较而言比较笨重, 但是启根据请求数据结构、响应数据结构自动生成表单的能力十分实用。 在采用gin开发时一般接口文档有两种选择 :

  • 在内部文档平台手搓文档, 并人工维护, 此方案最终演变方式大概率为文档主键滞后,与接口实现并不一致
  • 利用golang的文档生成工具swag 自动生成swagger文档, 此种方案需要在代码中引入大量swag工具解析时需要的注释, 且当输入/输出发生变化时需要维护相关注释 基于以上问题, 对gin的路由注册进行二次封装

二次封装解决哪些问题

  • 文档维护的繁琐性 : 会通过反射自动基于 请求的数据结构 + 返回的数据结构 , 生成接口文档, 专注于数据结构设计即可, 无需关注文档相关内容, 程序接管, 自动生成
  • 做接口设计的统一性规范约束, 如 :
    • 入参数据类型不能为 any
    • 入参类型不能为 map , 但是特定字段特定场景, 可以强行禁用此规则等
    • 返回值必须为结构体等

设计方案

###【可选】路由组定义

路由组可以通过函数进行定义, 函数名必须需为 : RouterPrefix , 函数无任何参数, 返回路由组名称, 示例 :

type TestController struct{}

func (t *TestController) RouterPrefix() string {
	return "/uri/prefix"
}

###【可选】路由组中间件定义

路由组中间件可以通过函数进行定义, 函数名必须需为 : RouterMiddleware , 函数无任何参数, 返回路由组中间件列表 []gin.HandlerFunc, 示例 :

type TestController struct{}

func (t *TestController) RouterPrefix() string {
	return "/uri/prefix"
}

func (t *TestController) RouterMiddleware() []gin.HandlerFunc {
	return []gin.HandlerFunc{
		func(ctx *gin.Context) {

		},
	}
}

接口逻辑处理定义

接口逻辑处理函数, 函数名称自定义, 必须是个 可导出函数 , 函数接收两个参数, 分别是 :

  • *gin.Context : gin框架的上下文信息
  • any: 表单参数 结构体指针 , 注意 : 类型必须为结构体指针

函数返回值有两个 :

  • any : 返回的业务数据, 必须是个 结构体指针
  • error : 可以是内置的 error , 也可以是 exception.IException , 建议使用 exception.IException , 可承载更多的异常信息

使用方式

type TestController struct{}

func (t *TestController) RouterPrefix() string {
	return "/uri/prefix"
}

func (t *TestController) RouterMiddleware() []gin.HandlerFunc {
	return []gin.HandlerFunc{
		func(ctx *gin.Context) {

		},
	}
}
func (t *TestController) Uri(ctx *gin.Context, formData *TestForm) (any, error) {
	return formData, nil
}

type TestForm struct {
	Meta `tag:"测试表单" path:"/a/b/c/d" desc:"测试接口" method:"get" strict:"true"`
	Age  int    `json:"age" form:"age"`
	Name string `json:"name" form:"name"`
	Test *Test  `json:"test" form:"test"`
	Num  *int64 `json:"num" form:"num"`
}
type Test struct {
	L string `json:"l"`
}

func Test_parseController(t *testing.T) {
	type args struct {
		controller any
	}
	Register(8080, &TestController{})
}

注意事项:

  • Register 方法第一个入参是监听的端口
  • 后面若干个controller实例, 朱一必须以指针的方式传入