Currency Forum 是一个基于 Go 构建的汇率资讯社区后端项目。系统围绕“币种对讨论”这一垂直场景展开,支持用户注册登录、文章发布与查询、汇率录入与查询、文章点赞等核心功能。
项目不是单纯的 CRUD Demo,而是把认证、分层架构、MySQL 持久化、Redis 缓存、事务一致性、分页筛选、健康检查、优雅停机、Docker Compose 和 Swagger 文档等后端工程能力组合到一个完整的小型服务中。
- 基于
Gin设计 RESTful API,完成用户、文章、汇率、点赞等核心业务模块。 - 采用
Controller-Service-Repository三层架构拆分接口层、业务层和数据访问层。 - 使用
GORM + MySQL完成用户、文章、汇率、点赞关系等数据建模,并支持服务启动阶段自动迁移。 - 基于
JWT + Gin Middleware实现登录鉴权,通过路由分组区分公开接口和受保护接口。 - 引入
Redis缓存文章点赞总数,并结合数据库回源机制提升热点点赞数据读取性能。 - 设计点赞关系表,通过
article_id + user_id联合唯一索引防止重复点赞。 - 点赞流程使用事务保证点赞关系写入与文章点赞数更新的一致性。
- 支持文章和汇率列表分页、筛选、排序查询,满足前端多条件列表展示需求。
- 提供健康检查、请求 ID、访问日志、优雅停机等基础服务治理能力。
- 提供
Dockerfile、docker-compose.yml和 OpenAPI/Swagger 文档,方便本地启动和接口调试。
| 分类 | 技术 |
|---|---|
| 语言 | Go |
| Web 框架 | Gin |
| ORM | GORM |
| 数据库 | MySQL |
| 缓存 | Redis |
| 配置管理 | Viper |
| 认证 | JWT, bcrypt |
| 接口文档 | OpenAPI 3.0, Swagger UI |
| 部署 | Docker, Docker Compose |
| 测试 | Go test |
flowchart TD
Client["Client / Web Page"] --> Router["Gin Router"]
Router --> Middleware["Middleware"]
Middleware --> Controller["Controller"]
Controller --> Service["Service"]
Service --> Repository["Repository"]
Repository --> MySQL["MySQL"]
Service --> Redis["Redis"]
| 层级 | 职责 |
|---|---|
| Controller | 接收 HTTP 请求,参数绑定与校验,返回统一响应 |
| Service | 处理业务规则、事务边界、跨组件协作 |
| Repository | 封装数据库查询、分页、筛选、排序等数据访问逻辑 |
| Model | 定义用户、文章、汇率、点赞关系等数据模型 |
| Middleware | 处理鉴权、请求 ID、访问日志、异常恢复等通用逻辑 |
- 用户注册
- 用户登录
- 密码使用
bcrypt加密存储 - 登录成功后返回 JWT
- 受保护接口通过
Authorization: Bearer <token>访问
- 发布文章
- 查询文章详情
- 查询文章列表
- 支持分页查询
- 支持按关键词、作者、币种对筛选
- 支持按最新、最热、最早排序
文章会绑定币种对,例如 USD/CNY,使内容和汇率场景产生业务关联,而不是普通的帖子系统。
- 新增汇率记录
- 查询汇率列表
- 支持按币种对筛选
- 支持按数据来源筛选
- 支持
latestOnly查询每个币种对的最新一条记录 - 保留
source和capturedAt字段,方便后续扩展第三方汇率源和定时同步
点赞模块不是简单地对文章表字段做自增,而是采用:
article_likes表保存真实点赞关系articles.likes_count保存聚合后的点赞数Redis缓存文章点赞总数
这样可以同时满足:
- 防止同一用户重复点赞
- 保留用户点赞关系,方便后续扩展取消点赞、点赞记录等功能
- 使用事务保证点赞关系和点赞数更新一致
- 使用 Redis 降低热点点赞数读取压力
sequenceDiagram
participant C as Client
participant M as Auth Middleware
participant S as Like Service
participant DB as MySQL
participant R as Redis
C->>M: POST /api/articles/{id}/like
M->>M: Parse JWT
M->>S: Pass username and article id
S->>DB: Check article and user
S->>DB: Check article_likes relation
alt Not liked
S->>DB: Insert like relation in transaction
S->>DB: Increment article likes_count
else Already liked
S->>S: Skip write
end
S->>DB: Count likes by article id
S->>R: Refresh like count cache
S-->>C: Return like result
erDiagram
USERS ||--o{ ARTICLES : writes
USERS ||--o{ ARTICLE_LIKES : likes
ARTICLES ||--o{ ARTICLE_LIKES : receives
USERS {
uint id
string username
string password
}
ARTICLES {
uint id
string title
string preview
string content
string base_currency
string quote_currency
string status
int likes_count
uint author_id
}
ARTICLE_LIKES {
uint id
uint article_id
uint user_id
}
EXCHANGE_RATES {
uint id
string base_currency
string quote_currency
decimal rate
string source
datetime captured_at
}
.
├── config # 配置加载、MySQL/Redis 初始化、数据迁移、资源关闭
│ └── global # 全局数据库和 Redis 客户端
├── controller # HTTP 控制层
│ └── middlewares # 鉴权、请求 ID、访问日志等中间件
├── docs # OpenAPI 文档和 Swagger UI 页面
├── models # GORM 数据模型
├── repository # 数据访问层
├── router # 路由注册
├── service # 业务逻辑层
├── utils # JWT、密码加密等工具函数
├── web # 简单演示页面
├── Dockerfile # 应用镜像构建文件
├── docker-compose.yml # app + MySQL + Redis 编排
├── main.go # 服务入口
└── README.md
推荐使用 Docker Compose 一键启动应用、MySQL 和 Redis:
docker compose up --build启动后访问:
| 地址 | 说明 |
|---|---|
http://localhost:3000/ |
演示页面 |
http://localhost:3000/docs |
Swagger API 文档 |
http://localhost:3000/openapi.yaml |
OpenAPI 原始文件 |
http://localhost:3000/healthz |
健康检查 |
如果不使用 Docker,需要先准备:
- Go
- MySQL
- Redis
修改 config/config.yml 中的数据库和 Redis 配置后执行:
go run main.go默认服务地址:
http://localhost:3000
默认配置文件位于 config/config.yml:
app:
name: CurrencyExchangeApp
port: 3000
database:
dsn: "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
redis:
addr: "127.0.0.1:6379"
jwt:
secret: "interview-demo-secret"
expireHours: 72项目支持通过环境变量覆盖配置,例如:
APP_PORT=3000
DATABASE_DSN="root:123456@tcp(mysql:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
REDIS_ADDR="redis:6379"
JWT_SECRET="interview-demo-secret"| 方法 | 路径 | 说明 | 鉴权 |
|---|---|---|---|
| POST | /api/auth/register |
用户注册 | 否 |
| POST | /api/auth/login |
用户登录 | 否 |
| 方法 | 路径 | 说明 | 鉴权 |
|---|---|---|---|
| GET | /api/articles |
查询文章列表 | 否 |
| GET | /api/articles/{id} |
查询文章详情 | 否 |
| POST | /api/articles |
发布文章 | 是 |
| GET | /api/articles/{id}/like |
查询文章点赞数 | 否 |
| POST | /api/articles/{id}/like |
点赞文章 | 是 |
| 方法 | 路径 | 说明 | 鉴权 |
|---|---|---|---|
| GET | /api/exchangeRates |
查询汇率列表 | 否 |
| POST | /api/exchangeRates |
新增汇率记录 | 是 |
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /healthz |
检查服务、MySQL、Redis 状态 |
完整接口参数请查看 Swagger 文档:
http://localhost:3000/docs
curl -X POST http://localhost:3000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"username":"demo_user","password":"demo123456"}'curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"demo_user","password":"demo123456"}'curl -X POST http://localhost:3000/api/articles \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"title": "USD/CNY short term view",
"preview": "A short note about USD/CNY movement.",
"content": "USD/CNY remains sensitive to policy signals and market liquidity.",
"baseCurrency": "USD",
"quoteCurrency": "CNY",
"status": "published"
}'curl -X POST http://localhost:3000/api/exchangeRates \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"baseCurrency": "USD",
"quoteCurrency": "CNY",
"rate": 7.2301,
"source": "manual"
}'执行全部测试:
go test ./...如果本机 Go 构建缓存目录存在权限问题,可以临时指定项目内缓存目录:
GOCACHE=.gocache go test ./...当前测试主要覆盖:
- JWT 生成与解析
- 密码加密与校验
- 分页参数规范化
- 请求 ID 中间件
- 配置文件和环境变量结合
- 服务启动阶段自动迁移数据表
- MySQL 和 Redis 连接初始化
- 请求 ID 中间件
- 访问日志中间件
- JWT 鉴权中间件
- 健康检查接口
- HTTP 服务优雅停机
- Docker Compose 一键启动
- Swagger API 文档
- 接入第三方汇率 API,增加定时同步任务
- 增加评论、收藏、热门币种榜等社区功能
- 增加 refresh token 和登出黑名单机制
- 增加角色权限控制
- 增加数据库和 Redis 的集成测试
- 对热点列表和汇率最新值查询做进一步索引优化
这个项目适合作为 Go 后端面试项目展示。它的重点不是业务模块数量,而是围绕一个垂直场景,把认证、缓存、事务、分层、分页、迁移、服务治理和容器化部署等常见后端能力串成一个可运行、可讲清楚、可继续扩展的小型系统。