支持嵌套结构体验证 #1
2
go.mod
2
go.mod
@ -7,7 +7,6 @@ require (
|
|||||||
git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20250319072714-eab2a7abde63
|
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-20241205105007-b8c8c9d4338c
|
||||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd
|
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/go-playground/validator/v10 v10.25.0
|
||||||
github.com/tidwall/gjson v1.18.0
|
github.com/tidwall/gjson v1.18.0
|
||||||
github.com/tidwall/sjson v1.2.5
|
github.com/tidwall/sjson v1.2.5
|
||||||
@ -16,6 +15,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 // indirect
|
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/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/BurntSushi/toml v1.5.0 // indirect
|
||||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect
|
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
|
35
validate.go
35
validate.go
@ -37,8 +37,25 @@ func Run(sourceData []byte, fieldList []StructField) ([]byte, error) {
|
|||||||
handleInstance := &handle{
|
handleInstance := &handle{
|
||||||
sourceData: sourceData,
|
sourceData: sourceData,
|
||||||
fieldList: fieldList,
|
fieldList: fieldList,
|
||||||
dynamicStruct: dynamicStructGenerate.NewStruct(),
|
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()
|
return handleInstance.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,11 +64,16 @@ type handle struct {
|
|||||||
fieldList []StructField
|
fieldList []StructField
|
||||||
dynamicStruct dynamicStructGenerate.Builder
|
dynamicStruct dynamicStructGenerate.Builder
|
||||||
formatVal string
|
formatVal string
|
||||||
|
parentFieldTable map[string]bool // 父级字段路径表
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run 执行验证
|
// Run 执行验证
|
||||||
func (h *handle) Run() ([]byte, error) {
|
func (h *handle) Run() ([]byte, error) {
|
||||||
for _, field := range h.fieldList {
|
for _, field := range h.fieldList {
|
||||||
|
if h.parentFieldTable[field.TargetPath] {
|
||||||
|
// 中间层级字段, 无需额外处理
|
||||||
|
continue
|
||||||
|
}
|
||||||
if len(field.Errmsg) == 0 {
|
if len(field.Errmsg) == 0 {
|
||||||
field.Errmsg = field.JsonTag + " : 参数校验不通过"
|
field.Errmsg = field.JsonTag + " : 参数校验不通过"
|
||||||
}
|
}
|
||||||
@ -70,12 +92,14 @@ func (h *handle) Run() ([]byte, error) {
|
|||||||
if nil != err {
|
if nil != err {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// 支持嵌套结构体
|
||||||
|
fieldTag := h.generateTag(field)
|
||||||
if nil == sourceValue {
|
if nil == sourceValue {
|
||||||
// 没出现异常, 但是value为nil, 视作参数不存在处理
|
// 没出现异常, 但是value为nil, 视作参数不存在处理
|
||||||
|
// TODO: 这里需要设置为对应类型的零值
|
||||||
|
h.dynamicStruct.AddField(field.JsonTag, "", "", fieldTag, false)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// TODO : 支持嵌套结构体
|
|
||||||
fieldTag := h.generateTag(field)
|
|
||||||
h.dynamicStruct.AddField(field.JsonTag, "", sourceValue, fieldTag, false)
|
h.dynamicStruct.AddField(field.JsonTag, "", sourceValue, fieldTag, false)
|
||||||
}
|
}
|
||||||
val := h.dynamicStruct.Build().New()
|
val := h.dynamicStruct.Build().New()
|
||||||
@ -104,12 +128,15 @@ func (h *handle) checkRequired(field StructField) (bool, bool) {
|
|||||||
if isHasRequiredRule {
|
if isHasRequiredRule {
|
||||||
required = true
|
required = true
|
||||||
}
|
}
|
||||||
if required && !isHasRequiredRule {
|
if required {
|
||||||
|
if !isHasRequiredRule {
|
||||||
// 必传, 但是没有必传校验规则
|
// 必传, 但是没有必传校验规则
|
||||||
return true, true
|
return true, true
|
||||||
}
|
}
|
||||||
return true, false
|
return true, false
|
||||||
}
|
}
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
|
||||||
// getSourceDataValue 获取源数据值
|
// getSourceDataValue 获取源数据值
|
||||||
func (h *handle) getSourceDataValue(field StructField) (any, error) {
|
func (h *handle) getSourceDataValue(field StructField) (any, error) {
|
||||||
|
@ -50,6 +50,39 @@ func TestRun_Simple_Data(t *testing.T) {
|
|||||||
TargetPath: "user_age",
|
TargetPath: "user_age",
|
||||||
Errmsg: "年龄必须在[1,2000]之间",
|
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)
|
res, err := Run(sourceByteData, fieldList)
|
||||||
fmt.Println(err, string(res))
|
fmt.Println(err, string(res))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user