jiezhang-backend

May 21, 2026 · View on GitHub

Go + Gin 实现的记账小程序后端

技术栈

组件选型
Web 框架Gin v1.12
ORMGORM v1.31 + MySQL 驱动
数据库MySQL 8.x
缓存Redis(可选,未配置时用内存缓存)
微信登录jscode2session API
Excel 导出excelize v2
签名 URLHMAC-SHA256(防私密文件直接访问)

快速开始

环境要求

  • Go 1.26+
  • MySQL 8.x
  • Redis(可选,建议生产环境配置)

启动

# 1. 克隆项目
git clone https://github.com/yigger/jiezhang-backend.git
cd jiezhang-backend

# 2. 创建环境配置
cp .env.example .env
# 编辑 .env,填入真实的数据库连接、小程序密钥等

# 3. 安装依赖并运行
go mod tidy
go run .

服务默认监听 http://localhost:10240

环境变量

变量必填默认值说明
MYSQL_DSNMySQL 连接串
MINIPROGRAM_APPID微信小程序 AppID
MINIPROGRAM_SECRET微信小程序 Secret
SESSION_TOKEN_SECRET会话签名密钥
PORT10240监听端口
PUBLIC_BASE_URLhttp://localhost:<PORT>生成图片/文件链接的域名
REDIS_URLRedis 连接(不配则用内存缓存)
GIN_MODEdebugdebug / release / test

项目结构

.
├── main.go                          # 入口
├── cmd/server/main.go               # 备选入口(内容相同)
├── go.mod
├── .env.example                     # 环境变量模板
├── API.md                           # 完整 API 接口文档
├── public/                          # 静态文件(图片、上传附件)
│   ├── images/
│   │   ├── asset/                   # 资产图标
│   │   └── category/                # 分类图标
│   └── private/                     # 私有文件(含签名鉴权)
└── internal/
    ├── bootstrap/
    │   ├── app.go                   # 应用启动组装(依赖注入)
    │   └── modules/                 # 15 个模块组装器
    │       ├── auth_module.go
    │       ├── user_module.go
    │       ├── home_module.go
    │       ├── statement_module.go
    │       ├── ...(每领域一个文件)
    │       └── super_module.go
    ├── config/
    │   └── config.go               # 配置加载(.env + 环境变量)
    ├── domain/                      # 领域实体
    │   ├── user.go
    │   ├── statement.go
    │   ├── category.go
    │   ├── account_book.go
    │   └── payee.go
    ├── repository/                  # 数据访问接口定义
    │   ├── user_repository.go
    │   ├── statement_repository.go
    │   ├── ...(每聚合一个接口)
    │   └── mysql/                   # GORM / MySQL 实现
    │       ├── user_repository.go
    │       ├── statement_repository.go
    │       └── ...
    ├── service/                     # 业务逻辑层
    │   ├── statement_service.go
    │   ├── statement_export_excel.go
    │   ├── home_service.go
    │   ├── ...(每领域一个服务)
    │   ├── auth/
    │   │   └── check_openid_service.go
    │   ├── statement/
    │   │   ├── types.go             # DTO + 响应类型
    │   │   └── mapper.go            # DB row → DTO 映射
    │   └── helper/
    │       └── statement_helper.go
    ├── http/
    │   ├── router/
    │   │   └── router.go           # 83 个路由注册
    │   ├── handler/                 # HTTP 处理层
    │   │   ├── auth_handler.go
    │   │   ├── statements_handler.go
    │   │   ├── ...(每领域一个 handler)
    │   │   └── request_context.go   # 请求上下文提取(currentUser 等)
    │   ├── middleware/
    │   │   ├── api_v1_auth.go       # Session 鉴权
    │   │   ├── signed_url.go        # 私有文件签名校验
    │   │   └── access_log.go        # 请求日志
    │   └── dto/                     # 请求体 DTO
    │       ├── statement.go
    │       ├── asset.go
    │       └── ...
    └── infrastructure/              # 基础设施
        ├── db/mysql.go              # MySQL 连接
        ├── sessioncache/            # 缓存抽象
        │   ├── cache.go             # Cache 接口
        │   └── redis_cache.go       # Redis 实现
        ├── signedurl/signer.go      # HMAC URL 签名
        ├── urlbuilder/              # 公开 URL 构建
        └── wechat/client.go         # 微信 API 客户端

架构

分层架构

┌─────────────────────────────────────────────┐
│  handler (HTTP)                              │  ← 请求绑定、响应序列化
├─────────────────────────────────────────────┤
│  service (业务逻辑)                           │  ← 核心逻辑、协调编排
├─────────────────────────────────────────────┤
│  repository (数据访问接口)                     │  ← 接口定义(无外部依赖)
│  repository/mysql (GORM 实现)                 │  ← SQL 查询、事务
├─────────────────────────────────────────────┤
│  domain (领域实体)                            │  ← 纯结构体,无 ORM 标签
├─────────────────────────────────────────────┤
│  infrastructure (基础设施)                    │  ← DB、缓存、微信 SDK、签名
└─────────────────────────────────────────────┘

设计约定

  • 依赖注入bootstrap/app.gobootstrap/modules/*.go 手动组装依赖,不使用 DI 框架
  • 接口隔离repository/ 下定义接口,repository/mysql/ 下实现,service 只依赖接口
  • 领域与持久化分离domain/ 的实体没有 GORM 标签,repository/mysql/ 有独立的 model 结构体
  • DTO 层http/dto/ 定义请求体结构,与领域实体彻底解耦
  • 模块化:每个业务领域(auth、statement、category 等)有独立的 handler、service、repository 模块构造函数

如何加入开发

1. 理解代码流程(以"创建账单"为例)

客户端 POST /api/statements
  → router.go 路由到 statementsHandler.Create
  → handler: 绑定 DTO → 调用 service
  → service: normalizeStatementWriteInput(校验 + 特殊分类查找 + 余额计算)
  → repository: MySQL INSERT
  → service: 回查 detail → rowMapper.ToListItem → 返回 JSON

2. 新增一个业务领域

# 以"标签"为例,需要创建以下文件:
internal/domain/tag.go                          # 领域实体
internal/repository/tag_repository.go           # 接口定义
internal/repository/mysql/tag_repository.go     # MySQL 实现
internal/service/tag_service.go                 # 业务逻辑
internal/http/handler/tag_handler.go            # HTTP 处理
internal/http/dto/tag.go                        # 请求 DTO
internal/bootstrap/modules/tag_module.go        # 依赖组装

# 然后在以下文件中注册:
internal/bootstrap/app.go                       # 调用 BuildTagModule
internal/http/router/router.go                  # 注册路由

3. 代码规范

  • 错误处理:repository 层定义 var ErrXxxNotFound,service 层用 errors.Is 判断
  • 事务:需要事务的操作在 repository 的 MySQL 实现中用 db.Transaction()
  • 日志:使用 Go 标准 log 包,关键节点打日志
  • 避免 N+1:列表查询尽量用 JOIN,不用循环单条查询

4. API 文档

详见 API.md,覆盖全部 83 个接口,含请求参数和响应格式。

部署

# 编译二进制
go build -o jiezhang-server .

# 直接运行
./jiezhang-server

# 或配合 systemd / supervisor 守护进程
# 要求:
# - .env 文件与二进制同目录(或通过环境变量注入)
# - MySQL 可达
# - Redis 可达(可选)
# - public/ 目录存在(用于静态文件服务)