# goframe_admin **Repository Path**: rongfei_me/goframe_admin ## Basic Information - **Project Name**: goframe_admin - **Description**: 基于 GoFrame v2 重构的站点项目:主域名提供博客前台,`/backend` 提供 Layui + Pear Admin 管理后台。 - **Primary Language**: Go - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-21 - **Last Updated**: 2026-10-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: Go语言, layui, CMS, GoFrame ## README # GoFrame 博客站与后台管理系统 基于 **GoFrame v2** 重构的站点项目:主域名提供博客前台,`/backend` 提供 Layui + Pear Admin 管理后台。 --- ## 1. 技术栈 | 分类 | 选型 | | --- | --- | | 语言 / 框架 | Go 1.26+ / GoFrame v2.10.3 | | 数据库 | MySQL 5.7+ / 8.0(驱动 `gf/contrib/drivers/mysql/v2`) | | 后台 UI | Layui + Pear Admin 壳(多标签页 + iframe) | | 鉴权 | JWT HS256(access + refresh),HttpOnly Cookie 存储 | | 验证码 | `mojocn/base64Captcha`(4 位数字) | | 密码哈希 | bcrypt,兼容 PHP `password_hash` 的 `$2y$` 前缀 | | 前台 | Go `html/template` + 原生 CSS/JS(无第三方前端框架) | --- ## 2. 功能概览 ### 2.1 博客前台(免登录) | 页面 | 地址 | 说明 | | --- | --- | --- | | 首页 | `/`(兼容 `/blog`) | 轮播图、文章列表、加载更多、侧边栏(最新/热门/分类) | | 分类页 | `/classify_{cid}.html`、`/classify_{cid}_{page}.html` | 分类文章列表 + 分页 | | 搜索页 | `/search.html?k=关键词&pages=N` | 标题模糊搜索 + 分页 | | 详情页 | `/detail/{id}.html` | 正文、浏览量自增、相关文章;不存在返回 404 页面 | | 404 | — | 统一错误页 | 前台 JSON 接口(`{code,msg,data}` 结构,供 uniapp 等端复用): | 接口 | 参数 | 说明 | | --- | --- | --- | | `GET /app/blogs/banners` | — | 轮播图列表 | | `GET /app/blogs/articles` | `cid`、`k`、`page`/`pages` | 文章分页(`data.data/current_page/last_page/total/per_page`) | | `GET /app/blogs/details` | `id` | 文章详情 | | `GET /app/blogs/classifys` | — | 有图分类列表 | 前台页面 URL 保持旧站伪静态形态,便于 SEO 与旧链接延续。 ### 2.2 管理后台(`/backend`) | 模块 | 地址前缀 | 功能 | | --- | --- | --- | | 仪表盘 | `/backend/main` | 数据概览、模块统计图表、快捷入口、系统信息 | | 菜单与权限 | `/backend/menu` | 菜单树 CRUD、按钮权限同步(`syncRules`)、权限规则树 | | 账户管理 | `/backend/admin` | 管理员 CRUD、角色分配、状态开关 | | 角色管理 | `/backend/role` | 角色 CRUD、父级角色、权限勾选树 | | 博客管理 | `/backend/blogs/article`、`/banner`、`/classify` | 文章 / 轮播图 / 文章分类 CRUD | | 数据库 | `/backend/table` | 表列表、表结构、数据浏览、建表/清空/删表(写操作仅超管) | | 通用设置 | `/backend/config`、`/dict`、`/attachment`、`/area` | 系统设置、数据字典、附件管理、省市区管理 | | 个人资料 | `/backend/profile` | 昵称/头像/邮箱/手机、修改密码 | | 开发辅助 | `/backend/dev/form-build` | Pear 可视化表单构建器 | | 占位页 | `/backend/coming/index` | 未迁移菜单的统一提示页 | 主要能力: - **多标签页后台**:Pear Admin 壳,标签会话持久化到 `sessionStorage`; - **通用 CRUD 引擎**:模块配置驱动,7 个标准动作(列表/数据/编辑/新增/修改/删除/状态); - **按钮级权限**:路由自动生成 `模块.动作` 权限码,后端逐请求校验;`/backend/menu/permission` 输出当前账号的权限码,供前端按需控制按钮; - **上传组件**:单图、头像、多图、附件、富文本图片,白名单校验 + 大小限制 + `gf_uploads` 登记; - **一键权限同步**:根据已注册路由增量生成/更新按钮权限; - **数据权限**:模块可配置为「不限制 / 仅本人」,按 `admin_id` 过滤。 --- ## 3. 目录结构 ```text goframe/ ├── main.go # 入口:引入 boot 与 router 后启动 Server ├── boot/ # 启动装配:加载 .env、初始化 DB(gdb)、视图与组件函数 ├── router/ │ ├── router.go # 全局中间件 + 后台 /backend 路由 + 探针 │ └── blog.go # 博客前台页面与 JSON 接口路由 ├── app/ │ ├── backend/ # 后台应用 │ │ ├── controller/ # 控制器:解析请求 → 调用 service → 写响应 │ │ ├── service/ # 业务服务(CRUD 引擎、菜单权限、上传、数据库、地区等) │ │ ├── dto/ # 请求入参对象 │ │ ├── vo/ # 响应/视图对象 │ │ └── widget/ # 模板组件函数(query/add/edit/switch/upload/editor…) │ ├── blog/ # 博客前台应用 │ │ ├── controller/ # 首页/分类/搜索/详情/JSON 接口 │ │ ├── service/ # 文章、分类、轮播、分页、SEO 服务 │ │ └── vo/ # 视图对象 │ ├── constant/ # 响应码、上下文键、令牌与 Cookie 常量 │ ├── dao/ # 表名常量、模型工厂、常用查询、表元信息 │ ├── middleware/ # CORS、安全头、输入清洗、异常恢复、兜底响应、登录鉴权 │ ├── model/entity/ # 数据表实体 │ └── utils/ # JWT/密码、媒体地址归一化、响应封装、模板渲染等 ├── config/ │ ├── config.toml # 服务、日志、视图、gf-cli、应用配置 │ └── config.example.toml # 配置模板 ├── public/ # 静态资源根(serverRoot) │ ├── resource/ # layui、pear、css、js、image、editor、blog 主题 │ └── uploads/ # 上传目录(含迁移的 legacy 资源) ├── template/ │ ├── backend/ # 后台模板(layout / index / login / main / 各模块页) │ └── blog/ # 前台模板(layout / index / classify / detail / 404) ├── install/ # 独立 Web 安装向导(四步向导 + 初始化 SQL) ├── document/ # 开发辅助(gf-cli、Makefile、部署样例) ├── library/ # 随项目分发的第三方库 └── runtime/ # 运行日志(git 忽略) ``` **多应用约定**:一个应用 = `app//`(controller/service/vo) + `template//` + `router/.go`。后台与前台业务服务完全隔离,互不引用。 --- ## 4. 快速开始 > 推荐使用内置安装向导完成首次部署(自动建表、导入基线数据、创建管理员并生成 `.env`),详见 [4.6 使用安装向导](#46-使用安装向导推荐)。手工部署可按 4.1–4.5 操作。 ### 4.1 环境要求 - Go 1.26 及以上 - MySQL 5.7 / 8.0 - 可写目录:`public/uploads/`、`runtime/` ### 4.2 配置环境变量 > 使用安装向导时本步骤可跳过,向导会自动生成 `.env`。 复制 `.env.example` 为 `.env` 并填写真实值(`.env` 已在 `.gitignore` 中): ```dotenv APP_ENV=local SERVER_ADDRESS=:9100 DB_TYPE=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_NAME=goframe DB_USER=your_user DB_PASSWORD=your_password DB_PREFIX= DB_DEBUG=false JWT_SECRET=至少16位的随机字符串 JWT_ACCESS_EXPIRE=900 JWT_REFRESH_EXPIRE=604800 JWT_ISSUER=goframe-admin LOGIN_FAIL_LIMIT=5 LOGIN_FAIL_WINDOW=300 LOGIN_CAPTCHA_ENABLED=true CORS_ALLOW_ORIGINS= ``` > 启动时缺少 `DB_HOST` / `DB_NAME` / `DB_USER` / `DB_PASSWORD` / `JWT_SECRET` 会直接 panic(快速失败)。`JWT_SECRET` 少于 16 字符同样拒绝启动。 ### 4.3 数据库 > 使用安装向导时只需准备一个空数据库(或授予 CREATE 权限由向导自动建库),表结构与初始化数据由向导导入。 需存在以下表: | 表 | 用途 | | --- | --- | | `gf_admins` / `gf_admin_roles` / `gf_roles` | 管理员、管理员-角色、角色(`rules` 逗号分隔规则 ID,`*` 为超管) | | `gf_rules` | 菜单与按钮权限(`type`:0 目录 / 1 菜单 / 2 按钮) | | `gf_options` | 键值配置(`system_config` 存站点与主框架配置) | | `gf_uploads` | 附件登记 | | `gf_area` | 省市区(约 4.6 万行) | | `blogs_articles` / `blogs_banners` / `blogs_classifys` | 博客文章 / 轮播图 / 分类 | 状态字段约定:`status = 0` 表示正常/启用。 ### 4.4 编译与运行 ```bash # Windows go build -o gf-admin-server.exe . .\gf-admin-server.exe # Linux CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o gf-admin . ./gf-admin ``` 常用命令: ```bash go build ./... # 编译检查 go vet ./... # 静态检查 ``` ### 4.5 访问地址 | 地址 | 说明 | | --- | --- | | `http://127.0.0.1:9100/` | 博客前台首页 | | `http://127.0.0.1:9100/backend` | 管理后台(未登录跳转 `/backend/login`) | | `http://127.0.0.1:9100/health` | 存活探针 | | `http://127.0.0.1:9100/ready` | 就绪探针(含数据库连通性) | ### 4.6 使用安装向导(推荐) `install/` 下是一套独立的 Go Web 安装程序,不加载主程序的 `boot` / `router`,因此无需预先准备 `.env` 或数据库表。安装程序内嵌模板、样式与初始化 SQL,可单文件分发。 #### 4.6.1 向导能力 - **四步向导**:环境检测 → 数据库配置 → 站点与管理员 → 安装完成; - **仅空库安装**:检测到目标库已有表立即中止,不会执行任何删除; - **自动初始化**:表结构、基线数据(当前为 92 条权限规则、2 个角色、站点配置、约 4.6 万条地区数据); - **可选演示内容**:文章、轮播图、文章分类; - **创建管理员**:bcrypt 密码哈希,自动绑定「超级管理员」角色; - **生成 `.env`**:随机 JWT 密钥;已有 `.env` 会备份为 `.env.bak.时间戳`; - **安装锁**:完成后写入 `install.lock`,向导无法再次运行; - **安全防护**:默认仅监听 `127.0.0.1`,禁止页面被 iframe 嵌入,校验 POST 的 `Origin` 防跨站提交。 #### 4.6.2 目录说明 | 路径 | 说明 | | --- | --- | | `install/main.go` | 程序入口:参数解析、项目根目录探测、安装锁检查 | | `install/web.go` | 四步向导的 HTTP 处理与页面渲染 | | `install/installer.go` | 写 `.env`、导入 SQL、创建管理员、更新站点配置、写安装锁 | | `install/db.go` | 数据库连接、空库检测、自动建库 | | `install/checks.go` | 环境检测(目录、模板、静态资源、写权限、端口) | | `install/templates/` | 向导页面(layout / step1–3 / done) | | `install/static/install.css` | 向导样式(无外部依赖) | | `install/sql/schema.sql` | 10 张表结构 | | `install/sql/baseline.sql` | 权限规则、角色、站点配置、地区数据 | | `install/sql/demo.sql` | 演示文章、轮播图、文章分类 | | `install/build.bat` / `start.bat` | Windows 构建与启动脚本 | | `install/build.sh` / `start.sh` | Linux 构建与启动脚本 | #### 4.6.3 构建与启动 Windows(在 `install` 目录双击或执行): ```bat build.bat :: 仅编译 start.bat :: 未编译时自动编译并启动 ``` Linux: ```bash cd install bash build.sh bash start.sh ``` 也可以直接从项目根目录构建: ```bash # Windows go build -trimpath -o install/gf-install.exe ./install # Linux go build -trimpath -o install/gf-install ./install ``` 启动参数: | 参数 | 默认值 | 说明 | | --- | --- | --- | | `-addr` | `127.0.0.1:9101` | 向导监听地址;服务器远程安装可临时改为 `0.0.0.0:9101` | | `-root` | 自动探测 | 项目根目录,需包含 `template/` 与 `public/`;自动探测失败时使用 | 启动后在浏览器打开 `http://127.0.0.1:9101/`。 #### 4.6.4 安装流程 1. **环境检测**:检查前后台模板、静态资源、项目根目录/`public/uploads`/`runtime` 写权限,并提示 9100 端口占用情况; 2. **数据库配置**:填写主机、端口、库名、账号密码;可选择「数据库不存在时自动创建」;通过后校验目标库为空; 3. **站点与管理员**:设置站点名称、运行环境、监听地址、管理员账号密码,决定是否导入演示内容; 4. **安装完成**:展示前台与后台地址,提示删除 `install` 目录或保留 `install.lock`。 安装完成后启动主程序: ```bash # Windows .\gf-admin-server.exe # Linux ./gf-admin ``` #### 4.6.5 注意事项 - **数据库密码必填**:主程序启动时 `DB_PASSWORD` 为必需项,空密码无法通过安装向导; - **空库限制**:若安装中断导致库中残留表,需先删除该库再重新安装; - **重新安装**:删除项目根目录的 `install.lock`,并使用新的空数据库(或删除原库后重建); - **运行环境**:`production` 会启用 Secure Cookie,必须通过 HTTPS 访问;HTTP 环境请选择 `local`; - **演示图片**:演示文章引用 `public/uploads/legacy` 下的存量图片,分发时需一并携带该目录; - **安装完成后**:请立即删除 `install` 目录,避免安装入口暴露在服务器上。 --- ## 5. 路由总览 ### 5.1 中间件链 按注册顺序执行: `CORS` → `SecurityHeaders` → `SanitizeInput` → `Recover` → `Response` → `CheckLogin` - **CORS**:来源白名单来自 `CORS_ALLOW_ORIGINS`;生产未配置时不下发跨域头; - **SecurityHeaders**:`X-Content-Type-Options`、`X-Frame-Options: SAMEORIGIN`、`Referrer-Policy`; - **SanitizeInput**:将查询串与表单体中的裸分号转义为 `%3B`,规避 Go `net/url` 解析异常; - **Recover**:捕获 panic,返回统一 500 JSON,不泄露堆栈; - **Response**:处理器未输出内容时兜底,避免空响应; - **CheckLogin**:仅对 `/backend` 路径生效,前台与静态资源直接放行。 ### 5.2 后台路由(前缀 `/backend`) | 分组 | 路由 | | --- | --- | | 主框架 | `GET /`、`/index`、`/main`、`/coming/index`、`GET/POST /login`、`GET /captcha`、`POST /refresh`、`ALL /userInfo`、`POST /updatePwd`、`GET /logout`、`/health`、`/ready` | | 菜单权限 | `/menu/info`、`/permission`、`/index`、`/list`、`/edit`、`/add`、`/update`、`/delete`、`/select`、`/syncRules` | | 开发辅助 | `/dev/form-build` | | 数据库 | `/table/index`、`/list`、`/schema`、`/data`、`/dataList`、`/create`、`/store`、`/truncate`、`/drop` | | 上传 | `/upload/image`、`/avatar`、`/album`、`/file`、`/richText` | | 字典 | `/dict/index`、`/list`、`/edit`、`/add`、`/update`、`/delete`、`/get/{name}` | | 系统设置 | `/config/index`、`/get`、`/save`、`/pear`、`/site` | | 个人资料 | `/profile/index`、`/update`、`/password` | | 附件 | `/attachment/index`、`/list`、`/add`、`/delete` | | 地区 | `/area/index`、`/list`、`/children`、`/options`、`/path`、`/edit`、`/add`、`/update`、`/delete` | | 角色 | `/role/index`、`/list`、`/edit`、`/add`、`/update`、`/delete`、`/options`、`/parentOptions`、`/ruleTree` | | 账户 | `/admin/index`、`/list`、`/edit`、`/add`、`/update`、`/delete`、`/setStatus`、`/role` | | 博客 | `/blogs/article/*`、`/blogs/banner/*`、`/blogs/classify/*`(含 `/classify/options`) | > `/backend` 不带尾斜杠时由独立绑定进入后台主框架。 --- ## 6. 鉴权与权限设计 ### 6.1 登录与令牌 1. `POST /backend/login` 校验「验证码 → 登录失败限流 → 账号密码 → 状态」; 2. 签发 access + refresh 令牌,写入 **HttpOnly Cookie**(`access_token` / `refresh_token`),不落 localStorage; 3. 令牌也可通过 `Authorization: Bearer ` 或 `X-Auth-Token` 请求头传递(便于接口调试); 4. 访问令牌过期后可调用 `POST /backend/refresh` 续签。 access 默认有效期 `JWT_ACCESS_EXPIRE`(900 秒),refresh 默认 `JWT_REFRESH_EXPIRE`(604800 秒)。 ### 6.2 路由白名单 - **免登录**:`/login`、`/captcha`、`/refresh`、`/health`、`/ready`、`/config/site`、`/dict/get/*` - **登录即可**(不校验具体权限):`/userInfo`、`/logout`、`/menu/info`、`/menu/permission`、`/menu/select`、`/config/pear`、`/role/options`、`/role/parentOptions`、`/role/ruleTree`、`/area/options`、`/area/children`、`/blogs/classify/options`、`/upload/*` 鉴权层比对前会先去掉 `/backend` 前缀(`NormalizeAdminURI`),因此白名单与权限码始终按 `/role/add` 这类原始路径维护。 ### 6.3 权限码 - 权限码 = 路由去掉 `/backend` 后的路径,将 `/` 替换为 `.`:`/backend/role/add` → `role.add`; - 按钮权限存于 `gf_rules`(`type=2`),角色 `rules` 存放规则 ID 列表,`*` 表示超级管理员; - `.index` 动作具备「任一子权限即放行」的语义; - 权限拦截发生在服务端,未授权的接口统一返回 `403`;前端可读取 `/backend/menu/permission` 的权限码自行决定按钮显隐; - `POST /backend/menu/syncRules` 可按当前已注册路由增量生成按钮权限。 ### 6.4 安全约束 - 所有 SQL 使用参数绑定,模块搜索字段来自配置白名单; - 表名白名单 `^[a-zA-Z0-9_]{1,64}$`,拒绝系统库;核心表禁止 DROP/TRUNCATE; - 上传扩展名白名单,图片 5MB、附件 20MB 上限; - DDL / TRUNCATE / DROP 需超级管理员(权限码 + 二次校验); - 非业务错误统一记录日志,客户端只看到规范化提示。 --- ## 7. 统一响应格式 接口统一返回: ```json { "code": 0, "msg": "操作成功", "data": null, "count": 0 } ``` | code | 含义 | | --- | --- | | `0` | 成功 | | `-1` | 通用业务错误 | | `401` | 未登录 / 令牌失效 | | `403` | 无权限 | | `500` | 服务器内部错误 | 例外: - `GET /backend/config/pear` 返回 Pear Admin 主框架裸配置对象; - 前台返回结构 `{code, msg, data}`; - 页面请求(`Accept: text/html`)鉴权失败时 302 到 `/backend/login`,接口请求返回 401 JSON。 --- ## 8. 模板与组件 ### 8.1 视图 - 模板根目录 `template/`,默认文件 `index.html`,分隔符 `{{ }}`; - 后台页面统一走 `backend/public/layout.html`(列表页)或 `backend/public/form.html`(表单页); - 前台统一走 `blog/public/layout.html`,通过 `mainTpl` 参数切换主体模板; - GoFrame 视图默认不自动转义,用户文本在控制器中显式 `HTMLEscapeString`。 ### 8.2 组件函数 `boot` 将 `app/backend/widget` 的函数注册到视图,模板中可直接使用: | 函数 | 用途 | | --- | --- | | `query` / `add` / `dall` | 查询、添加、批量删除按钮 | | `edit` / `delete` | 表格行内编辑、删除按钮 | | `submit` | 表单提交按钮 | | `switch` | 状态开关 | | `uploadImage` / `album` | 单图 / 多图上传组件 | | `editor` | 富文本编辑器 | | `controlName` | 按字段类型推荐表单控件(一键菜单预览) | --- ## 9. 扩展开发 ### 9.1 新增一个后台模块 1. 在 `app/backend/service/modules.go` 注册模块元信息: ```go RegisterModule(&Module{ Key: "notice", Table: "gf_notices", Title: "公告", TplDir: "backend/notice", // 模板目录,缺省等于 Key SearchLike: []string{"title"}, StatusField: "status", OrderBy: "id desc", }) ``` 2. 新建控制器并嵌入通用 CRUD: ```go type noticeCtl struct{ *crudCtl } var Notice = ¬iceCtl{crudCtl: newCrudCtl("notice")} ``` 3. 在 `router/router.go` 的 `/backend` 组内注册路由,并把路径加入 `service.RegisterRoutes(...)`; 4. 在 `template/backend/notice/` 下提供 `index.html`、`edit.html`; 5. 在「菜单管理」新增菜单并设置权限,或执行按钮权限同步。 ### 9.2 新增一个应用 参照 `app/blog`:新建 `app//{controller,service,vo}`、`template//`、`router/.go`,在 `router` 的 `init` 中注册路由。非后台路径不会进入 `CheckLogin`。 --- ## 10. 部署说明 - 二进制为单文件部署,运行时需同时具备 `config/`、`template/`、`public/` 目录; - 静态资源由 Go 服务直接提供(`serverRoot = public`),生产建议前置 Nginx 做 HTTPS 与缓存; - 反向代理需保留真实 Host 与 `X-Forwarded-*` 头; - 确保进程对 `public/uploads/`、`runtime/` 有写权限; - 生产环境设置 `APP_ENV=production`(Cookie 将启用 `Secure`),并显式配置 `CORS_ALLOW_ORIGINS`; - `runtime/`、`.env`、`config/config.toml`、`public/uploads/*` 已在 `.gitignore` 中,不应入库。 --- ## 11. 维护与兼容说明 - **媒体地址归一化**:存量数据中的 `/app/admin/upload/...` 会在读取时自动映射为 `/uploads/legacy/...`(图片字段与富文本正文均生效),无需批量 UPDATE; - **菜单地址归一化**:数据库中的 `href` 已迁移为 `/backend/...`;`/app/**` 等未迁移地址自动落到占位页; - **标签页会话迁移**:`public/resource/js/admin.js` 会在渲染前把 `sessionStorage` 中遗留的旧路径补全 `/backend` 前缀,避免升级后内容区空白; - **示例页面已移除**:原 Pear 示例菜单、`public/demos` 静态页及相关权限已清理; - **状态约定**:`status = 0` 为正常,前端开关与查询条件均按此约定。 --- ## 12. 相关文档 - `document/README.md`:开发辅助目录说明 - `public/README.md`:静态资源与上传目录约定 - `library/README.md`:第三方库放置说明 - `app/backend/widget/README.md`:组件层说明