153 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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)
 | |
| 	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)
 | |
| //
 | |
| // 参数 : 方法反射结果
 | |
| //
 | |
| // 返回值 : 第一个 -> 解析出的接口配置 第二个 -> 是否要注册为接口
 | |
| //
 | |
| // 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: 函数声明
 | |
| 	// num1: 第一个参数
 | |
| 	// num2: 第二个参数
 | |
| 	if methodType.NumIn() != 3 {
 | |
| 		needRegister = false
 | |
| 		return
 | |
| 	}
 | |
| 	// 第一个参数必须是 *gin.Context 或者 *define.Context
 | |
| 	paramOne := methodType.In(1).String()
 | |
| 	if paramOne != GinContextType && paramOne != CustomContextType {
 | |
| 		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 cfg.ResultDataType == nil {
 | |
| 	}
 | |
| 	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
 | |
| 		}
 | |
| 	}
 | |
| 	// 解析meta信息
 | |
| 	cfg.CtxType = paramOne
 | |
| 	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)
 | |
| 	cfg.OutputStrict = outputStrictModel == "1" || outputStrictModel == "true"
 | |
| 	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())
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	// 解析参数配置
 | |
| 	//cfg.ParamList = c.parseParamConfig(formType)
 | |
| 	cfg.ApiLogicFunc = reflectMethod
 | |
| 	needRegister = true
 | |
| 	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
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 	return res
 | |
| }
 |