feat(config): 添加配置管理模块和数据库连接功能
- 实现全局配置结构体,包含服务、数据库和日志配置 - 添加 Viper 配置加载功能,支持 YAML 文件和环境变量 - 创建 config.yaml 配置文件,包含服务器和数据库连接信息 - 集成 GORM 数据库连接功能,支持 PostgreSQL 驱动 - 更新依赖包,添加 postgres 驱动和相关工具库 - 实现 main 入口函数,加载配置并初始化服务 - 创建详细的 Phase 1 基础设施实施计划文档
This commit is contained in:
@@ -275,18 +275,16 @@ type Strategy interface {
|
|||||||
## 分阶段实施计划
|
## 分阶段实施计划
|
||||||
|
|
||||||
### Phase 1: 项目骨架 & 基础设施(第 1-2 天)
|
### Phase 1: 项目骨架 & 基础设施(第 1-2 天)
|
||||||
|
> 📋 **详细计划**: [phase-1-infrastructure.md](phase-1-infrastructure.md)
|
||||||
|
|
||||||
**学习目标**: Go 项目组织、package 管理、Gin 基础
|
**学习目标**: Go 项目组织、package 管理、Gin 基础
|
||||||
|
|
||||||
具体任务:
|
**核心任务**:
|
||||||
- [-] 初始化 `go.mod`(go mod init github.com/synoth/janus)
|
- 初始化 `go.mod`,安装 gin / gorm / viper / pgx 依赖
|
||||||
- [ ] 安装核心依赖:gin, gorm, viper, pgx 驱动
|
- 实现配置加载(Viper + YAML + 环境变量)
|
||||||
- [ ] 实现 `internal/config/config.go`:Viper 加载 YAML 配置
|
- 实现 GORM 数据库连接和连接池配置
|
||||||
- [ ] 编写 `config.yaml`:数据库连接、服务器端口等
|
- 实现 `/health` 端点,组装 Gin 启动流程
|
||||||
- [ ] 实现 `cmd/server/main.go`:组装依赖,启动 Gin
|
- 添加 `.env` 支持和 `.gitignore`
|
||||||
- [ ] 实现 `internal/router/router.go`:基础路由
|
|
||||||
- [ ] 实现 `internal/handler/health_handler.go`:GET /health
|
|
||||||
- [ ] 实现 GORM 数据库连接 & AutoMigrate
|
|
||||||
- [ ] 添加 `.env` 支持敏感配置
|
|
||||||
|
|
||||||
**交付物**: 可运行的服务,响应 `/health`,连接数据库
|
**交付物**: 可运行的服务,响应 `/health`,连接数据库
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,366 @@
|
|||||||
|
# Phase 1: 项目骨架 & 基础设施 — 详细计划
|
||||||
|
|
||||||
|
> **所属主计划**: [main-plan.md](main-plan.md#phase-1-项目骨架--基础设施第-1-2-天)
|
||||||
|
> **预计时间**: 第 1-2 天
|
||||||
|
> **核心学习**: Go 项目组织、package 管理、Gin 基础
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 学习目标
|
||||||
|
|
||||||
|
| Go 概念 | 说明 | Java 对照 |
|
||||||
|
|----------|------|-----------|
|
||||||
|
| `go mod init` / `go mod tidy` | 依赖管理 | Maven `pom.xml` / Gradle `build.gradle`,但更轻量 |
|
||||||
|
| package 组织 | 按功能分目录,每个目录一个 package | Java package 按目录组织 |
|
||||||
|
| `func main()` | 程序入口 | `public static void main(String[])` |
|
||||||
|
| `init()` | 包初始化函数,main 之前自动执行 | Spring `@PostConstruct` / static initializer |
|
||||||
|
| pointer `*` | 指针类型,传递引用而非拷贝 | Java 中除了基本类型,对象默认是引用 |
|
||||||
|
| value `&` | 取地址 | Java 无直接对应 |
|
||||||
|
| `defer` | 函数返回前执行,常用于清理资源 | `try-finally` 的 `finally` 块 |
|
||||||
|
| error 返回值 | 函数返回 error,调用方检查 | Java checked exception,但更显式 |
|
||||||
|
| `:=` vs `var` | 短声明 vs 显式声明 | `var` 类型推断 |
|
||||||
|
| struct tag | 结构体字段上的元数据注解 | Java annotation(`@JsonProperty` 等) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 任务分解
|
||||||
|
|
||||||
|
### Step 1.0: 初始化 Go Module
|
||||||
|
|
||||||
|
**任务**: 在项目根目录执行 `go mod init`,建立 Go 模块。
|
||||||
|
|
||||||
|
**关键点**:
|
||||||
|
- 模块路径已经在 CLAUDE.md 中定义为 `synoth.com/janus`
|
||||||
|
- 不要用 `github.com/xxx` —— 这是学习项目,不需要托管到 GitHub
|
||||||
|
- `go.mod` 相当于 Java Maven 的 `pom.xml`,记录模块名、Go 版本、依赖
|
||||||
|
|
||||||
|
**验证**: `cat go.mod` 确认模块声明正确
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Step 1.1: 安装核心依赖
|
||||||
|
|
||||||
|
**任务**: 通过 `go get` 安装以下依赖包:
|
||||||
|
|
||||||
|
| 包 | 用途 | Java 类比 |
|
||||||
|
|----|------|-----------|
|
||||||
|
| `github.com/gin-gonic/gin` | Web 框架,路由 + 中间件 | Spring MVC |
|
||||||
|
| `gorm.io/gorm` | ORM 核心库 | JPA / Hibernate |
|
||||||
|
| `gorm.io/driver/postgres` | GORM PostgreSQL 驱动 | PostgreSQL JDBC Driver |
|
||||||
|
| `github.com/spf13/viper` | 配置管理(YAML + 环境变量) | Spring `@ConfigurationProperties` |
|
||||||
|
| `github.com/joho/godotenv` | 加载 `.env` 文件到环境变量 | dotenv-java |
|
||||||
|
|
||||||
|
**关键点**:
|
||||||
|
- `go get` 会自动更新 `go.mod` 和生成 `go.sum`(类似 `pom.xml` + 依赖锁)
|
||||||
|
- `go.sum` 记录每个依赖的校验和,确保可复现构建
|
||||||
|
- 间接依赖(indirect)会被自动标记
|
||||||
|
|
||||||
|
**验证**: `go.mod` 中出现所有依赖,`go.sum` 非空
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Step 1.2: 实现配置加载 — `internal/config/config.go`
|
||||||
|
|
||||||
|
**任务**: 用 Viper 加载 `config.yaml` + 环境变量覆盖。
|
||||||
|
|
||||||
|
**需要定义的结构体**:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Config —— 顶层配置结构体
|
||||||
|
type Config struct {
|
||||||
|
Server ServerConfig `mapstructure:"server"`
|
||||||
|
Database DatabaseConfig `mapstructure:"database"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerConfig —— HTTP 服务器配置
|
||||||
|
type ServerConfig struct {
|
||||||
|
Port int `mapstructure:"port"` // 默认 8080
|
||||||
|
Mode string `mapstructure:"mode"` // debug / release / test
|
||||||
|
}
|
||||||
|
|
||||||
|
// DatabaseConfig —— PostgreSQL 连接配置
|
||||||
|
type DatabaseConfig struct {
|
||||||
|
Host string `mapstructure:"host"`
|
||||||
|
Port int `mapstructure:"port"`
|
||||||
|
User string `mapstructure:"user"`
|
||||||
|
Password string `mapstructure:"password"`
|
||||||
|
DBName string `mapstructure:"dbname"`
|
||||||
|
SSLMode string `mapstructure:"sslmode"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**需要实现的函数**:
|
||||||
|
- `Load(path string) (*Config, error)` — 加载配置文件
|
||||||
|
- 支持环境变量覆盖(如 `DATABASE_PASSWORD` 覆盖 YAML 中的明文密码)
|
||||||
|
|
||||||
|
**Go 学习点**:
|
||||||
|
- `mapstructure` tag 是 Viper 专用的 struct tag,类似 Java `@ConfigurationProperties(prefix="...")`
|
||||||
|
- `*Config` 返回指针而非值 — Go 中大型 struct 传指针避免拷贝
|
||||||
|
- error 作为返回值,调用方必须处理
|
||||||
|
|
||||||
|
**Viper 配置方式**:
|
||||||
|
```go
|
||||||
|
v := viper.New()
|
||||||
|
v.SetConfigFile(path) // 指定配置文件路径
|
||||||
|
v.AutomaticEnv() // 自动读取环境变量
|
||||||
|
v.SetEnvKeyReplacer(...) // 将 "." 替换为 "_"(database.host → DATABASE_HOST)
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证**: 写一个简单的测试(可选),或者直接在 main 中调用 Load 打印结果
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Step 1.3: 编写配置文件 — `config.yaml`
|
||||||
|
|
||||||
|
**任务**: 在项目根目录创建默认配置文件。
|
||||||
|
|
||||||
|
**内容要点**:
|
||||||
|
```yaml
|
||||||
|
server:
|
||||||
|
port: 8080
|
||||||
|
mode: debug # Gin 模式:debug(带日志)/ release(生产)/ test
|
||||||
|
|
||||||
|
database:
|
||||||
|
host: localhost
|
||||||
|
port: 5432
|
||||||
|
user: janus
|
||||||
|
password: "" # 留空,通过环境变量或 .env 传入
|
||||||
|
dbname: janus
|
||||||
|
sslmode: disable # 本地开发关 SSL,生产用 require
|
||||||
|
```
|
||||||
|
|
||||||
|
**Go 学习点**:
|
||||||
|
- YAML 用缩进表示层级,没有 XML/JSON 的括号
|
||||||
|
- Viper 默认支持 YAML、JSON、TOML 等格式
|
||||||
|
- 敏感信息(密码)不写死在 YAML 中,通过环境变量注入
|
||||||
|
|
||||||
|
**验证**: 文件语法正确(可以用在线 YAML 验证器或 `yamllint`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Step 1.4: 添加 `.env` 支持
|
||||||
|
|
||||||
|
**任务**: 创建 `.env.example` 模板文件,并在 `main.go` 中用 `godotenv.Load()` 加载。
|
||||||
|
|
||||||
|
**`.env.example` 内容**:
|
||||||
|
```
|
||||||
|
DATABASE_PASSWORD=your_password_here
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键点**:
|
||||||
|
- `.env` 加入 `.gitignore`,避免敏感信息提交
|
||||||
|
- `.env.example` 提交到仓库,作为模板
|
||||||
|
- `godotenv.Load()` 在 `main()` 最开始调用,失败不阻断启动(`.env` 可能不存在)
|
||||||
|
|
||||||
|
**Go 学习点**:
|
||||||
|
- `godotenv.Load()` 读取 `.env` 并设置到进程环境变量
|
||||||
|
- Viper 的 `AutomaticEnv()` 自动读取环境变量,两者配合工作
|
||||||
|
|
||||||
|
**验证**: 创建 `.env` 文件后,`os.Getenv("DATABASE_PASSWORD")` 能读到值
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Step 1.5: 实现 GORM 数据库连接
|
||||||
|
|
||||||
|
**任务**: 在 `internal/config/` 或单独的 `internal/database/` 中实现 DB 连接初始化。
|
||||||
|
|
||||||
|
**需要实现的函数**:
|
||||||
|
```go
|
||||||
|
func NewDatabase(cfg *DatabaseConfig) (*gorm.DB, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
**实现要点**:
|
||||||
|
1. 构造 PostgreSQL DSN(Data Source Name):
|
||||||
|
```
|
||||||
|
host=localhost user=janus password=xxx dbname=janus port=5432 sslmode=disable
|
||||||
|
```
|
||||||
|
2. `gorm.Open(postgres.Open(dsn), &gorm.Config{})` 打开连接
|
||||||
|
3. 获取底层 `*sql.DB`,配置连接池参数:
|
||||||
|
- `SetMaxOpenConns(25)` — 最大打开连接数
|
||||||
|
- `SetMaxIdleConns(10)` — 最大空闲连接数
|
||||||
|
- `SetConnMaxLifetime(5 * time.Minute)` — 连接最大存活时间
|
||||||
|
4. `db.Ping()` 验证连接是否可用
|
||||||
|
|
||||||
|
**Go 学习点**:
|
||||||
|
- GORM 的 `gorm.Open()` 返回 `(*gorm.DB, error)`,惯例返回 error
|
||||||
|
- `*sql.DB` 是 Go 标准库的数据库句柄,GORM 在其上构建
|
||||||
|
- 连接池配置对标 Java HikariCP 的 `maximumPoolSize`、`minimumIdle`、`maxLifetime`
|
||||||
|
- `defer` 不在这里用(连接需要在整个应用生命周期保持),而是在 `main.go` 中管理
|
||||||
|
|
||||||
|
**验证**: 启动程序,GORM 打印连接日志无报错
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Step 1.6: 实现健康检查 Handler — `internal/handler/health_handler.go`
|
||||||
|
|
||||||
|
**任务**: 实现一个简单的健康检查端点。
|
||||||
|
|
||||||
|
**代码结构**:
|
||||||
|
```go
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
type HealthHandler struct {
|
||||||
|
db *gorm.DB // 用于检查数据库连接
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHealthHandler(db *gorm.DB) *HealthHandler { ... }
|
||||||
|
|
||||||
|
func (h *HealthHandler) Check(c *gin.Context) {
|
||||||
|
// 1. ping 数据库
|
||||||
|
// 2. 返回 JSON: { "status": "ok", "db": "connected" }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**返回格式**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "ok",
|
||||||
|
"timestamp": "2026-07-08T12:00:00Z",
|
||||||
|
"db": "connected"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Go 学习点**:
|
||||||
|
- `(h *HealthHandler)` 是指针接收者(pointer receiver)— 方法可以修改 h 的状态
|
||||||
|
- `gin.Context` 封装了 HTTP 请求和响应,类似 Spring 的 `HttpServletRequest` + `HttpServletResponse`
|
||||||
|
- `c.JSON(200, obj)` 自动设置 Content-Type 并序列化 JSON
|
||||||
|
- Gin 的 handler 签名是 `func(c *gin.Context)`,不使用返回值 — 通过 `c` 写响应
|
||||||
|
|
||||||
|
**验证**: `curl http://localhost:8080/health` 返回 JSON
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Step 1.7: 实现路由注册 — `internal/router/router.go`
|
||||||
|
|
||||||
|
**任务**: 集中管理所有路由注册。
|
||||||
|
|
||||||
|
**代码结构**:
|
||||||
|
```go
|
||||||
|
package router
|
||||||
|
|
||||||
|
func Setup(r *gin.Engine, handler *handler.HealthHandler) {
|
||||||
|
r.GET("/health", handler.Check)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Go 学习点**:
|
||||||
|
- 函数接收 `*gin.Engine`(Gin 的路由引擎),在其上注册路由
|
||||||
|
- 这是"依赖注入"的最简形式 —— 手动传参,不用框架的 DI 容器
|
||||||
|
- 路由分离到单独文件,避免 `main.go` 膨胀
|
||||||
|
|
||||||
|
**验证**: 路由文件编译通过,程序运行后 `/health` 可访问
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Step 1.8: 实现程序入口 — `cmd/server/main.go`
|
||||||
|
|
||||||
|
**任务**: 组装所有依赖,启动 HTTP 服务器。
|
||||||
|
|
||||||
|
**流程**:
|
||||||
|
```
|
||||||
|
main()
|
||||||
|
├── godotenv.Load(".env") // 加载环境变量
|
||||||
|
├── config.Load("config.yaml") // 加载配置
|
||||||
|
├── database.NewDatabase(&cfg.Database) // 初始化 DB
|
||||||
|
├── handler.NewHealthHandler(db) // 创建 handler
|
||||||
|
├── gin.New() / gin.Default() // 创建 Gin 引擎
|
||||||
|
├── router.Setup(r, healthHandler) // 注册路由
|
||||||
|
└── r.Run(":8080") // 启动服务器
|
||||||
|
```
|
||||||
|
|
||||||
|
**Gin 模式选择**:
|
||||||
|
- `gin.Default()` — 带 Logger 和 Recovery 中间件(开发推荐)
|
||||||
|
- `gin.New()` — 空白引擎,手动添加中间件
|
||||||
|
|
||||||
|
**Go 学习点**:
|
||||||
|
- `main` 函数必须在 `package main` 中,否则无法编译成可执行文件
|
||||||
|
- `main()` 无参数、无返回值 — 退出用 `os.Exit(code)`
|
||||||
|
- `defer` 用于在 main 返回前关闭数据库连接等资源
|
||||||
|
- 包的 `init()` 函数在 main 之前自动执行(GORM 驱动注册就是通过 init)
|
||||||
|
|
||||||
|
**验证**: `go run ./cmd/server/main.go` 启动成功,访问 `http://localhost:8080/health`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Step 1.9: 创建 `.gitignore`
|
||||||
|
|
||||||
|
**任务**: 确保敏感文件和构建产物不提交。
|
||||||
|
|
||||||
|
**必须忽略的内容**:
|
||||||
|
```
|
||||||
|
# 环境变量
|
||||||
|
.env
|
||||||
|
|
||||||
|
# 构建产物
|
||||||
|
/server
|
||||||
|
/janus
|
||||||
|
*.exe
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# 依赖
|
||||||
|
vendor/
|
||||||
|
|
||||||
|
# 临时文件
|
||||||
|
tmp/
|
||||||
|
temp/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 文件清单(Phase 1 产出)
|
||||||
|
|
||||||
|
```
|
||||||
|
janus/
|
||||||
|
├── cmd/server/main.go ← Step 1.8 实现
|
||||||
|
├── internal/
|
||||||
|
│ ├── config/
|
||||||
|
│ │ └── config.go ← Step 1.2 实现
|
||||||
|
│ ├── handler/
|
||||||
|
│ │ └── health_handler.go ← Step 1.6 实现
|
||||||
|
│ └── router/
|
||||||
|
│ └── router.go ← Step 1.7 实现
|
||||||
|
├── config.yaml ← Step 1.3 编写
|
||||||
|
├── .env.example ← Step 1.4 编写
|
||||||
|
├── .gitignore ← Step 1.9 编写
|
||||||
|
├── go.mod ← Step 1.0 生成
|
||||||
|
└── go.sum ← Step 1.1 生成
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 1 完成标准
|
||||||
|
|
||||||
|
- [ ] `go build ./...` 编译通过,无错误
|
||||||
|
- [ ] `go vet ./...` 静态分析无警告
|
||||||
|
- [ ] 程序启动后 `curl http://localhost:8080/health` 返回 `{"status":"ok",...}`
|
||||||
|
- [ ] GORM 成功连接 PostgreSQL(或优雅报错"数据库未启动"而不 panic)
|
||||||
|
- [ ] 配置文件中的值被正确读取(改端口后服务在新端口启动)
|
||||||
|
- [ ] `.env` 中的密码能覆盖 `config.yaml` 中的空值
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见问题 & 排错
|
||||||
|
|
||||||
|
| 问题 | 可能原因 | 解决 |
|
||||||
|
|------|----------|------|
|
||||||
|
| `go get` 失败/慢 | 网络问题 | 设置 `GOPROXY=https://goproxy.cn,direct` |
|
||||||
|
| `cannot find package` | 模块路径不对 | 检查 `go.mod` 的 module 名和 import 路径一致 |
|
||||||
|
| GORM 连接报错 | PostgreSQL 未启动 | `pg_isready` 检查,或用 Docker 启动 PostgreSQL |
|
||||||
|
| `import cycle not allowed` | 循环依赖 | Go 禁止包之间循环引用,检查 import 关系 |
|
||||||
|
| Viper 读不到配置 | 路径问题 | 用绝对路径或相对于执行目录的路径 |
|
||||||
|
| `:=` vs `=` 报错 | 短声明只能用于新变量 | 已声明的变量用 `=` 赋值 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 关键设计决策
|
||||||
|
|
||||||
|
1. **手动依赖注入** — 不使用 wire/di 框架。Phase 1 依赖少,手动传参最清晰,也是 Go 社区的常见做法
|
||||||
|
2. **Config 用指针返回** — `func Load() (*Config, error)` 而非 `(Config, error)`,避免大 struct 拷贝
|
||||||
|
3. **health check 注入 `*gorm.DB`** — 真实检查数据库连通性,而非返回假 OK
|
||||||
|
4. **`gin.Default()` 而非 `gin.New()`** — 开发阶段带 Logger 和 Recovery 中间件更方便
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "synoth.com/janus/internal/config"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg, err := config.Load("config.yaml")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
server:
|
||||||
|
port: 8080
|
||||||
|
mode: debug
|
||||||
|
|
||||||
|
database:
|
||||||
|
host: 175.178.9.76
|
||||||
|
port: 25432
|
||||||
|
dbname: postgres
|
||||||
|
username: synoth
|
||||||
|
password: uKWjf4ns5ahx
|
||||||
|
sslmode: disable
|
||||||
|
|
||||||
|
log:
|
||||||
|
level: debug
|
||||||
@@ -20,8 +20,10 @@ require (
|
|||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
github.com/jackc/pgx/v5 v5.10.0 // indirect
|
github.com/jackc/pgx/v5 v5.10.0 // indirect
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
github.com/joho/godotenv v1.5.1 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
@@ -45,8 +47,10 @@ require (
|
|||||||
golang.org/x/arch v0.22.0 // indirect
|
golang.org/x/arch v0.22.0 // indirect
|
||||||
golang.org/x/crypto v0.48.0 // indirect
|
golang.org/x/crypto v0.48.0 // indirect
|
||||||
golang.org/x/net v0.51.0 // indirect
|
golang.org/x/net v0.51.0 // indirect
|
||||||
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
golang.org/x/sys v0.41.0 // indirect
|
golang.org/x/sys v0.41.0 // indirect
|
||||||
golang.org/x/text v0.34.0 // indirect
|
golang.org/x/text v0.34.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.10 // indirect
|
google.golang.org/protobuf v1.36.10 // indirect
|
||||||
|
gorm.io/driver/postgres v1.6.0 // indirect
|
||||||
gorm.io/gorm v1.31.2 // indirect
|
gorm.io/gorm v1.31.2 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -35,10 +35,14 @@ github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7Ulw
|
|||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
github.com/jackc/pgx/v5 v5.10.0 h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0=
|
github.com/jackc/pgx/v5 v5.10.0 h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0=
|
||||||
github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
|
github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||||
@@ -97,6 +101,8 @@ golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
|||||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||||
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
||||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||||
|
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||||
|
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
@@ -107,5 +113,7 @@ google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j
|
|||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
|
||||||
|
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
|
||||||
gorm.io/gorm v1.31.2 h1:3o8FXNo9v9S858gil+3LlZA1LkCOzgb4g5BL64FgaCo=
|
gorm.io/gorm v1.31.2 h1:3o8FXNo9v9S858gil+3LlZA1LkCOzgb4g5BL64FgaCo=
|
||||||
gorm.io/gorm v1.31.2/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
gorm.io/gorm v1.31.2/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config 全局配置
|
||||||
|
type Config struct {
|
||||||
|
Server ServerConfig `mapstructure:"server"`
|
||||||
|
Database DatabaseConfig `mapstructure:"database"`
|
||||||
|
Log LogConfig `mapstructure:"log"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerConfig 服务基础配置
|
||||||
|
type ServerConfig struct {
|
||||||
|
Port int `mapstructure:"port"`
|
||||||
|
Mode string `mapstructure:"mode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DatabaseConfig 数据库配置
|
||||||
|
type DatabaseConfig struct {
|
||||||
|
Host string `mapstructure:"host"`
|
||||||
|
Port int `mapstructure:"port"`
|
||||||
|
User string `mapstructure:"user"`
|
||||||
|
Password string `mapstructure:"password"`
|
||||||
|
DBName string `mapstructure:"dbname"`
|
||||||
|
SSLMode string `mapstructure:"sslmode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogConfig 日志配置
|
||||||
|
type LogConfig struct {
|
||||||
|
Level string `mapstructure:"level"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func Load(path string) (*Config, error) {
|
||||||
|
v := viper.New()
|
||||||
|
v.SetConfigFile(path)
|
||||||
|
v.AutomaticEnv()
|
||||||
|
|
||||||
|
if err := v.ReadInConfig(); err != nil {
|
||||||
|
return nil, fmt.Errorf("read config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var cfg Config
|
||||||
|
if err := v.Unmarshal(&cfg); err != nil {
|
||||||
|
return nil, fmt.Errorf("unmarshal config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) InitGinMode() {
|
||||||
|
switch c.Server.Mode {
|
||||||
|
case "release":
|
||||||
|
gin.SetMode(gin.ReleaseMode)
|
||||||
|
case "test":
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
default:
|
||||||
|
gin.SetMode(gin.DebugMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import "gorm.io/gorm"
|
||||||
|
|
||||||
|
type DatabaseConfig struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func Connect(cfg DatabaseConfig) (*gorm.DB, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user