mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
fix issue in function Parse for package ghttp
This commit is contained in:
@ -586,3 +586,38 @@ func Test_Params_Parse_DefaultValueTag(t *testing.T) {
|
||||
t.Assert(client.PostContent("/parse", `{"name":"smith", "score":100}`), `{"Name":"smith","Score":100}`)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Params_Parse_Validation(t *testing.T) {
|
||||
type RegisterReq struct {
|
||||
Name string `p:"username" v:"required|length:6,30#请输入账号|账号长度为:min到:max位"`
|
||||
Pass string `p:"password1" v:"required|length:6,30#请输入密码|密码长度不够"`
|
||||
Pass2 string `p:"password2" v:"required|length:6,30|same:password1#请确认密码|密码长度不够|两次密码不一致"`
|
||||
}
|
||||
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/parse", func(r *ghttp.Request) {
|
||||
var req *RegisterReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
r.Response.Write(err)
|
||||
} else {
|
||||
r.Response.Write("ok")
|
||||
}
|
||||
})
|
||||
s.SetPort(p)
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
prefix := fmt.Sprintf("http://127.0.0.1:%d", p)
|
||||
client := g.Client()
|
||||
client.SetPrefix(prefix)
|
||||
|
||||
t.Assert(client.GetContent("/parse"), `请输入账号; 账号长度为6到30位; 请输入密码; 密码长度不够; 请确认密码; 密码长度不够; 两次密码不一致`)
|
||||
t.Assert(client.GetContent("/parse?name=john11&password1=123456&password2=123"), `密码长度不够; 两次密码不一致`)
|
||||
t.Assert(client.GetContent("/parse?name=john&password1=123456&password2=123456"), `账号长度为6到30位`)
|
||||
t.Assert(client.GetContent("/parse?name=john11&password1=123456&password2=123456"), `ok`)
|
||||
})
|
||||
}
|
||||
|
||||
@ -21,8 +21,8 @@ func (v *Validator) CheckStruct(object interface{}) Error {
|
||||
|
||||
func (v *Validator) doCheckStruct(object interface{}) Error {
|
||||
var (
|
||||
// Returning error.
|
||||
errorMaps = make(map[string]map[string]string)
|
||||
errorMaps = make(map[string]map[string]string) // Returning error.
|
||||
fieldToAliasNameMap = make(map[string]string) // Field name to alias name map.
|
||||
)
|
||||
fieldMap, err := structs.FieldMap(object, aliasNameTagPriority, true)
|
||||
if err != nil {
|
||||
@ -44,6 +44,10 @@ func (v *Validator) doCheckStruct(object interface{}) Error {
|
||||
errorMaps[k] = m
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if field.TagValue != "" {
|
||||
fieldToAliasNameMap[field.Name()] = field.TagValue
|
||||
}
|
||||
}
|
||||
}
|
||||
// It here must use structs.TagFields not structs.FieldMap to ensure error sequence.
|
||||
@ -61,8 +65,7 @@ func (v *Validator) doCheckStruct(object interface{}) Error {
|
||||
checkRules = make(map[string]string)
|
||||
customMessage = make(CustomMsg)
|
||||
checkValueData = v.data
|
||||
fieldAliases = make(map[string]string) // Alias names for `messages` overwriting struct tag names.
|
||||
errorRules = make([]string, 0) // Sequence rules.
|
||||
errorRules = make([]string, 0) // Sequence rules.
|
||||
)
|
||||
if checkValueData == nil {
|
||||
checkValueData = object
|
||||
@ -128,19 +131,33 @@ func (v *Validator) doCheckStruct(object interface{}) Error {
|
||||
// Merge the custom validation rules with rules in struct tag.
|
||||
// The custom rules has the most high priority that can overwrite the struct tag rules.
|
||||
for _, field := range tagField {
|
||||
fieldName := field.Name()
|
||||
// sequence tag == struct tag
|
||||
// The name here is alias of field name.
|
||||
name, rule, msg := parseSequenceTag(field.TagValue)
|
||||
var (
|
||||
fieldName = field.Name() // Attribute name.
|
||||
name, rule, msg = parseSequenceTag(field.TagValue) // The `name` is different from `attribute alias`, which is used for validation only.
|
||||
)
|
||||
if len(name) == 0 {
|
||||
name = fieldName
|
||||
if v, ok := fieldToAliasNameMap[fieldName]; ok {
|
||||
// It uses alias name of the attribute if its alias name tag exists.
|
||||
name = v
|
||||
} else {
|
||||
// It or else uses the attribute name directly.
|
||||
name = fieldName
|
||||
}
|
||||
} else {
|
||||
fieldAliases[fieldName] = name
|
||||
// It uses the alias name from validation rule.
|
||||
fieldToAliasNameMap[fieldName] = name
|
||||
}
|
||||
// It here extends the params map using alias names.
|
||||
// Note that the variable `name` might be alias name or attribute name.
|
||||
if _, ok := inputParamMap[name]; !ok {
|
||||
if !v.useDataInsteadOfObjectAttributes {
|
||||
inputParamMap[name] = field.Value.Interface()
|
||||
} else {
|
||||
if name != fieldName {
|
||||
if foundKey, foundValue := gutil.MapPossibleItemByKey(inputParamMap, fieldName); foundKey != "" {
|
||||
inputParamMap[name] = foundValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if _, ok := checkRules[name]; !ok {
|
||||
@ -184,7 +201,7 @@ func (v *Validator) doCheckStruct(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, v := range msg {
|
||||
if a, ok := fieldAliases[k]; ok {
|
||||
if a, ok := fieldToAliasNameMap[k]; ok {
|
||||
// Overwrite the key of field name.
|
||||
customMessage[a] = v
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user