126 lines
3.7 KiB
Go
126 lines
3.7 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)
|
||
|
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
|
||
|
}
|