bw-cli 是一套面向企业项目的 Go 微服务脚手架,默认使用 Gin + gRPC + Gorm,按 DDD 思路组织代码,同时保持包名简单直观。bw-cli new 默认生成不带业务 demo 的干净框架;如果需要演示项目,可以使用 bw-cli demo 生成带 user-service 和 note-service 的示例工程。
- 快速生成 Gin + gRPC 微服务项目。
bw-cli new <项目名> --module <module>一条命令生成干净框架。bw-cli demo <项目名> --module <module>单独生成带示例业务的演示项目。bw-cli service <服务名> --tidy在现有项目中生成可启动的基础 CRUD 服务。- 使用清晰的 DDD 分层:
model、service、repo、handler。 - 默认支持 Gorm,并内置 SQLite、MySQL、PostgreSQL。
- 内置 MongoDB、Redis、Elasticsearch、Kafka 客户端封装。
- 内置文件上传封装,支持 MinIO、阿里云 OSS、七牛云 Kodo、腾讯云 COS。
- 内置 CORS、JWT、RequestID、请求日志等常用中间件。
- 使用 Zap + Lumberjack 记录结构化日志,日志默认保留 7 天。
- 通过
make命令完成 proto 生成、测试和本地启动。
先确认本机环境:
go version
protoc --version
git --version
make --version要求:
Go 1.25+
protoc 3.x+
Git 任意现代版本
Make macOS/Linux 默认可用
如果缺少 protoc,macOS 可以使用:
brew install protobuf如果 bw-cli 安装后提示 command not found,检查 Go bin 目录:
go env GOPATH然后把下面内容加入你的 shell 配置:
export PATH="$PATH:$(go env GOPATH)/bin"这个方式适合第一次体验脚手架,或者你要参与维护 bw-cli 本身。
git clone https://github.com/BwCloudWeGo/bw-cli.git
cd bw-climake tools它会安装:
protoc-gen-go
protoc-gen-go-grpc
make proto这一步会根据 api/proto 下的 proto 文件生成 api/gen 下的 Go 代码。
make tidymake test看到所有 package 都没有 FAIL 即可继续启动服务。
建议开三个终端,按顺序启动。
终端一:启动用户服务。
make run-user终端二:启动笔记服务。
make run-note终端三:启动网关。
make run-gateway默认端口:
gateway http://localhost:8080
user-service grpc://localhost:9001
note-service grpc://localhost:9002
健康检查:
curl http://localhost:8080/healthz注册用户:
curl -X POST http://localhost:8080/api/v1/users/register \
-H 'Content-Type: application/json' \
-d '{"email":"ada@example.com","display_name":"Ada","password":"secret123"}'登录用户:
curl -X POST http://localhost:8080/api/v1/users/login \
-H 'Content-Type: application/json' \
-d '{"email":"ada@example.com","password":"secret123"}'创建笔记:
curl -X POST http://localhost:8080/api/v1/notes \
-H 'Content-Type: application/json' \
-d '{"author_id":"<user_id>","title":"DDD scaffold","content":"Gin plus gRPC demo"}'发布笔记:
curl -X POST http://localhost:8080/api/v1/notes/<note_id>/publish这个方式适合业务项目使用。你只需要安装一次 bw-cli,后续可以随时生成新项目。
go install github.com/BwCloudWeGo/bw-cli/cmd/bw-cli@latest验证命令是否可用:
bw-cli new -hbw-cli new my-service \
--module github.com/acme/my-service \
--tidybw-cli new 默认从 https://github.com/BwCloudWeGo/bw-cli.git 的 main 分支拉取脚手架,并自动清理 demo 代码。日常使用只需要指定项目目录和 module。
参数说明:
| 参数 | 说明 |
|---|---|
my-service |
生成出来的新项目目录 |
--module github.com/acme/my-service |
新项目的 Go module |
--tidy |
生成后自动执行 go mod tidy |
生成完成后:
cd my-service
make tools
make proto
make test启动干净项目的 gateway:
make run-gateway端口监听成功后,控制台会直接输出启动项:
[Gateway Started]
service: gateway
env: local
listen: 0.0.0.0:8080
http: http://127.0.0.1:8080
health: http://127.0.0.1:8080/healthz
api: http://127.0.0.1:8080/api/v1
如果端口被占用,控制台会输出 [Gateway Start Failed],并显示失败的监听地址和系统错误。
验证:
curl http://localhost:8080/healthz如果想先看完整 user/note 示例,用 demo 命令:
bw-cli demo demo-service \
--module github.com/acme/demo-service \
--tidy生成后按第 3.6 节的方式启动三个服务。
如果你正在修改脚手架本身,可以直接用本地源码生成项目:
git clone https://github.com/BwCloudWeGo/bw-cli.git
cd bw-cli
go install ./cmd/bw-cli
bw-cli new ../my-service \
--module github.com/acme/my-service \
--source . \
--tidy如果要从本地源码生成带示例业务的演示项目:
bw-cli demo ../demo-service \
--module github.com/acme/demo-service \
--source . \
--tidy这适合调试模板变更,不需要每次都先推送到远程仓库。
bw-cli new 会执行这些动作:
- 默认从官方仓库克隆脚手架;如果传了
--source,则复制本地脚手架。 - 跳过
.git、.idea、logs、data、tmp等运行时目录。 - 把
go.mod、源码、配置和文档中的旧 module 路径替换成新项目 module。 - 跳过已生成的
*.pb.go,避免破坏 protobuf 原始描述符。 - 替换
.proto文件中的go_package。 new会移除 user/note 示例服务、示例 proto、示例 gateway handler 和脚手架自身 CLI 代码。demo会保留 user/note 示例服务,方便学习和演示。- 重写生成项目内的 README、usage、architecture、toolkit、mongodb 文档,让文档和实际目录保持一致。
- 如果指定
--tidy,自动执行go mod tidy。
生成后建议执行:
make proto
make testmake proto 会基于新的 go_package 重新生成 *.pb.go。
进入已生成的项目根目录,直接执行:
bw-cli service order --tidy这条命令会自动读取当前项目的 go.mod,并生成一整套可编译、可启动、带基础 CRUD 的服务代码,不需要先修改 configs/config.yaml:
api/proto/order/v1/order.proto
api/gen/order/v1
cmd/order/main.go
internal/order/model
internal/order/dto/command.go
internal/order/dto/order.go
internal/order/service/service.go
internal/order/repo/gorm_repository.go
internal/order/repo/mongo_repository.go
internal/order/handler
docs/services/order.md
同时会在 Makefile 中追加:
make run-order默认 gRPC 端口是 9100。如果需要指定端口,可以在生成时传 --port:
bw-cli service order --port 9103 --tidy端口不写入配置文件,而是固化在生成的 cmd/order/main.go 默认值里,也支持环境变量覆盖:
APP_ORDER_GRPC_PORT=9104 make run-order生成后的基础调用链已经成型:
HTTP client -> gateway router/handler -> gRPC client -> proto -> handler -> service -> model.Repository -> repo(Gorm) -> database
默认启动使用 repo/gorm_repository.go。命令也会生成 repo/mongo_repository.go,其中已经包含 MongoCollectionName()、mongox.NewDocumentStore[T] 和基础 CRUD 方法;如果该服务需要改用 MongoDB,只需要在 cmd/order/main.go 中改为注入 repo.NewMongoRepository。
默认提供:
CreateOrder
GetOrder
ListOrders
UpdateOrder
DeleteOrder
如果项目已经在 configs/config.yaml 中配置了关系型数据库,可以让 service 命令先校验表结构,再按字段生成代码:
bw-cli service order --table orders --tidy支持的 database.driver 为 sqlite、mysql、postgres。命令会在写文件前检查:
- 当前配置是否能连接数据库。
- 主表是否存在。
- 主表是否只有一个主键。
- 字段类型能否映射到 Go/proto 类型。
多表关系建议放在 YAML 中:
table: orders
readonly_fields:
- id
- created_at
- updated_at
relations:
- name: order_items
table: order_items
type: has_many
local_field: id
foreign_field: order_id执行:
bw-cli service order --table orders --schema configs/services/order.yaml --tidy主表会生成完整 CRUD;关联表只生成内部 model/dto/repo 和关系查询方法,例如 ListOrderItemsByOrderID。第一版只支持单字段主键和单字段关联,不会默认生成复杂 SQL join。表字段默认全部暴露到生成代码中,需要排除字段时使用 exclude_fields。
用户可以直接把示例字段 Name、Description 替换成真实业务字段,或者在现有 CRUD 上继续增加业务方法。
如果项目包含 gateway,命令会同步生成:
internal/gateway/request/order_request.go
internal/gateway/handler/order_handler.go
internal/gateway/router/order_routes.go
并自动挂载:
POST /api/v1/orders
GET /api/v1/orders
GET /api/v1/orders/:id
PUT /api/v1/orders/:id
DELETE /api/v1/orders/:id
gateway 默认连接生成服务端口,例如 --port 9103 时连接 127.0.0.1:9103;可用 APP_ORDER_GRPC_TARGET 覆盖,不需要改配置文件。
生成后常用流程:
make proto
make test
make run-order如果是 Windows PowerShell,覆盖服务端口时使用:
$env:APP_ORDER_GRPC_PORT="9101"; make run-order下面是脚手架仓库源码目录。通过 bw-cli new 生成的干净项目会移除 cmd/bw-cli、cmd/user、cmd/note、internal/user、internal/note 和示例 proto;通过 bw-cli demo 生成的演示项目会保留 user/note 示例。
核心目录:
.
├── api
│ ├── proto # proto 源文件
│ └── gen # protoc 生成的 Go 代码
├── cmd
│ ├── bw-cli # 脚手架命令入口
│ ├── gateway # HTTP 网关进程
│ ├── user # user-service 进程
│ └── note # note-service 进程
├── configs # 本地配置文件
├── docs # 架构和使用文档
├── internal
│ ├── gateway # Gin 网关
│ ├── user # 用户服务
│ └── note # 笔记服务
├── pkg # 可复用基础包
└── Makefile
业务服务统一四层:
internal/<service>
├── model # 实体、值对象、业务错误、仓储接口
├── dto
│ ├── command.go # 业务用例入参命令
│ └── <service>.go # 业务用例出参 DTO 和转换
├── service
│ └── service.go # 业务流程编排
├── repo # Gorm、MongoDB、Redis、外部依赖实现
└── handler # gRPC/HTTP 入站适配
Gateway 额外拆分:
internal/gateway
├── request # HTTP 入参 DTO
├── handler # HTTP 控制器
└── router
├── v1.go # /api/v1 版本路由
├── user_routes.go
└── note_routes.go
依赖方向:
handler -> service -> model
repo -> model
model 不依赖 Gin、gRPC、Gorm、MongoDB SDK 或日志框架,便于测试和替换基础设施。
service.go 只写业务流程;命令入参放 dto/command.go,返回 DTO 和转换函数放 dto/<service>.go,避免控制器或服务主文件堆字段。
README 使用 C4 模型描述架构,便于从“系统边界 -> 运行容器 -> 服务内部组件”逐层理解。图中的 bw-cli 是脚手架命令本身,Generated Project 是通过 bw-cli new 或 bw-cli demo 生成的业务工程。
C4Context
title System Context - bw-cli Go Microservice Scaffold
Person(developer, "开发者/业务团队", "使用脚手架生成、扩展和维护 Go 微服务项目")
Person_Ext(apiClient, "外部客户端", "Web、App、第三方系统或测试工具")
System(cli, "bw-cli", "用于生成干净项目、演示项目和新业务服务的 Go CLI")
System(project, "Generated Project", "Gin + gRPC + Gorm 微服务工程,承载业务 API 和公共基础能力")
System_Ext(gitRepo, "Git Repository", "脚手架源码仓库和业务项目仓库")
Rel(developer, cli, "执行 new/demo/service 命令", "Shell")
Rel(cli, gitRepo, "拉取脚手架模板", "Git")
Rel(cli, project, "生成项目源码、配置和文档", "File System")
Rel(developer, project, "开发业务逻辑、运行测试和启动服务", "Go/Make")
Rel(apiClient, project, "调用 HTTP API", "JSON/HTTP")
C4Container
title Container Diagram - Generated Project Runtime
Person(apiClient, "外部客户端", "Web、App、第三方系统或测试工具")
System_Boundary(project, "Generated Project") {
Container(gateway, "Gateway", "Gin HTTP", "统一入口、路由、中间件、HTTP 响应封装")
Container(service, "Business gRPC Service", "Go + gRPC", "承载业务用例、领域模型和仓储接口")
ContainerDb(sqlDb, "Relational Database", "SQLite/MySQL/PostgreSQL + Gorm", "默认业务数据持久化")
ContainerDb(mongoDb, "MongoDB", "MongoDB Driver", "文档型数据存储")
ContainerDb(redis, "Redis", "go-redis", "缓存、分布式锁和临时状态")
ContainerQueue(kafka, "Kafka", "segmentio/kafka-go", "异步事件生产和消费")
ContainerDb(es, "Elasticsearch", "elastic/go-elasticsearch", "搜索索引和检索")
ContainerDb(objectStorage, "Object Storage", "MinIO/OSS/Qiniu/COS", "文件上传和对象存储")
}
Rel(apiClient, gateway, "调用业务接口", "JSON/HTTP")
Rel(gateway, service, "调用内部服务", "gRPC")
Rel(service, sqlDb, "读写关系型数据", "Gorm")
Rel(service, mongoDb, "读写文档数据", "MongoDB Driver")
Rel(service, redis, "缓存或加锁", "Redis")
Rel(service, kafka, "发布或消费事件", "Kafka")
Rel(service, es, "写入索引或搜索", "HTTP")
Rel(service, objectStorage, "上传或读取文件", "SDK/API")
C4Component
title Component Diagram - internal/<service>
Container(gateway, "Gateway Handler", "Gin", "绑定 HTTP 入参并调用 gRPC client")
ContainerDb(sqlDb, "Database", "Gorm Supported DB", "业务数据表")
Container_Boundary(serviceBoundary, "Business Service") {
Component(grpcHandler, "handler", "gRPC Adapter", "把 proto request 转成 service command")
Component(command, "dto/command.go", "Command DTO", "定义业务用例入参")
Component(usecase, "service/service.go", "Use Case Service", "编排业务流程和事务意图")
Component(dto, "dto/<service>.go", "Response DTO", "定义业务出参并转换领域模型")
Component(model, "model", "Domain Model", "实体、值对象、业务错误和 Repository 接口")
Component(repo, "repo", "Gorm Repository", "实现 model.Repository 并操作数据库")
}
Rel(gateway, grpcHandler, "调用 RPC", "gRPC")
Rel(grpcHandler, command, "组装入参")
Rel(grpcHandler, usecase, "调用业务用例")
Rel(usecase, model, "执行业务规则")
Rel(usecase, repo, "通过接口访问仓储")
Rel(repo, model, "实现 Repository 接口")
Rel(repo, sqlDb, "读写数据", "Gorm")
Rel(usecase, dto, "返回业务出参")
这三张图对应开发时的三个判断:
- 看系统边界时,先看 Level 1,确认
bw-cli、生成项目、外部调用方和 Git 仓库的关系。 - 看运行时调用链时,看 Level 2,确认 gateway、gRPC 服务和各类数据源之间的依赖。
- 写具体业务代码时,看 Level 3,确认入参、业务流程、DTO、领域模型和数据库实现分别放在哪一层。
Makefile 只调用 Go 命令,不依赖 find、sed、if [ ... ] 等 Unix shell 语法;make proto 内部通过 tools/protogen 使用 Go 自动适配 Windows、macOS、Linux 的路径分隔符和插件目录。
Windows 仍需要安装 GNU Make;如果没有 make,可以直接执行等价的 Go 命令,例如 go run ./tools/protogen、go test ./...、go run ./cmd/gateway。
| 命令 | 作用 |
|---|---|
make tools |
安装 proto 生成插件 |
make proto |
生成 gRPC/protobuf Go 代码 |
make tidy |
执行 go mod tidy |
make test |
执行 go test ./... |
make run-user |
启动 user-service |
make run-note |
启动 note-service |
make run-gateway |
启动 HTTP gateway |
make install-cli |
本地安装 bw-cli |
Windows PowerShell 设置临时环境变量时使用:
$env:APP_HTTP_PORT="8081"; make run-gatewaymacOS/Linux 使用:
APP_HTTP_PORT=8081 make run-gateway默认配置文件:
configs/config.yaml
配置支持环境变量覆盖,规则是:
APP_ + 配置路径大写 + 下划线
示例:
export APP_HTTP_PORT=8081
export APP_GRPC_USER_TARGET='127.0.0.1:9001'
export APP_LOG_LEVEL=debug默认使用 SQLite,适合本地快速体验:
database:
driver: sqlite
dsn: data/xiaolanshu.dbSQLite 文件会写入 data/ 目录,该目录已被 .gitignore 忽略。
export APP_DATABASE_DRIVER=mysql
export APP_MYSQL_DSN='user:pass@tcp(mysql.example.com:3306)/app?charset=utf8mb4&parseTime=True&loc=Local'
export APP_MYSQL_MAX_IDLE_CONNS=10
export APP_MYSQL_MAX_OPEN_CONNS=100
export APP_MYSQL_CONN_MAX_LIFETIME_SECONDS=3600export APP_DATABASE_DRIVER=postgres
export APP_POSTGRESQL_DSN='host=postgres.example.com user=app password=replace-with-real-password dbname=app port=5432 sslmode=require TimeZone=Asia/Shanghai'
export APP_POSTGRESQL_MAX_IDLE_CONNS=10
export APP_POSTGRESQL_MAX_OPEN_CONNS=100
export APP_POSTGRESQL_CONN_MAX_LIFETIME_SECONDS=3600支持的关系型数据库 driver:
sqlite
mysql
postgres
postgresql
pg
默认配置:
mongodb:
uri: mongodb://127.0.0.1:27017
username: ""
password: ""
database: xiaolanshu
app_name: bw-cli
min_pool_size: 0
max_pool_size: 100
connect_timeout_seconds: 10
server_selection_timeout_seconds: 5服务启动时会读取 configs/config.yaml 中的 mongodb.* 配置,并通过 cfg.MongoDB.MongoxConfig() 创建连接。用户名、密码、数据库名都写在配置文件对应字段中。
业务仓储建议通过公共操作类读写 collection:
type NoteDocument struct {
ID string `bson:"_id"`
Title string `bson:"title"`
}
func (NoteDocument) MongoCollectionName() string {
return "notes"
}
db := mongox.Database(client, cfg.MongoDB.Database)
notes := mongox.NewDocumentStore[NoteDocument](db)
_, err := notes.UpsertByID(ctx, "note-1", &NoteDocument{ID: "note-1", Title: "MongoDB note"})
note, err := notes.FindByID(ctx, "note-1")MongoDB 调用实战见 MongoDB 调用示例全流程。
脚手架通过 pkg/filex 提供统一上传接口,默认最大文件大小是 100 MB,支持 Word、PDF、常见图片、视频和音频格式。存储方式通过配置选择:
file_storage:
provider: minio
max_size_mb: 100
object_prefix: uploads
public_base_url: ""支持的 provider:
minio
oss
qiniu
cos
常用环境变量:
export APP_FILE_STORAGE_PROVIDER=minio
export APP_FILE_STORAGE_MAX_SIZE_MB=100
export APP_FILE_STORAGE_MINIO_ENDPOINT='127.0.0.1:9000'
export APP_FILE_STORAGE_MINIO_ACCESS_KEY_ID='replace-with-real-access-key'
export APP_FILE_STORAGE_MINIO_SECRET_ACCESS_KEY='replace-with-real-secret-key'
export APP_FILE_STORAGE_MINIO_BUCKET='app-files'业务代码直接使用统一接口:
uploader, err := filex.NewUploader(cfg.FileStorage)
result, err := uploader.Upload(ctx, filex.UploadRequest{
Reader: file,
Filename: header.Filename,
ContentType: header.Header.Get("Content-Type"),
Size: header.Size,
})完整配置和调用流程见 工具组件总览与调用流程。
日志默认使用 Zap + Lumberjack:
- 默认保留 7 天。
- 单文件最大 128 MB。
- 最多保留 14 个备份。
- 历史日志压缩。
- 文件名按服务名和当前日期生成,例如
logs/gateway-2026-04-29.log。
日志覆盖维度:
- HTTP:method、path、route、status、client_ip、user_agent、latency_ms、request_bytes、response_bytes、error_code。
- gRPC:full_method、peer、status_code、latency_ms、request_id、trace_id、error_code。
- 业务:service、env、request_id、user_id、aggregate_id、use_case。
- 仓储:repository、operation、rows_affected、latency_ms、error。
日志目录 logs/ 已被 .gitignore 忽略。
这些包可以在其他项目中通过 go get 引入:
go get github.com/BwCloudWeGo/bw-cli/pkg/logger
go get github.com/BwCloudWeGo/bw-cli/pkg/mysqlx
go get github.com/BwCloudWeGo/bw-cli/pkg/postgresx
go get github.com/BwCloudWeGo/bw-cli/pkg/mongox
go get github.com/BwCloudWeGo/bw-cli/pkg/redisx
go get github.com/BwCloudWeGo/bw-cli/pkg/esx
go get github.com/BwCloudWeGo/bw-cli/pkg/kafkax
go get github.com/BwCloudWeGo/bw-cli/pkg/middleware
go get github.com/BwCloudWeGo/bw-cli/pkg/filex包说明:
| 包 | 说明 |
|---|---|
pkg/config |
Viper 配置加载和环境变量覆盖 |
pkg/logger |
Zap + Lumberjack 结构化日志 |
pkg/errors |
统一业务错误码 |
pkg/middleware |
CORS、JWT、RequestID、请求日志 |
pkg/grpcx |
gRPC 拦截器和 metadata 透传 |
pkg/httpx |
HTTP 响应封装 |
pkg/mysqlx |
MySQL/Gorm 初始化 |
pkg/postgresx |
PostgreSQL/Gorm 初始化 |
pkg/mongox |
MongoDB 官方 driver 初始化和公共 DocumentStore CRUD 操作 |
pkg/redisx |
Redis 客户端初始化 |
pkg/esx |
Elasticsearch 客户端初始化 |
pkg/kafkax |
Kafka reader/writer 初始化 |
pkg/filex |
文件上传校验和 MinIO/OSS/Qiniu/COS 存储适配 |
pkg/scaffold |
脚手架生成逻辑 |
确认 Go bin 目录在 PATH 中:
export PATH="$PATH:$(go env GOPATH)/bin"执行:
make tools然后重新执行:
make proto生成项目后执行:
make proto原因是 bw-cli 会跳过 *.pb.go 的直接字符串替换,避免破坏 protobuf 原始描述符。make proto 会根据新的 .proto go_package 重新生成代码。
默认端口:
8080 gateway
9001 user-service
9002 note-service
可以通过环境变量覆盖:
export APP_HTTP_PORT=8081
export APP_GRPC_USER_PORT=9101
export APP_GRPC_NOTE_PORT=9102同时记得调整 gateway 连接下游服务的 target:
export APP_GRPC_USER_TARGET='127.0.0.1:9101'
export APP_GRPC_NOTE_TARGET='127.0.0.1:9102'- 架构说明:分层、路由、公共包和扩展方式。
- 详细使用说明:发布
bw-cli、安装命令、生成项目、初始化依赖、配置服务、启动验证和扩展业务。 - 工具组件总览与调用流程:配置、日志、中间件、数据库、MongoDB、Redis、ES、Kafka、文件上传等公共工具的调用方式。
- MongoDB 调用示例全流程:配置、初始化、repo 封装、note/order/audit 多服务调用示例和测试方式。