From db7779e488dc80dfb18b2a47445a79aab5fde427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Wed, 19 Mar 2025 15:53:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=9F=BA=E7=A1=80=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=9F=BA=E4=BA=8E=E8=BF=90=E8=A1=8C=E6=97=B6=E7=9A=84?= =?UTF-8?q?=E5=8A=A8=E6=80=81=E7=BB=93=E6=9E=84=E4=BD=93=E7=94=9F=E6=88=90?= =?UTF-8?q?=20+=20=E5=8F=82=E6=95=B0=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- format.go | 55 +++++++++++++++++++++++++++++++++++++++++++ go.mod | 8 ++++--- go.sum | 7 ++++++ validate.go | 61 +++++++++++++++++++++++++++++++++--------------- validate_test.go | 4 ++-- 5 files changed, 111 insertions(+), 24 deletions(-) create mode 100644 format.go diff --git a/format.go b/format.go new file mode 100644 index 0000000..40dfe83 --- /dev/null +++ b/format.go @@ -0,0 +1,55 @@ +// Package validate ... +// +// Description : validate ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-03-19 15:50 +package validate + +import ( + "errors" + "fmt" + "github.com/go-playground/validator/v10" + "reflect" + "strings" +) + +// GetValidateErr 格式化验证结果错误信息 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 15:51 2025/3/19 +func GetValidateErr(obj any, rawErr error) error { + if nil == rawErr { + return nil + } + if nil == obj { + return rawErr + } + var ( + ok bool + validationErrs validator.ValidationErrors + errString []string + field reflect.StructField + ) + if ok = errors.As(rawErr, &validationErrs); !ok { + return rawErr + } + objType := reflect.TypeOf(obj) + if objType.Kind() == reflect.Ptr { + objType = objType.Elem() + } + for _, validationErr := range validationErrs { + if field, ok = objType.FieldByName(validationErr.Field()); ok { + if e := field.Tag.Get(TagErrMsg); e != "" { + errString = append(errString, fmt.Sprintf("%s: %s", field.Tag.Get("json"), e)) + continue + } else { + errString = append(errString, fmt.Sprintf("%s: %v", field.Tag.Get("json"), validationErr.Value())) + } + } + errString = append(errString, validationErr.Error()) + } + return errors.New(strings.Join(errString, "\n")) +} diff --git a/go.mod b/go.mod index 9acd167..d9b83bf 100644 --- a/go.mod +++ b/go.mod @@ -4,14 +4,17 @@ go 1.24.1 require ( git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250227040546-863c03f34bb8 + 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 ) require ( git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 // indirect - git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd // indirect git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e // indirect github.com/BurntSushi/toml v1.5.0 // indirect github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect @@ -19,7 +22,6 @@ require ( github.com/go-ini/ini v1.67.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.25.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mozillazg/go-pinyin v0.20.0 // indirect @@ -33,4 +35,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace git.zhangdeman.cn/zhangdeman/wrapper => ../wrapper +replace git.zhangdeman.cn/zhangdeman/dynamic-struct => ../dynamic-struct diff --git a/go.sum b/go.sum index 5364df8..e4eb31f 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd h1:q7G git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd/go.mod h1:+D6uPSljwHywjVY5WSBY4TRVMj26TN5f5cFGEYMldjs= git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e h1:Q973S6CcWr1ICZhFI1STFOJ+KUImCl2BaIXm6YppBqI= 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= 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= @@ -18,6 +20,8 @@ github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3G github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= @@ -38,6 +42,7 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -45,6 +50,8 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= diff --git a/validate.go b/validate.go index 12e4a00..a8b4e0f 100644 --- a/validate.go +++ b/validate.go @@ -12,15 +12,22 @@ import ( "errors" "fmt" "git.zhangdeman.cn/zhangdeman/consts" + 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" "strings" ) -var validatorInstance = validator.New() +var validatorInstance *validator.Validate + +func init() { + validatorInstance = validator.New() + validatorInstance.SetTagName(TagValidate) +} // Run 执行参数验证 // @@ -31,7 +38,7 @@ func Run(sourceData []byte, fieldList []StructField) ([]byte, error) { handleInstance := &handle{ sourceData: sourceData, fieldList: fieldList, - dynamicStruct: wrapper.NewDynamic(), + dynamicStruct: dynamicStructGenerate.NewStruct(), } return handleInstance.Run() } @@ -39,7 +46,8 @@ func Run(sourceData []byte, fieldList []StructField) ([]byte, error) { type handle struct { sourceData []byte fieldList []StructField - dynamicStruct *wrapper.DynamicStruct + dynamicStruct dynamicStructGenerate.Builder + formatVal string } // Run 执行验证 @@ -67,16 +75,20 @@ func (h *handle) Run() ([]byte, error) { // 没出现异常, 但是value为nil, 视作参数不存在处理 continue } - // fieldName := wrapper.String(field.JsonTag).SnakeCaseToCamel() - h.dynamicStruct.AddAny(field.JsonTag, h.generateTag(field), "dynamic_struct", sourceValue) + fieldName := wrapper.String(field.JsonTag).SnakeCaseToCamel() + + fieldTag := h.generateTag(field) + h.dynamicStruct.AddField(fieldName, "", sourceValue, fieldTag, false) } - val := h.dynamicStruct.ToStructDefaultValue() - if err := serialize.JSON.Transition(h.dynamicStruct.MapData(), &val); nil != err { + val := h.dynamicStruct.Build().New() + if err := serialize.JSON.UnmarshalWithNumber([]byte(h.formatVal), &val); nil != err { return nil, err } + if err := validatorInstance.Struct(val); nil != err { + return nil, GetValidateErr(val, err) + } targetByte, _ := json.Marshal(val) - err := validatorInstance.Struct(val) - return targetByte, err + return targetByte, nil } // checkRequired 格式化必传参数 @@ -123,46 +135,57 @@ func (h *handle) getSourceDataValue(field StructField) (any, error) { return nil, nil } } + var ( + val any + err error + ) + defer func() { + if nil == err && nil != val { + // 更新到格式化之后的数据结构中 + h.formatVal, err = sjson.Set(h.formatVal, field.TargetPath, val) + } + }() switch field.Type { case consts.DataTypeInt: // Int类型 fallthrough case consts.DataTypeIntPtr: // Uint类型 - val, err := gjson_hack.Int(sourceValue) + val, err = gjson_hack.Int(sourceValue) return val, err case consts.DataTypeUint: fallthrough case consts.DataTypeUintPtr: // Uint类型 - val, err := gjson_hack.Uint(sourceValue) + val, err = gjson_hack.Uint(sourceValue) return val, err case consts.DataTypeFloat: fallthrough case consts.DataTypeFloatPtr: // Float类型 - val, err := gjson_hack.Float64(sourceValue) + val, err = gjson_hack.Float64(sourceValue) return val, err case consts.DataTypeString: // String类型 return sourceValue.String(), nil case consts.DataTypeBool: // Bool类型 return sourceValue.Bool(), nil case consts.DataTypeSliceFloat: // Float slice - val, err := gjson_hack.SliceFloat(sourceValue) + val, err = gjson_hack.SliceFloat(sourceValue) return val, err case consts.DataTypeSliceInt: // Int slice - val, err := gjson_hack.SliceInt(sourceValue) + val, err = gjson_hack.SliceInt(sourceValue) return val, err case consts.DataTypeSliceUint: // Uint slice - val, err := gjson_hack.SliceUint(sourceValue) + val, err = gjson_hack.SliceUint(sourceValue) return val, err case consts.DataTypeSliceString: // String slice - val, err := gjson_hack.SliceString(sourceValue) + val, err = gjson_hack.SliceString(sourceValue) return val, err case consts.DataTypeSliceBool: // Bool slice - val, err := gjson_hack.SliceBool(sourceValue) + val, err = gjson_hack.SliceBool(sourceValue) return val, err case consts.DataTypeMapStrAny: // Bool slice - val, err := gjson_hack.MapStrAny[any](sourceValue) + val, err = gjson_hack.MapStrAny[any](sourceValue) return val, err } - return sourceValue.Value(), nil + val = sourceValue.Value() + return val, nil } // 生成结构体的tag标签 diff --git a/validate_test.go b/validate_test.go index 65ce148..b4a8156 100644 --- a/validate_test.go +++ b/validate_test.go @@ -17,14 +17,14 @@ import ( // TestRun_Simple_Data 无嵌套、无复杂数据类型的处理 func TestRun_Simple_Data(t *testing.T) { testMap := map[string]any{ - "age": 180, + "age": 18, "height": 179.5, "name": "baicha", } sourceByteData, _ := json.Marshal(testMap) fieldList := []StructField{ { - JsonTag: "age", + JsonTag: "user_age", Type: consts.DataTypeInt, Required: false, RuleList: []Rule{