From 7b7aee4070ff37b3e9c212f08b7c7ef6eaa08258 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, 1 Feb 2023 18:46:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AD=97=E6=AE=B5=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E5=AE=9A=E4=B9=89=20+=20=E5=8D=8A=E6=88=90=E5=93=81?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E8=A7=84=E5=88=99=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- define.go | 63 ++++++++++++++++++++++++--- reflect.go | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 183 insertions(+), 6 deletions(-) diff --git a/define.go b/define.go index c201cc6..382dae7 100644 --- a/define.go +++ b/define.go @@ -10,14 +10,18 @@ package event import "reflect" const ( - // OutputKeyTag 事件数据输出key的标签 - OutputKeyTag = "event" + // OutEventTag 事件数据输出key的标签 + OutEventTag = "event" // JsonTag json输出的标签 JsonTag = "json" // IgnoreTagValue 不做输出的标签值 IgnoreTagValue = "-" // MappingTag 参数映射标签 MappingTag = "mapping" + // PriorityTag 处理数据时, mapping数据查找的优先级, 默认值 : field + PriorityTag = "priority" + // OmitemptyTag ... + OmitemptyTag = "omitempty" ) const ( @@ -33,15 +37,52 @@ const ( MappingLocationExtension = "extension" ) +var ( + mappingLocationList = []string{ + MappingLocationHeader, + MappingLocationParam, + MappingLocationResponse, + MappingLocationExtension, + } +) + +// SetMappingLocationList 只持续该默认的查找优先级 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 18:17 2023/2/1 +func SetMappingLocationList(locationList []string) { + if len(locationList) > 0 { + mappingLocationList = locationList + } +} + +const ( + // PriorityLocation 读取位置优先 + PriorityLocation = "location" + // PriorityField 读取字段优先 + PriorityField = "field" +) + +// MappingRuleItem 规则 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 17:36 2023/2/1 +type MappingRuleItem struct { + Location string `json:"location"` // 数据所在位置, header-请求头 param-参数获取 response-响应数据获取 extension-扩展数据读取 all-自动按照header/param/response/extension的顺序查询 + Field string `json:"field"` // 查询的字段名称 +} + // MappingRule 数据映射规则 // // Author : go_developer@163.com<白茶清欢> // // Date : 14:24 2023/2/1 type MappingRule struct { - Location string `json:"location"` // 数据所在位置, header-请求头 param-参数获取 response-响应数据获取 extension-扩展数据读取 all-自动按照header/param/response/extension的顺序查询 - Field []string `json:"field"` // 查询的字段名称, 列表, 按照优先级诸葛查询 - Priority string `json:"priority"` // 查找优先级 : location - 位置优先 field - 字段优先 + RuleList []MappingRuleItem `json:"rule_list"` // 规则列表 + Priority string `json:"priority"` // 查找优先级 : location - 位置优先 field - 字段优先 + TargetField string `json:"target_field"` // 目标字段 } // StructField 结构体字段信息 @@ -50,9 +91,21 @@ type MappingRule struct { // // Date : 14:35 2023/2/1 type StructField struct { + Idx int // 字段在结构体的索引 Name string // 字段名 Type reflect.Kind // 字段类型 JsonTag string // json标签 EventTag string // 事件标签 MappingRule *MappingRule // 数据映射规则 } + +// StructInfo 结构体信息 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 16:17 2023/2/1 +type StructInfo struct { + Flag string // 结构体标识 + IsStruct bool // 是否为结构体 + StructFieldList []*StructField // 结构体字段列表 +} diff --git a/reflect.go b/reflect.go index 839093a..d748e44 100644 --- a/reflect.go +++ b/reflect.go @@ -7,12 +7,34 @@ // Date : 2023-02-01 14:30 package event +import ( + "reflect" + "strings" + "sync" +) + +var ( + // ReflectTypeInstance 反射实例 + ReflectTypeInstance *ReflectType +) + +func init() { + ReflectTypeInstance = &ReflectType{ + lock: &sync.RWMutex{}, + cacheTable: make(map[string]*StructInfo), + } +} + // ReflectType 反射数据类型 // // Author : go_developer@163.com<白茶清欢> // // Date : 14:31 2023/2/1 type ReflectType struct { + // 数据锁 + lock *sync.RWMutex + // 反射结果缓存 + cacheTable map[string]*StructInfo } // Do 反射获取数据类型 @@ -20,6 +42,108 @@ type ReflectType struct { // Author : go_developer@163.com<白茶清欢> // // Date : 14:34 2023/2/1 -func (rt *ReflectType) Do(data interface{}) { +// +// 为特定结构体生成全局唯一的标识, 并进行缓存, 加速反射结果获取 +func (rt *ReflectType) Do(dataFlag string, data interface{}) *StructInfo { + rt.lock.Lock() + defer rt.lock.Unlock() + if cacheResult, exist := rt.cacheTable[dataFlag]; exist { + // 缓存存在, 直接是有缓存结果 + return cacheResult + } + // 缓存不存在, 解析 + res := &StructInfo{ + Flag: dataFlag, + IsStruct: false, + StructFieldList: make([]*StructField, 0), + } + reflectType := reflect.TypeOf(data) + if reflectType.Kind() == reflect.Ptr { + reflectType = reflectType.Elem() + } + if reflectType.Kind() != reflect.Struct { + // 非结构体,无需反射 + return res + } + res.IsStruct = true + for idx := 0; idx < reflectType.NumField(); idx++ { + field := &StructField{ + Idx: idx, + Name: reflectType.Field(idx).Name, + Type: reflectType.Field(idx).Type.Kind(), + JsonTag: reflectType.Field(idx).Tag.Get(JsonTag), + EventTag: reflectType.Field(idx).Tag.Get(OutEventTag), + MappingRule: nil, + } + + res.StructFieldList = append(res.StructFieldList, field) + } + return res +} + +// fillTagInfo 填充标签信息 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 17:11 2023/2/1 +func (rt *ReflectType) fillTagInfo(field *StructField) { + if len(field.JsonTag) == 0 { + field.JsonTag = field.Name + } + + // jsonTag 去掉 omitempty + jsonTagValArr := strings.Split(field.JsonTag, ",") + for _, item := range jsonTagValArr { + if len(item) > 0 && item != OmitemptyTag { + field.JsonTag = item + break + } + } + + // 没有设置event tag,则和 + if len(field.EventTag) == 0 { + field.EventTag = field.JsonTag + } +} + +// fillMappingRule 解析参数映射规则 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 17:14 2023/2/1 +// +// mapping:"user_id:param#user_id|header#id" +func (rt *ReflectType) fillMappingRule(field *StructField, inputMappingVal string, inputPriorityVal string) { + rule := &MappingRule{ + RuleList: make([]MappingRuleItem, 0), + Priority: "", + TargetField: "", + } + switch inputPriorityVal { + case PriorityLocation: + rule.Priority = PriorityLocation + case PriorityField: + rule.Priority = PriorityField + default: + rule.Priority = PriorityField + } + if len(inputMappingVal) == 0 { + // 没有指定规则, 有默认规则 + for _, location := range mappingLocationList { + rule.RuleList = append(rule.RuleList, MappingRuleItem{ + Location: location, + Field: field.JsonTag, + }) + } + field.MappingRule = rule + return + } + mappingArr := strings.Split(inputMappingVal, ",") + for _, item := range mappingArr { + item = strings.TrimSpace(item) + // 要赋值的字段名 + itemArr := strings.Split(item, ":") + rule.TargetField = strings.TrimSpace(itemArr[0]) + } }