From 0754f879e88fe18df3eefaefba838759ebf02320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Thu, 20 Mar 2025 18:58:53 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E6=95=B4=E5=90=88=E5=B5=8C=E5=A5=97?= =?UTF-8?q?=E7=BB=93=E6=9E=84,=20=E5=9F=BA=E7=A1=80=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- validate.go | 4 +--- validate_test.go | 22 +++++++++++++++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/validate.go b/validate.go index b507034..4649e16 100644 --- a/validate.go +++ b/validate.go @@ -15,7 +15,6 @@ import ( dynamicStructGenerate "git.zhangdeman.cn/zhangdeman/dynamic-struct" "git.zhangdeman.cn/zhangdeman/json_filter/gjson_hack" "git.zhangdeman.cn/zhangdeman/serialize" - "git.zhangdeman.cn/zhangdeman/wrapper" "github.com/go-playground/validator/v10" "github.com/tidwall/gjson" "github.com/tidwall/sjson" @@ -75,10 +74,9 @@ func (h *handle) Run() ([]byte, error) { // 没出现异常, 但是value为nil, 视作参数不存在处理 continue } - fieldName := wrapper.String(field.JsonTag).SnakeCaseToCamel() // TODO : 支持嵌套结构体 fieldTag := h.generateTag(field) - h.dynamicStruct.AddField(fieldName, "", sourceValue, fieldTag, false) + h.dynamicStruct.AddField(field.JsonTag, "", sourceValue, fieldTag, false) } val := h.dynamicStruct.Build().New() if err := serialize.JSON.UnmarshalWithNumber([]byte(h.formatVal), &val); nil != err { diff --git a/validate_test.go b/validate_test.go index b4a8156..708e070 100644 --- a/validate_test.go +++ b/validate_test.go @@ -16,11 +16,19 @@ import ( // TestRun_Simple_Data 无嵌套、无复杂数据类型的处理 func TestRun_Simple_Data(t *testing.T) { - testMap := map[string]any{ - "age": 18, + userInfo := map[string]any{ + "age": 1800, "height": 179.5, "name": "baicha", } + companyInfo := map[string]any{ + "address": "beijing", + } + + testMap := map[string]any{ + "user": userInfo, + "company": companyInfo, + } sourceByteData, _ := json.Marshal(testMap) fieldList := []StructField{ { @@ -34,15 +42,15 @@ func TestRun_Simple_Data(t *testing.T) { }, { Tag: "max", - Args: []string{"20"}, + Args: []string{"2000"}, }, }, DefaultValue: "", - SourcePath: "age", + SourcePath: "user.age", TargetPath: "user_age", - Errmsg: "年龄必须在[1,20]之间", + Errmsg: "年龄必须在[1,2000]之间", }, } - _, err := Run(sourceByteData, fieldList) - fmt.Println(err) + res, err := Run(sourceByteData, fieldList) + fmt.Println(err, string(res)) } From be6b8e644fc8442cc3e8e21635887f5cb4f942bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Fri, 21 Mar 2025 16:48:16 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=BA=90=E4=B8=8D?= =?UTF-8?q?=E5=AD=98=E5=9C=A8=E6=8C=87=E5=AE=9A=E6=95=B0=E6=8D=AE,?= =?UTF-8?q?=E7=94=9F=E6=88=90=E7=9B=AE=E6=A0=87=E7=BB=93=E6=9E=84=E4=BD=93?= =?UTF-8?q?=E4=B9=9F=E9=9C=80=E8=A6=81=E7=94=9F=E6=88=90=E5=AF=B9=E5=BA=94?= =?UTF-8?q?=E7=9A=84=E7=BB=93=E6=9E=84=E4=BD=93,=E5=90=A6=E5=88=99?= =?UTF-8?q?=E4=BC=9A=E4=B8=A2=E5=A4=B1=E7=9B=B8=E5=85=B3=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- validate.go | 53 ++++++++++++++++++++++++++++++++++++------------ validate_test.go | 33 ++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index d9b83bf..778c81f 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ require ( git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20250319072714-eab2a7abde63 git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20241205105007-b8c8c9d4338c git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd - git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250302133417-c1588abcb436 github.com/go-playground/validator/v10 v10.25.0 github.com/tidwall/gjson v1.18.0 github.com/tidwall/sjson v1.2.5 @@ -16,6 +15,7 @@ require ( require ( git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 // indirect git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e // indirect + git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250302133417-c1588abcb436 // indirect github.com/BurntSushi/toml v1.5.0 // indirect github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect diff --git a/validate.go b/validate.go index 4649e16..d4de74a 100644 --- a/validate.go +++ b/validate.go @@ -35,23 +35,45 @@ func init() { // Date : 15:12 2025/3/18 func Run(sourceData []byte, fieldList []StructField) ([]byte, error) { handleInstance := &handle{ - sourceData: sourceData, - fieldList: fieldList, - dynamicStruct: dynamicStructGenerate.NewStruct(), + sourceData: sourceData, + fieldList: fieldList, + parentFieldTable: map[string]bool{}, } + tagTable := map[string]string{} + for _, item := range fieldList { + tagTable[item.TargetPath] = handleInstance.generateTag(item) + // 检测当前字段是否是某一个字段的父级字段 + for _, field := range fieldList { + if field.TargetPath == item.TargetPath { + continue + } + // 当前字段以itemTarget开头 + if strings.HasPrefix(field.TargetPath, item.TargetPath) { + // item.TargetPath是父级字段 + handleInstance.parentFieldTable[item.TargetPath] = true + } + } + } + handleInstance.dynamicStruct = dynamicStructGenerate.NewStruct(tagTable) + return handleInstance.Run() } type handle struct { - sourceData []byte - fieldList []StructField - dynamicStruct dynamicStructGenerate.Builder - formatVal string + sourceData []byte + fieldList []StructField + dynamicStruct dynamicStructGenerate.Builder + formatVal string + parentFieldTable map[string]bool // 父级字段路径表 } // Run 执行验证 func (h *handle) Run() ([]byte, error) { for _, field := range h.fieldList { + if h.parentFieldTable[field.TargetPath] { + // 中间层级字段, 无需额外处理 + continue + } if len(field.Errmsg) == 0 { field.Errmsg = field.JsonTag + " : 参数校验不通过" } @@ -70,12 +92,14 @@ func (h *handle) Run() ([]byte, error) { if nil != err { return nil, err } + // 支持嵌套结构体 + fieldTag := h.generateTag(field) if nil == sourceValue { // 没出现异常, 但是value为nil, 视作参数不存在处理 + // TODO: 这里需要设置为对应类型的零值 + h.dynamicStruct.AddField(field.JsonTag, "", "", fieldTag, false) continue } - // TODO : 支持嵌套结构体 - fieldTag := h.generateTag(field) h.dynamicStruct.AddField(field.JsonTag, "", sourceValue, fieldTag, false) } val := h.dynamicStruct.Build().New() @@ -104,11 +128,14 @@ func (h *handle) checkRequired(field StructField) (bool, bool) { if isHasRequiredRule { required = true } - if required && !isHasRequiredRule { - // 必传, 但是没有必传校验规则 - return true, true + if required { + if !isHasRequiredRule { + // 必传, 但是没有必传校验规则 + return true, true + } + return true, false } - return true, false + return false, false } // getSourceDataValue 获取源数据值 diff --git a/validate_test.go b/validate_test.go index 708e070..6e57a99 100644 --- a/validate_test.go +++ b/validate_test.go @@ -50,6 +50,39 @@ func TestRun_Simple_Data(t *testing.T) { TargetPath: "user_age", Errmsg: "年龄必须在[1,2000]之间", }, + { + JsonTag: "company_name", + Type: consts.DataTypeString, + Required: false, + RuleList: []Rule{ + { + Tag: "min", + Args: []string{"1"}, + }, + { + Tag: "max", + Args: []string{"20"}, + }, + }, + DefaultValue: "", + SourcePath: "company.name", + TargetPath: "company.cname", + Errmsg: "公司名称必须在[1,20]之间", + }, + { + JsonTag: "company", + Type: consts.DataTypeString, + Required: false, + RuleList: []Rule{ + { + Tag: "required", + }, + }, + DefaultValue: "", + SourcePath: "company", + TargetPath: "company", + Errmsg: "公司信息必传", + }, } res, err := Run(sourceByteData, fieldList) fmt.Println(err, string(res)) From f42606bf682d522d15aa2d68d5e9eec529108ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Fri, 21 Mar 2025 18:48:05 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E7=9A=84BUG=20+=20=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E4=B8=8D=E5=90=8C=E7=B1=BB=E5=9E=8B=E6=95=B0=E6=8D=AE=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E5=80=BC=E7=9A=84=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 6 +++--- go.sum | 8 ++++++++ validate.go | 26 ++++++++++++-------------- validate_test.go | 10 +++------- 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 778c81f..55ace56 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module git.zhangdeman.cn/gateway/validate go 1.24.1 require ( - git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250227040546-863c03f34bb8 + git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321102241-d6e86b64f7ca git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20250319072714-eab2a7abde63 - git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20241205105007-b8c8c9d4338c + git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20250321103029-786c03293a28 git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd github.com/go-playground/validator/v10 v10.25.0 github.com/tidwall/gjson v1.18.0 @@ -15,7 +15,7 @@ require ( require ( git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 // indirect git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e // indirect - git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250302133417-c1588abcb436 // indirect + git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250321102712-1cbfbe959740 // indirect github.com/BurntSushi/toml v1.5.0 // indirect github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect diff --git a/go.sum b/go.sum index e4eb31f..6fc1460 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,13 @@ git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250227040546-863c03f34bb8 h1:VEifPc+vkpEQoX9rj7zxmT1m+IA81XjOxe7+Z1aqWNM= git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250227040546-863c03f34bb8/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k= +git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321101544-734d9a9f7733 h1:j5tG00W5C+1kYLJV73Iw3wvMo212x4taUHGolf3kikQ= +git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321101544-734d9a9f7733/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k= +git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321102241-d6e86b64f7ca h1:uxjzbY5fDozjyK6jkoQtuQouVTcVfXjbe3chARYSjRM= +git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321102241-d6e86b64f7ca/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k= git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20241205105007-b8c8c9d4338c h1:y8WLSdY8dBkKmazLt/XokW/LGz3hbdvNUdCUnsWXpRw= git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20241205105007-b8c8c9d4338c/go.mod h1:GzCzTobrpI6J94Cluj9gjN/o5ZdNEyrXQcfGfj05ohs= +git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20250321103029-786c03293a28 h1:wzEv9TXimkXuvjIgLuU+JETmWzj3AjfS3JA2cvU51xM= +git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20250321103029-786c03293a28/go.mod h1:RHYpM8BsZg9CuK78oY0+/n3g4kHMXk04+Gj1Sfg6E3U= git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 h1:gUDlQMuJ4xNfP2Abl1Msmpa3fASLWYkNlqDFF/6GN0Y= git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0/go.mod h1:VHb9qmhaPDAQDcS6vUiDCamYjZ4R5lD1XtVsh55KsMI= git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd h1:q7GG14qgXKB4MEXQFOe7/UYebsqMfPaSX80TcPdOosI= @@ -10,6 +16,8 @@ git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e h1:Q973S6Cc git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e/go.mod h1:VpPjBlwz8U+OxZuxzHQBv1aEEZ3pStH6bZvT21ADEbI= git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250302133417-c1588abcb436 h1:SM4zc54W2wmM72+4pMNQ8iS371H6lj4J8rj8KJKf7pw= git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250302133417-c1588abcb436/go.mod h1:YJ1FlvFgkfAHkxkt3l5rKKUqEpQkNMbCFDzDmgteEU8= +git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250321102712-1cbfbe959740 h1:zPUoylfJTbc0EcxW+NEzOTBmoeFZ2I/rLFBnEzxb4Wk= +git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250321102712-1cbfbe959740/go.mod h1:1ct92dbVc49pmXusA/iGfcQUJzcYmJ+cjAhgc3sDv1I= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ= diff --git a/validate.go b/validate.go index d4de74a..29f35ea 100644 --- a/validate.go +++ b/validate.go @@ -88,19 +88,14 @@ func (h *handle) Run() ([]byte, error) { Args: nil, }) } - sourceValue, err := h.getSourceDataValue(field) - if nil != err { + // 格式化数据 + if _, err := h.formatDataValue(field); nil != err { return nil, err } // 支持嵌套结构体 fieldTag := h.generateTag(field) - if nil == sourceValue { - // 没出现异常, 但是value为nil, 视作参数不存在处理 - // TODO: 这里需要设置为对应类型的零值 - h.dynamicStruct.AddField(field.JsonTag, "", "", fieldTag, false) - continue - } - h.dynamicStruct.AddField(field.JsonTag, "", sourceValue, fieldTag, false) + // 这里需要设置为对应类型的零值就行, 此处传入值的目的只是为了确认数据类型 + h.dynamicStruct.AddField(field.JsonTag, "", consts.GetDataTypeDefaultValue(field.Type), fieldTag, false) } val := h.dynamicStruct.Build().New() if err := serialize.JSON.UnmarshalWithNumber([]byte(h.formatVal), &val); nil != err { @@ -139,7 +134,7 @@ func (h *handle) checkRequired(field StructField) (bool, bool) { } // getSourceDataValue 获取源数据值 -func (h *handle) getSourceDataValue(field StructField) (any, error) { +func (h *handle) formatDataValue(field StructField) (any, error) { sourceValue := gjson.GetBytes(h.sourceData, field.SourcePath) if !sourceValue.Exists() { if field.Required { @@ -171,6 +166,7 @@ func (h *handle) getSourceDataValue(field StructField) (any, error) { } }() switch field.Type { + case consts.DataTypeInt: // Int类型 fallthrough case consts.DataTypeIntPtr: // Uint类型 @@ -181,15 +177,17 @@ func (h *handle) getSourceDataValue(field StructField) (any, error) { case consts.DataTypeUintPtr: // Uint类型 val, err = gjson_hack.Uint(sourceValue) return val, err - case consts.DataTypeFloat: + case consts.DataTypeFloat32: fallthrough - case consts.DataTypeFloatPtr: // Float类型 + case consts.DataTypeFloat32Ptr: // Float类型 val, err = gjson_hack.Float64(sourceValue) return val, err case consts.DataTypeString: // String类型 - return sourceValue.String(), nil + val = sourceValue.String() + return val, nil case consts.DataTypeBool: // Bool类型 - return sourceValue.Bool(), nil + val = sourceValue.Bool() + return val, nil case consts.DataTypeSliceFloat: // Float slice val, err = gjson_hack.SliceFloat(sourceValue) return val, err diff --git a/validate_test.go b/validate_test.go index 6e57a99..c21720c 100644 --- a/validate_test.go +++ b/validate_test.go @@ -23,6 +23,7 @@ func TestRun_Simple_Data(t *testing.T) { } companyInfo := map[string]any{ "address": "beijing", + "name": "xxxx", } testMap := map[string]any{ @@ -56,17 +57,12 @@ func TestRun_Simple_Data(t *testing.T) { Required: false, RuleList: []Rule{ { - Tag: "min", - Args: []string{"1"}, - }, - { - Tag: "max", - Args: []string{"20"}, + Tag: "required", }, }, DefaultValue: "", SourcePath: "company.name", - TargetPath: "company.cname", + TargetPath: "company.company_name", Errmsg: "公司名称必须在[1,20]之间", }, { From 9859cba9931bea91526aa983775ac4868f8f6166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Fri, 21 Mar 2025 22:53:28 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E5=AD=98=E5=9C=A8=E5=BF=85=E4=BC=A0=E9=AA=8C=E8=AF=81=E8=A7=84?= =?UTF-8?q?=E5=88=99=E7=9A=84BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- validate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate.go b/validate.go index 29f35ea..8ebb081 100644 --- a/validate.go +++ b/validate.go @@ -130,7 +130,7 @@ func (h *handle) checkRequired(field StructField) (bool, bool) { } return true, false } - return false, false + return false, isHasRequiredRule } // getSourceDataValue 获取源数据值 From d973b5c5fce7c120733d73e906531d7646d51974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Fri, 21 Mar 2025 23:01:41 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=AE=BE=E7=BD=AE=E9=BB=98=E8=AE=A4=E5=80=BC?= =?UTF-8?q?=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- define.go | 18 +++++++++--------- go.mod | 1 + go.sum | 2 ++ validate.go | 8 ++++++++ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/define.go b/define.go index b9bd623..bdf1997 100644 --- a/define.go +++ b/define.go @@ -14,23 +14,23 @@ import ( const ( TagErrMsg = "err" // json结构体中, 错误信息 tag 字段 TagValidate = "validator" // json结构体中, 验证规则 rule 字段 - TagDefaultValue = "d" // json结构体中默认值标签 + TagDefaultValue = "default" // json结构体中默认值标签 ) // Rule 规则定义 type Rule struct { Tag string `json:"tag" dc:"规则标签,如:required, email, phone, etc."` // 规则标签,如:required, email, phone, etc. - Args []string `json:"args" dc:"规则参数"` // 规则参数,如: Tag=min, Args=[1], 则会转化成验证规则 min=1 + Args []string `json:"args" dc:"规则参数"` // 规则参数,如: Tag=min, Args=[1], 则会转化成验证规则 min=1 } // StructField 结构体字段定义 type StructField struct { - JsonTag string `json:"json_tag" dc:"字段对外输出的json标签"` // 结构体字段名称, 不单独设置, 从 TargetPath 解析 - Type consts.DataType `json:"type" dc:"字段的数据类型"` // 字段的数据类型 - Required bool `json:"required" dc:"是否必传"` // 对应验证规则的 required 属性, 在非必传的情况下, 字段不存在, 不会进行规则验证, 字段存在, 才会进行验证, Required == false 时, 会在 RuleList 检测是否有required 规则 - RuleList []Rule `json:"rule_list" dc:"字段规则列表"` // 字段规则列表 - DefaultValue string `json:"default_value" dc:"字段默认值"` // 字段默认值, 仅对非必传字段生效, 统一用字符串类型, 后面会转换成 FieldType 类型 - SourcePath string `json:"source_path" dc:"读取数据的数据源路径"` // 读取数据的数据源路径 - TargetPath string `json:"target_path" dc:"数据设置哪一个路径"` // 目标数据路径 + JsonTag string `json:"json_tag" dc:"字段对外输出的json标签"` // 结构体字段名称, 不单独设置, 从 TargetPath 解析 + Type consts.DataType `json:"type" dc:"字段的数据类型"` // 字段的数据类型 + Required bool `json:"required" dc:"是否必传"` // 对应验证规则的 required 属性, 在非必传的情况下, 字段不存在, 不会进行规则验证, 字段存在, 才会进行验证, Required == false 时, 会在 RuleList 检测是否有required 规则 + RuleList []Rule `json:"rule_list" dc:"字段规则列表"` // 字段规则列表 + DefaultValue string `json:"default_value" dc:"字段默认值"` // 字段默认值, 仅对非必传字段生效, 统一用字符串类型, 后面会转换成 FieldType 类型 + SourcePath string `json:"source_path" dc:"读取数据的数据源路径"` // 读取数据的数据源路径 + TargetPath string `json:"target_path" dc:"数据设置哪一个路径"` // 目标数据路径 Errmsg string `json:"errmsg" dc:"规则验证不通过时, 报错的信息"` // 规则验证不通过时, 报错的信息 } diff --git a/go.mod b/go.mod index 55ace56..21b94e1 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20250319072714-eab2a7abde63 git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20250321103029-786c03293a28 git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd + github.com/creasty/defaults v1.8.0 github.com/go-playground/validator/v10 v10.25.0 github.com/tidwall/gjson v1.18.0 github.com/tidwall/sjson v1.2.5 diff --git a/go.sum b/go.sum index 6fc1460..5718e3d 100644 --- a/go.sum +++ b/go.sum @@ -22,6 +22,8 @@ github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ= github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg= +github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk= +github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= diff --git a/validate.go b/validate.go index 8ebb081..55ba407 100644 --- a/validate.go +++ b/validate.go @@ -15,6 +15,7 @@ import ( dynamicStructGenerate "git.zhangdeman.cn/zhangdeman/dynamic-struct" "git.zhangdeman.cn/zhangdeman/json_filter/gjson_hack" "git.zhangdeman.cn/zhangdeman/serialize" + "github.com/creasty/defaults" "github.com/go-playground/validator/v10" "github.com/tidwall/gjson" "github.com/tidwall/sjson" @@ -101,6 +102,10 @@ func (h *handle) Run() ([]byte, error) { if err := serialize.JSON.UnmarshalWithNumber([]byte(h.formatVal), &val); nil != err { return nil, err } + if err := defaults.Set(&val); nil != err { + // 默认值设置失败 + return nil, err + } if err := validatorInstance.Struct(val); nil != err { return nil, GetValidateErr(val, err, TagErrMsg) } @@ -231,6 +236,9 @@ func (h *handle) generateTag(field StructField) string { // 验证规则tag tagList = append(tagList, fmt.Sprintf(`%s:"%s"`, TagValidate, strings.Join(validateRuleList, ","))) // 默认值 + if field.DefaultValue == "-" && (field.Type == consts.DataTypeString || field.Type == consts.DataTypeStringPtr) { + field.DefaultValue = "" + } tagList = append(tagList, fmt.Sprintf(`%s:"%s"`, TagDefaultValue, field.DefaultValue)) return strings.Join(tagList, " ") } From a7d4df6e6e8161c049fb9d55e3f3bb4fd5abd2f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Fri, 21 Mar 2025 23:42:35 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E5=B5=8C=E5=A5=97=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E4=B8=AD=E9=97=B4=E5=B1=82=E7=BA=A7=E6=94=AF=E6=8C=81=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E5=BF=85=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- validate.go | 13 ++++++++----- validate_test.go | 28 ++++++++++++++-------------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/validate.go b/validate.go index 55ba407..ceedbe6 100644 --- a/validate.go +++ b/validate.go @@ -71,15 +71,18 @@ type handle struct { // Run 执行验证 func (h *handle) Run() ([]byte, error) { for _, field := range h.fieldList { - if h.parentFieldTable[field.TargetPath] { - // 中间层级字段, 无需额外处理 - continue - } if len(field.Errmsg) == 0 { field.Errmsg = field.JsonTag + " : 参数校验不通过" } required, hasRequired := h.checkRequired(field) field.Required = required + if h.parentFieldTable[field.TargetPath] { + // 中间层级字段, 无需额外处理, 验一下必传就行 + if !gjson.GetBytes(h.sourceData, field.SourcePath).Exists() && field.Required { + return nil, errors.New(field.TargetPath + " : 数据源路径数据不存在 => " + field.SourcePath) + } + continue + } if field.Required && !hasRequired { if nil == field.RuleList { field.RuleList = make([]Rule, 0) @@ -102,7 +105,7 @@ func (h *handle) Run() ([]byte, error) { if err := serialize.JSON.UnmarshalWithNumber([]byte(h.formatVal), &val); nil != err { return nil, err } - if err := defaults.Set(&val); nil != err { + if err := defaults.Set(val); nil != err { // 默认值设置失败 return nil, err } diff --git a/validate_test.go b/validate_test.go index c21720c..705f302 100644 --- a/validate_test.go +++ b/validate_test.go @@ -51,20 +51,6 @@ func TestRun_Simple_Data(t *testing.T) { TargetPath: "user_age", Errmsg: "年龄必须在[1,2000]之间", }, - { - JsonTag: "company_name", - Type: consts.DataTypeString, - Required: false, - RuleList: []Rule{ - { - Tag: "required", - }, - }, - DefaultValue: "", - SourcePath: "company.name", - TargetPath: "company.company_name", - Errmsg: "公司名称必须在[1,20]之间", - }, { JsonTag: "company", Type: consts.DataTypeString, @@ -79,6 +65,20 @@ func TestRun_Simple_Data(t *testing.T) { TargetPath: "company", Errmsg: "公司信息必传", }, + { + JsonTag: "company_name", + Type: consts.DataTypeString, + Required: false, + RuleList: []Rule{ + { + Tag: "required", + }, + }, + DefaultValue: "", + SourcePath: "company.name", + TargetPath: "company.company_name", + Errmsg: "公司名称必须在[1,20]之间", + }, } res, err := Run(sourceByteData, fieldList) fmt.Println(err, string(res)) From fd51bf84632611cc1fecafea8b7653e303c65346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Fri, 21 Mar 2025 23:44:01 +0800 Subject: [PATCH 7/7] update go mod --- go.mod | 4 +--- go.sum | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 21b94e1..0fbb584 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.24.1 require ( git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321102241-d6e86b64f7ca - git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20250319072714-eab2a7abde63 + git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20250321154326-850866d6f568 git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20250321103029-786c03293a28 git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd github.com/creasty/defaults v1.8.0 @@ -35,5 +35,3 @@ require ( golang.org/x/text v0.23.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -replace git.zhangdeman.cn/zhangdeman/dynamic-struct => ../dynamic-struct diff --git a/go.sum b/go.sum index 5718e3d..f19a9ee 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,9 @@ git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321101544-734d9a9f7733 h1:j5tG00 git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321101544-734d9a9f7733/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k= git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321102241-d6e86b64f7ca h1:uxjzbY5fDozjyK6jkoQtuQouVTcVfXjbe3chARYSjRM= git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321102241-d6e86b64f7ca/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k= +git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20250319072714-eab2a7abde63/go.mod h1:10CdqBLr/d7vDQ7HlZoPdJWV9PF7zNM9QmhKt9Iz0/8= +git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20250321154326-850866d6f568 h1:LKmmtWBhhw2ne8/mZ5qsgm9d4tX0ut2u1FFrM745N7g= +git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20250321154326-850866d6f568/go.mod h1:S5KcY8KjsOFC/jPaUz4ndxcD8Prqwwsa7Thp9VHBD0Y= git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20241205105007-b8c8c9d4338c h1:y8WLSdY8dBkKmazLt/XokW/LGz3hbdvNUdCUnsWXpRw= git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20241205105007-b8c8c9d4338c/go.mod h1:GzCzTobrpI6J94Cluj9gjN/o5ZdNEyrXQcfGfj05ohs= git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20250321103029-786c03293a28 h1:wzEv9TXimkXuvjIgLuU+JETmWzj3AjfS3JA2cvU51xM=