增加部分数据验证转化逻辑
This commit is contained in:
350
run.go
350
run.go
@ -7,6 +7,354 @@
|
||||
// Date : 2024-04-29 10:51
|
||||
package validator
|
||||
|
||||
func Run() {
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.zhangdeman.cn/gateway/validator/define"
|
||||
"git.zhangdeman.cn/zhangdeman/consts"
|
||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||
"git.zhangdeman.cn/zhangdeman/util"
|
||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RunForStruct 验证结构体
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:18 2024/4/29
|
||||
func RunForStruct(sourceData interface{}, ruleList []*define.FieldRule) (map[string]interface{}, error) {
|
||||
if nil == sourceData {
|
||||
return map[string]interface{}{}, nil
|
||||
}
|
||||
byteData, _ := json.Marshal(sourceData)
|
||||
var (
|
||||
sourceMapData map[string]interface{}
|
||||
err error
|
||||
)
|
||||
|
||||
d := json.NewDecoder(bytes.NewReader(byteData))
|
||||
d.UseNumber()
|
||||
if err = d.Decode(&sourceMapData); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
if err = Run(sourceMapData, ruleList); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
return sourceMapData, nil
|
||||
}
|
||||
|
||||
// Run 运行参数验证
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:13 2024/4/29
|
||||
func Run(sourceData map[string]interface{}, ruleList []*define.FieldRule) error {
|
||||
if nil == sourceData || len(sourceData) == 0 {
|
||||
return nil
|
||||
}
|
||||
byteData, _ := json.Marshal(sourceData)
|
||||
for _, itemRule := range ruleList {
|
||||
if len(itemRule.Path) == 0 {
|
||||
// 未指定验证数据位置
|
||||
continue
|
||||
}
|
||||
inputFieldVal := gjson.GetBytes(byteData, itemRule.Path)
|
||||
if formatRule, err := validate(byteData, inputFieldVal, itemRule); nil != err {
|
||||
return err
|
||||
} else {
|
||||
if !itemRule.DisableRewrite {
|
||||
// 更新数据
|
||||
byteData, _ = sjson.SetBytes(byteData, itemRule.Path, formatRule)
|
||||
}
|
||||
}
|
||||
}
|
||||
sourceData = make(map[string]interface{})
|
||||
d := json.NewDecoder(bytes.NewReader(byteData))
|
||||
d.UseNumber()
|
||||
if err := d.Decode(&sourceData); nil != err {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getDataStatus 获取数据状态
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:59 2024/4/29
|
||||
func getDataStatus(val gjson.Result, dataType string) string {
|
||||
if !val.Exists() {
|
||||
return consts.DataStatusNotFound
|
||||
}
|
||||
switch dataType {
|
||||
case consts.DataTypeString:
|
||||
if len(val.String()) == 0 {
|
||||
return consts.DataStatusIsEmpty
|
||||
}
|
||||
case consts.DataTypeFloat:
|
||||
fallthrough
|
||||
case consts.DataTypeInt:
|
||||
if val.Float() == 0 {
|
||||
return consts.DataStatusIsZero
|
||||
}
|
||||
default:
|
||||
if strings.HasPrefix(dataType, "[]") {
|
||||
// 数组
|
||||
if len(val.Array()) == 0 {
|
||||
return consts.DataStatusIsEmpty
|
||||
}
|
||||
} else if strings.HasPrefix(dataType, "map") {
|
||||
// 对象
|
||||
if len(val.Map()) == 0 {
|
||||
return consts.DataStatusIsEmpty
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// validate 验证字段
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:32 2024/4/29
|
||||
func validate(sourceData []byte, val gjson.Result, rule *define.FieldRule) (interface{}, error) {
|
||||
inputVal := val.Value()
|
||||
if !val.Exists() {
|
||||
if rule.IsRequired {
|
||||
return nil, fmt.Errorf("%v : field is required, but not found", rule.Path)
|
||||
}
|
||||
// TODO : 验证有条件必传
|
||||
inputVal = rule.DefaultValue
|
||||
} else {
|
||||
if inputVal == nil {
|
||||
if !rule.AllowNil {
|
||||
return nil, fmt.Errorf("%v : field value is nil, but not allowed", rule.Path)
|
||||
}
|
||||
inputVal = rule.DefaultValue
|
||||
}
|
||||
}
|
||||
|
||||
return handleData(inputVal, rule)
|
||||
}
|
||||
|
||||
// handleData 处理数据
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:43 2024/4/29
|
||||
func handleData(inputVal interface{}, rule *define.FieldRule) (interface{}, error) {
|
||||
switch rule.Type {
|
||||
case consts.DataTypeAny: // 任意类型
|
||||
return inputVal, nil
|
||||
case consts.DataTypeFloat: // float数据
|
||||
return handleFloat(inputVal, rule)
|
||||
case consts.DataTypeInt: // int类型
|
||||
return handleInt(inputVal, rule)
|
||||
case consts.DataTypeString: // 字符串处理
|
||||
return handleString(inputVal, rule)
|
||||
case consts.DataTypeMapStrFloat, consts.DataTypeMapStrBool,
|
||||
consts.DataTypeMapStrInt, consts.DataTypeMapStrUint:
|
||||
// 一律按照 map[string]float64处理
|
||||
return handleMapStringFloat(inputVal, rule)
|
||||
case consts.DataTypeMapStrAny: // 对象结构
|
||||
return handleMapStringAny(inputVal, rule)
|
||||
case consts.DataTypeMapStrSlice: // map列表
|
||||
|
||||
case consts.DataTypeMapAnyAny: // 任意类型map
|
||||
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// handleFloat 处理float数据
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:29 2024/4/29
|
||||
func handleFloat(inputVal interface{}, rule *define.FieldRule) (float64, error) {
|
||||
var (
|
||||
err error
|
||||
formatData float64
|
||||
)
|
||||
if err = util.ConvertAssign(&formatData, inputVal); nil != err {
|
||||
return 0, err
|
||||
}
|
||||
if !rule.AllowZero {
|
||||
return 0, fmt.Errorf("%v : field type is float, but zero val is not allowed", rule.Path)
|
||||
}
|
||||
if nil == rule.ValueLimit {
|
||||
return formatData, nil
|
||||
}
|
||||
if nil != rule.ValueLimit.Min && formatData < *rule.ValueLimit.Min {
|
||||
return 0, fmt.Errorf("%v : field type is float, min val is %v, real val is %v", rule.Path, *rule.ValueLimit.Min, formatData)
|
||||
}
|
||||
if nil != rule.ValueLimit.Max && formatData > *rule.ValueLimit.Max {
|
||||
return 0, fmt.Errorf("%v : field type is float, max val is %v, real val is %v", rule.Path, *rule.ValueLimit.Max, formatData)
|
||||
}
|
||||
if len(rule.ValueLimit.EnumList) > 0 {
|
||||
if wrapper.ArrayType(rule.ValueLimit.EnumList).Has(formatData) < 0 {
|
||||
return 0, fmt.Errorf("%v : field type is float, real val is %v, is not in enum list", rule.Path, formatData)
|
||||
}
|
||||
}
|
||||
return formatData, nil
|
||||
}
|
||||
|
||||
// handleInt ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:36 2024/4/29
|
||||
func handleInt(inputVal interface{}, rule *define.FieldRule) (int64, error) {
|
||||
var (
|
||||
err error
|
||||
formatData int64
|
||||
)
|
||||
if err = util.ConvertAssign(&formatData, inputVal); nil != err {
|
||||
return 0, err
|
||||
}
|
||||
if _, err = handleFloat(formatData, rule); nil != err {
|
||||
return 0, err
|
||||
}
|
||||
return formatData, nil
|
||||
}
|
||||
|
||||
// handleString ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:53 2024/4/29
|
||||
func handleString(inputVal interface{}, rule *define.FieldRule) (string, error) {
|
||||
var (
|
||||
err error
|
||||
formatData string
|
||||
)
|
||||
if err = util.ConvertAssign(&formatData, inputVal); nil != err {
|
||||
return "", err
|
||||
}
|
||||
if nil == rule.ValueLimit {
|
||||
return formatData, nil
|
||||
}
|
||||
if nil != rule.ValueLimit.Min {
|
||||
if float64(len(formatData)) < *rule.ValueLimit.Min {
|
||||
return "", fmt.Errorf("%v : data type is string, min length is %v, real length is %v", rule.Path, *rule.ValueLimit.Min, len(formatData))
|
||||
}
|
||||
}
|
||||
if nil != rule.ValueLimit.Max {
|
||||
if float64(len(formatData)) >= *rule.ValueLimit.Max {
|
||||
return "", fmt.Errorf("%v : data type is string, max length is %v, real length is %v", rule.Path, *rule.ValueLimit.Max, len(formatData))
|
||||
}
|
||||
}
|
||||
if len(rule.ValueLimit.EnumList) > 0 {
|
||||
if wrapper.ArrayType(rule.ValueLimit.EnumList).Has(formatData) < 0 {
|
||||
return "", fmt.Errorf("%v : data type is string, not in enum list, real val is %v", rule.Path, formatData)
|
||||
}
|
||||
}
|
||||
return formatData, nil
|
||||
}
|
||||
|
||||
// handleMapStringFloat ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:38 2024/4/29
|
||||
func handleMapStringFloat(inputVal interface{}, rule *define.FieldRule) (map[string]float64, error) {
|
||||
var (
|
||||
err error
|
||||
res map[string]float64
|
||||
)
|
||||
|
||||
if err = strOrMapConvert(inputVal, &res); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dataFieldTable := make(map[string]string)
|
||||
for k, _ := range res {
|
||||
dataFieldTable[k] = k
|
||||
}
|
||||
|
||||
if err = validateMap(dataFieldTable, rule); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// handleMapStringAny ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:19 2024/4/29
|
||||
func handleMapStringAny(inputVal interface{}, rule *define.FieldRule) (map[string]interface{}, error) {
|
||||
var (
|
||||
err error
|
||||
res map[string]interface{}
|
||||
)
|
||||
|
||||
if err = strOrMapConvert(inputVal, &res); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dataFieldTable := make(map[string]string)
|
||||
for k, _ := range res {
|
||||
dataFieldTable[k] = k
|
||||
}
|
||||
|
||||
if err = validateMap(dataFieldTable, rule); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// strOrMapConvert 字符串或map转map
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:26 2024/4/29
|
||||
func strOrMapConvert(inputVal interface{}, receiver interface{}) error {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
if inputValStr, ok := inputVal.(string); ok {
|
||||
if err = serialize.JSON.UnmarshalWithNumber([]byte(inputValStr), receiver); nil != err {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
byteData := serialize.JSON.MarshalForByte(inputVal)
|
||||
if err = serialize.JSON.UnmarshalWithNumber(byteData, receiver); nil != err {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateMap 验证map数据
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:21 2024/4/29
|
||||
func validateMap(dataFieldTable map[string]string, rule *define.FieldRule) error {
|
||||
if nil == rule.ValueLimit {
|
||||
return nil
|
||||
}
|
||||
if nil != rule.ValueLimit.Min && float64(len(dataFieldTable)) < *rule.ValueLimit.Min {
|
||||
return fmt.Errorf("%v : data type is map, min item cnt is %v, real item cnt is %v", rule.Path, *rule.ValueLimit.Min, len(dataFieldTable))
|
||||
}
|
||||
if nil != rule.ValueLimit.Max && float64(len(dataFieldTable)) >= *rule.ValueLimit.Max {
|
||||
return fmt.Errorf("%v : data type is map, max item cnt is %v, real item max is %v", rule.Path, *rule.ValueLimit.Max, len(dataFieldTable))
|
||||
}
|
||||
if nil != rule.ValueLimit.Map {
|
||||
for _, itemField := range rule.ValueLimit.Map.IncludeFieldList {
|
||||
if _, exist := dataFieldTable[itemField]; !exist {
|
||||
return fmt.Errorf("%v : data type is map, %v field is required, but not found", rule.Path, itemField)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user