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

张开发
2026/4/3 15:02:30 15 分钟阅读
一款Go语言Gin框架DDD脚手架,适合快速搭建项目
核心特点严格 DDD 四层架构领域层、应用层、基础设施层、接口层Gin Web 框架高性能 HTTP 服务事件驱动领域事件 RocketMQ 生产者/消费者双数据库支持用户库 订单库可独立配置默认 MySQL PostgreSQL统一响应格式Response 封装错误码集中管理全局中间件日志、恢复、跨域可选邮件通知订单创建事件驱动 SMTP 邮件发送技术栈技术版本说明Go1.21语言版本Gin1.9HTTP 框架RocketMQ5.3事件消息队列MySQL8.0用户库默认PostgreSQL14订单库默认YAML-配置文件格式工程结构工程结构图基础设施层领域层应用层接口层实现实现发布事件HTTP Handler / 路由应用服务领域服务聚合根/实体仓储接口通知接口仓储实现邮件服务消息队列数据库工程结构列表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.21MySQL 8.0 与 PostgreSQL 14或自行选择其一RocketMQ 5.3可选2. 初始化数据库默认配置使用双数据库用户库MySQL订单库PostgreSQLMySQL 用户库示例可直接用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 id3. 配置应用编辑config/config.yaml至少配置数据库与 RocketMQserver:host: 0.0.0.0port: 8080mode: debugdatabase:user:driver: mysqlhost: localhostport: 3306username: rootpassword: your_passworddatabase: gin_dddorder:driver: postgreshost: localhostport: 5432username: postgrespassword: your_passworddatabase: seedrocketmq:enabled: truenameserver: localhost:9876group_name: gin-ddd-groupinstance_name: gin-ddd-instancetopics:order_event: order-event-topic说明rocketmq.enabled: true才会初始化生产者与消费者当前订单事件 Topic 在代码中使用固定值order-event-topic需与配置保持一致4. 启动 RocketMQ可选sh bin/mqnamesrvsh bin/mqbroker -n localhost:98765. 启动应用go mod tidygo run cmd/server/main.go6. 验证接口curl http://localhost:8080/healthcurl http://localhost:8080/api/userscurl http://localhost:8080/api/orders如何基于脚手架开发新功能示例新增“商品管理”模块步骤 1新增领域模型internal/domain/model/product/product.gopackage productimport timetype Product struct {ID int64Name stringPrice float64Stock intCreatedAt time.TimeUpdatedAt time.Time}步骤 2新增仓储接口internal/domain/repository/product/product_repository.gopackage productimport (contextgin-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.gopackage productimport (contextdatabase/sqlgin-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.gopackage productimport (contexttimegin-ddd/internal/domain/model/productproductDomain 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.createdorder.paidorder.shippedorder.deliveredorder.cancelledorder.refunded用户事件user.createduser.activateduser.deactivateduser.blockeduser.deleted消息流转HTTP 请求 - Application Service - Domain Model- 发布 DomainEvent - RocketMQ Producer- RocketMQ Broker - Consumer- 事件处理 - 发送邮件/触发后续流程事件发布与消费关键点订单创建后会发布order.created事件发布失败不会影响主流程消费端按 Tag 解析为OrderEvent或UserEvent订单邮件通知仅在order.created且启用邮件时触发邮件发送配置QQ 邮箱在config/config.yaml中开启邮件配置mail:enabled: truehost: smtp.qq.comport: 465username: yourqq.compassword: 你的SMTP授权码from_email: yourqq.comfrom_name: 订单系统注意事项必须使用 SMTP 授权码不是 QQ 登录密码端口 465 使用 TLS端口 587 使用 STARTTLS收件人取自用户表中的email字段常见问题排查日志提示“事件发布器未初始化”RocketMQ 未启用或初始化失败订单事件已发送但邮件未到确认用户邮箱字段正确且 SMTP 授权码可用消费者没有收到消息确认 Topic 与 Tag 正确、Broker 启动正常开发规范命名建议领域模型名词如Order、User应用服务XxxService仓储接口XxxRepository仓储实现XxxRepositoryImplHandlerXxxHandler分层原则领域层不依赖基础设施应用层只做编排与事务协调基础设施提供技术实现接口层只负责 HTTP 交互常用命令go mod tidygo test ./...

更多文章