From 03c1eadd603e60680965cf3d9303d2cf61667546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Fri, 26 Dec 2025 11:25:13 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E5=AF=B9=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=85=83=E6=95=B0=E6=8D=AE=20Meta=20=E7=9A=84?= =?UTF-8?q?=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- router/controller.go | 56 +++++++++++++++------------------------ router/define.go | 12 +++++---- router/server.go | 62 ++++++++++++++++---------------------------- 3 files changed, 50 insertions(+), 80 deletions(-) diff --git a/router/controller.go b/router/controller.go index 97e1da1..fae87fe 100644 --- a/router/controller.go +++ b/router/controller.go @@ -52,10 +52,6 @@ func (c controller) Parse(inputController any) map[string]UriConfig { // 参数 : 方法反射结果 // // 返回值 : 第一个 -> 解析出的接口配置 第二个 -> 是否要注册为接口 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:05 2025/1/27 func (c controller) methodConfig(reflectMethod reflect.Method) (cfg UriConfig, needRegister bool) { methodType := reflectMethod.Type // num0: 函数声明 @@ -71,7 +67,7 @@ func (c controller) methodConfig(reflectMethod reflect.Method) (cfg UriConfig, n needRegister = false return } - // 解析第二个参数是组合Meta的form表单 + // 解析第二个参数是组合 Meta 的form表单 formType := methodType.In(2) cfg.FormDataType = formType if formType.Kind() == reflect.Ptr { @@ -89,7 +85,7 @@ func (c controller) methodConfig(reflectMethod reflect.Method) (cfg UriConfig, n // 判断是否是实现 error接口的方法 outputErrParse := false for j := 0; j < methodType.Out(1).NumMethod(); j++ { - if methodType.Out(1).Method(j).Name == ErrorInterfaceFuncName && // 实现Error方法 + if methodType.Out(1).Method(j).Name == ErrorInterfaceFuncName && // 实现 Error 方法 methodType.Out(1).Method(j).Type.NumIn() == 0 && // 没有任何参数 methodType.Out(1).Method(j).Type.NumOut() == 1 && // 一个返回值 methodType.Out(1).Method(j).Type.Out(0).Kind().String() == reflect.String.String() { @@ -102,16 +98,8 @@ func (c controller) methodConfig(reflectMethod reflect.Method) (cfg UriConfig, n return } } - // 解析meta信息 - cfg.Path = metaField.Tag.Get(TagNamePath) - cfg.RequestMethod = metaField.Tag.Get(TagNameMethod) - cfg.Desc = metaField.Tag.Get(TagNameDesc) - cfg.TagList = strings.Split(metaField.Tag.Get(TagNameUriTag), ",") - // 解析第一个返回值, 要求必须是结构体或者是map - outputStrictModel := metaField.Tag.Get(TagNameOutputStrict) - hookSync := strings.ToLower(metaField.Tag.Get(TagNameHookSync)) - cfg.HookSync = hookSync == "1" || hookSync == "true" // 同步执行判断 - cfg.OutputStrict = outputStrictModel == "1" || outputStrictModel == "true" + c.setUriMeta(metaField, &cfg) + if cfg.OutputStrict { // 开启输出严格模式校验 if methodType.Out(0).Kind() != reflect.Struct && methodType.Out(0).Kind() != reflect.Map { @@ -119,6 +107,7 @@ func (c controller) methodConfig(reflectMethod reflect.Method) (cfg UriConfig, n return } } + // 解析参数配置 //cfg.ParamList = c.parseParamConfig(formType) cfg.ApiLogicFunc = reflectMethod @@ -126,24 +115,21 @@ func (c controller) methodConfig(reflectMethod reflect.Method) (cfg UriConfig, n return } -// parseParamConfig 解析参数配置 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 14:35 2025/2/7 -func (c controller) parseParamConfig(formDataType reflect.Type) []UriParam { - res := make([]UriParam, 0) - for i := 0; i < formDataType.NumField(); i++ { - structField := formDataType.Field(i) - if structField.Name == FieldNameMeta { - // Meta 字段, 忽略 - continue - } - jsonTag := structField.Tag.Get("json") - if jsonTag == "" { - jsonTag = structField.Name - } - +// setUriMeta 设置接口的 meta 信息 +func (c controller) setUriMeta(metaField reflect.StructField, cfg *UriConfig) { + // 解析 meta 信息 + cfg.Path = metaField.Tag.Get(TagNamePath) // 接口路由 + cfg.RequestMethod = strings.Split(strings.ToUpper(metaField.Tag.Get(TagNameMethod)), ",") // 请求方法 + cfg.Desc = metaField.Tag.Get(TagNameDesc) // 接口描述 + cfg.TagList = strings.Split(metaField.Tag.Get(TagNameUriTag), ",") // 接口标签 + // 以下是bool类型的配置解析 + var boolMetaParse = func(tagName string) bool { + val := strings.ToLower(metaField.Tag.Get(tagName)) + return val == "1" || val == "true" } - return res + cfg.OutputStrict = boolMetaParse(TagNameOutputStrict) // 配置接口数据是否严格要求是对象 + cfg.HookSync = boolMetaParse(TagNameHookSync) // 同步执行判断 + cfg.IsWebsocket = boolMetaParse(TagNameIsWebsocket) // 是否是 websocket 接口 + cfg.IsSse = boolMetaParse(TagNameIsSse) // 是否是 sse 接口 + cfg.NoLogin = boolMetaParse(TagNameNoLogin) // 是否需要登录 } diff --git a/router/define.go b/router/define.go index 0d54038..d9ccbdc 100644 --- a/router/define.go +++ b/router/define.go @@ -24,25 +24,27 @@ const ( TagNameMethod = "method" // 接口的请求方法 TagNameUriTag = "tag" // 接口的 tag TagNameDesc = "desc" // 接口的描述 + TagNameIsSse = "is-sse" // 是否 SSE 连接 + TagNameIsWebsocket = "is-ws" // 是否 websocket 连接 TagNameOutputStrict = "output_strict" // 接口数据是否为严格模式 : 严格模式, 响应数据必须是结构体/map,非严格模式返回任意值 TagNameHookSync = "hook-sync" // hook 同步执行 + TagNameNoLogin = "no-login" // 接口是否需要登录(无需登录, 则有token就验证, 无token不验证) TagNameBinding = "binding" // gin 内置的验证规则tag TagNameValidate = "validate" // validator v10 默认的验证规则tag TagNameErrMsg = "err" // 验证失败错误信息 tag ) // UriConfig 接口配置 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 15:41 2024/7/21 type UriConfig struct { Path string `json:"path"` // 接口路由, 必须配置 - RequestMethod string `json:"request_method"` // 接口请求方法, 必须配置 + RequestMethod []string `json:"request_method"` // 接口请求方法, 必须配置 TagList []string `json:"tag_list"` // 接口分组 Desc string `json:"desc"` // 接口描述 + IsSse bool `json:"is_sse"` // 是否 SSE 连接 + IsWebsocket bool `json:"is_ws"` // 是否 websocket 连接 OutputStrict bool `json:"output_strict"` // 接口是否为严格模式 : 不配置,可返回任意类型, 配置, 必须返回结构体或者map HookSync bool `json:"hook_sync"` // 接口主逻辑执行完成之后,hook是否同步执行, 默认异步执行 + NoLogin bool `json:"no_login"` // 接口是否需要登录(无需登录, 则有token就验证, 无token不验证) FormDataType reflect.Type `json:"-"` // 表单数据类型 ResultDataType reflect.Type `json:"-"` // 返回值数据类型 ApiStructValue reflect.Value `json:"-"` // 逻辑函数所属结构体取值 diff --git a/router/server.go b/router/server.go index ca39410..3ceecfc 100644 --- a/router/server.go +++ b/router/server.go @@ -135,10 +135,6 @@ type server struct { } // Start 启动服务 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 18:31 2025/2/7 func (s *server) Start() { // 注册文档 s.uiInstance.RegisterHandler(s.router, s.option.swaggerBaseUri) @@ -153,28 +149,16 @@ func (s *server) Start() { } // Router 对外访问路由实例, 不建议直接用 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 17:35 2025/2/18 func (s *server) Router() *gin.Engine { return s.router } // Handler404 注册404的处理方法 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:01 2025/2/22 func (s *server) Handler404(f gin.HandlerFunc) { s.router.NoRoute(f) } // SetCustomRouter 自定义路由处理 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:09 2025/2/22 func (s *server) SetCustomRouter(f func(r *gin.Engine)) { if nil == f { return @@ -183,10 +167,6 @@ func (s *server) SetCustomRouter(f func(r *gin.Engine)) { } // Group 注册接口路由 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 19:35 2025/1/27 func (s *server) Group(routerPrefix string, middlewareList []gin.HandlerFunc, cList ...any) { g := s.router.Group(routerPrefix) g.Use(middlewareList...) @@ -195,27 +175,29 @@ func (s *server) Group(routerPrefix string, middlewareList []gin.HandlerFunc, cL urlTable := cParser.Parse(c) for _, itemUriCfg := range urlTable { _ = s.uiInstance.DocInstance().AddApiFromInAndOut(routerPrefix, itemUriCfg.FormDataType, itemUriCfg.ResultDataType) - method := strings.ToUpper(itemUriCfg.RequestMethod) handleFunc := s.RequestHandler(itemUriCfg) - switch method { - case http.MethodGet: - g.GET(itemUriCfg.Path, handleFunc) - case http.MethodHead: - g.HEAD(itemUriCfg.Path, handleFunc) - case http.MethodPost: - g.POST(itemUriCfg.Path, handleFunc) - case http.MethodPut: - g.PUT(itemUriCfg.Path, handleFunc) - case http.MethodPatch: - g.PATCH(itemUriCfg.Path, handleFunc) - case http.MethodDelete: - g.DELETE(itemUriCfg.Path, handleFunc) - case http.MethodOptions: - g.OPTIONS(itemUriCfg.Path, handleFunc) - case http.MethodTrace: - panic(`method Trace is not supported`) - default: - panic("method " + itemUriCfg.RequestMethod + " is not support") + // 一个接口支持注册多种请求方法 + for _, method := range itemUriCfg.RequestMethod { + switch method { + case http.MethodGet: + g.GET(itemUriCfg.Path, handleFunc) + case http.MethodHead: + g.HEAD(itemUriCfg.Path, handleFunc) + case http.MethodPost: + g.POST(itemUriCfg.Path, handleFunc) + case http.MethodPut: + g.PUT(itemUriCfg.Path, handleFunc) + case http.MethodPatch: + g.PATCH(itemUriCfg.Path, handleFunc) + case http.MethodDelete: + g.DELETE(itemUriCfg.Path, handleFunc) + case http.MethodOptions: + g.OPTIONS(itemUriCfg.Path, handleFunc) + case http.MethodTrace: + panic(`method Trace is not supported`) + default: + panic("method " + method + " is not support") + } } } }