yjp 1 жил өмнө
parent
commit
d20d8883ef

+ 7 - 7
convenient/domain_gateway/configuration/configuration.go

@@ -4,8 +4,8 @@ import (
 	"git.sxidc.com/go-framework/baize/framework/core/api"
 	"git.sxidc.com/go-framework/baize/framework/gateway"
 	"git.sxidc.com/go-tools/utils/strutils"
-	"git.sxidc.com/service-supports/fserr"
 	"github.com/gin-gonic/gin"
+	"github.com/pkg/errors"
 	"net/http"
 	"net/url"
 	"sync"
@@ -51,14 +51,14 @@ func BuildGateway(gw *gateway.Gateway, opts ...Option) {
 
 					serviceShortName, ok := jsonBody.Get("serviceShortName").(string)
 					if !ok {
-						return "", fserr.New("没有传递服务名缩写或服务名缩写不是string类型")
+						return "", errors.New("没有传递服务名缩写或服务名缩写不是string类型")
 					}
 
 					jsonBody.Delete("serviceShortName")
 
 					serviceBaseUrl, loaded := serviceBaseUrlMap.Load(serviceShortName)
 					if !loaded {
-						return "", fserr.New("没有注册对应的服务: " + serviceShortName)
+						return "", errors.New("没有注册对应的服务: " + serviceShortName)
 					}
 
 					var serviceUrl string
@@ -96,14 +96,14 @@ func BuildGateway(gw *gateway.Gateway, opts ...Option) {
 
 					serviceShortName, ok := jsonBody.Get("serviceShortName").(string)
 					if !ok {
-						return "", fserr.New("没有传递服务名缩写或服务名缩写不是string类型")
+						return "", errors.New("没有传递服务名缩写或服务名缩写不是string类型")
 					}
 
 					jsonBody.Delete("serviceShortName")
 
 					serviceBaseUrl, loaded := serviceBaseUrlMap.Load(serviceShortName)
 					if !loaded {
-						return "", fserr.New("没有注册对应的服务: " + serviceShortName)
+						return "", errors.New("没有注册对应的服务: " + serviceShortName)
 					}
 
 					var serviceUrl string
@@ -138,14 +138,14 @@ func BuildGateway(gw *gateway.Gateway, opts ...Option) {
 
 					serviceShortName := queryParams.Get("serviceShortName")
 					if strutils.IsStringEmpty(serviceShortName) {
-						return "", fserr.New("没有传递服务名缩写")
+						return "", errors.New("没有传递服务名缩写")
 					}
 
 					queryParams.Delete("serviceShortName")
 
 					serviceBaseUrl, loaded := serviceBaseUrlMap.Load(serviceShortName)
 					if !loaded {
-						return "", fserr.New("没有注册对应的服务: " + serviceShortName)
+						return "", errors.New("没有注册对应的服务: " + serviceShortName)
 					}
 
 					var serviceUrl string

+ 5 - 5
convenient/domain_gateway/sql_executor/sql_executor.go

@@ -4,8 +4,8 @@ import (
 	"git.sxidc.com/go-framework/baize/framework/core/api"
 	"git.sxidc.com/go-framework/baize/framework/gateway"
 	"git.sxidc.com/go-tools/utils/strutils"
-	"git.sxidc.com/service-supports/fserr"
 	"github.com/gin-gonic/gin"
+	"github.com/pkg/errors"
 	"net/http"
 	"net/url"
 	"sync"
@@ -50,14 +50,14 @@ func BuildGateway(gw *gateway.Gateway, opts ...Option) {
 
 					serviceShortName, ok := jsonBody.Get("serviceShortName").(string)
 					if !ok {
-						return "", fserr.New("没有传递服务名缩写或服务名缩写不是string类型")
+						return "", errors.New("没有传递服务名缩写或服务名缩写不是string类型")
 					}
 
 					jsonBody.Delete("serviceShortName")
 
 					serviceBaseUrl, loaded := serviceBaseUrlMap.Load(serviceShortName)
 					if !loaded {
-						return "", fserr.New("没有注册对应的服务: " + serviceShortName)
+						return "", errors.New("没有注册对应的服务: " + serviceShortName)
 					}
 
 					var serviceUrl string
@@ -112,14 +112,14 @@ func BuildGateway(gw *gateway.Gateway, opts ...Option) {
 
 					serviceShortName := queryParams.Get("serviceShortName")
 					if strutils.IsStringEmpty(serviceShortName) {
-						return "", fserr.New("没有传递服务名缩写")
+						return "", errors.New("没有传递服务名缩写")
 					}
 
 					queryParams.Delete("serviceShortName")
 
 					serviceBaseUrl, loaded := serviceBaseUrlMap.Load(serviceShortName)
 					if !loaded {
-						return "", fserr.New("没有注册对应的服务: " + serviceShortName)
+						return "", errors.New("没有注册对应的服务: " + serviceShortName)
 					}
 
 					var serviceUrl string

+ 17 - 8
framework/core/api/context.go

@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"encoding/json"
 	"git.sxidc.com/go-framework/baize/framework/core/infrastructure/logger"
-	"git.sxidc.com/service-supports/fserr"
 	"github.com/gin-gonic/gin"
 	"github.com/pkg/errors"
 	"io"
@@ -92,7 +91,7 @@ func (c *Context) GetBytesBody() (*CacheBody, error) {
 	case map[string]any:
 		bytesBody, err := json.Marshal(b)
 		if err != nil {
-			return nil, err
+			return nil, errors.New(err.Error())
 		}
 
 		return &CacheBody{
@@ -100,7 +99,7 @@ func (c *Context) GetBytesBody() (*CacheBody, error) {
 			bytesBody: bytesBody,
 		}, nil
 	default:
-		return nil, fserr.New("不支持的body类型")
+		return nil, errors.New("不支持的body类型")
 	}
 }
 
@@ -128,7 +127,12 @@ func (jsonBody *JsonBody) Map() map[string]any {
 }
 
 func (jsonBody *JsonBody) Bytes() ([]byte, error) {
-	return json.Marshal(jsonBody.jsonBodyMap)
+	jsonBytes, err := json.Marshal(jsonBody.jsonBodyMap)
+	if err != nil {
+		return nil, errors.New(err.Error())
+	}
+
+	return jsonBytes, nil
 }
 
 func (jsonBody *JsonBody) Unmarshal(output any) error {
@@ -137,7 +141,12 @@ func (jsonBody *JsonBody) Unmarshal(output any) error {
 		return err
 	}
 
-	return json.Unmarshal(jsonBytes, output)
+	err = json.Unmarshal(jsonBytes, output)
+	if err != nil {
+		return errors.New(err.Error())
+	}
+
+	return nil
 }
 
 func (c *Context) GetJsonBody() (*JsonBody, error) {
@@ -151,7 +160,7 @@ func (c *Context) GetJsonBody() (*JsonBody, error) {
 		jsonBodyMap := make(map[string]any)
 		err = json.Unmarshal(bytesBody, &jsonBodyMap)
 		if err != nil {
-			return nil, err
+			return nil, errors.New(err.Error())
 		}
 
 		return &JsonBody{
@@ -165,7 +174,7 @@ func (c *Context) GetJsonBody() (*JsonBody, error) {
 		jsonBodyMap := make(map[string]any)
 		err := json.Unmarshal(b, &jsonBodyMap)
 		if err != nil {
-			return nil, err
+			return nil, errors.New(err.Error())
 		}
 
 		return &JsonBody{
@@ -178,7 +187,7 @@ func (c *Context) GetJsonBody() (*JsonBody, error) {
 			jsonBodyMap: body.(map[string]any),
 		}, nil
 	default:
-		return nil, fserr.New("不支持的body类型")
+		return nil, errors.New("不支持的body类型")
 	}
 }
 

+ 3 - 6
framework/core/api/response/response.go

@@ -4,10 +4,8 @@ import (
 	"encoding/json"
 	"git.sxidc.com/go-framework/baize/framework/core/api"
 	"git.sxidc.com/go-framework/baize/framework/core/infrastructure/logger"
-	"git.sxidc.com/service-supports/fserr"
 	"git.sxidc.com/service-supports/websocket"
 	"github.com/pkg/errors"
-	"net/http"
 )
 
 type SendResponseFunc[O any] func(c *api.Context, statusCode int, data O, err error)
@@ -96,7 +94,7 @@ func formMsgResponse(err error) MsgResponse {
 
 		return MsgResponse{
 			Success: false,
-			ErrCode: http.StatusOK,
+			ErrCode: 1,
 			Msg:     err.Error(),
 		}
 	}
@@ -112,11 +110,10 @@ func formMapMsgResponse(err error) map[string]any {
 	resp := make(map[string]any)
 	if err != nil {
 		logger.GetInstance().Error(err)
-		serviceErr := fserr.ParseCode(err)
 
 		resp["success"] = false
-		resp["errCode"] = serviceErr.BusinessCode
-		resp["msg"] = serviceErr.Msg
+		resp["errCode"] = 1
+		resp["msg"] = err.Error()
 
 		return resp
 	}

+ 277 - 0
framework/core/infrastructure/cache/cache.go

@@ -0,0 +1,277 @@
+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"
+)
+
+type Cache interface {
+	Set(key string, value string) error
+	Get(key string) (string, error)
+	GetMulti(keys []string) (map[string]string, error)
+	GetAll() (map[string]string, error)
+	Delete(key string) error
+	Clear() error
+}
+
+func Set(cache Cache, key string, value any) 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)
+}
+
+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
+}
+
+func GetMulti(cache Cache, keys []string) (map[string]string, error) {
+	return cache.GetMulti(keys)
+}
+
+func GetAll(cache Cache) (map[string]string, error) {
+	return cache.GetAll()
+}
+
+func Delete(cache Cache, key string) error {
+	return cache.Delete(key)
+}
+
+func Clear(cache Cache) error {
+	return cache.Clear()
+}
+
+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())
+	}
+}

+ 84 - 0
framework/core/infrastructure/cache/local/local.go

@@ -0,0 +1,84 @@
+package local
+
+import (
+	"strings"
+	"sync"
+)
+
+type Cache struct {
+	namespace string
+	syncMap   *sync.Map
+}
+
+func New(namespace string) *Cache {
+	return &Cache{
+		namespace: namespace,
+		syncMap:   new(sync.Map),
+	}
+}
+
+func Destroy(cache *Cache) {
+	if cache == nil {
+		return
+	}
+
+	cache.syncMap = nil
+}
+
+func (cache *Cache) Set(key string, value string) error {
+	cache.syncMap.Store(cache.key2CacheKey(key), value)
+	return nil
+}
+
+func (cache *Cache) Get(key string) (string, error) {
+	value, loaded := cache.syncMap.Load(cache.key2CacheKey(key))
+	if !loaded {
+		return "", nil
+	}
+
+	return value.(string), nil
+}
+
+func (cache *Cache) GetMulti(keys []string) (map[string]string, error) {
+	result := make(map[string]string)
+
+	for _, key := range keys {
+		value, loaded := cache.syncMap.Load(cache.key2CacheKey(key))
+		if !loaded {
+			result[key] = ""
+		}
+
+		result[key] = value.(string)
+	}
+
+	return result, nil
+}
+
+func (cache *Cache) GetAll() (map[string]string, error) {
+	result := make(map[string]string)
+
+	cache.syncMap.Range(func(key any, value any) bool {
+		result[cache.cacheKey2Key(key.(string))] = value.(string)
+		return true
+	})
+
+	return result, nil
+}
+
+func (cache *Cache) Delete(key string) error {
+	cache.syncMap.Delete(cache.key2CacheKey(key))
+	return nil
+}
+
+func (cache *Cache) Clear() error {
+	cache.syncMap = new(sync.Map)
+	return nil
+}
+
+func (cache *Cache) key2CacheKey(key string) string {
+	return cache.namespace + "::" + key
+}
+
+func (cache *Cache) cacheKey2Key(cacheKey string) string {
+	return strings.TrimPrefix(cacheKey, cache.namespace+"::")
+}

+ 145 - 0
framework/core/infrastructure/cache/redis/redis.go

@@ -0,0 +1,145 @@
+package redis
+
+import (
+	"context"
+	"github.com/pkg/errors"
+	"github.com/redis/go-redis/v9"
+	"strings"
+)
+
+const (
+	keyPrefix = "baize::cache::"
+)
+
+type Cache struct {
+	namespace   string
+	redisClient *redis.Client
+}
+
+func New(address string, userName string, password string, db int, namespace string) (*Cache, error) {
+	if address == "" {
+		return nil, errors.New("redis address不能为空")
+	}
+
+	return &Cache{
+		namespace: namespace,
+		redisClient: redis.NewClient(&redis.Options{
+			Addr:     address,
+			Username: userName,
+			Password: password,
+			DB:       db,
+		})}, nil
+}
+
+func Destroy(cache *Cache) error {
+	if cache == nil || cache.redisClient == nil {
+		return nil
+	}
+
+	err := cache.redisClient.Close()
+	if err != nil {
+		return errors.New(err.Error())
+	}
+
+	cache.redisClient = nil
+
+	return nil
+}
+
+func (cache *Cache) Set(key string, value string) error {
+	cmd := cache.redisClient.Set(context.Background(), cache.key2CacheKey(key), value, 0)
+	if cmd.Err() != nil {
+		return errors.New(cmd.Err().Error())
+	}
+
+	return nil
+}
+
+func (cache *Cache) Get(key string) (string, error) {
+	cmd := cache.redisClient.Get(context.Background(), cache.key2CacheKey(key))
+	if cmd.Err() != nil {
+		if cmd.Err().Error() == redis.Nil.Error() {
+			return "", nil
+		}
+
+		return "", errors.New(cmd.Err().Error())
+	}
+
+	return cmd.Val(), nil
+}
+
+func (cache *Cache) GetMulti(keys []string) (map[string]string, error) {
+	result := make(map[string]string)
+
+	for _, key := range keys {
+		cmd := cache.redisClient.Get(context.Background(), cache.key2CacheKey(key))
+		if cmd.Err() != nil {
+			if cmd.Err().Error() == redis.Nil.Error() {
+				result[key] = ""
+				continue
+			}
+
+			return nil, cmd.Err()
+		}
+
+		result[key] = cmd.Val()
+	}
+
+	return result, nil
+}
+
+func (cache *Cache) GetAll() (map[string]string, error) {
+	result := make(map[string]string)
+
+	keysCmd := cache.redisClient.Keys(context.Background(), keyPrefix+cache.namespace+"::*")
+	if keysCmd.Err() != nil {
+		return nil, errors.New(keysCmd.Err().Error())
+	}
+
+	for _, cacheKey := range keysCmd.Val() {
+		cmd := cache.redisClient.Get(context.Background(), cacheKey)
+		if cmd.Err() != nil {
+			if cmd.Err().Error() == redis.Nil.Error() {
+				result[cache.cacheKey2Key(cacheKey)] = ""
+				continue
+			}
+
+			return nil, cmd.Err()
+		}
+
+		result[cache.cacheKey2Key(cacheKey)] = cmd.Val()
+	}
+
+	return result, nil
+}
+
+func (cache *Cache) Delete(key string) error {
+	cmd := cache.redisClient.Del(context.Background(), cache.key2CacheKey(key))
+	if cmd.Err() != nil {
+		return errors.New(cmd.Err().Error())
+	}
+
+	return nil
+}
+
+func (cache *Cache) Clear() error {
+	keysCmd := cache.redisClient.Keys(context.Background(), keyPrefix+cache.namespace+"::*")
+	if keysCmd.Err() != nil {
+		return errors.New(keysCmd.Err().Error())
+	}
+
+	delCmd := cache.redisClient.Del(context.Background(), keysCmd.Val()...)
+	if delCmd.Err() != nil {
+		return errors.New(delCmd.Err().Error())
+	}
+
+	return nil
+}
+
+func (cache *Cache) key2CacheKey(key string) string {
+	return keyPrefix + cache.namespace + "::" + key
+}
+
+func (cache *Cache) cacheKey2Key(cacheKey string) string {
+	return strings.TrimPrefix(cacheKey, keyPrefix+cache.namespace+"::")
+}

+ 50 - 4
framework/core/infrastructure/infrastructure.go

@@ -1,13 +1,18 @@
 package infrastructure
 
 import (
+	"git.sxidc.com/go-framework/baize/framework/core/infrastructure/cache"
+	"git.sxidc.com/go-framework/baize/framework/core/infrastructure/cache/local"
+	"git.sxidc.com/go-framework/baize/framework/core/infrastructure/cache/redis"
 	"git.sxidc.com/go-framework/baize/framework/core/infrastructure/database"
 	"git.sxidc.com/go-framework/baize/framework/core/infrastructure/database/data_service"
 	"git.sxidc.com/go-framework/baize/framework/core/infrastructure/database/operations"
+	"git.sxidc.com/go-tools/utils/strutils"
 )
 
 type Config struct {
 	DatabaseConfig
+	CacheConfig
 }
 
 type DatabaseConfig struct {
@@ -15,8 +20,20 @@ type DatabaseConfig struct {
 	DataService *data_service.Config `json:"data_service" yaml:"data_service"`
 }
 
+type CacheConfig struct {
+	Namespace string `json:"namespace" yaml:"namespace"`
+	Redis     *struct {
+		Address  string `json:"address" yaml:"address"`
+		UserName string `json:"user_name" yaml:"user_name"`
+		Password string `json:"password" yaml:"password"`
+		DB       int    `json:"db" yaml:"db"`
+	} `json:"redis" yaml:"redis"`
+}
+
 type Infrastructure struct {
 	dbExecutor database.Executor
+	localCache cache.Cache
+	redisCache cache.Cache
 }
 
 func NewInfrastructure(config Config) *Infrastructure {
@@ -26,19 +43,37 @@ func NewInfrastructure(config Config) *Infrastructure {
 	if config.DatabaseConfig.Operations != nil {
 		op, err := operations.NewOperations(config.DatabaseConfig.Operations)
 		if err != nil {
-			panic("创建数据库操作失败" + err.Error())
+			panic("创建数据库操作失败: " + err.Error())
 		}
 
 		i.dbExecutor = op
 	} else if config.DatabaseConfig.DataService != nil {
 		dataService, err := data_service.NewDataService(config.DatabaseConfig.DataService)
 		if err != nil {
-			panic("创建数据服务失败" + err.Error())
+			panic("创建数据服务失败: " + err.Error())
 		}
 
 		i.dbExecutor = dataService
 	}
 
+	// 初始化缓存
+	if strutils.IsStringNotEmpty(config.CacheConfig.Namespace) {
+		namespace := config.CacheConfig.Namespace
+
+		i.localCache = local.New(namespace)
+
+		if config.CacheConfig.Redis != nil {
+			redisConf := config.CacheConfig.Redis
+
+			redisCache, err := redis.New(redisConf.Address, redisConf.UserName, redisConf.Password, redisConf.DB, namespace)
+			if err != nil {
+				panic("初始化Redis缓存失败: " + err.Error())
+			}
+
+			i.redisCache = redisCache
+		}
+	}
+
 	return i
 }
 
@@ -47,17 +82,28 @@ func DestroyInfrastructure(i *Infrastructure) {
 		return
 	}
 
+	if i.redisCache != nil {
+		err := redis.Destroy(i.redisCache.(*redis.Cache))
+		if err != nil {
+			panic("销毁Redis缓存失败: " + err.Error())
+		}
+	}
+
+	if i.localCache != nil {
+		local.Destroy(i.localCache.(*local.Cache))
+	}
+
 	if i.dbExecutor != nil {
 		switch dbExecutor := i.dbExecutor.(type) {
 		case *operations.Operations:
 			err := operations.DestroyOperation(dbExecutor)
 			if err != nil {
-				panic("销毁数据库操作失败" + err.Error())
+				panic("销毁数据库操作失败: " + err.Error())
 			}
 		case *data_service.DataService:
 			err := data_service.DestroyDataService(dbExecutor)
 			if err != nil {
-				panic("销毁数据服务失败" + err.Error())
+				panic("销毁数据服务失败: " + err.Error())
 			}
 		default:
 			panic("不支持的数据库执行器类型")

+ 3 - 3
go.mod

@@ -4,7 +4,6 @@ go 1.22.3
 
 require (
 	git.sxidc.com/go-tools/utils v1.5.15
-	git.sxidc.com/service-supports/fserr v0.3.5
 	git.sxidc.com/service-supports/websocket v1.3.1
 	github.com/gin-gonic/gin v1.10.0
 	github.com/go-playground/locales v0.14.1
@@ -14,6 +13,7 @@ require (
 	github.com/iancoleman/strcase v0.3.0
 	github.com/mwitkow/go-proto-validators v0.3.2
 	github.com/pkg/errors v0.9.1
+	github.com/redis/go-redis/v9 v9.4.0
 	go.uber.org/zap v1.27.0
 	google.golang.org/grpc v1.64.0
 	google.golang.org/protobuf v1.34.1
@@ -24,14 +24,15 @@ require (
 )
 
 require (
-	git.sxidc.com/service-supports/fslog v0.5.9 // indirect
 	github.com/Masterminds/goutils v1.1.1 // indirect
 	github.com/Masterminds/semver/v3 v3.2.0 // indirect
 	github.com/Masterminds/sprig/v3 v3.2.3 // indirect
 	github.com/bytedance/sonic v1.11.6 // indirect
 	github.com/bytedance/sonic/loader v0.1.1 // indirect
+	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/cloudwego/base64x v0.1.4 // indirect
 	github.com/cloudwego/iasm v0.2.0 // indirect
+	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
 	github.com/gabriel-vasile/mimetype v1.4.3 // indirect
 	github.com/gin-contrib/sse v0.1.0 // indirect
 	github.com/go-resty/resty/v2 v2.11.0 // indirect
@@ -56,7 +57,6 @@ require (
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/olahol/melody v1.2.1 // indirect
 	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
-	github.com/puzpuzpuz/xsync v1.5.2 // indirect
 	github.com/rogpeppe/go-internal v1.12.0 // indirect
 	github.com/satori/go.uuid v1.2.0 // indirect
 	github.com/shopspring/decimal v1.2.0 // indirect

+ 10 - 6
go.sum

@@ -1,9 +1,5 @@
 git.sxidc.com/go-tools/utils v1.5.15 h1:7xs/EM8XZyKycrSSHcPZ6wvyYs+v8uWQ7ZmPP/fHyFI=
 git.sxidc.com/go-tools/utils v1.5.15/go.mod h1:fkobAXFpOMTvkZ82TQXWcpsayePcyk/MS5TN6GTlRDg=
-git.sxidc.com/service-supports/fserr v0.3.5 h1:1SDC60r3FIDd2iRq/oHRLK4OMa1gf67h9B7kierKTUE=
-git.sxidc.com/service-supports/fserr v0.3.5/go.mod h1:8U+W/ulZIGVPFojV6cE18shkGXqvaICuzaxIJpOcBqI=
-git.sxidc.com/service-supports/fslog v0.5.9 h1:q2XIK2o/fk/qmByy4x5kKLC+k7kolT5LrXHcWRSffXQ=
-git.sxidc.com/service-supports/fslog v0.5.9/go.mod h1:/m03ATmmOle75qtEgvEw8a1+Dcg6iHp08M1bGFXJTBU=
 git.sxidc.com/service-supports/websocket v1.3.1 h1:1mRfUwvpg0QA2JVKVMK8YJ/B33HFpDhY9srqroIuNGc=
 git.sxidc.com/service-supports/websocket v1.3.1/go.mod h1:YqEZXkN8ZFzUp01tDlekgIJJ0Yz+67d6eTXyA0ZIkgM=
 github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
@@ -12,10 +8,16 @@ github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7Y
 github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
 github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
 github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
+github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
+github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
+github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
+github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
 github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
 github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
 github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
 github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
 github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
 github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
@@ -23,6 +25,8 @@ github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQ
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
 github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
 github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
 github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
@@ -105,8 +109,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/puzpuzpuz/xsync v1.5.2 h1:yRAP4wqSOZG+/4pxJ08fPTwrfL0IzE/LKQ/cw509qGY=
-github.com/puzpuzpuz/xsync v1.5.2/go.mod h1:K98BYhX3k1dQ2M63t1YNVDanbwUPmBCAhNmVrrxfiGg=
+github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk=
+github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
 github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
 github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
 github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=