feat: 实现公共工具包,包括日志、错误处理、数据库和缓存
This commit is contained in:
120
backend/shared/pkg/cache/redis.go
vendored
Normal file
120
backend/shared/pkg/cache/redis.go
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"backend/shared/pkg/logger"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
type RedisConfig struct {
|
||||
Addr string
|
||||
Password string
|
||||
DB int
|
||||
}
|
||||
|
||||
type RedisCache struct {
|
||||
Client *redis.Client
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewRedisCache 创建新的 Redis 缓存连接
|
||||
func NewRedisCache(config RedisConfig) (*RedisCache, error) {
|
||||
client := redis.NewClient(&redis.Options{
|
||||
Addr: config.Addr,
|
||||
Password: config.Password,
|
||||
DB: config.DB,
|
||||
})
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// 测试连接
|
||||
if _, err := client.Ping(ctx).Result(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger.Info("Connected to Redis cache")
|
||||
|
||||
return &RedisCache{
|
||||
Client: client,
|
||||
ctx: ctx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Close 关闭 Redis 连接
|
||||
func (r *RedisCache) Close() error {
|
||||
if r.Client != nil {
|
||||
return r.Client.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set 设置缓存
|
||||
func (r *RedisCache) Set(key string, value interface{}, expiration time.Duration) error {
|
||||
return r.Client.Set(r.ctx, key, value, expiration).Err()
|
||||
}
|
||||
|
||||
// Get 获取缓存
|
||||
func (r *RedisCache) Get(key string) (string, error) {
|
||||
return r.Client.Get(r.ctx, key).Result()
|
||||
}
|
||||
|
||||
// Delete 删除缓存
|
||||
func (r *RedisCache) Delete(key string) error {
|
||||
return r.Client.Del(r.ctx, key).Err()
|
||||
}
|
||||
|
||||
// Exists 检查键是否存在
|
||||
func (r *RedisCache) Exists(key string) (bool, error) {
|
||||
result, err := r.Client.Exists(r.ctx, key).Result()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return result > 0, nil
|
||||
}
|
||||
|
||||
// Expire 设置键的过期时间
|
||||
func (r *RedisCache) Expire(key string, expiration time.Duration) error {
|
||||
return r.Client.Expire(r.ctx, key, expiration).Err()
|
||||
}
|
||||
|
||||
// TTL 获取键的剩余过期时间
|
||||
func (r *RedisCache) TTL(key string) (time.Duration, error) {
|
||||
return r.Client.TTL(r.ctx, key).Result()
|
||||
}
|
||||
|
||||
// Incr 递增键的值
|
||||
func (r *RedisCache) Incr(key string) (int64, error) {
|
||||
return r.Client.Incr(r.ctx, key).Result()
|
||||
}
|
||||
|
||||
// Decr 递减键的值
|
||||
func (r *RedisCache) Decr(key string) (int64, error) {
|
||||
return r.Client.Decr(r.ctx, key).Result()
|
||||
}
|
||||
|
||||
// HashSet 设置哈希表字段
|
||||
func (r *RedisCache) HashSet(key, field string, value interface{}) error {
|
||||
return r.Client.HSet(r.ctx, key, field, value).Err()
|
||||
}
|
||||
|
||||
// HashGet 获取哈希表字段
|
||||
func (r *RedisCache) HashGet(key, field string) (string, error) {
|
||||
return r.Client.HGet(r.ctx, key, field).Result()
|
||||
}
|
||||
|
||||
// HashDelete 删除哈希表字段
|
||||
func (r *RedisCache) HashDelete(key string, fields ...string) error {
|
||||
return r.Client.HDel(r.ctx, key, fields...).Err()
|
||||
}
|
||||
|
||||
// HashExists 检查哈希表字段是否存在
|
||||
func (r *RedisCache) HashExists(key, field string) (bool, error) {
|
||||
result, err := r.Client.HExists(r.ctx, key, field).Result()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
79
backend/shared/pkg/database/postgres.go
Normal file
79
backend/shared/pkg/database/postgres.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"backend/shared/pkg/logger"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
type PostgresConfig struct {
|
||||
Host string
|
||||
Port int
|
||||
User string
|
||||
Password string
|
||||
DBName string
|
||||
SSLMode string
|
||||
}
|
||||
|
||||
type PostgresDB struct {
|
||||
DB *sql.DB
|
||||
}
|
||||
|
||||
// NewPostgresDB 创建新的 PostgreSQL 数据库连接
|
||||
func NewPostgresDB(config PostgresConfig) (*PostgresDB, error) {
|
||||
connStr := fmt.Sprintf(
|
||||
"host=%s port=%d user=%s password=%s dbname=%s sslmode=%s",
|
||||
config.Host, config.Port, config.User, config.Password, config.DBName, config.SSLMode,
|
||||
)
|
||||
|
||||
db, err := sql.Open("postgres", connStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 设置连接池参数
|
||||
db.SetMaxOpenConns(25)
|
||||
db.SetMaxIdleConns(5)
|
||||
db.SetConnMaxLifetime(5 * time.Minute)
|
||||
|
||||
// 测试连接
|
||||
if err := db.Ping(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger.Info("Connected to PostgreSQL database")
|
||||
|
||||
return &PostgresDB{DB: db}, nil
|
||||
}
|
||||
|
||||
// Close 关闭数据库连接
|
||||
func (p *PostgresDB) Close() error {
|
||||
if p.DB != nil {
|
||||
return p.DB.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Exec 执行 SQL 语句
|
||||
func (p *PostgresDB) Exec(query string, args ...interface{}) (sql.Result, error) {
|
||||
return p.DB.Exec(query, args...)
|
||||
}
|
||||
|
||||
// Query 执行查询
|
||||
func (p *PostgresDB) Query(query string, args ...interface{}) (*sql.Rows, error) {
|
||||
return p.DB.Query(query, args...)
|
||||
}
|
||||
|
||||
// QueryRow 执行单行查询
|
||||
func (p *PostgresDB) QueryRow(query string, args ...interface{}) *sql.Row {
|
||||
return p.DB.QueryRow(query, args...)
|
||||
}
|
||||
|
||||
// Begin 开始事务
|
||||
func (p *PostgresDB) Begin() (*sql.Tx, error) {
|
||||
return p.DB.Begin()
|
||||
}
|
||||
96
backend/shared/pkg/errors/errors.go
Normal file
96
backend/shared/pkg/errors/errors.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// 错误类型定义
|
||||
var (
|
||||
ErrNotFound = errors.New("resource not found")
|
||||
ErrInvalidInput = errors.New("invalid input")
|
||||
ErrInternalServer = errors.New("internal server error")
|
||||
ErrUnauthorized = errors.New("unauthorized")
|
||||
ErrForbidden = errors.New("forbidden")
|
||||
ErrConflict = errors.New("conflict")
|
||||
ErrBadRequest = errors.New("bad request")
|
||||
ErrTimeout = errors.New("timeout")
|
||||
ErrServiceUnavailable = errors.New("service unavailable")
|
||||
)
|
||||
|
||||
// AppError 应用错误结构
|
||||
type AppError struct {
|
||||
Err error
|
||||
Message string
|
||||
Code int
|
||||
}
|
||||
|
||||
func (e *AppError) Error() string {
|
||||
if e.Message != "" {
|
||||
return e.Message
|
||||
}
|
||||
return e.Err.Error()
|
||||
}
|
||||
|
||||
func (e *AppError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// NewAppError 创建新的应用错误
|
||||
func NewAppError(err error, message string, code int) *AppError {
|
||||
return &AppError{
|
||||
Err: err,
|
||||
Message: message,
|
||||
Code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WrapError 包装错误
|
||||
func WrapError(err error, message string) error {
|
||||
return fmt.Errorf("%s: %w", message, err)
|
||||
}
|
||||
|
||||
// IsNotFound 检查是否为资源未找到错误
|
||||
func IsNotFound(err error) bool {
|
||||
return errors.Is(err, ErrNotFound)
|
||||
}
|
||||
|
||||
// IsInvalidInput 检查是否为无效输入错误
|
||||
func IsInvalidInput(err error) bool {
|
||||
return errors.Is(err, ErrInvalidInput)
|
||||
}
|
||||
|
||||
// IsInternalServer 检查是否为内部服务器错误
|
||||
func IsInternalServer(err error) bool {
|
||||
return errors.Is(err, ErrInternalServer)
|
||||
}
|
||||
|
||||
// IsUnauthorized 检查是否为未授权错误
|
||||
func IsUnauthorized(err error) bool {
|
||||
return errors.Is(err, ErrUnauthorized)
|
||||
}
|
||||
|
||||
// IsForbidden 检查是否为禁止访问错误
|
||||
func IsForbidden(err error) bool {
|
||||
return errors.Is(err, ErrForbidden)
|
||||
}
|
||||
|
||||
// IsConflict 检查是否为冲突错误
|
||||
func IsConflict(err error) bool {
|
||||
return errors.Is(err, ErrConflict)
|
||||
}
|
||||
|
||||
// IsBadRequest 检查是否为请求错误
|
||||
func IsBadRequest(err error) bool {
|
||||
return errors.Is(err, ErrBadRequest)
|
||||
}
|
||||
|
||||
// IsTimeout 检查是否为超时错误
|
||||
func IsTimeout(err error) bool {
|
||||
return errors.Is(err, ErrTimeout)
|
||||
}
|
||||
|
||||
// IsServiceUnavailable 检查是否为服务不可用错误
|
||||
func IsServiceUnavailable(err error) bool {
|
||||
return errors.Is(err, ErrServiceUnavailable)
|
||||
}
|
||||
38
backend/shared/pkg/logger/logger.go
Normal file
38
backend/shared/pkg/logger/logger.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
infoLogger *log.Logger
|
||||
errorLogger *log.Logger
|
||||
debugLogger *log.Logger
|
||||
}
|
||||
|
||||
var instance *Logger
|
||||
|
||||
func init() {
|
||||
instance = NewLogger()
|
||||
}
|
||||
|
||||
func NewLogger() *Logger {
|
||||
return &Logger{
|
||||
infoLogger: log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile),
|
||||
errorLogger: log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile),
|
||||
debugLogger: log.New(os.Stdout, "DEBUG: ", log.Ldate|log.Ltime|log.Lshortfile),
|
||||
}
|
||||
}
|
||||
|
||||
func Info(format string, v ...interface{}) {
|
||||
instance.infoLogger.Printf(format, v...)
|
||||
}
|
||||
|
||||
func Error(format string, v ...interface{}) {
|
||||
instance.errorLogger.Printf(format, v...)
|
||||
}
|
||||
|
||||
func Debug(format string, v ...interface{}) {
|
||||
instance.debugLogger.Printf(format, v...)
|
||||
}
|
||||
Reference in New Issue
Block a user