当前位置: 首页 > news >正文

一款Go语言Gin框架DDD脚手架,适合快速搭建项目

一款Go语言Gin框架DDD脚手架,适合快速搭建项目

一个开箱即用的 DDD(领域驱动设计)Go 脚手架,基于 Gin + RocketMQ,包含双数据库、统一响应、中间件与事件驱动示例。

这是什么

Gin-Framework-DDD 是一个面向 Go 语言的 DDD 工程脚手架,帮你快速搭建符合 DDD 分层规范的 Web 服务。项目内置用户与订单示例、领域事件与 RocketMQ 生产/消费、邮件通知示例、统一响应与中间件,适合作为团队工程模板或教学示例。

为什么要用DDD?

很多人认为 Go 语言没必要用 DDD,毕竟它和 Python、JS 一样轻巧灵活,用 MVC 就足够了。确实,大多数场景下 MVC 完全够用。工程化无非是把接口处理、业务逻辑、数据处理区分开,让各部分各司其职,方便维护和扩展。DDD 相对更适合中大型项目:如果项目有几十个模块、上百个接口,用 DDD 设计会更合适;模块少、接口不多的话,简单分层就够了。

总之,是否采用 DDD 和语言无关,只跟业务规模有关。一个东西变复杂了,就需要用一些机制去规范它,才能更好掌控。

源码地址:https://github.com/microwind/design-patterns/tree/main/practice-projects/gin-ddd

项目目录:gin-ddd/

核心特点

  • 严格 DDD 四层架构:领域层、应用层、基础设施层、接口层
  • Gin Web 框架:高性能 HTTP 服务
  • 事件驱动:领域事件 + RocketMQ 生产者/消费者
  • 双数据库支持:用户库 + 订单库可独立配置(默认 MySQL + PostgreSQL)
  • 统一响应格式:Response 封装,错误码集中管理
  • 全局中间件:日志、恢复、跨域
  • 可选邮件通知:订单创建事件驱动 SMTP 邮件发送

技术栈

技术 版本 说明
Go 1.21+ 语言版本
Gin 1.9+ HTTP 框架
RocketMQ 5.3+ 事件消息队列
MySQL 8.0+ 用户库默认
PostgreSQL 14+ 订单库默认
YAML - 配置文件格式

工程结构

工程结构图

flowchart TBsubgraph 接口层Handler[HTTP Handler / 路由]endsubgraph 应用层AppService[应用服务]endsubgraph 领域层DomainService[领域服务]Model[聚合根/实体]RepoInterface[仓储接口]NotificationInterface[通知接口]endsubgraph 基础设施层RepoImpl[仓储实现]Mail[邮件服务]MQ[消息队列]DB[(数据库)]endHandler --> AppServiceAppService --> DomainServiceAppService --> RepoInterfaceDomainService --> ModelDomainService --> NotificationInterfaceRepoInterface -.实现.-> RepoImplNotificationInterface -.实现.-> MailRepoImpl --> DBAppService -.发布事件.-> MQ

工程结构列表

gin-ddd/
├── cmd/server/main.go                            # 启动入口,装配各层并启动 HTTP + MQ
├── config/config.yaml                            # 应用配置
├── docs/init.sql                                 # MySQL 初始化脚本(示例)
├── internal/
│   ├── domain/                                   # 领域层
│   │   ├── model/
│   │   │   ├── order/order.go                    # 订单聚合根
│   │   │   └── user/user.go                      # 用户聚合根
│   │   ├── repository/                           # 仓储接口
│   │   │   ├── order/order_repository.go
│   │   │   └── user/user_repository.go
│   │   ├── event/                                # 领域事件
│   │   │   ├── domain_event.go
│   │   │   ├── order_event.go
│   │   │   ├── user_event.go
│   │   │   └── event_publisher.go
│   │   ├── notification/mail_service.go          # 通知领域接口(邮件)
│   │   └── service/                              # 领域服务(预留)
│   ├── application/                              # 应用层
│   │   ├── dto/
│   │   │   ├── order/order_dto.go
│   │   │   └── user/user_dto.go
│   │   └── service/
│   │       ├── order/order_service.go            # 订单应用服务(发布事件)
│   │       └── user/user_service.go              # 用户应用服务
│   ├── infrastructure/                           # 基础设施层
│   │   ├── config/                               # 配置与 DB 初始化
│   │   ├── persistence/                          # 仓储实现
│   │   │   ├── order/order_repository_impl.go
│   │   │   └── user/user_repository_impl.go
│   │   ├── mq/                                   # RocketMQ 实现
│   │   │   ├── rocketmq_producer.go
│   │   │   └── rocketmq_consumer.go
│   │   ├── mail/                                 # SMTP 邮件实现
│   │   ├── middleware/                           # Gin 中间件
│   │   ├── common/response.go                    # 统一响应
│   │   └── constants/error_code.go               # 错误码
│   └── interfaces/                               # 接口层
│       ├── handler/                              # HTTP 处理器
│       ├── router/                               # 路由配置
│       └── vo/                                   # 请求/响应对象
└── pkg/utils/                                    # 日志等工具

