Skip to content
yaocat55Public

About

心血来潮重写的go电商,当个玩具看就行

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

40 Commits

Folders and files

Repository files navigation

Mall Go — 电商系统 Go 重构版

Go Version Gin GORM MySQL Redis Elasticsearch MongoDB RabbitMQ RocketMQ MinIO JWT Swagger License

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

环境准备

1. 安装 Go

去 https://go.dev/dl/ 下载 Windows/macOS/Linux 安装包。

安装完成后,打开终端验证:

go version
# 输出: go version go1.26.0 windows/amd64

2. 配置 Go 代理(中国大陆必做)

go env -w GOPROXY=https://goproxy.cn,direct

3. 必需的基础设施

服务 用途 必须?
MySQL 8.0+ 主数据库 + 订单分片库 ✅ 必须
Redis 6.0+ 缓存 / Session / 分布式锁 ✅ 必须
Elasticsearch 8.x 商品搜索 ⚠️ 可选(不可用时搜索返回空)
MongoDB 5.0+ 商品详情富文本 ⚠️ 可选(不可用时仅 MySQL)
RabbitMQ 消息队列 ⚠️ 可选
RocketMQ 消息队列(延迟消息) ⚠️ 可选
MinIO 对象存储(文件/图片上传) ⚠️ 可选

快速开始(新人向)

如果你之前没写过 Go,跟着这 6 步就能跑起来。

第 1 步:克隆项目

git clone <repo-url> mall_go
cd mall_go

第 2 步:下载依赖

go mod download

这一步会自动下载 go.mod 里声明的所有第三方库到本机缓存。

第 3 步:创建本地配置文件

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 覆盖。

第 4 步:创建数据库

连接你的 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。

第 5 步:启动服务

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

第 6 步:验证

# 健康检查
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.yml

application-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 上限制权限

数据库初始化

MySQL 建库

-- 主库
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 三张表落在同一个分片中,保证事务性。

API 文档

启动服务后访问:

地址 说明
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"

常见问题

启动报 read config failed

检查 configs/ 目录下是否有 application.yml,且格式正确(YAML 缩进用空格,不要用 Tab)。

启动报 MySQL 连接失败

  • 确认 MySQL 服务已启动
  • 确认 application-local.yml 中的 DSN 地址、用户名、密码正确
  • 确认数据库已创建(mall_db, mall_db_order_0, mall_db_order_1)

启动报 Redis 连接失败

  • 确认 Redis 服务已启动:redis-cli ping
  • 确认地址和密码正确
  • Redis 是必须的,不是可选的

Elasticsearch 连接失败

  • ES 是可选的,连接失败只会打印一条 Warning,不影响服务启动
  • 没有 ES 时,商品搜索接口会返回空结果(而不是报错)
  • 如果连接成功但没有数据,需要先通过管理后台创建商品,系统会自动同步到 ES

商品搜索返回空

  1. 确认 ES 是否已连接(看启动日志)
  2. 确认 ES 中是否有数据:curl http://localhost:9200/product/_count
  3. 如果是新部署,需要创建商品后才会索引到 ES
  4. 首次部署需要全量同步历史数据(功能待实现,目前仅增量同步)

Windows 下编译报 CGO 相关错误

部分依赖可能需要 GCC。如果不想装 GCC,可以禁用 CGO:

CGO_ENABLED=0 go build -o server.exe cmd/server/main.go

端口被占用

默认端口 8011。修改 application.yml 中的 server.port:

server:
  port: 8012

Go mod 下载慢

设置国内代理:

go env -w GOPROXY=https://goproxy.cn,direct

License

MIT

About

心血来潮重写的go电商,当个玩具看就行

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages