// Package event ... // // Description : event ... // // Author : go_developer@163.com<白茶清欢> // // Date : 2023-02-01 14:30 package event import ( "encoding/json" "git.zhangdeman.cn/zhangdeman/event/abstract" "git.zhangdeman.cn/zhangdeman/util" "github.com/tidwall/gjson" "net/http" "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 反射获取数据类型 // // Author : go_developer@163.com<白茶清欢> // // Date : 14:34 2023/2/1 // // 为特定结构体生成全局唯一的标识, 并进行缓存, 加速反射结果获取 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, IsStructPtr: false, StructFieldList: make([]*StructField, 0), } isPtr := false reflectType := reflect.TypeOf(data) if reflectType.Kind() == reflect.Ptr { isPtr = true reflectType = reflectType.Elem() } if reflectType.Kind() != reflect.Struct { // 非结构体,无需反射 rt.cacheTable[dataFlag] = res return res } res.IsStruct = true res.IsStructPtr = isPtr for idx := 0; idx < reflectType.NumField(); idx++ { field := &StructField{ Idx: idx, Name: reflectType.Field(idx).Name, JsonTag: reflectType.Field(idx).Tag.Get(JsonTag), EventTag: reflectType.Field(idx).Tag.Get(OutEventTag), MappingRuleList: make([]MappingRuleItem, 0), } rt.fillFieldType(field, reflectType.Field(idx).Type) rt.fillMappingRule(field, reflectType.Field(idx).Tag.Get(MappingTag)) res.StructFieldList = append(res.StructFieldList, field) } rt.cacheTable[dataFlag] = res return res } // fillFieldType 填充字段类型 // // Author : go_developer@163.com<白茶清欢> // // Date : 20:46 2023/2/1 func (rt *ReflectType) fillFieldType(field *StructField, dataType reflect.Type) { switch dataType.Kind() { case reflect.Float32: fallthrough case reflect.Float64: field.Type = reflect.Float64 case reflect.String: field.Type = reflect.String case reflect.Struct: field.Type = reflect.Struct case reflect.Slice: field.Type = reflect.Slice case reflect.Map: field.Type = reflect.Map case reflect.Ptr: field.IsPtr = true // 指针再次判断基础类型 field.Type = dataType.Elem().Kind() default: if strings.Contains(dataType.String(), "int") { field.Type = reflect.Int64 } else { field.Type = reflect.Interface } } } // 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,则和 json 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) { if len(inputMappingVal) == 0 { // 没有指定规则, 有默认规则 for _, location := range mappingLocationList { field.MappingRuleList = append(field.MappingRuleList, MappingRuleItem{ Location: location, Field: field.JsonTag, }) } return } mappingArr := strings.Split(inputMappingVal, ",") for _, item := range mappingArr { item = strings.TrimSpace(item) // 要赋值的字段名 itemArr := strings.Split(item, ":") if len(itemArr) != 2 { // 配置格式错误, 跳过 continue } mapRuleArr := strings.Split(strings.TrimSpace(itemArr[1]), "|") for _, itemMapRule := range mapRuleArr { itemMapRule = strings.TrimLeft(itemMapRule, "#") itemMapRuleArr := strings.Split(itemMapRule, "#") // 注意 : # 为特殊分隔符, 如配置成 mapping:"project_id:#source_project_id#xxx_project_id" 实际等价于 mapping:"project_id:#source_project_id" 多余配置自动跳过 if len(itemMapRuleArr[0]) < 2 { // 没有指定位置,默认all, 即配置格式: mapping:"project_id:#source_project_id" itemMapRuleArr[0] = MappingLocationAll itemMapRuleArr = []string{MappingLocationAll, itemMapRuleArr[0]} } switch itemMapRuleArr[0] { // 从header读取 case MappingLocationHeader: field.MappingRuleList = append(field.MappingRuleList, MappingRuleItem{ Location: MappingLocationHeader, Field: itemMapRuleArr[1], }) // 从请求参数读取 case MappingLocationParam: field.MappingRuleList = append(field.MappingRuleList, MappingRuleItem{ Location: MappingLocationParam, Field: itemMapRuleArr[1], }) // 从响应数据读取 case MappingLocationResponse: field.MappingRuleList = append(field.MappingRuleList, MappingRuleItem{ Location: MappingLocationResponse, Field: itemMapRuleArr[1], }) // 从扩展数据读取 case MappingLocationExtension: field.MappingRuleList = append(field.MappingRuleList, MappingRuleItem{ Location: MappingLocationExtension, Field: itemMapRuleArr[1], }) // 全部读取一遍 case MappingLocationAll: fallthrough default: for _, itemLocation := range mappingLocationList { field.MappingRuleList = append(field.MappingRuleList, MappingRuleItem{ Location: itemLocation, Field: itemMapRuleArr[1], }) } } } } } // ReflectValue 反射值的实例 // // Author : go_developer@163.com<白茶清欢> // // Date : 10:53 2023/2/2 type ReflectValue struct { } // Do 通过反射机制,对data进行数据填充,此逻辑要求 data 必须是结构体或者结构体指针 // // Author : go_developer@163.com<白茶清欢> // // Date : 11:52 2023/2/2 func (rv *ReflectValue) Do(dataFlag string, data interface{}, preSendHandler abstract.IPreSendHandler) { structInfo := ReflectTypeInstance.Do(dataFlag, data) if !structInfo.IsStruct { return } reflectValue := reflect.ValueOf(data) if structInfo.IsStructPtr { reflectValue = reflectValue.Elem() } for _, fieldInfo := range structInfo.StructFieldList { if !rv.isZeroInputFieldValue(reflectValue, fieldInfo) { // 不是零值, 无需处理 continue } // 是零值, 填充默认值 } } // isZeroInputFieldValue 判断对应的字段是否为对应类型默认的零值 // // Author : go_developer@163.com<白茶清欢> // // Date : 12:04 2023/2/2 func (rv *ReflectValue) isZeroInputFieldValue(reflectValue reflect.Value, fieldInfo *StructField) bool { inputVal := reflectValue.Field(fieldInfo.Idx).Interface() switch fieldInfo.Type { case reflect.Float64: var f float64 if err := util.ConvertAssign(&f, inputVal); nil == err { if f != 0 { return false } return true } case reflect.String: var s string if err := util.ConvertAssign(&s, inputVal); nil == err { if len(s) > 0 { return false } return true } case reflect.Int64: var i int64 if err := util.ConvertAssign(&i, inputVal); nil == err { if i != 0 { return false } return true } case reflect.Map: if nil == inputVal { return true } var m map[interface{}]interface{} if err := util.ConvertAssign(&m, inputVal); nil == err { if len(m) != 0 { return false } return true } case reflect.Slice: if nil == inputVal { return true } var sl []interface{} if err := util.ConvertAssign(&sl, inputVal); nil == err { if len(sl) != 0 { return false } return true } case reflect.Interface: if inputVal == nil { return true } return false default: // 默认不处理 return false } return false } // fillFieldValue 填充字段值 // // Author : go_developer@163.com<白茶清欢> // // Date : 14:00 2023/2/2 func (rv *ReflectValue) fillFieldValue(reflectValue reflect.Value, fieldInfo *StructField, preSendHandler abstract.IPreSendHandler) { paramByte, _ := json.Marshal(preSendHandler.GetRequestParam()) header := preSendHandler.GetRequestHeader() responseByte, _ := json.Marshal(preSendHandler.GetResponseData()) extensionByte, _ := json.Marshal(preSendHandler.GetExtensionData()) for _, item := range fieldInfo.MappingRuleList { } } // getInputValue 获取输入的值 // // Author : go_developer@163.com<白茶清欢> // // Date : 14:24 2023/2/2 func (rv *ReflectValue) setDataValue(reflectVal reflect.Value, fieldInfo *StructField, rule MappingRuleItem, header http.Header, paramByte, responseByte, extensionByte []byte) bool { switch rule.Location { case MappingLocationHeader: str := header.Get(rule.Field) if len(str) == 0 { // 未进行值设置 return false } case MappingLocationParam: case MappingLocationResponse: case MappingLocationExtension: default: return false } return true } // getInputValue 获取输入的值 // // Author : go_developer@163.com<白茶清欢> // // Date : 14:43 2023/2/2 func (rv *ReflectValue) getInputValue(rule MappingRuleItem, header http.Header, paramByte, responseByte, extensionByte []byte) string { switch rule.Location { case MappingLocationHeader: return header.Get(rule.Field) case MappingLocationParam: return gjson.GetBytes(paramByte, rule.Field).String() case MappingLocationResponse: return gjson.GetBytes(responseByte, rule.Field).String() case MappingLocationExtension: return gjson.GetBytes(extensionByte, rule.Field).String() case MappingLocationAll: str := header.Get(rule.Field) if len(str) == 0 { str = gjson.GetBytes(paramByte, rule.Field).String() } if len(str) == 0 { str = gjson.GetBytes(responseByte, rule.Field).String() } if len(str) == 0 { str = gjson.GetBytes(extensionByte, rule.Field).String() } return str default: return "" } }