event/reflect.go

292 lines
7.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package event ...
//
// Description : event ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2023-02-01 14:30
package event
import (
"git.zhangdeman.cn/zhangdeman/event/abstract"
"git.zhangdeman.cn/zhangdeman/util"
"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.Kind())
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.Kind) {
switch dataType {
case reflect.Float32:
fallthrough
case reflect.Float64:
field.Type = reflect.Float64
case reflect.String:
field.Type = reflect.String
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.Interface:
if inputVal == nil {
return true
}
return false
default:
// 默认不处理
return false
}
return false
}