fix issue in function Parse for package ghttp

This commit is contained in:
John Guo
2021-06-02 21:12:27 +08:00
parent 702a296258
commit 742c7913ea
2 changed files with 63 additions and 11 deletions

View File

@ -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`)
})
}

View File

@ -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 {