diff --git a/g/internal/structs/structs_tag.go b/g/internal/structs/structs_tag.go index 9040e9560..52167b3cf 100644 --- a/g/internal/structs/structs_tag.go +++ b/g/internal/structs/structs_tag.go @@ -40,7 +40,19 @@ func TagMapField(pointer interface{}, priority []string, recursive bool) map[str if v, ok := pointer.(reflect.Value); ok { fields = structs.Fields(v.Interface()) } else { - fields = structs.Fields(pointer) + rv := reflect.ValueOf(pointer) + kind := rv.Kind() + if kind == reflect.Ptr { + rv = rv.Elem() + kind = rv.Kind() + } + // If pointer is type of **struct and nil, then automatically create a temporary struct, + // which is used for structs.Fields. + if kind == reflect.Ptr && (!rv.IsValid() || rv.IsNil()) { + fields = structs.Fields(reflect.New(rv.Type().Elem()).Elem().Interface()) + } else { + fields = structs.Fields(pointer) + } } tag := "" name := "" diff --git a/g/net/ghttp/ghttp_unit_param_struct_test.go b/g/net/ghttp/ghttp_unit_param_struct_test.go new file mode 100644 index 000000000..382f24642 --- /dev/null +++ b/g/net/ghttp/ghttp_unit_param_struct_test.go @@ -0,0 +1,67 @@ +// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package ghttp_test + +import ( + "fmt" + "testing" + "time" + + "github.com/gogf/gf/g/util/gvalid" + + "github.com/gogf/gf/g" + "github.com/gogf/gf/g/net/ghttp" + "github.com/gogf/gf/g/test/gtest" +) + +func Test_Params_Struct(t *testing.T) { + type User struct { + Id int + Name string + Pass1 string `params:"password1"` + Pass2 string `params:"password2" gvalid:"passwd1 @required|length:2,20|password3||密码强度不足"` + } + p := ports.PopRand() + s := g.Server(p) + s.BindHandler("/struct1", func(r *ghttp.Request) { + if m := r.GetMap(); len(m) > 0 { + user := new(User) + r.GetToStruct(user) + r.Response.Write(user.Id, user.Name, user.Pass1, user.Pass2) + } + }) + s.BindHandler("/struct2", func(r *ghttp.Request) { + if m := r.GetMap(); len(m) > 0 { + user := (*User)(nil) + r.GetToStruct(&user) + r.Response.Write(user.Id, user.Name, user.Pass1, user.Pass2) + } + }) + s.BindHandler("/struct-valid", func(r *ghttp.Request) { + if m := r.GetMap(); len(m) > 0 { + user := new(User) + r.GetToStruct(user) + err := gvalid.CheckStruct(user, nil) + r.Response.Write(err.Maps()) + } + }) + s.SetPort(p) + s.SetDumpRouteMap(false) + s.Start() + defer s.Shutdown() + + // 等待启动完成 + time.Sleep(time.Second) + gtest.Case(t, func() { + client := ghttp.NewClient() + client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p)) + gtest.Assert(client.GetContent("/struct1", `id=1&name=john&password1=123&password2=456`), `1john123456`) + gtest.Assert(client.PostContent("/struct1", `id=1&name=john&password1=123&password2=456`), `1john123456`) + gtest.Assert(client.PostContent("/struct2", `id=1&name=john&password1=123&password2=456`), `1john123456`) + gtest.Assert(client.PostContent("/struct-valid", `id=1&name=john&password1=123&password2=0`), `{"passwd1":{"length":"字段长度为2到20个字符","password3":"密码格式不合法,密码格式为任意6-18位的可见字符,必须包含大小写字母、数字和特殊字符"}}`) + }) +} diff --git a/geg/util/gvalid/gvalid_struct3.go b/geg/util/gvalid/gvalid_struct3.go index cfe55a33e..7b0b9e356 100644 --- a/geg/util/gvalid/gvalid_struct3.go +++ b/geg/util/gvalid/gvalid_struct3.go @@ -8,14 +8,12 @@ import ( // same校验 func main() { type User struct { - Password string `gvalid:"password@password"` - ConfirmPassword string `gvalid:"confirm_password@password|same:password#|密码与确认密码不一致"` + Pass string `gvalid:"passwd1 @required|length:2,20|password3||密码强度不足"` } user := &User{ - Password: "123456", - ConfirmPassword: "", + Pass: "1", } - g.Dump(gvalid.CheckStruct(user, nil)) + g.Dump(gvalid.CheckStruct(user, nil).Maps()) }