feat: 自动字段注入支持解析二级匿名字段

This commit is contained in:
2025-10-31 14:51:00 +08:00
parent 463523f0b8
commit 2deff38f9d
4 changed files with 72 additions and 23 deletions

View File

@ -36,24 +36,42 @@ func (s *server) AddCommonParamRules(rules map[string]GetCommonParam) {
func (s *server) injectCommonParam(ctx *gin.Context, formValue any) error { func (s *server) injectCommonParam(ctx *gin.Context, formValue any) error {
innerCtx := util.GinCtxToContext(ctx) innerCtx := util.GinCtxToContext(ctx)
var ( var (
val any val any
err error err error
reflectFormValue reflect.Value
reflectType reflect.Type
ok bool
) )
reflectType := reflect.TypeOf(formValue) if reflectFormValue, ok = formValue.(reflect.Value); !ok {
reflectFormValue = reflect.ValueOf(formValue)
reflectType = reflect.TypeOf(formValue)
} else {
reflectType = reflectFormValue.Type()
}
fieldTable := map[string]bool{} fieldTable := map[string]bool{}
fieldNum := reflectType.Elem().NumField() fieldNum := reflectType.Elem().NumField()
for i := 0; i < fieldNum; i++ { for i := 0; i < fieldNum; i++ {
// 提取全部结构体字段 if reflectType.Elem().Field(i).Anonymous && ((reflectType.Elem().Field(i).Type.Kind() == reflect.Ptr && reflectType.Elem().Field(i).Type.Kind() == reflect.Struct) || reflectType.Elem().Field(i).Type.Kind() == reflect.Struct) {
fieldTable[reflectType.Elem().Field(i).Name] = true anonymousFieldType := reflectType.Elem().Field(i).Type
if anonymousFieldType.Kind() == reflect.Ptr {
anonymousFieldType = anonymousFieldType.Elem()
}
for j := 0; j < anonymousFieldType.NumField(); j++ {
fieldTable[anonymousFieldType.Field(j).Name] = true
}
} else {
// 提取全部结构体字段
fieldTable[reflectType.Elem().Field(i).Name] = true
}
} }
reflectValue := reflect.ValueOf(formValue)
for fieldName, getParamFunc := range s.commonParam { for fieldName, getParamFunc := range s.commonParam {
if _, ok := fieldTable[fieldName]; !ok { if _, ok = fieldTable[fieldName]; !ok {
// 结构体字段未配置自动注入 // 结构体字段未配置自动注入
logger.Instance.Debug("当前结构体不包含指定字段, 忽略执行", pkgLogger.NewLogData(innerCtx, logger.RecordType, logger.CodeInjectCommonParam, map[string]any{ logger.Instance.Debug("当前结构体不包含指定字段, 忽略执行", pkgLogger.NewLogData(innerCtx, logger.RecordType, logger.CodeInjectCommonParam, map[string]any{
"field_name": fieldName, "field_name": fieldName,
"struct": reflectValue.Elem().Type().String(), "struct": reflectFormValue.Elem().Type().String(),
}).ToFieldList()...) }).ToFieldList()...)
continue continue
} }
@ -64,7 +82,7 @@ func (s *server) injectCommonParam(ctx *gin.Context, formValue any) error {
}).ToFieldList()...) }).ToFieldList()...)
return err return err
} }
fieldValue := reflectValue.Elem().FieldByName(fieldName) fieldValue := reflectFormValue.Elem().FieldByName(fieldName)
if !fieldValue.CanSet() { if !fieldValue.CanSet() {
logDataList := pkgLogger.NewLogData(util.GinCtxToContext(ctx), logger.RecordType, logger.CodeInjectCommonParam, map[string]any{ logDataList := pkgLogger.NewLogData(util.GinCtxToContext(ctx), logger.RecordType, logger.CodeInjectCommonParam, map[string]any{
"field_name": fieldName, "field_name": fieldName,

View File

@ -46,10 +46,11 @@ func (s *server) getFormInitValue(ctx *gin.Context, uriCfg UriConfig) (any, erro
func (s *server) RequestHandler(uriCfg UriConfig) gin.HandlerFunc { func (s *server) RequestHandler(uriCfg UriConfig) gin.HandlerFunc {
return func(ctx *gin.Context) { return func(ctx *gin.Context) {
var ( var (
err error err error
ok bool ok bool
e exception.IException e exception.IException
formValue any formValue any
firstParam reflect.Value
) )
if formValue, err = s.getFormInitValue(ctx, uriCfg); nil != err { if formValue, err = s.getFormInitValue(ctx, uriCfg); nil != err {
@ -60,6 +61,17 @@ func (s *server) RequestHandler(uriCfg UriConfig) gin.HandlerFunc {
ctx.Abort() ctx.Abort()
return return
} }
// 表单数据
inputValue := reflect.ValueOf(formValue)
// 注入公共参数
if err = s.injectCommonParam(ctx, inputValue); nil != err {
e = exception.NewFromError(500, err)
response.SendWithException(ctx, e, &define.ResponseOption{
ContentType: consts.MimeTypeJson,
})
ctx.Abort()
return
}
isSuccess := false isSuccess := false
// 初始化响应之后logic // 初始化响应之后logic
@ -94,11 +106,9 @@ func (s *server) RequestHandler(uriCfg UriConfig) gin.HandlerFunc {
}() }()
}() }()
// 执行逻辑 // 执行逻辑
inputValue := reflect.ValueOf(formValue)
if uriCfg.FormDataType.Kind() != reflect.Ptr { if uriCfg.FormDataType.Kind() != reflect.Ptr {
inputValue = inputValue.Elem() inputValue = inputValue.Elem()
} }
var firstParam reflect.Value
if uriCfg.CtxType == CustomContextType { if uriCfg.CtxType == CustomContextType {
customCtx := ctx.MustGet(define.CustomContextKey) customCtx := ctx.MustGet(define.CustomContextKey)
firstParam = reflect.ValueOf(customCtx) firstParam = reflect.ValueOf(customCtx)
@ -109,7 +119,7 @@ func (s *server) RequestHandler(uriCfg UriConfig) gin.HandlerFunc {
if resList[1].IsNil() { if resList[1].IsNil() {
// 请求成功 // 请求成功
isSuccess = true isSuccess = true
response.SuccessWithExtension(ctx, resList[0].Interface(), &define.ResponseOption{ContentType: "application/json;charset=utf-8"}) response.SuccessWithExtension(ctx, resList[0].Interface(), &define.ResponseOption{ContentType: consts.MimeTypeJson})
return return
} }
// 请求失败 // 请求失败
@ -123,7 +133,7 @@ func (s *server) RequestHandler(uriCfg UriConfig) gin.HandlerFunc {
}) })
} }
response.SendWithException(ctx, e, &define.ResponseOption{ response.SendWithException(ctx, e, &define.ResponseOption{
ContentType: "application/json;charset=utf-8", ContentType: consts.MimeTypeJson,
}) })
return return
} }

View File

@ -126,11 +126,12 @@ func NewServer(port int, optionList ...SetServerOptionFunc) *server {
pprof.Register(r) pprof.Register(r)
} }
return &server{ return &server{
router: r, router: r,
uiInstance: apiDoc.NewSwaggerUI(option.serverInfo, option.serverList, apiDocEnum.SwaggerUITheme(option.swaggerUiTheme)), uiInstance: apiDoc.NewSwaggerUI(option.serverInfo, option.serverList, apiDocEnum.SwaggerUITheme(option.swaggerUiTheme)),
port: port, port: port,
option: option, option: option,
lock: &sync.RWMutex{}, lock: &sync.RWMutex{},
commonParam: map[string]GetCommonParam{},
} }
} }

View File

@ -13,8 +13,28 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
type testCommon struct {
UserID uint `json:"user_id"`
}
type testForm struct {
Meta `json:"-" method:"get" path:"test"`
testCommon
Name string `json:"name"`
}
func TestNewServer(t *testing.T) { func TestNewServer(t *testing.T) {
s := NewServer(9087) s := NewServer(9087)
s.Router().GET("/ping", func(c *gin.Context) {}) s.AddCommonParamRule("UserID", func(ctx *gin.Context) (any, error) {
return uint(123456), nil
})
s.Group("", nil, testController{})
s.Start() s.Start()
} }
type testController struct {
}
func (tc testController) Test(ctx *gin.Context, requestData *testForm) (*testCommon, error) {
return &testCommon{UserID: requestData.UserID}, nil
}