保存路由统一注册方法

This commit is contained in:
白茶清欢 2025-01-27 19:46:34 +08:00
parent 851de1b3ef
commit b408076fa7
5 changed files with 207 additions and 7 deletions

125
router/controller.go Normal file
View File

@ -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
}

View File

@ -28,10 +28,27 @@ const (
// //
// Date : 15:41 2024/7/21 // Date : 15:41 2024/7/21
type UriConfig struct { type UriConfig struct {
Path string `json:"path"` // 接口路由, 必须配置 Path string `json:"path"` // 接口路由, 必须配置
Method string `json:"method"` // 接口请求方法, 必须配置 Method string `json:"method"` // 接口请求方法, 必须配置
TagList []string `json:"tag_list"` // 接口分组 TagList []string `json:"tag_list"` // 接口分组
Desc string `json:"desc"` // 接口描述 Desc string `json:"desc"` // 接口描述
Strict bool `json:"strict"` // 接口是否为严格模式 : 不配置, 则为严格模式.严格模式 : POST 仅解析 BODY , GET 仅解析 QUERY Strict bool `json:"strict"` // 接口是否为严格模式 : 不配置, 则为严格模式.严格模式 : POST 仅解析 BODY , GET 仅解析 QUERY
FormDataType reflect.Type `json:"-"` // 表单数据类型 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" // 元信息字段
)

37
router/group.go Normal file
View File

@ -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
}

21
router/handler.go Normal file
View File

@ -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) {
}
}

View File

@ -118,7 +118,7 @@ func parseUriConfig(methodType reflect.Type, routerPrefix string) (*UriConfig, e
if formType.Kind() == reflect.Ptr { if formType.Kind() == reflect.Ptr {
formType = methodType.In(2).Elem() formType = methodType.In(2).Elem()
} }
metaField, metaFieldExist := formType.FieldByName("Meta") metaField, metaFieldExist := formType.FieldByName(FieldNameMeta)
if !metaFieldExist { if !metaFieldExist {
return nil, nil return nil, nil
} }