feat: 自动字段注入支持解析二级匿名字段
This commit is contained in:
		| @ -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, | ||||||
|  | |||||||
| @ -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 | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -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{}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -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 | ||||||
|  | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user