Go语言Gin框架MVC脚手架,能适配场景需求吗?
摘要:一款Go语言Gin框架MVC脚手架,满足大部分场景 一个开箱即用的 MVC(Model-View-Controller)Go 脚手架,基于 Gin + RocketMQ,包含双数据库、统一响应、中间件与事件驱动示例。 这是
一款Go语言Gin框架MVC脚手架,满足大部分场景
一个开箱即用的 MVC(Model-View-Controller)Go 脚手架,基于 Gin + RocketMQ,包含双数据库、统一响应、中间件与事件驱动示例。
这是什么
Gin-Framework-MVC 是一个面向 Go 语言的 MVC 工程脚手架,帮你快速搭建分层清晰的 Web 服务。项目内置用户与订单示例、RocketMQ 生产/消费、邮件通知示例、统一响应与中间件,适合作为团队工程模板,用于代码初始化,适用于大多数场景。
功能与 practice-projects/gin-ddd一致。有别于DDD架构,MVC架构更加简洁清晰,可以对比下DDD与MVC工程目录结构的差异,根据业务需要选择DDD或者MVC架构。
为什么要用 MVC?
很多人会在 Go 项目里直接把路由、业务、数据访问写在一起,小项目可以跑得很快,但模块一多就容易失控。MVC 的价值在于把职责拆开:Controller 负责 HTTP 交互,Service 承载业务规则,Repository 专注数据访问,Model 维护核心状态与行为。
总之,是否采用 MVC 和语言无关,重点在于业务复杂度与团队协作成本。对于中小型到中大型业务系统,MVC 能在“足够清晰”和“实现成本”之间取得很好平衡。
源码地址:https://github.com/microwind/design-patterns/tree/main/practice-projects/gin-mvc
项目目录:gin-mvc/
核心特点
清晰 MVC 分层:Controller、Service、Repository、Model
Gin Web 框架:高性能 HTTP 服务
事件驱动:业务事件 + RocketMQ 生产者/消费者
双数据库支持:用户库 + 订单库可独立配置(默认 MySQL + PostgreSQL)
统一响应格式:Response 封装,错误码按业务域划分
全局中间件:请求 ID、日志、恢复、跨域
可选邮件通知:订单创建事件驱动 SMTP 邮件发送
技术栈
技术
版本
说明
Go
1.21+
语言版本
Gin
1.9+
HTTP 框架
RocketMQ
5.3+
事件消息队列
MySQL
8.0+
用户库默认
PostgreSQL
14+
订单库默认
YAML
-
配置文件格式
工程结构
工程结构图
flowchart LR
Client[客户端]
subgraph Web["Web 入口"]
Router[Gin Router]
Middleware[Middleware]
end
subgraph MVC["MVC 核心"]
Controller[Controller]
Service[Service]
Model[Model]
View[View JSON/Template ]
end
subgraph Repo["数据访问"]
Repository[Repository]
UserDB[(MySQL 用户库)]
OrderDB[(PostgreSQL 订单库)]
end
subgraph Event["事件与通知"]
Producer[RocketMQ Producer]
Topic[(RocketMQ Topic)]
Consumer[RocketMQ Consumer]
Handler[Event Handler]
Mail[SMTP Mail]
end
Client --> Router
Router --> Middleware
Middleware --> Controller
Controller --> Service
Service --> Model
Service --> Repository
Repository --> UserDB
Repository --> OrderDB
Controller --> View
View --> Client
Service -.发布事件.-> Producer
Producer --> Topic
Topic --> Consumer
Consumer --> Handler
Handler --> Mail
工程结构列表
gin-mvc/
├── cmd/main.go # 启动入口,装配各层并启动 HTTP + MQ
├── config/config.yaml # 应用配置
├── docs/
│ ├── init_user_mysql.sql # MySQL 用户库初始化脚本
│ └── init_order_postgres.sql # PostgreSQL 订单库初始化脚本
├── internal/
│ ├── controllers/ # Controller 层(HTTP 处理)
│ │ ├── home/home_controller.go
│ │ ├── order/order_controller.go
│ │ └── user/user_controller.go
│ ├── services/ # Service 层(业务编排)
│ │ ├── order/order_service.go # 订单服务(状态流转 + 发布事件)
│ │ ├── user/user_service.go # 用户服务
│ │ ├── event/order_handler.go # 事件消费处理
│ │ └── notification/mail_service.go # 邮件服务接口
│ ├── repository/ # Repository 层(数据访问与外部依赖)
│ │ ├── db/ # DB 连接与方言占位符
│ │ ├── order/
│ │ │ ├── order_repository.go
│ │ │ └── order_sql_repository.go
│ │ ├── user/
│ │ │ ├── user_repository.go
│ │ │ └── user_sql_repository.go
│ │ ├── mq/ # RocketMQ 实现
│ │ │ ├── rocketmq_producer.go
│ │ │ └── rocketmq_consumer.go
│ │ └── mail/smtp_mail_repository.go # SMTP 邮件实现
│ ├── models/ # Model 层(核心模型与事件)
│ │ ├── order/order.go
│ │ ├── user/user.go
│ │ └── event/
│ │ ├── event.go
│ │ ├── order_event.go
│ │ └── user_event.go
│ ├── middleware/ # Gin 中间件
│ │ ├── request_id.go
│ │ ├── logging.go
│ │ ├── recovery.go
│ │ ├── cors.go
│ │ └── context.go
│ └── config/config.go # 配置加载与校验
├── pkg/
│ ├── logger/logger.go # 日志工具
│ └── response/response.go # 统一响应
└── web/templates/order.tmpl # 示例页面模板
各层职责说明
层级
位置
职责
关键原则
Model 层
internal/models/
核心业务对象、状态机与事件模型
聚焦业务语义,不依赖 HTTP/DB 细节
Service 层
internal/services/
编排业务流程、状态流转、事件发布
业务规则集中,避免散落到 Controller
Repository 层
internal/repository/
DB 访问、MQ/SMTP 等外部系统集成
只做 IO 与持久化,不承载业务规则
Controller 层
internal/controllers/
HTTP 请求解析、参数校验、响应输出
轻量薄层,不直接操作数据库
快速开始
1. 环境准备
Go 1.21+
MySQL 8.0+ 与 PostgreSQL 14+(或自行选择其一)
RocketMQ 5.3+(可选)
SMTP 邮箱(可选,推荐 QQ 邮箱)
2. 初始化数据库
默认配置使用双数据库:
用户库:MySQL(默认库名 gin_mvc_user)
订单库:PostgreSQL(默认库名 gin_mvc_order)
执行初始化脚本:
mysql -u root -p < docs/init_user_mysql.sql
psql -U postgres -f docs/init_order_postgres.sql
数据库适配注意:
当前仓储已同时支持 MySQL 与 PostgreSQL 占位符
切换驱动时,确保 config/config.yaml 的 database.user.driver 与 database.order.driver 正确
3. 配置应用
编辑 config/config.yaml,至少配置数据库与 RocketMQ:
server:
host: "0.0.0.0"
port: 8080
mode: "debug"
database:
user:
driver: "mysql"
host: "localhost"
port: 3306
username: "root"
password: "your_password"
database: "gin_mvc_user"
order:
driver: "postgres"
host: "localhost"
port: 5432
username: "postgres"
password: "your_password"
database: "gin_mvc_order"
rocketmq:
enabled: true
nameserver: "localhost:9876"
group_name: "gin-mvc-group"
instance_name: "gin-mvc-instance"
topics:
order_event: "order-event-topic"
说明:
rocketmq.enabled: true 才会初始化生产者与消费者
rocketmq.topics.order_event 不能为空,否则配置校验会失败
若暂不使用 MQ,可设置 rocketmq.enabled: false
最小可运行配置(本地联调推荐):
database.user 和 database.order 配置正确可连通
rocketmq.enabled: false(如果暂不使用消息)
mail.enabled: false(如果暂不发邮件)
4. 启动 RocketMQ(可选)
sh bin/mqnamesrv
sh bin/mqbroker -n localhost:9876
5. 启动应用
go mod tidy
go run cmd/main.go
6. 验证接口
curl http://localhost:8080/health
curl http://localhost:8080/api/users
curl http://localhost:8080/api/orders
API 一览
用户接口
POST /api/users
GET /api/users
GET /api/users/:id
PUT /api/users/:id/email
PUT /api/users/:id/phone
DELETE /api/users/:id
GET /api/users/:id/orders
示例:
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{"name":"张三","email":"zhangsan@example.com","phone":"13800138000"}'
订单接口
POST /api/orders
GET /api/orders
GET /api/orders/:id
PUT /api/orders/:id/pay
PUT /api/orders/:id/ship
PUT /api/orders/:id/deliver
PUT /api/orders/:id/cancel
PUT /api/orders/:id/refund
示例:
curl -X POST http://localhost:8080/api/orders \
-H "Content-Type: application/json" \
-d '{"user_id":1,"total_amount":99.99}'
配置说明
config/config.yaml 主要分区:
server:主机、端口、Gin 模式、超时
database.user:用户库连接
database.order:订单库连接
log:日志级别与输出格式(text/json)
rocketmq:开关、nameserver、group、topic
mail:SMTP 开关与账号配置
如何基于脚手架开发新功能
示例:新增“商品管理”模块
步骤 1:新增模型 internal/models/product/product.go
package product
import "time"
type Product struct {
ID int64
Name string
Price float64
Stock int
CreatedAt time.Time
UpdatedAt time.Time
}
步骤 2:新增仓储接口 internal/repository/product/product_repository.go
package product
import (
"context"
"gin-mvc/internal/models/product"
)
type Repository interface {
Create(ctx context.Context, p *product.Product) error
Update(ctx context.Context, p *product.Product) error
FindByID(ctx context.Context, id int64) (*product.Product, error)
FindAll(ctx context.Context) ([]*product.Product, error)
}
步骤 3:新增仓储实现 internal/repository/product/product_sql_repository.go
package product
import (
"context"
"database/sql"
"gin-mvc/internal/models/product"
)
type SQLRepository struct {
db *sql.DB
}
func NewSQLRepository(db *sql.DB) *SQLRepository {
return &SQLRepository{db: db}
}
func (r *SQLRepository) Create(ctx context.Context, p *product.Product) error {
_, err := r.db.ExecContext(ctx,
`INSERT INTO products (name, price, stock, created_at, updated_at) VALUES (?, ?, ?, ?, ?)`,
p.Name, p.Price, p.Stock, p.CreatedAt, p.UpdatedAt,
)
return err
}
步骤 4:新增业务服务 internal/services/product/product_service.go
package product
import (
"context"
"time"
"gin-mvc/internal/models/product"
productRepo "gin-mvc/internal/repository/product"
)
type Service struct {
repo productRepo.Repository
}
func New(repo productRepo.Repository) *Service {
return &Service{repo: repo}
}
func (s *Service) Create(ctx context.Context, name string, price float64, stock int) error {
p := &product.Product{
Name: name,
Price: price,
Stock: stock,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
return s.repo.Create(ctx, p)
}
步骤 5:新增 Controller 和路由
将 Controller 放到 internal/controllers/product/,并在 cmd/main.go 中注册路由组 api.Group("/products")。
步骤 6:新增数据库表
CREATE TABLE IF NOT EXISTS products (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
stock INT NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
事件驱动与 RocketMQ
事件类型
订单事件:
order.created
order.paid
order.shipped
order.delivered
order.cancelled
order.refunded
用户事件:
user.created
user.deleted
消息流转
HTTP 请求 -> Controller -> Service -> Model/Repository
-> 发布 DomainEvent -> RocketMQ Producer
-> RocketMQ Broker -> Consumer
-> 事件处理 -> 发送邮件/触发后续流程
订单创建场景(更具体):
HTTP 请求
-> OrderController
-> OrderService(入库后发布事件)
-> RocketMQ Producer
-> RocketMQ Topic(order-event-topic)
-> RocketMQ Consumer
-> event handler
-> SMTP MailService(order.created 时发送确认邮件)
事件发布与消费关键点
订单创建、支付、取消流程会尝试发布订单事件(发布失败不会中断主业务)
消费端按 Tag 前缀解析消息:order.* 映射 OrderEvent,user.* 映射 UserEvent
订单邮件通知仅在 order.created 且启用邮件时触发
邮件发送配置(QQ 邮箱)
在 config/config.yaml 中开启邮件配置:
mail:
enabled: true
host: "smtp.qq.com"
port: 465
username: "your@qq.com"
password: "你的SMTP授权码"
from_email: "your@qq.com"
from_name: "订单系统"
注意事项:
必须使用 SMTP 授权码,不是 QQ 登录密码
端口 465 使用 TLS,端口 587 使用 STARTTLS
收件人取自用户表中的 email 字段
常见问题排查
开启了 RocketMQ 但没有消息发布
检查 rocketmq.enabled、NameServer/Broker 连接、topics.order_event 配置
订单事件已消费但邮件未发送
检查 mail.enabled、SMTP 授权码、用户邮箱字段是否正确
消费者没有收到消息
检查 Topic 与 Tag 是否匹配、Consumer Group 是否正常
数据库报占位符或驱动错误
检查 database.*.driver 与目标数据库是否匹配
开发规范
命名建议:
模型:名词,如 Order、User
服务:Service 或 XxxService
仓储接口:Repository
仓储实现:SQLRepository
控制器:Controller 或 XxxController
分层原则:
Controller 只处理 HTTP 参数与响应
Service 负责业务规则、流程编排与事件发布
Repository 负责数据访问与外部依赖调用
Model 负责领域状态和对象行为
对比 DDD 版本
和 practice-projects/gin-ddd 对比:
功能面保持一致:用户/订单/MQ/邮件/双库
分层方式改为 MVC:更易理解和教学展示
依赖注入在 cmd/main.go 统一装配,便于快速定位启动流程
常用命令
go mod tidy
go test ./...
源码地址
MVC架构:
https://github.com/microwind/design-patterns/tree/main/practice-projects/gin-mvc
DDD架构:
https://github.com/microwind/design-patterns/tree/main/practice-projects/gin-ddd
