From b408076fa716a67820d588ac681de80b347b5776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Mon, 27 Jan 2025 19:46:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=9D=E5=AD=98=E8=B7=AF=E7=94=B1=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E6=B3=A8=E5=86=8C=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- router/controller.go | 125 +++++++++++++++++++++++++++++++++++++++++++ router/define.go | 29 +++++++--- router/group.go | 37 +++++++++++++ router/handler.go | 21 ++++++++ router/register.go | 2 +- 5 files changed, 207 insertions(+), 7 deletions(-) create mode 100644 router/controller.go create mode 100644 router/group.go create mode 100644 router/handler.go diff --git a/router/controller.go b/router/controller.go new file mode 100644 index 0000000..fd3e558 --- /dev/null +++ b/router/controller.go @@ -0,0 +1,125 @@ +// Package router ... +// +// Description : router ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-01-27 15:29 +package router + +import ( + "reflect" + "strings" +) + +// controller 解析controller有哪些方法要注册为接口 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 15:30 2025/1/27 +type controller struct { +} + +// Parse 执行解析 +// +// 符合注册为借口的方法具有如下特征: +// +// 1. 函数接受两个入参, 第一个参数为 gin.Context , 第二个参数为 任意结构体指针, 但是必须声明 Meta 相关信息, 否则会报错 +// +// 2. 函数有两个返回值, 第一个返回值为任意结构体/结构体指针(限制死不能为map/slice, 方便后续统一标准化) , 第二个返回值为 error , 代表处理的异常, 会自动适配 exception.IException 类型 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 15:31 2025/1/27 +func (c controller) Parse(inputController any) map[string]UriConfig { + parseRes := make(map[string]UriConfig) + if nil == inputController { + return parseRes + } + controllerType := reflect.TypeOf(inputController) + controllerValue := reflect.ValueOf(inputController) + if controllerType.Kind() == reflect.Func { + // 直接函数注册 + cfg, isNeedRegister := c.methodConfig(controllerType) + if isNeedRegister { + parseRes[cfg.Path] = cfg + } + return parseRes + } + if controllerType.Kind() == reflect.Ptr { + controllerValue = controllerValue.Elem() + } + if controllerValue.IsNil() { + return parseRes + } + for methodIdx := 0; methodIdx < controllerType.NumMethod(); methodIdx++ { + uriCfg, needRegister := c.methodConfig(controllerType.Method(methodIdx).Type) + if !needRegister { + continue + } + parseRes[uriCfg.Path] = uriCfg + } + return parseRes +} + +// methodConfig 解析方法配置, 要求函数格式, 两个参数, 两个返回值, 格式 : func(ctx *gin.Context, formData anyStruct[组合Meta]) (anyStruct|map[response], error) +// +// 参数 : 方法反射结果 +// +// 返回值 : 第一个 -> 解析出的接口配置 第二个 -> 是否要注册为接口 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 16:05 2025/1/27 +func (c controller) methodConfig(methodType reflect.Type) (cfg UriConfig, needRegister bool) { + // num0: 函数声明 + // num1: 第一个参数 + // num2: 第二个参数 + if methodType.NumIn() != 3 { + needRegister = false + return + } + // 第一个参数必须是 *gin.Context + if methodType.In(1).String() != "*gin.Context" { + needRegister = false + return + } + // 解析第二个参数是组合Meta的form表单 + formType := methodType.In(2) + if formType.Kind() == reflect.Ptr { + formType = methodType.In(2).Elem() + } + metaField, metaFieldExist := formType.FieldByName(FieldNameMeta) + if !metaFieldExist { + needRegister = false + return + } + // 解析第一个返回值, 要求必须是结构体或者是map + if methodType.Out(0).Kind() != reflect.Struct && methodType.Out(0).Kind() != reflect.Map { + needRegister = false + return + } + if methodType.Out(1).Kind().String() != "error" { + // 判断是否是实现 error接口的方法 + outputErrParse := false + for j := 0; j < methodType.Out(1).NumMethod(); j++ { + if methodType.Out(1).Method(j).Name == "Error" && // 实现Error方法 + methodType.Out(1).Method(j).Type.NumIn() == 1 && // 没有任何参数 + methodType.Out(1).Method(j).Type.NumOut() == 1 && // 一个返回值 + methodType.Out(1).Method(j).Type.Out(0).Kind().String() == reflect.String.String() { + outputErrParse = true + break + } + } + if !outputErrParse { + needRegister = false + } + return + } + // 解析meta信息 + cfg.Path = metaField.Tag.Get(TagNamePath) + cfg.Method = metaField.Tag.Get(TagNameMethod) + cfg.Desc = metaField.Tag.Get(TagNameDesc) + cfg.TagList = strings.Split(metaField.Tag.Get(TagNameUriTag), ",") + return +} diff --git a/router/define.go b/router/define.go index a761be7..4e4b7bd 100644 --- a/router/define.go +++ b/router/define.go @@ -28,10 +28,27 @@ const ( // // Date : 15:41 2024/7/21 type UriConfig struct { - Path string `json:"path"` // 接口路由, 必须配置 - Method string `json:"method"` // 接口请求方法, 必须配置 - TagList []string `json:"tag_list"` // 接口分组 - Desc string `json:"desc"` // 接口描述 - Strict bool `json:"strict"` // 接口是否为严格模式 : 不配置, 则为严格模式.严格模式 : POST 仅解析 BODY , GET 仅解析 QUERY - FormDataType reflect.Type `json:"-"` // 表单数据类型 + Path string `json:"path"` // 接口路由, 必须配置 + Method string `json:"method"` // 接口请求方法, 必须配置 + TagList []string `json:"tag_list"` // 接口分组 + Desc string `json:"desc"` // 接口描述 + Strict bool `json:"strict"` // 接口是否为严格模式 : 不配置, 则为严格模式.严格模式 : POST 仅解析 BODY , GET 仅解析 QUERY + ParamTable map[string]UriParam `json:"param_table"` // 参数信息表 + FormDataType reflect.Type `json:"-"` // 表单数据类型 } + +// UriParam 接口参数配置 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 15:40 2025/1/27 +type UriParam struct { + Name string `json:"name"` // 参数名称 + Type string `json:"type"` // 参数类型 + DisableAutoType bool `json:"disable_auto_type"` // 禁用自动类型转换 + Sort string `json:"sort"` // 参数读取顺序: 默认 POST : body > query > path GET : query > path > body +} + +const ( + FieldNameMeta = "Meta" // 元信息字段 +) diff --git a/router/group.go b/router/group.go new file mode 100644 index 0000000..1455f5f --- /dev/null +++ b/router/group.go @@ -0,0 +1,37 @@ +// Package router ... +// +// Description : router ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-01-27 19:33 +package router + +import ( + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +// Group 注册接口路由 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 19:35 2025/1/27 +func Group(router *gin.Engine, routerPrefix string, middlewareList []gin.HandlerFunc, cList ...any) error { + g := router.Group(routerPrefix) + g.Use(middlewareList...) + cParser := controller{} + for _, c := range cList { + urlTable := cParser.Parse(c) + for _, itemUriCfg := range urlTable { + method := strings.ToUpper(itemUriCfg.Method) + switch method { + case http.MethodGet: + g.HEAD(itemUriCfg.Path) + + } + } + } + return nil +} diff --git a/router/handler.go b/router/handler.go new file mode 100644 index 0000000..6ac773d --- /dev/null +++ b/router/handler.go @@ -0,0 +1,21 @@ +// Package router ... +// +// Description : router ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-01-27 19:42 +package router + +import "github.com/gin-gonic/gin" + +// RequestHandler 获取请求处理方法 TODO : 待完成 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 19:44 2025/1/27 +func RequestHandler(uriCfg UriConfig) gin.HandlerFunc { + return func(ctx *gin.Context) { + + } +} diff --git a/router/register.go b/router/register.go index 5cce58f..1ac03d3 100644 --- a/router/register.go +++ b/router/register.go @@ -118,7 +118,7 @@ func parseUriConfig(methodType reflect.Type, routerPrefix string) (*UriConfig, e if formType.Kind() == reflect.Ptr { formType = methodType.In(2).Elem() } - metaField, metaFieldExist := formType.FieldByName("Meta") + metaField, metaFieldExist := formType.FieldByName(FieldNameMeta) if !metaFieldExist { return nil, nil }