diff --git a/net/ghttp/ghttp_z_unit_issue_test.go b/net/ghttp/ghttp_z_unit_issue_test.go index fd7fb0ab2..3b2666dd5 100644 --- a/net/ghttp/ghttp_z_unit_issue_test.go +++ b/net/ghttp/ghttp_z_unit_issue_test.go @@ -280,3 +280,88 @@ func Test_Issue2334(t *testing.T) { t.Assert(res.StatusCode, 304) }) } + +type CreateOrderReq struct { + g.Meta `path:"/order" tags:"订单" method:"put" summary:"创建订单"` + Details []*OrderDetail `p:"detail" v:"required#请输入订单详情" dc:"订单详情"` +} + +type OrderDetail struct { + Name string `p:"name" v:"required#请输入物料名称" dc:"物料名称"` + Sn string `p:"sn" v:"required#请输入客户编号" dc:"客户编号"` + Images string `p:"images" dc:"图片"` + Desc string `p:"desc" dc:"备注"` + Number int `p:"number" v:"required#请输入数量" dc:"数量"` + Price float64 `p:"price" v:"required" dc:"单价"` +} + +type CreateOrderRes struct{} +type OrderController struct{} + +func (c *OrderController) CreateOrder(ctx context.Context, req *CreateOrderReq) (res *CreateOrderRes, err error) { + return +} + +// https://github.com/gogf/gf/issues/2482 +func Test_Issue2482(t *testing.T) { + s := g.Server(guid.S()) + s.Group("/api/v2", func(group *ghttp.RouterGroup) { + group.Middleware(ghttp.MiddlewareHandlerResponse) + group.Bind(OrderController{}) + }) + s.SetDumpRouterMap(false) + s.Start() + defer s.Shutdown() + time.Sleep(1000 * time.Millisecond) + + c := g.Client() + c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) + gtest.C(t, func(t *gtest.T) { + content := ` +{ + "detail": [ + { + "images": "string", + "desc": "string", + "number": 0, + "price": 0 + } + ] + } +` + t.Assert(c.PutContent(ctx, "/api/v2/order", content), `{"code":51,"message":"请输入物料名称","data":null}`) + }) + gtest.C(t, func(t *gtest.T) { + content := ` +{ + "detail": [ + { + "images": "string", + "desc": "string", + "number": 0, + "name": "string", + "price": 0 + } + ] + } +` + t.Assert(c.PutContent(ctx, "/api/v2/order", content), `{"code":51,"message":"请输入客户编号","data":null}`) + }) + gtest.C(t, func(t *gtest.T) { + content := ` +{ + "detail": [ + { + "images": "string", + "desc": "string", + "number": 0, + "name": "string", + "sn": "string", + "price": 0 + } + ] + } +` + t.Assert(c.PutContent(ctx, "/api/v2/order", content), `{"code":0,"message":"","data":null}`) + }) +} diff --git a/util/gvalid/gvalid_validator_check_struct.go b/util/gvalid/gvalid_validator_check_struct.go index 2b5affa18..77e10d486 100644 --- a/util/gvalid/gvalid_validator_check_struct.go +++ b/util/gvalid/gvalid_validator_check_struct.go @@ -215,9 +215,9 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error // which have the most priority than `rules` and struct tag. if msg, ok := v.messages.(CustomMsg); ok && len(msg) > 0 { for k, msgName := range msg { - if a, ok := fieldToAliasNameMap[k]; ok { + if aliasName, ok := fieldToAliasNameMap[k]; ok { // Overwrite the key of field name. - customMessage[a] = msgName + customMessage[aliasName] = msgName } else { customMessage[k] = msgName } @@ -245,13 +245,17 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error } } } else { + // The `field.TagValue` is the alias name of field.Name(). + // Eg, value from struct tag `p`. if field.TagValue != "" { fieldToAliasNameMap[field.Name()] = field.TagValue } switch field.OriginalKind() { case reflect.Map, reflect.Struct, reflect.Slice, reflect.Array: // Recursively check attribute slice/map. - _, value = gutil.MapPossibleItemByKey(inputParamMap, field.Name()) + value = getPossibleValueFromMap( + inputParamMap, field.Name(), fieldToAliasNameMap[field.Name()], + ) if value == nil { switch field.Kind() { case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Array: @@ -279,12 +283,9 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error // The following logic is the same as some of CheckMap but with sequence support. for _, checkRuleItem := range checkRules { if !checkRuleItem.IsMeta { - _, value = gutil.MapPossibleItemByKey(inputParamMap, checkRuleItem.Name) - if value == nil { - if aliasName := fieldToAliasNameMap[checkRuleItem.Name]; aliasName != "" { - _, value = gutil.MapPossibleItemByKey(inputParamMap, aliasName) - } - } + value = getPossibleValueFromMap( + inputParamMap, checkRuleItem.Name, fieldToAliasNameMap[checkRuleItem.Name], + ) } // Empty json string checks according to mapping field kind. if value != nil { @@ -347,3 +348,11 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error } return nil } + +func getPossibleValueFromMap(inputParamMap map[string]interface{}, fieldName, aliasName string) (value interface{}) { + _, value = gutil.MapPossibleItemByKey(inputParamMap, fieldName) + if value == nil && aliasName != "" { + _, value = gutil.MapPossibleItemByKey(inputParamMap, aliasName) + } + return +}