191 lines
5.5 KiB
Go
191 lines
5.5 KiB
Go
// Package validate ...
|
|
//
|
|
// Description : validate ...
|
|
//
|
|
// Author : go_developer@163.com<白茶清欢>
|
|
//
|
|
// Date : 2025-03-18 15:10
|
|
package validate
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"git.zhangdeman.cn/zhangdeman/consts"
|
|
"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"
|
|
"strings"
|
|
)
|
|
|
|
var validatorInstance = validator.New()
|
|
|
|
// Run 执行参数验证
|
|
//
|
|
// Author : go_developer@163.com<白茶清欢>
|
|
//
|
|
// Date : 15:12 2025/3/18
|
|
func Run(sourceData []byte, fieldList []StructField) ([]byte, error) {
|
|
handleInstance := &handle{
|
|
sourceData: sourceData,
|
|
fieldList: fieldList,
|
|
dynamicStruct: wrapper.NewDynamic(),
|
|
}
|
|
return handleInstance.Run()
|
|
}
|
|
|
|
type handle struct {
|
|
sourceData []byte
|
|
fieldList []StructField
|
|
dynamicStruct *wrapper.DynamicStruct
|
|
}
|
|
|
|
// Run 执行验证
|
|
func (h *handle) Run() ([]byte, error) {
|
|
for _, field := range h.fieldList {
|
|
if len(field.Errmsg) == 0 {
|
|
field.Errmsg = field.JsonTag + " : 参数校验不通过"
|
|
}
|
|
required, hasRequired := h.checkRequired(field)
|
|
field.Required = required
|
|
if field.Required && !hasRequired {
|
|
if nil == field.RuleList {
|
|
field.RuleList = make([]Rule, 0)
|
|
}
|
|
field.RuleList = append(field.RuleList, Rule{
|
|
Tag: consts.ValidatorRuleCommonRequired.String(),
|
|
Args: nil,
|
|
})
|
|
}
|
|
sourceValue, err := h.getSourceDataValue(field)
|
|
if nil != err {
|
|
return nil, err
|
|
}
|
|
if nil == sourceValue {
|
|
// 没出现异常, 但是value为nil, 视作参数不存在处理
|
|
continue
|
|
}
|
|
// fieldName := wrapper.String(field.JsonTag).SnakeCaseToCamel()
|
|
h.dynamicStruct.AddAny(field.JsonTag, h.generateTag(field), "dynamic_struct", sourceValue)
|
|
}
|
|
val := h.dynamicStruct.ToStructDefaultValue()
|
|
if err := serialize.JSON.Transition(h.dynamicStruct.MapData(), &val); nil != err {
|
|
return nil, err
|
|
}
|
|
targetByte, _ := json.Marshal(val)
|
|
err := validatorInstance.Struct(val)
|
|
return targetByte, err
|
|
}
|
|
|
|
// checkRequired 格式化必传参数
|
|
// 返回值1, 是否必传
|
|
// 返回值2, 校验规则中是否存在必传校验
|
|
func (h *handle) checkRequired(field StructField) (bool, bool) {
|
|
required := field.Required
|
|
isHasRequiredRule := false
|
|
for _, rule := range field.RuleList {
|
|
if rule.Tag == consts.ValidatorRuleCommonRequired.String() {
|
|
isHasRequiredRule = true
|
|
break
|
|
}
|
|
}
|
|
if isHasRequiredRule {
|
|
required = true
|
|
}
|
|
if required && !isHasRequiredRule {
|
|
// 必传, 但是没有必传校验规则
|
|
return true, true
|
|
}
|
|
return true, false
|
|
}
|
|
|
|
// getSourceDataValue 获取源数据值
|
|
func (h *handle) getSourceDataValue(field StructField) (any, error) {
|
|
sourceValue := gjson.GetBytes(h.sourceData, field.SourcePath)
|
|
if !sourceValue.Exists() {
|
|
if field.Required {
|
|
return nil, errors.New(field.SourcePath + " is required")
|
|
}
|
|
if len(field.DefaultValue) > 0 {
|
|
// 非必传, 且设置了默认值, 在数据源不存在时, 这只默认值
|
|
sourceValue = gjson.Result{
|
|
Type: gjson.String,
|
|
Raw: field.DefaultValue,
|
|
Str: field.DefaultValue,
|
|
Num: 0,
|
|
Index: 0,
|
|
Indexes: nil,
|
|
}
|
|
} else {
|
|
// 非必传, 且没有默认值, 就当做数据不存在
|
|
return nil, nil
|
|
}
|
|
}
|
|
switch field.Type {
|
|
case consts.DataTypeInt: // Int类型
|
|
fallthrough
|
|
case consts.DataTypeIntPtr: // Uint类型
|
|
val, err := gjson_hack.Int(sourceValue)
|
|
return val, err
|
|
case consts.DataTypeUint:
|
|
fallthrough
|
|
case consts.DataTypeUintPtr: // Uint类型
|
|
val, err := gjson_hack.Uint(sourceValue)
|
|
return val, err
|
|
case consts.DataTypeFloat:
|
|
fallthrough
|
|
case consts.DataTypeFloatPtr: // Float类型
|
|
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)
|
|
return val, err
|
|
case consts.DataTypeSliceInt: // Int slice
|
|
val, err := gjson_hack.SliceInt(sourceValue)
|
|
return val, err
|
|
case consts.DataTypeSliceUint: // Uint slice
|
|
val, err := gjson_hack.SliceUint(sourceValue)
|
|
return val, err
|
|
case consts.DataTypeSliceString: // String slice
|
|
val, err := gjson_hack.SliceString(sourceValue)
|
|
return val, err
|
|
case consts.DataTypeSliceBool: // Bool slice
|
|
val, err := gjson_hack.SliceBool(sourceValue)
|
|
return val, err
|
|
case consts.DataTypeMapStrAny: // Bool slice
|
|
val, err := gjson_hack.MapStrAny[any](sourceValue)
|
|
return val, err
|
|
}
|
|
return sourceValue.Value(), nil
|
|
}
|
|
|
|
// 生成结构体的tag标签
|
|
func (h *handle) generateTag(field StructField) string {
|
|
tagList := []string{
|
|
fmt.Sprintf(`json:"%s"`, field.JsonTag), // json tag
|
|
}
|
|
if len(field.Errmsg) == 0 {
|
|
field.Errmsg = field.JsonTag + ": 参数校验不通过"
|
|
}
|
|
tagList = append(tagList, fmt.Sprintf(`%s:"%s"`, TagErrMsg, field.Errmsg)) // 错误信息tag
|
|
validateRuleList := []string{}
|
|
for _, itemRule := range field.RuleList {
|
|
if len(itemRule.Args) == 0 {
|
|
validateRuleList = append(validateRuleList, itemRule.Tag)
|
|
} else {
|
|
validateRuleList = append(validateRuleList, fmt.Sprintf("%s=%s", itemRule.Tag, strings.Join(itemRule.Args, " ")))
|
|
}
|
|
}
|
|
// 验证规则tag
|
|
tagList = append(tagList, fmt.Sprintf(`%s:"%s"`, TagValidate, strings.Join(validateRuleList, ",")))
|
|
// 默认值
|
|
tagList = append(tagList, fmt.Sprintf(`%s:"%s"`, TagDefaultValue, field.DefaultValue))
|
|
return strings.Join(tagList, " ")
|
|
}
|