package cache import ( "encoding/json" "git.sxidc.com/go-tools/utils/reflectutils" "git.sxidc.com/go-tools/utils/strutils" "github.com/pkg/errors" "reflect" "strconv" "strings" "time" ) // Cache 缓存基础设施接口 type Cache interface { // Set 设置缓存值 Set(key string, value string, expireSec int64) error // Get 获取缓存值 Get(key string) (string, error) // GetMulti 获取多个缓存值 GetMulti(keys []string) (map[string]string, error) // GetAll 获取所有缓存值 GetAll() (map[string]string, error) // Delete 删除缓存值 Delete(key string) error // Clear 清除缓存 Clear() error // Expire 使用秒数设置key的过期时间 Expire(key string, expireSec int64) error // TTL 获取过期剩余秒数 TTL(key string) (int64, error) } // Set 设置缓存值 // 参数: // - cache: 缓存基础设施接口 // - key: 缓存的键 // - value: 要设置的缓存值 // - expireSec: 缓存过期时间,单位秒 // 返回值: // - 错误 func Set(cache Cache, key string, value any, expireSec int64) error { valueReflectValue := reflect.ValueOf(value) if !valueReflectValue.IsValid() { return errors.New("缓存值无效") } stringValue, err := toString(valueReflectValue) if err != nil { return err } return cache.Set(key, stringValue, expireSec) } // Get 获取缓存值 // 泛型参数: // - T: 缓存值类型 // 参数: // - cache: 缓存基础设施接口 // - key: 缓存的键 // 返回值: // - 缓存值 // - 错误 func Get[T any](cache Cache, key string) (T, error) { var zero T stringValue, err := cache.Get(key) if err != nil { return zero, err } retValue := reflectutils.Zero[T]() retValueReflectType := reflect.TypeOf(retValue) if retValueReflectType.Kind() == reflect.Pointer { err := fromString(stringValue, retValue) if err != nil { return zero, err } } else { err := fromString(stringValue, &retValue) if err != nil { return zero, err } } return retValue, nil } // GetMulti 批量获取缓存值 // 参数: // - cache: 缓存基础设施接口 // - keys: 缓存的键(多个) // 返回值: // - 缓存值,value以string类型先返回 // - 错误 func GetMulti(cache Cache, keys []string) (map[string]string, error) { return cache.GetMulti(keys) } // GetAll 获取所有缓存值 // 参数: // - cache: 缓存基础设施接口 // 返回值: // - 缓存值,value以string类型先返回 // - 错误 func GetAll(cache Cache) (map[string]string, error) { return cache.GetAll() } // Delete 删除缓存值 // 参数: // - cache: 缓存基础设施接口 // - key: 缓存的键 // 返回值: // - 错误 func Delete(cache Cache, key string) error { return cache.Delete(key) } // Clear 清除缓存 // 参数: // - cache: 缓存基础设施接口 // 返回值: // - 错误 func Clear(cache Cache) error { return cache.Clear() } // Expire 使用秒数设置key的过期时间 // 参数: // - cache: 缓存基础设施接口 // - expireSec: 缓存过期时间,单位秒 // 返回值: // - 错误 func Expire(cache Cache, key string, expireSec int64) error { return cache.Expire(key, expireSec) } // TTL 获取过期剩余秒数 // 参数: // - cache: 缓存基础设施接口 // - key: 缓存的键 // 返回值: // - 剩余过期秒数 // - 错误 func TTL(cache Cache, key string) (int64, error) { return cache.TTL(key) } func toString(valueReflectValue reflect.Value) (string, error) { dataVal := reflect.Indirect(valueReflectValue) dataKind := reflectutils.GroupValueKind(dataVal) switch dataKind { case reflect.String: return dataVal.String(), nil case reflect.Bool: if dataVal.Bool() { return "true", nil } else { return "false", nil } case reflect.Int64: return strconv.FormatInt(dataVal.Int(), 10), nil case reflect.Uint64: return strconv.FormatUint(dataVal.Uint(), 10), nil case reflect.Float64: return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil case reflect.Slice, reflect.Array: dataElementType := reflectutils.PointerTypeElem(dataVal.Type().Elem()) // []byte,直接转换为string if dataElementType.Kind() == reflect.Uint8 { if dataVal.Len() == 0 { return "", nil } uints := make([]uint8, dataVal.Len(), dataVal.Len()) for i := 0; i < dataVal.Len(); i++ { uints[i] = dataVal.Index(i).Interface().(uint8) } return string(uints), nil } else { if dataVal.Len() == 0 { return "[]", nil } stringBuilder := strings.Builder{} stringBuilder.WriteString("[") for i := 0; i < dataVal.Len(); i++ { strValue, err := toString(dataVal.Index(i)) if err != nil { return "", err } if i > 0 { stringBuilder.WriteString(",") } stringBuilder.WriteString(strValue) } stringBuilder.WriteString("]") return stringBuilder.String(), nil } case reflect.Map, reflect.Struct: if dataVal.Type().Name() == "time.Time" { return dataVal.Interface().(time.Time).Format(time.RFC3339Nano), nil } else { jsonBytes, err := json.Marshal(dataVal.Interface()) if err != nil { return "", errors.New(err.Error()) } return string(jsonBytes), nil } default: return "", errors.New("不支持的缓存值类型: " + dataVal.Type().Elem().String()) } } func fromString(stringValue string, retValue any) error { retValueReflectValue := reflect.ValueOf(retValue) if retValueReflectValue.Kind() != reflect.Pointer { return errors.New("返回值不是指针类型") } dataVal := reflect.Indirect(retValueReflectValue) dataKind := reflectutils.GroupValueKind(dataVal) switch dataKind { case reflect.String: dataVal.SetString(stringValue) return nil case reflect.Bool: if strutils.IsStringEmpty(stringValue) { dataVal.SetBool(false) } else { if stringValue == "false" { dataVal.SetBool(false) } else { dataVal.SetBool(true) } } return nil case reflect.Int64: intValue, err := strconv.ParseInt(stringValue, 10, 64) if err != nil { return errors.New(err.Error()) } dataVal.SetInt(intValue) return nil case reflect.Uint64: uintValue, err := strconv.ParseUint(stringValue, 10, 64) if err != nil { return err } dataVal.SetUint(uintValue) return nil case reflect.Float64: floatValue, err := strconv.ParseFloat(stringValue, 64) if err != nil { return err } dataVal.SetFloat(floatValue) return nil case reflect.Slice, reflect.Array: dataElementType := reflectutils.PointerTypeElem(dataVal.Type().Elem()) // []byte直接用string赋值 if dataElementType.Kind() == reflect.Uint8 { dataSliceVal := reflect.MakeSlice(dataVal.Type(), 0, 0) for _, b := range []byte(stringValue) { if dataVal.Type().Elem().Kind() == reflect.Pointer { dataSliceVal = reflect.Append(dataSliceVal, reflect.ValueOf(&b)) } else { dataSliceVal = reflect.Append(dataSliceVal, reflect.ValueOf(b)) } } dataVal.Set(dataSliceVal) return nil } else { if !strings.HasPrefix(stringValue, "[") || !strings.HasSuffix(stringValue, "]") { return errors.New("缓存值不是切片或数组形式") } dataSliceVal := reflect.MakeSlice(dataVal.Type(), 0, 0) stringValue = strings.TrimSuffix(strings.TrimPrefix(stringValue, "["), "]") stringValueParts := strings.Split(stringValue, ",") for _, strValuePart := range stringValueParts { dataSliceElementType := dataVal.Type().Elem() dataSliceElementVal := reflect.Indirect(reflect.New(dataSliceElementType)) if dataSliceElementVal.Kind() == reflect.Pointer { dataSliceElementVal.Set(reflect.New(dataSliceElementVal.Type().Elem())) err := fromString(strValuePart, dataSliceElementVal.Interface()) if err != nil { return err } } else { err := fromString(strValuePart, dataSliceElementVal.Addr().Interface()) if err != nil { return err } } dataSliceVal = reflect.Append(dataSliceVal, dataSliceElementVal) } dataVal.Set(dataSliceVal) return nil } case reflect.Map, reflect.Struct: if dataVal.Type().Name() == "time.Time" { parsedTime, err := time.ParseInLocation(time.RFC3339Nano, stringValue, time.Local) if err != nil { return err } dataVal.Set(reflect.ValueOf(parsedTime)) return nil } else { err := json.Unmarshal([]byte(stringValue), dataVal.Addr().Interface()) if err != nil { return errors.New(err.Error()) } return nil } default: return errors.New("不支持的缓存值类型: " + dataVal.Type().Elem().String()) } }