签入版本
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
# 2.2 后端服务启动
|
||||
|
||||
:::tip 概述
|
||||
后端为标准 GoFrame v2 工程,单入口 `main.go`,启动后监听 `:8000`。本节覆盖从编译到运行的完整步骤与常见启动问题。
|
||||
:::
|
||||
|
||||
## 启动流程
|
||||
|
||||
```text
|
||||
main.go
|
||||
├─ 注册五数据库驱动(mysql/pgsql/mssql/oracle/sqlite blank import)
|
||||
├─ 注册 Redis 适配器
|
||||
└─ internal/cmd.Run(ctx)
|
||||
├─ 1) utility/cache.Init Redis 探测,失败降级进程内存
|
||||
├─ 2) wireDependencies 校验中间件依赖接线(缺失仅告警)
|
||||
├─ 3) g.Server + router.Register 中间件链 + 路由绑定
|
||||
├─ 4) DaemonInit(延时 2s) 定时任务调度器加载 status=1 任务
|
||||
├─ 5) gcron 注册 CleanTemp 每日 03:30 清理上传临时目录
|
||||
└─ 6) s.Run() 阻塞运行 HTTP 服务
|
||||
```
|
||||
|
||||
## 编译与运行
|
||||
|
||||
```sh
|
||||
# 在项目根目录执行
|
||||
|
||||
# 方式一:直接运行(开发)
|
||||
go run main.go
|
||||
|
||||
# 方式二:编译后运行(推荐)
|
||||
go build -o bin/admin-server.exe main.go
|
||||
./bin/admin-server.exe
|
||||
```
|
||||
|
||||
启动成功后控制台输出路由表与监听地址,服务监听 **:8000**。
|
||||
|
||||
## 启动前检查
|
||||
|
||||
1. **配置文件**:确认 `manifest/config/config.yaml` 中:
|
||||
- `database.default.link` 数据库连接串(默认 MySQL root/root)
|
||||
- `redis.default` 地址与密码
|
||||
2. **数据库已初始化**:参见 [2.4 数据库初始化](./database-init)
|
||||
3. **端口未占用**:
|
||||
|
||||
```sh
|
||||
# Windows 查看端口占用
|
||||
netstat -ano | findstr ":8000" | findstr LISTENING
|
||||
```
|
||||
|
||||
## 验证启动成功
|
||||
|
||||
```sh
|
||||
# 健康检查(免登录公开接口)
|
||||
curl http://127.0.0.1:8000/api/health
|
||||
# {"code":0,"ok":true,"msg":"操作成功","data":{"status":"up"}}
|
||||
|
||||
# OpenAPI 文档
|
||||
# 浏览器打开 http://127.0.0.1:8000/swagger (本地 Redoc 页面)
|
||||
# 原生 JSON:http://127.0.0.1:8000/api.json
|
||||
```
|
||||
|
||||
## 服务重启(Windows)
|
||||
|
||||
```sh
|
||||
netstat -ano | findstr ":8000" | findstr LISTENING
|
||||
taskkill /F /PID <pid>
|
||||
go build -o bin/admin-server.exe main.go && ./bin/admin-server.exe
|
||||
```
|
||||
|
||||
服务已开启优雅重启(`server.graceful: true`),生产环境可使用进程管理器发 SIGHUSR2 热重启。
|
||||
|
||||
## 启动日志说明
|
||||
|
||||
| 日志 | 含义 |
|
||||
|------|------|
|
||||
| `IdentityLoader`/`TenantLoader`/`LogSink` 告警 | 中间件依赖未接线(不阻断启动),表现为不加载角色权限/跳过租户校验/日志不落库 |
|
||||
| Redis 连接失败告警 + `memory fallback` | 已降级内存缓存,多实例共享能力退化 |
|
||||
| 路由表输出(`server.dumpRouterMap`) | 配置为 true 时打印全部注册路由,调试路由问题用 |
|
||||
|
||||
## 常见启动失败原因
|
||||
|
||||
+ **端口占用**:8000 被其他进程占用,改 `server.address` 或释放端口
|
||||
+ **数据库连不上**:检查 link 串、库是否存在、账号密码;库名含点需确认拼写
|
||||
+ **配置文件缺失**:必须从项目根目录运行(相对路径读取 `manifest/config/config.yaml`)
|
||||
+ **Go 版本过低**:go.mod 声明 1.27.2,低版本报 `go.mod requires go >= 1.27.2`
|
||||
@@ -0,0 +1,104 @@
|
||||
# 2.4 数据库初始化
|
||||
|
||||
:::tip 概述
|
||||
项目以 MySQL 为规范基准数据库,五方言定稿脚本统一存放于 `document/{数据库}/easygoadmin.goframe.elevue.sql`。本节演示最短初始化路径与验证方法。
|
||||
:::
|
||||
|
||||
## 定稿脚本目录
|
||||
|
||||
```text
|
||||
document/
|
||||
├── mysql/easygoadmin.goframe.elevue.sql # MySQL 定稿(规范基准,人工导入维护)
|
||||
├── postgresql/easygoadmin.goframe.elevue.sql # PostgreSQL 定稿(由基准转换,待人工校对)
|
||||
├── sqlserver/easygoadmin.goframe.elevue.sql # SQL Server 定稿(由基准转换,待人工校对)
|
||||
├── oracle/easygoadmin.goframe.elevue.sql # Oracle 定稿(由基准转换,待人工校对)
|
||||
└── sqlite/easygoadmin.goframe.elevue.sql # SQLite 定稿(由基准转换,待人工校对)
|
||||
```
|
||||
|
||||
::: warning 定稿以 MySQL 为准
|
||||
五份脚本中 **MySQL 版为规范基准**,后四份由基准转换生成,尚待人工校对。生产使用非 MySQL 库前,请人工核对后四份脚本(尤其是唯一索引 `uk_*` 与列注释枚举)。
|
||||
:::
|
||||
|
||||
## 方式一:导入 MySQL 定稿脚本(推荐)
|
||||
|
||||
```sh
|
||||
# 创建库(注意库名含点,utf8mb4)
|
||||
mysql -uroot -p -e "CREATE DATABASE \`easygoadmin.goframe.elevue\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
|
||||
|
||||
# 导入定稿脚本(含 25 张表 + 索引 + 种子数据:超管账号/菜单/字典/参数/租户等)
|
||||
mysql -uroot -p easygoadmin.goframe.elevue < document/mysql/easygoadmin.goframe.elevue.sql
|
||||
```
|
||||
|
||||
导入后验证:
|
||||
|
||||
```sql
|
||||
SHOW TABLES; -- 25 张 goframe_ 前缀表
|
||||
SELECT username FROM goframe_user WHERE id=1; -- admin
|
||||
```
|
||||
|
||||
## 其他数据库初始化
|
||||
|
||||
PostgreSQL 示例:
|
||||
|
||||
```sh
|
||||
createdb -U postgres easygoadmin.goframe.elevue
|
||||
psql -U postgres -d easygoadmin.goframe.elevue -f document/postgresql/easygoadmin.goframe.elevue.sql
|
||||
```
|
||||
|
||||
SQLite 示例(文件库,无需建库):
|
||||
|
||||
```sh
|
||||
sqlite3 easygoadmin.db < document/sqlite/easygoadmin.goframe.elevue.sql
|
||||
```
|
||||
|
||||
SQL Server / Oracle 使用对应客户端工具执行 `document/sqlserver/`、`document/oracle/` 下脚本。
|
||||
|
||||
导入后修改 `manifest/config/config.yaml` 的 `database.default.type/link` 切换连接(五驱动已在 main.go 预注册,改配置即切换)。
|
||||
|
||||
## 从现有库迁移
|
||||
|
||||
已有 MySQL 数据要搬到其他方言,**不要手工导 SQL**,使用内置整库迁移器(结构 + 注释 + 索引 + 数据 + 序列一体搬运,五方言互迁):
|
||||
|
||||
```sh
|
||||
go run ./cmd/migrator \
|
||||
-src-type=mysql -src-host=127.0.0.1 -src-hostport=3306 \
|
||||
-src-database=easygoadmin.goframe.elevue -src-username=root -src-password=root \
|
||||
-dst-type=pgsql -dst-host=127.0.0.1 -dst-hostport=5432 \
|
||||
-dst-database=easygoadmin.goframe.elevue -dst-username=postgres -dst-password=123456 \
|
||||
-drop-target-first
|
||||
```
|
||||
|
||||
详见 [7.6 数据库迁移工具](../tools/db-migrate) 与 [11.3 数据库迁移](../deploy/db-migrate)。仓库保留有实测日志:`document/数据迁移PostgreSQL版本日志.txt`、`数据迁移SqlServer版本日志.txt`、`数据迁移Sqlite版本日志.txt`。
|
||||
|
||||
## 表结构通用规范
|
||||
|
||||
全部 25 张表统一以下规范(建新表必须遵循,详见 [3.2 数据库建表](../guide/database)):
|
||||
|
||||
```sql
|
||||
-- 统一审计列(25 表齐备)
|
||||
id int NOT NULL AUTO_INCREMENT, -- 主键:数据库自增(禁用雪花)
|
||||
create_user varchar(50), -- 创建人
|
||||
create_time datetime DEFAULT (now()), -- 创建时间
|
||||
update_user varchar(50), -- 更新人
|
||||
update_time datetime DEFAULT (now()), -- 更新时间
|
||||
del_flag int DEFAULT 0, -- 软删:0-正常 1-已删除
|
||||
-- 租户级表(9 张)另有:
|
||||
tenant_id int DEFAULT 0 -- 0=平台级
|
||||
```
|
||||
|
||||
## 验证数据完整性
|
||||
|
||||
```sql
|
||||
-- 种子超管与角色
|
||||
SELECT u.username, r.code FROM goframe_user u
|
||||
JOIN goframe_user_role ur ON ur.user_id=u.id
|
||||
JOIN goframe_role r ON r.id=ur.role_id; -- admin / ROLE_SUPER_ADMIN
|
||||
|
||||
-- 字典种子
|
||||
SELECT code FROM goframe_dict; -- role_data_scope 等
|
||||
|
||||
-- 唯一索引检查(13 个)
|
||||
SELECT TABLE_NAME, INDEX_NAME FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA='easygoadmin.goframe.elevue' AND INDEX_NAME LIKE 'uk_%'
|
||||
GROUP BY TABLE_NAME, INDEX_NAME;
|
||||
```
|
||||
@@ -0,0 +1,167 @@
|
||||
# 2.7 Docker 快速体验
|
||||
|
||||
:::tip 概述
|
||||
项目根目录已内置完整 Docker 化文件(`docker/` 目录 + 根目录 `.dockerignore`),一条命令拉起 后端 + MySQL + Redis 三容器全栈。生产部署细节见 [11.6 Docker 生产部署](../deploy/docker)。
|
||||
:::
|
||||
|
||||
## 文件布局
|
||||
|
||||
```text
|
||||
EasyGoAdmin_GoFrame_EleVue/
|
||||
├── .dockerignore # 构建上下文排除清单(Docker 硬规则:必须在上下文根目录)
|
||||
└── docker/
|
||||
├── Dockerfile # 多阶段构建:golang:1.27-alpine 编译 → alpine 运行
|
||||
├── docker-compose.yml # 三服务编排:后端 + MySQL8 + Redis7
|
||||
└── .env.example # 环境变量模板(复制为 .env 使用,含明文密钥不入库)
|
||||
```
|
||||
|
||||
:::warning 为什么 `.dockerignore` 不在 docker/ 里
|
||||
`.dockerignore` 由**构建上下文根目录**决定,与 Dockerfile 位置无关。放 `docker/` 里会完全失效,`ui/node_modules`(数百 MB)会被打进构建上下文,构建极慢。而 `Dockerfile` / `docker-compose.yml` 位置无所谓,构建/启动时用 `-f` 指定即可。
|
||||
:::
|
||||
|
||||
## 文件注释速览
|
||||
|
||||
**Dockerfile**(多阶段,关键设计):
|
||||
|
||||
```dockerfile
|
||||
# 阶段一:builder —— 编译静态二进制
|
||||
# 纯 Go 项目(sqlite 驱动为 modernc 系,无 CGO),CGO_ENABLED=0 静态编译
|
||||
# 先拷 go.mod/go.sum 再 go mod download:源码变更但依赖未变时不重复下载
|
||||
# -trimpath 去除本地路径,-s -w 去除符号表与调试信息
|
||||
FROM golang:1.27-alpine AS builder
|
||||
ENV GOPROXY=https://goproxy.cn,direct CGO_ENABLED=0 GOOS=linux
|
||||
WORKDIR /build
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY . .
|
||||
RUN go build -trimpath -ldflags "-s -w" -o /build/bin/admin-server main.go
|
||||
|
||||
# 阶段二:runtime —— 最终业务镜像
|
||||
# 运行时资产四件(缺一运行报错):
|
||||
# manifest/config 配置文件
|
||||
# manifest/data ip2region.xdb 归属地库
|
||||
# resource 字体/swagger 静态资源
|
||||
# templates 代码生成器模板(tool 域运行时读取)
|
||||
# 先于二进制 COPY,业务代码变动不破坏资产层缓存
|
||||
# 非 root 运行;tzdata 供 app.timezone=Asia/Shanghai 使用
|
||||
FROM alpine:3.22 AS runtime
|
||||
ENV TZ=Asia/Shanghai
|
||||
RUN apk add --no-cache tzdata ca-certificates \
|
||||
&& addgroup -g 1000 app && adduser -u 1000 -G app -s /sbin/nologin -D app
|
||||
WORKDIR /opt/easygoadmin
|
||||
COPY --chown=app:app manifest/config ./manifest/config
|
||||
COPY --chown=app:app manifest/data ./manifest/data
|
||||
COPY --chown=app:app resource ./resource
|
||||
COPY --chown=app:app templates ./templates
|
||||
COPY --chown=app:app --from=builder /build/bin/admin-server ./bin/admin-server
|
||||
USER app
|
||||
# 健康检查:/api/health 为公开白名单路径,不带 /v1
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
||||
CMD wget -qO- "http://127.0.0.1:8000/api/health" || exit 1
|
||||
ENTRYPOINT ["./bin/admin-server"]
|
||||
```
|
||||
|
||||
**docker-compose.yml**(三服务编排,关键设计):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
easygoadmin:
|
||||
build:
|
||||
context: .. # 上下文为项目根(compose 在 docker/ 目录)
|
||||
dockerfile: docker/Dockerfile
|
||||
# 敏感/环境相关配置一律 GF_ 前缀覆盖,不改镜像内 config.yaml
|
||||
# (键名 = 配置路径大写下划线,如 file.uploadDir → GF_FILE_UPLOADDIR)
|
||||
environment:
|
||||
# 连接串由 .env 参数拼装:主机/端口/账号/密码/库名均可覆盖(连外部库改 .env 即可)
|
||||
GF_DATABASE_DEFAULT_LINK: "mysql:${MYSQL_USER}:${MYSQL_PASSWORD}@tcp(${MYSQL_HOST}:${MYSQL_PORT})/${MYSQL_DATABASE}?..."
|
||||
GF_REDIS_DEFAULT_ADDRESS: "${REDIS_HOST}:${REDIS_PORT}"
|
||||
GF_FILE_UPLOADDIR: "/data/upload" # 配置默认是 Windows 绝对路径,容器内必须覆盖
|
||||
GF_CAPTCHA_BYPASSCODE: "" # 生产清空万能验证码
|
||||
GF_APP_ERRORMSG: "false" # 生产关闭详细错误信息
|
||||
volumes:
|
||||
- ../upload:/data/upload # 宿主路径相对 compose 文件目录,需 ../ 回到项目根
|
||||
- ../log:/opt/easygoadmin/log
|
||||
depends_on:
|
||||
mysql: { condition: service_healthy } # 等 healthcheck 通过再启动
|
||||
redis: { condition: service_healthy }
|
||||
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
volumes:
|
||||
- mysql-data:/var/lib/mysql
|
||||
# 首次初始化:导入定稿 SQL(仅空数据卷时执行一次)
|
||||
- ../document/mysql/easygoadmin.goframe.elevue.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
||||
command: [--character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --lower_case_table_names=1]
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
command: ["redis-server", "--requirepass", "${REDIS_PASSWORD:-123456}", "--appendonly", "yes"]
|
||||
```
|
||||
|
||||
## 三步启动
|
||||
|
||||
```sh
|
||||
cd docker
|
||||
|
||||
# 1. 首次:生成 .env 并按需修改密钥(JWT_SECRET / 数据库 / Redis 密码)
|
||||
copy .env.example .env
|
||||
|
||||
# 2. 构建并启动全栈(首次 MySQL 自动导入定稿 SQL 建库)
|
||||
docker compose up -d --build
|
||||
|
||||
# 3. 验证
|
||||
curl http://127.0.0.1:8000/api/health
|
||||
```
|
||||
|
||||
默认账号 `admin / 123456`。`.env` 变量说明:
|
||||
|
||||
| 变量 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| APP_PORT | 8000 | 后端宿主端口 |
|
||||
| JWT_SECRET | please-change-... | 令牌签名密钥,**生产必改** |
|
||||
| MYSQL_HOST | mysql | **连接串内主机**:自带服务用服务名;连外部库填 IP/域名 |
|
||||
| MYSQL_PORT | 3306 | **数据库监听端口**(进连接串;连外部库填外部库端口) |
|
||||
| MYSQL_USER / MYSQL_PASSWORD | root / root | 数据库账号与密码 |
|
||||
| MYSQL_DATABASE | easygoadmin.goframe.elevue | 库名(与定稿 SQL 一致,勿随意改) |
|
||||
| REDIS_HOST | redis | 同 MYSQL_HOST 规则 |
|
||||
| REDIS_PORT / REDIS_PASSWORD | 6379 / 123456 | Redis 监听端口(进连接串)与密码 |
|
||||
|
||||
> 自带 mysql/redis 服务的**宿主映射端口已在 compose 写死**(3306/6379,仅供宿主机客户端直连调试),不在 `.env` 中配置;占用冲突时直接改 compose 的 `ports`。
|
||||
|
||||
**连宿主机已有数据库/Redis**:`.env` 中把 `MYSQL_HOST` / `REDIS_HOST` 改为 `host.docker.internal`(Windows/Mac Docker Desktop;Linux 需 compose 加 `extra_hosts: host.docker.internal:host-gateway`),端口填宿主机上实际监听端口。
|
||||
|
||||
::: warning 容器内 127.0.0.1 不是宿主机
|
||||
bridge 网络下每个容器有独立网络栈,`MYSQL_HOST=127.0.0.1` / `REDIS_HOST=127.0.0.1` 指向**容器自身**,连接必失败(Redis 会静默降级内存缓存,JWT 黑名单、验证码共享随之失效)。连宿主机一律用 `host.docker.internal` 或宿主机实际 IP。
|
||||
:::
|
||||
|
||||
## 仅构建后端镜像(连宿主机已有 DB/Redis)
|
||||
|
||||
不启动 compose 里的 mysql/redis 服务时,在**项目根目录**执行:
|
||||
|
||||
```sh
|
||||
docker build -f docker/Dockerfile -t easygoadmin:latest .
|
||||
|
||||
docker run -d --name easygoadmin -p 8000:8000 \
|
||||
-e GF_DATABASE_DEFAULT_LINK="mysql:root:root@tcp(host.docker.internal:3306)/easygoadmin.goframe.elevue?charset=utf8mb4&parseTime=true&loc=Local" \
|
||||
-e GF_REDIS_DEFAULT_ADDRESS="host.docker.internal:6379" \
|
||||
-e GF_FILE_UPLOADDIR="/data/upload" \
|
||||
-v ${PWD}/upload:/data/upload easygoadmin:latest
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
::: warning 容器内注意
|
||||
1. `file.uploadDir` 配置默认是 Windows 绝对路径,容器内**必须**用 `GF_FILE_UPLOADDIR` 覆盖并挂持久卷,否则重建丢文件。
|
||||
2. 跨卷上传"复制后删源"逻辑依赖同一文件系统,upload 目录必须是独立卷。
|
||||
3. 定稿 SQL 挂载到 `docker-entrypoint-initdb.d` **仅在 MySQL 数据卷为空时执行一次**;改表结构后需手动执行或 `docker volume rm` 清卷重建。
|
||||
4. 代码生成器(tool 域)在容器内可用(`templates/` 已打入镜像),但生成产物写在容器文件系统里,**生产容器不建议使用**,开发期仍在宿主机跑 `go run ./cmd/generator`。
|
||||
5. 连接串/Redis 地址在 bridge 网络下用**服务名**(`mysql`、`redis`)互访;连宿主机服务用 `host.docker.internal`;**容器内 127.0.0.1 指向容器自身**,填了连不上(详见上方变量表警示)。
|
||||
:::
|
||||
|
||||
## 其他运行形态
|
||||
|
||||
| 形态 | 说明 |
|
||||
|------|------|
|
||||
| 二进制 + systemd | `go build` 产物 + systemd unit(见 [11.4 后端部署](../deploy/backend)) |
|
||||
| 前端 Nginx 容器 | `ui/` 独立构建 dist 后由 Nginx 托管并反代 /api(见 [11.6](../deploy/docker)) |
|
||||
| k8s | 按拓扑拆分 Deployment/Service,上传目录用 PV |
|
||||
@@ -0,0 +1,142 @@
|
||||
# 2.5 配置文件说明
|
||||
|
||||
:::tip 概述
|
||||
本项目唯一运行时配置文件为 `manifest/config/config.yaml`,GoFrame gcfg 加载。环境变量覆盖规则:使用 `GF_` 前缀,例如 `GF_DATABASE_DEFAULT_LINK`。本节速览全部配置块,完整键值速查见[附录 C 配置项速查](../appendix/config-reference)。
|
||||
:::
|
||||
|
||||
## 配置文件全景
|
||||
|
||||
```text
|
||||
manifest/config/config.yaml
|
||||
├─ server 服务端:监听地址、OpenAPI、优雅重启
|
||||
├─ logger 日志:级别、输出、目录
|
||||
├─ database 多数据库连接(type/link 切换五方言)
|
||||
├─ redis 缓存连接(黑名单/验证码/字典/租户/身份缓存)
|
||||
├─ jwt 双令牌:签名密钥、签发者、双有效期
|
||||
├─ captcha 图形验证码:字符集、尺寸、干扰参数、万能码
|
||||
├─ rateLimit 接口限流:窗口、普通阈值、认证入口阈值
|
||||
├─ operationLog 操作日志:总开关、查询类记录开关
|
||||
├─ job 定时任务:日志保留天数
|
||||
├─ tenant 租户:超管新增的默认归属租户
|
||||
├─ app 应用:时区、演示模式、错误信息开关
|
||||
├─ api 接口:驼峰转换、受信代理列表
|
||||
├─ cors 跨域:允许来源
|
||||
├─ file 文件上传:目录、域名、白名单、大小、临时保留天数
|
||||
├─ generator 代码生成器:父菜单 ID、覆盖开关
|
||||
└─ ip2region 归属地库:xdb 文件路径
|
||||
```
|
||||
|
||||
## 核心配置速览
|
||||
|
||||
### 服务端
|
||||
|
||||
```yaml
|
||||
server:
|
||||
address: ":8000" # 监听地址与端口
|
||||
openapiPath: "/api.json" # OpenAPI 文档路径(原生自动生成)
|
||||
swaggerPath: "" # Swagger UI(本地托管 resource/swagger/)
|
||||
errorStack: true # 响应携带错误堆栈(生产建议 false)
|
||||
graceful: true # 优雅重启
|
||||
```
|
||||
|
||||
### 数据库与缓存
|
||||
|
||||
```yaml
|
||||
database:
|
||||
default:
|
||||
type: "mysql"
|
||||
link: "mysql:root:root@tcp(127.0.0.1:3306)/easygoadmin.goframe.elevue?charset=utf8mb4&parseTime=true&loc=Local"
|
||||
debug: false # 调试期可开 SQL 日志,生产关闭
|
||||
redis:
|
||||
default:
|
||||
address: "127.0.0.1:6379"
|
||||
pass: "123456"
|
||||
```
|
||||
|
||||
### JWT 与验证码
|
||||
|
||||
```yaml
|
||||
jwt:
|
||||
secret: "…" # 签名密钥(生产必须改)
|
||||
issuer: "easygoadmin"
|
||||
accessTokenExpire: 7200 # 访问令牌 2 小时
|
||||
refreshTokenExpire: 604800 # 刷新令牌 7 天
|
||||
captcha:
|
||||
expire: 300
|
||||
bypassCode: "618618" # 万能验证码(生产必须留空)
|
||||
length: 6
|
||||
```
|
||||
|
||||
### 限流与防护
|
||||
|
||||
```yaml
|
||||
rateLimit:
|
||||
enable: true
|
||||
limit: 120 # 普通接口每窗口每 IP 每路径上限
|
||||
windowSeconds: 60
|
||||
authLimit: 10 # 登录/验证码/令牌兑换独立更严阈值
|
||||
operationLog:
|
||||
enable: true
|
||||
logQuery: true
|
||||
app:
|
||||
demo: false # 演示模式:true 时拦截全部写操作
|
||||
errorMsg: true # 详细错误信息(生产建议 false)
|
||||
```
|
||||
|
||||
### 文件与生成器
|
||||
|
||||
```yaml
|
||||
file:
|
||||
uploadDir: "…" # 物理根目录(当前配置为开发机绝对路径,建议改相对项目根;
|
||||
# 容器部署用 GF_FILE_UPLOADDIR 覆盖并挂持久卷)
|
||||
domainUrl: "http://file.goframe.elevue" # 文件访问域名,空则 /upload/ 相对路径
|
||||
imageExt: "gif,jpg,jpeg,png,bmp,webp,svg"
|
||||
fileExt: "gif,jpg,…,csv,mp3,mp4,sql,js,css"
|
||||
maxSize: 10 # 单文件上限 MB
|
||||
tempExpireDays: 7 # 临时目录保留天数(0=不清理)
|
||||
generator:
|
||||
parentMenuId: 189 # 新模块菜单挂载父级 ID
|
||||
overwrite: true # 覆盖开关(true 生成即覆盖;false=缺失补生成、存在跳过)
|
||||
ip2region:
|
||||
path: "manifest/data/ip2region.xdb"
|
||||
```
|
||||
|
||||
## 环境变量覆盖
|
||||
|
||||
容器化/CI 部署时无需改镜像内配置文件,用环境变量覆盖任意键(12-Factor 标准,**环境变量 > 配置文件**):
|
||||
|
||||
```sh
|
||||
GF_DATABASE_DEFAULT_LINK="mysql:root:secret@tcp(db:3306)/easygoadmin?charset=utf8mb4&parseTime=true"
|
||||
GF_REDIS_DEFAULT_ADDRESS="redis:6379"
|
||||
GF_APP_DEMO="false"
|
||||
GF_FILE_UPLOADDIR="/data/upload"
|
||||
```
|
||||
|
||||
**键名规则**:配置路径大写、点换下划线并加 `GF_` 前缀。
|
||||
|
||||
```text
|
||||
配置键 database.default.link → 环境变量 GF_DATABASE_DEFAULT_LINK
|
||||
配置键 file.uploadDir → 环境变量 GF_FILE_UPLOADDIR
|
||||
配置键 jwt.secret → 环境变量 GF_JWT_SECRET
|
||||
```
|
||||
|
||||
**生效语义**(实现见 `utility/config`,启动时经 `RegisterEnvOverride` 接线环境变量优先适配器):
|
||||
|
||||
```text
|
||||
优先级 环境变量 > 配置文件(未设环境变量时行为与纯文件读取完全一致)
|
||||
空值 环境变量为空串视为未设置,不会清空配置文件中的有效值
|
||||
范围 仅覆盖配置文件中已存在的键(新增键须先在 config.yaml 声明)
|
||||
整节点 读取 database 整节点(如框架初始化连接)时逐叶叠加覆盖,
|
||||
连接串同样被环境变量接管
|
||||
```
|
||||
|
||||
**Docker 部署的推荐姿势**:`.env` 用 `MYSQL_HOST` 等运维友好名,由 compose 的 `environment` 块映射为 `GF_` 规范键注入(`docker/docker-compose.yml` 即此模式);**不要**把友好名原样透传给应用——应用只认 `GF_` 前缀键。`.env` 值中含 `$` 须写成 `$$`(compose 插值会吞掉单 `$`)。
|
||||
|
||||
::: warning 生产环境必改项
|
||||
1. `jwt.secret` 更换为随机长字符串
|
||||
2. `captcha.bypassCode` 留空(万能验证码禁止上线)
|
||||
3. `app.errorMsg: false`(不暴露错误堆栈)
|
||||
4. `server.errorStack: false`
|
||||
5. `database.default.debug: false`
|
||||
6. `redis.default.pass` 设置强密码
|
||||
:::
|
||||
@@ -0,0 +1,110 @@
|
||||
# 2.1 开发环境准备
|
||||
|
||||
:::tip 概述
|
||||
本章指导您从零搭建开发环境,包括 Go、Node.js/pnpm、MySQL、Redis 的安装与配置。项目后端支持 MySQL、PostgreSQL、SQL Server、Oracle、SQLite 五种数据库,默认使用 MySQL。
|
||||
:::
|
||||
|
||||
## 安装流程总览
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[开始] --> B[安装 Go 1.27+]
|
||||
B --> C[安装 MySQL 8.x]
|
||||
C --> D[安装 Redis]
|
||||
D --> E[安装 Node.js 18+ / pnpm]
|
||||
E --> F[安装 GoFrame CLI gf]
|
||||
F --> G[配置开发工具]
|
||||
G --> H[环境就绪 ✅]
|
||||
|
||||
style A fill:#e8f5e9
|
||||
style H fill:#e8f5e9
|
||||
style C fill:#fff3e0
|
||||
```
|
||||
|
||||
## Go 安装
|
||||
|
||||
:::warning 版本要求
|
||||
项目 go.mod 声明 `go 1.27.2`,请安装 Go 1.27.2 及以上版本,过低版本会直接编译失败。
|
||||
:::
|
||||
|
||||
### Windows
|
||||
|
||||
从 [https://go.dev/dl/](https://go.dev/dl/) 下载 `go1.27.2.windows-amd64.msi` 默认安装。验证:
|
||||
|
||||
```sh
|
||||
go version # go version go1.27.2 windows/amd64
|
||||
```
|
||||
|
||||
建议配置国内代理(下载依赖加速):
|
||||
|
||||
```sh
|
||||
go env -w GOPROXY=https://goproxy.cn,direct
|
||||
```
|
||||
|
||||
### GoFrame CLI(可选但推荐)
|
||||
|
||||
```sh
|
||||
go install github.com/gogf/gf/cmd/gf/v2@latest
|
||||
gf -v
|
||||
```
|
||||
|
||||
`gf` 仅在表结构变更后刷新 dao 时使用(`gf gen dao -c hack/config.yaml`),日常开发不依赖。
|
||||
|
||||
## MySQL 安装
|
||||
|
||||
推荐 MySQL 8.x,安装后创建数据库(**注意库名含点**):
|
||||
|
||||
```sql
|
||||
CREATE DATABASE `easygoadmin.goframe.elevue` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
|
||||
```
|
||||
|
||||
默认连接账号 `root/root@127.0.0.1:3306`,如不同请同步修改 `manifest/config/config.yaml` 的 `database.default.link`。
|
||||
|
||||
::: warning 库名注意
|
||||
库名 `easygoadmin.goframe.elevue` 含点号,DDL 语句中引用库名/表名时 MySQL 需要反引号包裹。MySQL 定稿导入脚本为 `document/mysql/easygoadmin.goframe.elevue.sql`(其余方言见 `document/{postgresql,sqlserver,oracle,sqlite}/`)。
|
||||
:::
|
||||
|
||||
## Redis 安装
|
||||
|
||||
Redis 用于缓存、JWT 黑名单、验证码、在线用户、限流计数、任务执行锁。默认连接 `127.0.0.1:6379`,密码 `123456`(见 config.yaml `redis.default.pass`)。
|
||||
|
||||
```sh
|
||||
# Windows 可使用 Memurai / WSL / Redis for Windows
|
||||
# 验证
|
||||
redis-cli -a 123456 ping # PONG
|
||||
```
|
||||
|
||||
::: tip 降级说明
|
||||
Redis 不可用时系统自动降级为进程内存缓存(`utility/cache`),服务可正常启动,但限流计数、任务锁、在线用户、黑名单等多实例共享能力退化为单机语义。生产环境 Redis 必须可用。
|
||||
:::
|
||||
|
||||
## Node.js / pnpm 安装
|
||||
|
||||
前端要求 Node.js 18+,推荐 pnpm 包管理:
|
||||
|
||||
```sh
|
||||
# 安装 Node.js(https://nodejs.org LTS 版)
|
||||
node -v # v18+
|
||||
|
||||
# 安装 pnpm
|
||||
npm install -g pnpm
|
||||
pnpm -v
|
||||
```
|
||||
|
||||
## 开发工具推荐
|
||||
|
||||
| 工具 | 用途 |
|
||||
|------|------|
|
||||
| GoLand / VS Code + Go 插件 | 后端开发 |
|
||||
| VS Code + Volar 插件 | 前端开发(关闭 Vetur) |
|
||||
| Navicat / DBeaver | 数据库管理 |
|
||||
| RedisInsight / Another Redis Desktop | Redis 管理 |
|
||||
| Apifox / Postman | 接口调试(也可直接用内置 /swagger) |
|
||||
|
||||
## 环境检查清单
|
||||
|
||||
+ [ ] `go version` 输出 1.27.2+
|
||||
+ [ ] MySQL 已建库 `easygoadmin.goframe.elevue`(utf8mb4)
|
||||
+ [ ] `redis-cli ping` 返回 PONG
|
||||
+ [ ] `node -v` 输出 18+,`pnpm -v` 正常
|
||||
+ [ ] `manifest/config/config.yaml` 中数据库/Redis 连接信息与实际一致
|
||||
@@ -0,0 +1,98 @@
|
||||
# 2.8 常见问题 FAQ
|
||||
|
||||
:::tip 概述
|
||||
本节收录环境搭建与首次运行阶段最常遇到的问题。更多排障条目见 [附录 A 常见问题汇总](../appendix/faq) 与 [11.10 故障排查手册](../deploy/troubleshooting)。
|
||||
:::
|
||||
|
||||
## 环境与编译
|
||||
|
||||
### Q:`go build` 报 `go.mod requires go >= 1.27.2`
|
||||
|
||||
go.mod 声明的版本高于本机 Go 版本。升级 Go 到 1.27.2+,或使用 go env 切换已安装的高版本。
|
||||
|
||||
### Q:依赖下载缓慢或失败
|
||||
|
||||
```sh
|
||||
go env -w GOPROXY=https://goproxy.cn,direct
|
||||
go mod tidy
|
||||
```
|
||||
|
||||
### Q:前端 `pnpm install` 报引擎不匹配
|
||||
|
||||
检查 Node 版本(要求 18+)。部分依赖对 pnpm 版本敏感,可升级 pnpm 后重装:
|
||||
|
||||
```sh
|
||||
npm install -g pnpm@latest
|
||||
pnpm install
|
||||
```
|
||||
|
||||
## 数据库
|
||||
|
||||
### Q:连接 MySQL 报错 `Unknown database`
|
||||
|
||||
库名是 `easygoadmin.goframe.elevue`(含点号),确认已建库且拼写一致;建库语句见 [2.4 数据库初始化](./database-init)。
|
||||
|
||||
### Q:切换数据库类型后启动报驱动错误
|
||||
|
||||
确认 `database.default.type` 与 `link` 前缀一致(如 `type: "pgsql"` 且 `link: "pgsql:..."`)。五驱动已预注册,无需改代码。
|
||||
|
||||
### Q:导入脚本后缺少唯一索引
|
||||
|
||||
`document/` 各方言脚本中 MySQL 版为规范基准,后四份待人工校对。以 MySQL 版核对 `uk_*` 唯一索引清单(应有 13 个),缺失需人工补齐——唯一索引是并发唯一性的最终保证。
|
||||
|
||||
## 启动与运行
|
||||
|
||||
### Q:启动报端口占用
|
||||
|
||||
```sh
|
||||
netstat -ano | findstr ":8000" | findstr LISTENING
|
||||
taskkill /F /PID <pid>
|
||||
```
|
||||
|
||||
或修改 `manifest/config/config.yaml` 的 `server.address`。
|
||||
|
||||
### Q:启动日志出现 `IdentityLoader`/`LogSink` 告警
|
||||
|
||||
中间件依赖未接线(不阻断启动)。通常原因:`internal/cmd` 缺少对 `internal/logic` 的空白导入,或 init 注册被误删。表现为:不加载角色权限 / 跳过租户校验 / 操作日志不落库。
|
||||
|
||||
### Q:日志提示 Redis 连接失败并降级
|
||||
|
||||
服务以进程内存缓存运行(`UsingMemory()=true`)。限流计数、任务执行锁、在线用户、JWT 黑名单、验证码全部退化单机语义。检查 Redis 地址/密码,确认后可通过 `/api/cache/info` 验证 `mode` 是否恢复为 `redis`。
|
||||
|
||||
### Q:接口返回 `{"code":401}`
|
||||
|
||||
令牌缺失、过期或已被拉黑。重新登录获取新令牌;带 refresh_token 走 `POST /api/oauth2/token` 轮换。注意登录响应字段是 `access_token`(下划线)。
|
||||
|
||||
### Q:接口返回 `{"code":403}`
|
||||
|
||||
权限不足:确认 gmeta `permission` 标签对应节点已在「菜单管理」存在,且已在「角色管理」为当前角色勾选。超管(ROLE_SUPER_ADMIN)不受限。
|
||||
|
||||
### Q:接口返回 `{"code":429}`
|
||||
|
||||
触发限流(默认普通接口 120 次/分钟/IP/路径;登录/验证码/令牌兑换 10 次/分钟/IP)。等待窗口过期或调整 `rateLimit.*` 配置。
|
||||
|
||||
### Q:写操作被拒绝并提示"演示环境,禁止操作!"
|
||||
|
||||
`app.demo: true` 时拦截全部写操作(读操作与公开白名单放行)。本地开发改回 `false` 并重启。
|
||||
|
||||
### Q:验证码图片不显示
|
||||
|
||||
检查 `/api/captcha` 是否 200;字体文件 `resource/static/fonts/Vera.ttf` 缺失会降级 SVG 渲染(仍可用);若被限流(认证入口 10 次/分钟)等待窗口过期。
|
||||
|
||||
### Q:登录报"验证码错误"
|
||||
|
||||
开发环境可在验证码栏直接填配置中的 `captcha.bypassCode`(默认 618618)免校验;生产环境该值应留空。注意验证码为一次性校验(命中即删)。
|
||||
|
||||
## 前端
|
||||
|
||||
### Q:登录成功但刷新页面回到登录页
|
||||
|
||||
确认后端返回的令牌字段读取的是 `data.access_token`;检查浏览器 localStorage 是否被拦截清除;确认系统时间正常(令牌 exp 校验)。
|
||||
|
||||
### Q:页面菜单为空
|
||||
|
||||
菜单按角色权限动态生成。在「角色管理 → 权限」为角色勾选菜单节点;超管返回全量菜单。也可能是 `getUser` 接口 401——检查令牌。
|
||||
|
||||
### Q:接口 404
|
||||
|
||||
本项目全部路由统一 `/api` 前缀且**无 `/v1` 版本段**。`/api/v1/user/page` 形式会 404,正确为 `/api/user/page`。
|
||||
@@ -0,0 +1,99 @@
|
||||
# 2.6 第一个接口调试
|
||||
|
||||
:::tip 概述
|
||||
本节通过三个最基础的接口(健康检查 → 登录 → 带令牌调用业务接口)带你完成第一次接口调试。项目内置 OpenAPI 文档(/api.json)与本地 Redoc 页面(/swagger),可在线查看全部接口并调试。
|
||||
:::
|
||||
|
||||
## 接口调试三步走
|
||||
|
||||
### 第一步:健康检查(免登录)
|
||||
|
||||
```sh
|
||||
curl http://127.0.0.1:8000/api/health
|
||||
```
|
||||
|
||||
```json
|
||||
{"code":0,"ok":true,"msg":"操作成功","data":{"status":"up"}}
|
||||
```
|
||||
|
||||
### 第二步:获取验证码 + 登录
|
||||
|
||||
```sh
|
||||
# 1. 获取图形验证码(公开接口)
|
||||
curl http://127.0.0.1:8000/api/captcha
|
||||
# 返回 {"key":"uuid...","captcha":"data:image/png;base64,..."}
|
||||
|
||||
# 2. 登录(公开接口;开发环境可携带万能验证码 bypassCode 免校验)
|
||||
curl -X POST http://127.0.0.1:8000/api/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"123456","code":"618618","key":"上一步返回的key"}'
|
||||
```
|
||||
|
||||
登录成功返回(**OAuth2 惯例下划线命名**):
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0, "ok": true, "msg": "操作成功",
|
||||
"data": {
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIs…",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIs…",
|
||||
"expires_in": 7200,
|
||||
"token_type": "Bearer"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 第三步:带令牌调用业务接口
|
||||
|
||||
```sh
|
||||
curl http://127.0.0.1:8000/api/user/page?pageNo=1&pageSize=3 \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs…"
|
||||
```
|
||||
|
||||
分页响应(统一信封 + PageData):
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0, "ok": true, "msg": "操作成功",
|
||||
"data": {
|
||||
"records": [ { "id": 1, "username": "admin", … } ],
|
||||
"total": 1, "size": 3, "current": 1, "pages": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 在线文档调试
|
||||
|
||||
浏览器打开:
|
||||
|
||||
| 地址 | 内容 |
|
||||
|------|------|
|
||||
| `http://127.0.0.1:8000/swagger` | 本地托管 Redoc UI(免登录) |
|
||||
| `http://127.0.0.1:8000/api.json` | 原生 OpenAPI JSON(gmeta 补注册生成) |
|
||||
|
||||
gmeta 注解(method/path/summary/permission)会完整体现在文档中,接口与文档天然同步。
|
||||
|
||||
## 响应信封约定
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| `code` | 0=成功;1=通用失败;401=未认证(HTTP 401);403=无权限;429=限流;其余业务码见 [8.2 错误码对照表](../api-spec/error-code) |
|
||||
| `ok` | 布尔,与 code==0 等价 |
|
||||
| `msg` | 提示信息,失败时前端弹出 |
|
||||
| `data` | 业务数据,失败时为空对象 `{}` |
|
||||
|
||||
## 认证方式速记
|
||||
|
||||
```text
|
||||
1. access_token 放 Header:Authorization: Bearer <token>
|
||||
2. access_token 过期(401)→ POST /api/oauth2/token
|
||||
{"grant_type":"refresh_token","refresh_token":"<refresh_token>"}
|
||||
→ 拿到新令牌对(旧 refresh 拉黑防重放)
|
||||
3. 登出:GET /api/logout(当前 jti 拉黑)
|
||||
```
|
||||
|
||||
::: tip 调试技巧
|
||||
+ 开发环境把 `captcha.bypassCode`(默认 618618)作为 code 值可跳过验证码校验。
|
||||
+ 令牌接口返回字段是 `access_token`(下划线),业务接口出入参是驼峰,这是唯一的命名例外。
|
||||
+ 每次登录签发新令牌对,旧 access 仍有效直到过期或被拉黑;强退会双令牌一并拉黑。
|
||||
:::
|
||||
@@ -0,0 +1,74 @@
|
||||
# 2.3 前端服务启动
|
||||
|
||||
:::tip 概述
|
||||
前端为 Vue3 + TypeScript + Vite + Element Plus 工程(`ui/` 目录),通过 pnpm 安装依赖后一条命令启动开发服务器,接口代理指向后端 `:8000`。
|
||||
:::
|
||||
|
||||
## 安装依赖
|
||||
|
||||
```sh
|
||||
cd ui
|
||||
|
||||
# 推荐 pnpm(仓库脚本按 pnpm 编写)
|
||||
pnpm install
|
||||
|
||||
# 国内镜像加速(可选)
|
||||
pnpm config set registry https://registry.npmmirror.com
|
||||
```
|
||||
|
||||
## 启动开发服务器
|
||||
|
||||
```sh
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
启动后终端输出本地地址(默认 Vite 端口),浏览器访问即可看到登录页。
|
||||
|
||||
## 代理与接口地址
|
||||
|
||||
开发环境下 Vite 把 `/api` 代理到后端 `http://127.0.0.1:8000`(见 `ui/vite.config.ts` 的 proxy 配置)。前端 axios baseURL 为 `/api`,模块路径与后端 gmeta path 逐条对齐。
|
||||
|
||||
::: tip URL 约定
|
||||
全部接口统一 `/api` 前缀,**没有 `/v1` 版本段**(`api/v1` 只是 Go 包名)。例如用户分页是 `GET /api/user/page`。公开路由(登录/验证码/令牌兑换/健康检查)同样不带版本段。
|
||||
:::
|
||||
|
||||
## 构建生产包
|
||||
|
||||
```sh
|
||||
pnpm build # production 模式构建
|
||||
pnpm build:prod # 显式 production
|
||||
pnpm build:uat # uat 环境
|
||||
pnpm build:test # test 环境
|
||||
pnpm build:dev # dev 环境
|
||||
```
|
||||
|
||||
构建产物经 `build/script/postBuild.ts` 后处理,输出 `dist/`,交给 Nginx 等静态服务器托管(部署见 [11.5 前端部署](../deploy/frontend))。
|
||||
|
||||
## 常用脚本
|
||||
|
||||
| 命令 | 说明 |
|
||||
|------|------|
|
||||
| `pnpm dev` | 启动开发服务器 |
|
||||
| `pnpm build` | 生产构建 |
|
||||
| `pnpm type:check` | vue-tsc 类型检查 |
|
||||
| `pnpm lint:eslint` | ESLint 修复 |
|
||||
| `pnpm lint:prettier` | Prettier 格式化 |
|
||||
| `pnpm lint:stylelint` | Stylelint 样式检查 |
|
||||
| `pnpm preview` | 构建并本地预览 |
|
||||
|
||||
## 本地测试账号
|
||||
|
||||
| 账号 | 密码 | 角色 |
|
||||
|------|------|------|
|
||||
| admin | 123456 | 超管(ROLE_SUPER_ADMIN,通配权限 `*:*:*`) |
|
||||
|
||||
::: warning 演示模式
|
||||
若 `config.yaml` 中 `app.demo: true`,所有写操作会被拦截并提示"演示环境,禁止操作!"。本地开发请保持 `app.demo: false`。
|
||||
:::
|
||||
|
||||
## 前端启动失败排查
|
||||
|
||||
+ **依赖安装失败**:切换 pnpm 镜像源;Node 版本低于 18 升级后再装
|
||||
+ **接口 404/跨域**:确认后端已在 `:8000` 启动;开发代理仅在 `pnpm dev` 生效
|
||||
+ **登录页验证码不显示**:后端未启动或 `/api/captcha` 被限流(认证入口默认 10 次/分钟/IP)
|
||||
+ **页面白屏**:浏览器控制台看路由守卫报错;确认已登录或访问常量路由 `/login`
|
||||
Reference in New Issue
Block a user