// Package router ... // // Description : router ... // // Author : go_developer@163.com<白茶清欢> // // Date : 2025-01-27 15:29 package router import ( "reflect" "strings" "git.zhangdeman.cn/zhangdeman/util" ) // controller 解析controller有哪些方法要注册为接口 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) inputController = reflect.New(controllerType).Interface() controllerType = reflect.TypeOf(inputController) controllerValue := reflect.ValueOf(inputController) for methodIdx := 0; methodIdx < controllerType.NumMethod(); methodIdx++ { uriCfg, needRegister := c.methodConfig(controllerType.Method(methodIdx)) if !needRegister { continue } uriCfg.ApiStructValue = controllerValue parseRes[uriCfg.Path] = uriCfg } return parseRes } // methodConfig 解析方法配置, 要求函数格式, 两个参数, 两个返回值, 格式 : func(ctx *gin.Context, formData anyStruct[组合Meta]) (anyStruct|map[response], error) // // 参数 : 方法反射结果 // // 返回值 : 第一个 -> 解析出的接口配置 第二个 -> 是否要注册为接口 func (c controller) methodConfig(reflectMethod reflect.Method) (cfg UriConfig, needRegister bool) { methodType := reflectMethod.Type // num0: 函数声明 // num1: 第一个参数 // num2: 第二个参数 if methodType.NumIn() != 3 { needRegister = false return } // 第一个参数必须是 *gin.Context 或者 *define.Context paramOne := methodType.In(1).String() if paramOne != GinContextType { needRegister = false return } // 解析第二个参数是组合 Meta 的form表单 formType := methodType.In(2) cfg.FormDataType = formType if formType.Kind() == reflect.Ptr { formType = methodType.In(2).Elem() } metaField, metaFieldExist := formType.FieldByName(FieldNameMeta) if !metaFieldExist { needRegister = false return } cfg.ResultDataType = methodType.Out(0) if methodType.Out(1).Kind().String() != ErrorType { // 判断是否是实现 error接口的方法 outputErrParse := false for j := 0; j < methodType.Out(1).NumMethod(); j++ { 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() { outputErrParse = true break } } if !outputErrParse { needRegister = false return } } c.setUriMeta(metaField, &cfg) if cfg.OutputStrict { // 开启输出严格模式校验 if methodType.Out(0).Kind() != reflect.Struct && methodType.Out(0).Kind() != reflect.Map { panic(cfg.Path + " : 接口配置输出严格校验, 输出数据类型必须为 struct 或 *struct 或 map, 实际返回数据类型 : " + methodType.Out(0).Kind().String()) } } // 解析参数配置 //cfg.ParamList = c.parseParamConfig(formType) cfg.ApiLogicFunc = reflectMethod needRegister = true return } // 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" } cfg.OutputStrict = boolMetaParse(TagNameOutputStrict) // 配置接口数据是否严格要求是对象 cfg.HookSync = boolMetaParse(TagNameHookSync) // 同步执行判断 cfg.IsWebsocket = boolMetaParse(TagNameIsWebsocket) // 是否是 websocket 接口 cfg.IsSse = boolMetaParse(TagNameIsSse) // 是否是 sse 接口 cfg.NoLogin = boolMetaParse(TagNameNoLogin) // 是否需要登录 // 最大执行时间 cfg.MaxExecTime = uint(0) if tagVal := strings.ToLower(metaField.Tag.Get(TagNameMaxExecTime)); tagVal != "" { if err := util.ConvertAssign(&cfg.MaxExecTime, tagVal); nil != err { panic(cfg.Path + " : 最大执行时间配置错误(配置的值必须是无符号整型), 请检查配置 : " + err.Error()) } } }