各层职责说明

层级 位置 职责 关键原则
领域层 internal/domain/ 领域模型、规则与事件 不依赖框架、业务逻辑内聚
应用层 internal/application/ 编排领域对象、事务边界 薄而清晰,不实现业务规则
基础设施层 internal/infrastructure/ DB、MQ、邮件等技术细节 向上提供实现,细节下沉
接口层 internal/interfaces/ HTTP 请求/响应与路由 处理外部交互,不含业务规则

快速开始

1. 环境准备

  • Go 1.21+
  • MySQL 8.0+ 与 PostgreSQL 14+(或自行选择其一)
  • RocketMQ 5.3+(可选)

2. 初始化数据库

默认配置使用双数据库:

  • 用户库:MySQL
  • 订单库:PostgreSQL

MySQL 用户库示例(可直接用 docs/init.sql 作为起点):

CREATE DATABASE IF NOT EXISTS gin_ddd CHARACTER SET utf8mb4;
USE gin_ddd;CREATE TABLE IF NOT EXISTS users (id BIGINT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(50) NOT NULL UNIQUE,email VARCHAR(100) NOT NULL UNIQUE,phone VARCHAR(20),created_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,updated_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

PostgreSQL 订单库示例(与当前订单仓储字段一致):

CREATE DATABASE seed;
\c seed;CREATE TABLE IF NOT EXISTS orders (id BIGSERIAL PRIMARY KEY,order_no VARCHAR(50) NOT NULL UNIQUE,user_id BIGINT NOT NULL,total_amount DECIMAL(10, 2) NOT NULL DEFAULT 0.00,status VARCHAR(20) NOT NULL DEFAULT 'PENDING',created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

数据库适配注意:

  • 若订单库改为 MySQL,需要将 SQL 占位符从 $1 形式改为 ?
  • 若用户库改为 PostgreSQL,需要将插入 ID 获取逻辑改为 RETURNING id

3. 配置应用

编辑 config/config.yaml,至少配置数据库与 RocketMQ:

server:host: "0.0.0.0"port: 8080mode: "debug"database:user:driver: "mysql"host: "localhost"port: 3306username: "root"password: "your_password"database: "gin_ddd"order:driver: "postgres"host: "localhost"port: 5432username: "postgres"password: "your_password"database: "seed"rocketmq:enabled: truenameserver: "localhost:9876"group_name: "gin-ddd-group"instance_name: "gin-ddd-instance"topics:order_event: "order-event-topic"

说明:

  • rocketmq.enabled: true 才会初始化生产者与消费者
  • 当前订单事件 Topic 在代码中使用固定值 order-event-topic,需与配置保持一致

4. 启动 RocketMQ(可选)

sh bin/mqnamesrv
sh bin/mqbroker -n localhost:9876

5. 启动应用

go mod tidy
go run cmd/server/main.go

6. 验证接口

curl http://localhost:8080/health
curl http://localhost:8080/api/users
curl http://localhost:8080/api/orders

如何基于脚手架开发新功能

示例:新增“商品管理”模块

步骤 1:新增领域模型 internal/domain/model/product/product.go

package productimport "time"type Product struct {ID        int64Name      stringPrice     float64Stock     intCreatedAt time.TimeUpdatedAt time.Time
}

步骤 2:新增仓储接口 internal/domain/repository/product/product_repository.go

package productimport ("context""gin-ddd/internal/domain/model/product"
)type ProductRepository interface {Create(ctx context.Context, p *product.Product) errorUpdate(ctx context.Context, p *product.Product) errorFindByID(ctx context.Context, id int64) (*product.Product, error)FindAll(ctx context.Context) ([]*product.Product, error)
}

步骤 3:新增仓储实现 internal/infrastructure/persistence/product/product_repository_impl.go

package productimport ("context""database/sql""gin-ddd/internal/domain/model/product"
)type ProductRepositoryImpl struct {db *sql.DB
}func NewProductRepository(db *sql.DB) *ProductRepositoryImpl {return &ProductRepositoryImpl{db: db}
}func (r *ProductRepositoryImpl) 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/application/service/product/product_service.go

package productimport ("context""time""gin-ddd/internal/domain/model/product"productDomain "gin-ddd/internal/domain/repository/product"
)type ProductService struct {repo productDomain.ProductRepository
}func NewProductService(repo productDomain.ProductRepository) *ProductService {return &ProductService{repo: repo}
}func (s *ProductService) 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:新增 HTTP Handler 和路由

将请求/响应对象放到 internal/interfaces/vo/product/,Handler 放到 internal/interfaces/handler/product/,并在 internal/interfaces/router/router.go 中注册路由。

步骤 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.activated
  • user.deactivated
  • user.blocked
  • user.deleted

消息流转

HTTP 请求 -> Application Service -> Domain Model-> 发布 DomainEvent -> RocketMQ Producer-> RocketMQ Broker -> Consumer-> 事件处理 -> 发送邮件/触发后续流程

事件发布与消费关键点

  • 订单创建后会发布 order.created 事件(发布失败不会影响主流程)
  • 消费端按 Tag 解析为 OrderEventUserEvent
  • 订单邮件通知仅在 order.created 且启用邮件时触发

邮件发送配置(QQ 邮箱)

config/config.yaml 中开启邮件配置:

mail:enabled: truehost: "smtp.qq.com"port: 465username: "your@qq.com"password: "你的SMTP授权码"from_email: "your@qq.com"from_name: "订单系统"

注意事项:

  • 必须使用 SMTP 授权码,不是 QQ 登录密码
  • 端口 465 使用 TLS,端口 587 使用 STARTTLS
  • 收件人取自用户表中的 email 字段

常见问题排查

  • 日志提示“事件发布器未初始化”:RocketMQ 未启用或初始化失败
  • 订单事件已发送但邮件未到:确认用户邮箱字段正确,且 SMTP 授权码可用
  • 消费者没有收到消息:确认 Topic 与 Tag 正确、Broker 启动正常

开发规范

命名建议:

  • 领域模型:名词,如 OrderUser
  • 应用服务:XxxService
  • 仓储接口:XxxRepository
  • 仓储实现:XxxRepositoryImpl
  • Handler:XxxHandler

分层原则:

  • 领域层不依赖基础设施
  • 应用层只做编排与事务协调
  • 基础设施提供技术实现
  • 接口层只负责 HTTP 交互

常用命令

go mod tidy
go test ./...

源码地址

https://github.com/microwind/design-patterns/tree/main/practice-projects/gin-ddd

http://www.jsqmd.com/news/377320/

相关文章:

  • 24小时网球场没有前台,美团的券谁来扫?教你快速接入美团核销
  • 为了接上美团核销这跟“管”,自助球馆老板差点办了张假证
  • Flutter-OH适配流程全解析:从代码迁移到最终发布
  • 沃尔玛购物卡回收靠谱吗? - 团团收购物卡回收
  • 【计算机基础】-44-RT-Thread-代码与运行期的内存分布,内存管理关注的是哪一步内存空间?专注于“运行期堆内存”的动态分配与回收,而不管理代码、全局变量、栈等静态或半静态内存区域。
  • 十大商用高清正版素材网站推荐,图片购买网站盘点(2026一月更新) - 品牌2026
  • 2026年市面上诚信的阀门供应商排行榜,升降止回阀/电动闸阀/铸钢截止阀/电液动盲板阀/气动调节阀,阀门供应商哪家好 - 品牌推荐师
  • 退货率飙升的季节,跨境卖家如何用售后前置守住利润
  • 安装Synology Active Backup for Business Agent时出现无法访问你试图使用的功能所在的网络位置
  • 靠谱的AI训练素材供应商怎么选,AI训练图片、视频、数据集供应商优选 - 品牌2026
  • 2026年当下口碑好的环氧玻璃钢品牌选哪家,无溶剂环氧涂料/石墨烯涂料/光固化保护套,环氧玻璃钢采购厂家怎么找 - 品牌推荐师
  • AI训练素材供应商推荐,专业AI训练图片、视频、数据集供应商卓特视觉 - 品牌2026
  • 工作学习笔记 —— 解决刷新缓存障碍
  • 2026别错过!8个AI论文平台测评:专科生毕业论文+开题报告高效写作指南
  • 2026年十大高清免费可商用图片素材网站正版下载推荐,设计师必藏网站 - 品牌2026
  • 电商素材网哪个好:2026 十大跨境电商+电商主图合规素材图库精选 - 品牌2026
  • 2026大模型新格局:智谱GLM-5发布,DSA+MoE架构如何破解落地痛点?
  • 2026年十大免费版权图片素材下载网站推荐:高清图库、可商用图片资源全攻略 - 品牌2026
  • 大模型浪潮下的IT行业变革:程序员职业转型启示,迎接AI编程时代的新挑战!
  • OECT更换大容量硬盘后如何扩容分区大小
  • 2026年十大商用版权高清正版图片素材网站推荐,商用素材资源平台及图片购买渠道盘点 - 品牌2026
  • Python移动端反爬:Charles抓包+Frida Hook破解实战
  • 2026别错过!10个AI论文网站测评:本科生毕业论文写作与格式规范全攻略
  • 2026 年十大印刷、快消、服装印花、旅游、金融行业高清图片素材网站推荐合集 - 品牌2026
  • Python JS逆向实战:混淆代码还原+加密算法抠取全流程
  • 2026少儿编程品牌怎么选?十大品牌综合实力榜重磅发布! - 匠言榜单
  • 6款好用的微信编辑器推荐:2026年最新工具详解 - peipei33
  • 详细介绍:Redis:Redis脚本
  • Python反爬性能天花板:突破并发限制+隐藏爬虫特征
  • fork和vfork区别