Spring Boot 电商项目的 Go 语言重构版本。
| 层级 | 技术 |
|---|---|
| 语言 | Go 1.26 |
| HTTP 框架 | Gin |
| ORM | GORM (MySQL) |
| 缓存 | Redis (go-redis/v9) |
| 搜索引擎 | Elasticsearch v8 |
| 文档数据库 | MongoDB (mongo-driver) |
| 消息队列 | RocketMQ (stub) + RabbitMQ |
| 对象存储 | MinIO / Qiniu / RustFS |
| 依赖注入 | 手动 DI (main.go) + Wire (备用) |
| 定时任务 | robfig/cron/v3 |
| ID 生成 | Snowflake (bwmarrin/snowflake) |
| 配置管理 | Viper |
| 认证 | JWT (golang-jwt/v5) |
| 密码加密 | bcrypt + RSA (前端加密传输) |
| API 文档 | Swagger + Redoc |
mall_go/
├── cmd/ # 入口程序
│ ├── server/main.go # 主服务启动
│ ├── genkey/main.go # RSA 密钥生成工具
│ ├── encrypt/main.go # 密码加密工具
│ ├── encrypt_pwd/main.go # bcrypt 密码哈希工具
│ ├── login_test/main.go # 登录测试工具
│ └── redis_check/main.go # Redis 连通性检查
├── configs/ # 配置文件目录
│ ├── application.yml # 基础配置(占位符,可提交)
│ ├── application-dev.yml # 开发环境覆盖(占位符,可提交)
│ ├── application-local.yml # 本地真实密钥(gitignore,不提交)
│ ├── application-local.example.yml # 本地配置模板(可提交)
│ └── application-prod.example.yml # 生产环境模板(可提交)
├── internal/ # 内部包(不对外暴露)
│ ├── config/ # 配置加载
│ ├── dto/ # 数据传输对象 (VO/Query)
│ │ ├── mall/ # 商品相关
│ │ ├── trade/ # 订单相关
│ │ ├── shopping/ # 购物车/地址
│ │ ├── marketing/ # 优惠券
│ │ ├── seckill/ # 秒杀
│ │ ├── aftersale/ # 售后/退款
│ │ ├── sys/ # 系统管理
│ │ └── ...
│ ├── handler/ # HTTP 处理器 (Controller)
│ │ ├── auth/ # 登录认证
│ │ ├── mobile/ # C 端(移动端)接口
│ │ │ ├── mall/ # 商品/搜索
│ │ │ ├── trade/ # 订单
│ │ │ ├── shopping/ # 购物车/地址
│ │ │ ├── marketing/ # 优惠券
│ │ │ ├── seckill/ # 秒杀
│ │ │ ├── aftersale/ # 退款
│ │ │ ├── pay/ # 支付
│ │ │ └── ...
│ │ ├── admin/ # B 端(管理后台)接口
│ │ │ └── (同上结构)
│ │ ├── sys/ # 系统管理
│ │ └── upload/ # 文件上传
│ ├── middleware/ # 中间件
│ │ ├── jwt.go # JWT 认证
│ │ ├── cors.go # 跨域
│ │ ├── logger.go # 请求日志
│ │ ├── trace.go # 链路追踪
│ │ └── recovery.go # Panic 恢复
│ ├── model/ # GORM 实体模型
│ ├── repository/ # 数据访问层 (DAO)
│ ├── service/ # 业务逻辑层
│ ├── router/router.go # 路由注册
│ ├── infra/ # 基础设施(DB/Redis/ES 连接)
│ └── pkg/ # 公共工具包
│ ├── jwt/ # JWT 签发/解析
│ ├── crypto/ # RSA 加解密
│ ├── errcode/ # 错误码
│ ├── response/ # 统一响应格式
│ ├── trade/ # 订单常量/分片路由
│ └── validator/ # 参数校验
├── docs/ # Swagger 生成的 API 文档
├── go.mod # Go 模块定义
├── go.sum # 依赖校验
└── .gitignore
去 https://go.dev/dl/ 下载 Windows/macOS/Linux 安装包。
安装完成后,打开终端验证:
go version
# 输出: go version go1.26.0 windows/amd64go env -w GOPROXY=https://goproxy.cn,direct| 服务 | 用途 | 必须? |
|---|---|---|
| MySQL 8.0+ | 主数据库 + 订单分片库 | ✅ 必须 |
| Redis 6.0+ | 缓存 / Session / 分布式锁 | ✅ 必须 |
| Elasticsearch 8.x | 商品搜索 | |
| MongoDB 5.0+ | 商品详情富文本 | |
| RabbitMQ | 消息队列 | |
| RocketMQ | 消息队列(延迟消息) | |
| MinIO | 对象存储(文件/图片上传) |
如果你之前没写过 Go,跟着这 6 步就能跑起来。
git clone <repo-url> mall_go
cd mall_gogo mod download这一步会自动下载 go.mod 里声明的所有第三方库到本机缓存。
cp configs/application-local.example.yml configs/application-local.yml然后编辑 configs/application-local.yml,填入你的真实数据库密码、Redis 地址等。
最小配置(如果只跑通基础功能,你只需要填 MySQL 和 Redis):
mysql:
master:
dsn: root:你的密码@tcp(127.0.0.1:3306)/mall_db?charset=utf8mb4&parseTime=True&loc=Local
order_shard_0:
dsn: root:你的密码@tcp(127.0.0.1:3306)/mall_db_order_0?charset=utf8mb4&parseTime=True&loc=Local
order_shard_1:
dsn: root:你的密码@tcp(127.0.0.1:3306)/mall_db_order_1?charset=utf8mb4&parseTime=True&loc=Local
redis:
addr: 127.0.0.1:6379
password: 你的Redis密码
db: 0这个文件已加入
.gitignore,不会被提交到 Git。application.yml中的默认值会被application-local.yml覆盖。
连接你的 MySQL,执行:
CREATE DATABASE IF NOT EXISTS mall_db DEFAULT CHARSET utf8mb4;
CREATE DATABASE IF NOT EXISTS mall_db_order_0 DEFAULT CHARSET utf8mb4;
CREATE DATABASE IF NOT EXISTS mall_db_order_1 DEFAULT CHARSET utf8mb4;程序启动时会自动建表(AutoMigrate),无需手动导入 SQL。
go run cmd/server/main.go看到以下日志说明启动成功:
snowflake initialized workerID=1
MySQL master connected
sys tables auto-migrated
mall tables auto-migrated
Redis connected
server starting port=8011
# 健康检查
curl http://localhost:8011/health
# API 文档(浏览器打开)
# http://localhost:8011/doc (Redoc)
# http://localhost:8011/swagger/index.html (Swagger UI)服务启动后,你需要往数据库插入一个管理员用户。最简单的办法是用自带的工具:
# 1. 生成 bcrypt 密码哈希(比如密码是 123456)
go run cmd/encrypt_pwd/main.go -pwd 123456
# 2. 用上面输出的哈希值,去 MySQL 插入一条记录:
# INSERT INTO sys_user (id, username, password, nick_name, enabled, account_non_expired, account_non_locked, credentials_non_expired, create_user_id, create_user_name, create_time)
# VALUES (1, 'admin', '<上一步的哈希>', '管理员', 1, 1, 1, 1, 1, '系统管理员', UNIX_TIMESTAMP()*1000);然后用 admin / 123456 登录 /v1/web/user/login。
注意:admin 的用户 ID 建议设为 1,代码里有些地方硬编码了
DefaultUserID = 1。
真实密钥从 application*.yml 中抽取出来放在 application-local.yml,分类如下:
| 文件 | 内容 | 是否提交 Git | 说明 |
|---|---|---|---|
application.yml |
占位符 | ✅ | 基础配置模板,任何人 clone 下来都能看到 |
application-dev.yml |
占位符 | ✅ | 开发环境默认值,不含真实密钥 |
application-local.yml |
真实密钥 | ❌ | 本地私密配置,.gitignore 已忽略 |
application-local.example.yml |
占位符模板 | ✅ | 给别人看的示例,复制后改名填值 |
application-prod.example.yml |
占位符模板 | ✅ | 生产环境模板 |
你 clone 下来后的操作:
# 复制模板 → 填入你自己的真实密钥
cp configs/application-local.example.yml configs/application-local.ymlapplication-local.yml 的内容会覆盖 application.yml 和 application-dev.yml 中的同名配置项。
application.yml ← 基础配置(第一层)
↓ 合并
application-{APP_ENV}.yml ← 环境配置(第二层,dev/prod)
↓ 合并
application-local.yml ← 本地密钥(第三层,gitignore)
↓ 覆盖
环境变量 MALL_* ← 环境变量(最高优先级)
三层叠加,相同 key 的后面覆盖前面。比如 application.yml 里 redis.password: "",application-local.yml 里 redis.password: your_redis_password,最终生效的是 your_redis_password。
所有配置项都可以通过环境变量覆盖,格式为 MALL_<层级>_<KEY>(点号替换为下划线):
# 覆盖 MySQL 主库 DSN
export MALL_MYSQL_MASTER_DSN="root:pwd@tcp(192.168.1.100:3306)/mall_db?charset=utf8mb4&parseTime=True&loc=Local"
# 覆盖 Redis 地址
export MALL_REDIS_ADDR="192.168.1.100:6379"
# 覆盖 JWT 密钥
export MALL_MALL_API_TOKENSECRET="my-production-secret"通过 APP_ENV 环境变量切换环境:
# 开发环境(默认,未设置时自动使用 dev)
go run cmd/server/main.go
# 生产环境
APP_ENV=prod go run cmd/server/main.go
# 编译后运行
go build -o server.exe cmd/server/main.go
APP_ENV=prod ./server.exe不同环境的区别:
| 配置 | dev 环境 | prod 环境 |
|---|---|---|
| 短信 | mockSms=true(不发真短信) | mockSms=false |
| 验证码 | mockCaptcha=true(跳过验证) | mockCaptcha=false |
| JWT 密钥 | dev-secret-change-in-prod | 必须换成强密钥 |
| 导出分页 | 2 条/页(方便调试) | 500 条/页 |
application-{env}.yml |
application-dev.yml |
application-prod.yml(需自行创建) |
cp configs/application-prod.example.yml configs/application-prod.yml
# 编辑 application-prod.yml,填入生产环境的真实值
chmod 600 configs/application-prod.yml # Linux/macOS 上限制权限-- 主库
CREATE DATABASE mall_db DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 订单分片库(订单表按 code 哈希分片到两个库)
CREATE DATABASE mall_db_order_0 DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE mall_db_order_1 DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;程序使用 GORM AutoMigrate 自动建表,启动时会自动创建所有表结构。
注意: AutoMigrate 只会创建表、添加缺失的列,不会删除已有列或修改列类型。如果修改了模型字段类型,需要手动 ALTER TABLE。
订单相关表按 code 字段哈希分片:
ShardIndex = abs(hash(trade_code)) % 2
Shard 0 → mall_db_order_0 (order_trade_0, order_trade_1)
Shard 1 → mall_db_order_1 (order_trade_0, order_trade_1)
同一笔订单的 trade、item、address 三张表落在同一个分片中,保证事务性。
启动服务后访问:
| 地址 | 说明 |
|---|---|
http://localhost:8011/doc |
Redoc 文档(推荐,更紧凑) |
http://localhost:8011/swagger/index.html |
Swagger UI |
http://localhost:8011/swagger/doc.json |
Swagger JSON 规范 |
接口分组:
| 路径前缀 | 说明 | 认证 |
|---|---|---|
/v1/web/user/* |
登录/注册/个人信息 | JWT(部分白名单) |
/v1/web/product/* |
商品搜索/详情/收藏/购物车 | 部分公开 |
/v1/web/trade/* |
订单确认/提交/支付 | JWT |
/v1/web/coupon/* |
优惠券领取/查询 | JWT |
/v1/web/seckill/* |
秒杀 | JWT |
/v1/web/refund/* |
退款申请 | JWT |
/v1/web/pay/* |
支付 | JWT |
/v1/admin/* |
管理后台 | JWT + 权限码 |
/v1/image/upload |
图片上传 | 公开 |
/v1/file/upload |
文件上传 | 公开 |
Authorization: Bearer <JWT_TOKEN>
JWT Token 通过 /v1/web/user/login 获取。前端登录时,密码需先 RSA 加密(公钥从后端获取),后端用私钥解密后再 bcrypt 比对。
# 启动开发服务器
go run cmd/server/main.go
# 编译
go build -o server.exe cmd/server/main.go
# 运行测试
go test ./...
# 代码检查
go vet ./...
# 生成 RSA 密钥对(用于密码加密传输)
go run cmd/genkey/main.go
# 生成 bcrypt 密码哈希
go run cmd/encrypt_pwd/main.go -pwd 123456
# 测试用公钥加密一段文本
go run cmd/encrypt/main.go -text "123456"检查 configs/ 目录下是否有 application.yml,且格式正确(YAML 缩进用空格,不要用 Tab)。
- 确认 MySQL 服务已启动
- 确认
application-local.yml中的 DSN 地址、用户名、密码正确 - 确认数据库已创建(
mall_db,mall_db_order_0,mall_db_order_1)
- 确认 Redis 服务已启动:
redis-cli ping - 确认地址和密码正确
- Redis 是必须的,不是可选的
- ES 是可选的,连接失败只会打印一条 Warning,不影响服务启动
- 没有 ES 时,商品搜索接口会返回空结果(而不是报错)
- 如果连接成功但没有数据,需要先通过管理后台创建商品,系统会自动同步到 ES
- 确认 ES 是否已连接(看启动日志)
- 确认 ES 中是否有数据:
curl http://localhost:9200/product/_count - 如果是新部署,需要创建商品后才会索引到 ES
- 首次部署需要全量同步历史数据(功能待实现,目前仅增量同步)
部分依赖可能需要 GCC。如果不想装 GCC,可以禁用 CGO:
CGO_ENABLED=0 go build -o server.exe cmd/server/main.go默认端口 8011。修改 application.yml 中的 server.port:
server:
port: 8012设置国内代理:
go env -w GOPROXY=https://goproxy.cn,directMIT