gin-路由handler封装思路

发布于:2025-03-23 ⋅ 阅读:(19) ⋅ 点赞:(0)
  • 约束handler入参和返回为func(ctx, req) (resp, error)。
  • 通过反射,封装handler,在调用前后写入入参和返回的处理。
package testing

import (
	"context"
	"fmt"
	"reflect"
	"strings"
	"testing"
)

type ReqParams struct {
	Name string
	Age  int
}

type RouteHandlers struct{}

func (r *RouteHandlers) Test(c *context.Context, req *ReqParams) {
	fmt.Println("req:", req)
}

type Router struct {
	Method reflect.Value // 请求中的handler
	Params reflect.Value // 请求参数
}

func TestReflact(t *testing.T) {
	controller := &RouteHandlers{}
	handlerRef := reflect.ValueOf(controller)
	if handlerRef.NumMethod() == 0 {
		// 结构体无方法,不进行后续处理
		return
	}
	hMap := make(map[string]map[string]Router)
	// 1.提取控制器名:TypeOf获取到含*的package.type的完整类型
	structName := reflect.TypeOf(controller).String()
	if strings.Contains(structName, ".") {
		structName = structName[strings.Index(structName, ".")+1:]
	}
	if hMap[structName] == nil {
		hMap[structName] = make(map[string]Router)
	}

	// 2.提取方法名:Method获取可操作目标(后续调用)
	// 提取入参,生成实例,后续进行前置校验
	for i := 0; i < handlerRef.NumMethod(); i++ {
		mCall := handlerRef.Method(i)
		mName := handlerRef.Type().Method(i).Name
		// 人为约束:2个参数,第一个为context,第二个为请求参数
		reqParams := reflect.New(mCall.Type().In(1).Elem())

		// 亦可约束返回参数,做出统一处理:reflect.New(mCall.Type().Out().Elem())

		hMap[structName][mName] = Router{
			Method: mCall,
			Params: reqParams,
		}
	}
	fmt.Println(hMap)
	// 模拟请求时的调用
	c := context.TODO()
	hMap[structName]["Test"].Method.Call([]reflect.Value{reflect.ValueOf(&c), hMap[structName]["Test"].Params})

	// 后续封装func(r Router)func(c *gin.Context),返回gin可使用的handler时,写入下述参数验证
	//
	// 参数为 *A
	// reflect.New  => 生成一个指针,指向类型零值,req = **A
	// req.Interface => 返回req的实际值,并用interface包装,**A -> *A,再var i interface = *A
	// req.Elem => 返回interface或point指向的实际值,*A
	// if err := c.ShouldBindJson(r.Params.Interface()); err != nil {
	//     c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
	//     c.Abort()
	// 	   return
	// } else {
	//     args := []reflect.Value{reflect.ValueOf(c), r.Params.Elem()}
	//	   r.Method.Call(args)
	// }
}