4.11 扩展性设计
概述
扩展性来自两方面:一是标准变更的操作清单(按变更类型给出 checklist,不漏步骤、不变异架构);二是逃生舱挂点(基座装不下的需求有明确的合法出口)。本节按变更类型组织。
变更类型 Checklist
1. 给现有模块新增一个接口
text
□ api/v1/{模块}.go:新增 {Mod}{Action}Req(内嵌 gmeta.Meta,path 带 /api 前缀、
permission、log、logType)+ {Mod}{Action}Res
□ controller:同名方法,签名 func (c *CXxx) Action(ctx, req) (res, err)
□ service/{模块}.go:接口追加方法声明(手维护)
□ logic:实现方法(基座可表达走 spec 钩子,复杂走手写)
□ 权限节点同步:若 permission 为新码,需在菜单管理为角色勾选
(或插入 goframe_menu type=1 节点)
□ go build ./... && gofmt;重启;/api.json 核对新条目2. 给现有模块加字段
text
□ MySQL ALTER(列注释按枚举规范写"字段:1-x 2-y";需要唯一性则补 uk_*)
□ gf gen dao -c hack/config.yaml(刷新 entity/do/dao internal;service 不动)
□ api/v1:Req/Res/Item 结构体补字段(json 驼峰 + dc 注释)
□ logic:ToData 补键;枚举补 SerializeMaps(字典编码 {模块}_{字段});
文件字段补 FileFields+FileSaveDir;富文本补 ContentFields
□ 前端:columns.ts / querySchemas.ts / edit.vue 同步
□ document/ 五方言脚本同步;必要时附录表清单更新
□ go build → 重启 → page/detail 黄金样本更新3. 新增模块
text
□ 设计表(统一审计列 + del_flag + uk_* + 注释枚举)→ DDL 落库
□ 租户级?→ hooks.tenantTables 登记
□ go run ./cmd/generator -tables "goframe_x|中文名"(或手动四件套)
□ logic 调整:spec 声明(筛选/树形/字典/文件/唯一 Group)、扩展接口
□ service 接口核对;router.go 注册行确认
□ go build ./... → 重启 → 角色勾选新权限节点4. 新增中间件
text
□ internal/middleware/{name}.go:func(r *ghttp.Request),职责单一;
读配置用 cfgBool/cfgInt;客户端 IP 用 realClientIP;响应用 utility/response
□ 不得 import 业务包——需要业务数据时在 wire.go 增加 Loader 函数变量,
由 logic init 注册(参照 IdentityLoader 模式)
□ router.Register 的 s.Use 链按序插入(顺序即语义,评审明确插入点)
□ public 路径行为:确认对 IsPublicPath 的放行策略5. 新增定时任务
text
□ internal/task/{task_name}.go + init RegisterJobHandler("TaskName", h)
□ handler 签名 (ctx, params) (string, error);长任务分批+上限;禁 HTTP 于事务内
□ 任务表配置:url="TaskName"、params JSON、cron(6 段或 # 5 段)、
execute_policy/is_sync;发布(status=1)
□ 验证:daemonStatus 挂载 + runOnce + job/log 成功记录
□ go build 重启(init 注册发生在进程加载期)6. 自定义 / 扩展 dao
text
□ dao/{m}.go 尾部"Add your custom methods"区追加方法(统计/联查等)
□ 修改模板本身:改 hack/tpl/dao_index.tpl 后 gf gen dao 重新生成
(overwriteDao:false 保留手工扩展;新旧模板产物差异需人工合并)
□ 红线:自定义方法也必须以 Ctx(ctx) 为查询入口;禁止在 dao 内做业务判断7. 配置变更
text
□ manifest/config/config.yaml 修改
□ 多环境差异用 GF_ 环境变量覆盖,不改文件
□ 新增配置键:注释说明 + 代码 cfgBool/cfgInt 带默认值读取(缺失不 panic)
□ 影响限流/日志/上传/调度的键变更后跑对应回归逃生舱与扩展挂点
| 挂点 | 场景 | 说明 |
|---|---|---|
| BodyUnmarshaler | 请求体形态不规则(平铺 map 等) | Req 实现 UnmarshalBody(r) 跳过默认 Parse(自行做 gvalid) |
| ModuleSpec.Filter | 复杂查询条件 | 不与 Like/Eq 重复声明 |
| ModuleSpec.DataScope | 数据权限挂点 | 共享工厂 ApplyDataScope(col),声明即生效 |
| ModuleSpec 钩子装不下 | 基座禁止按模块分支 | 整个方法手写(合法逃生舱,如 job.Detail 因嵌入结构手写) |
| logic 包级共享函数 | 跨模块复用 | 放具体模块文件顶部(同包可见);横切能力进 base.go(15 导出上限) |
| RegisterJobHandler | 本地任务处理器 | 全局注册表(重名 panic) |
| middleware wire | 业务与中间件解耦 | 三 Loader/Sink 函数变量 |
未启用项与前端遗留
| 项 | 现状 | 启用/处理要点 |
|---|---|---|
| 用户注册 | publicPaths 含 /api/register(路由未注册) | 启用时补建表逻辑 + 开放策略 + 租户归属规则 |
| 数据范围自定义档 | 现四档纯列值(role.data_scope) | 第 5 档需部门关联表 + 角色表单部门树多选 |
| 导出增强 | 当前导出返回临时文件 URL | 可加流式下载/异步导出 |
| SendSms 任务 | task/send_sms.go 仅记日志 | 接短信通道时替换实现 |
| 站内信/数据源/短信/OSS/WebSocket | 前端遗留死代码(后端桩已删除) | 不再调用即无影响 |
封板后的变更纪律
text
1) 一切接口行为以 API 接口清单 + /api.json 为准,改动即更新文档
2) 表结构改动三同步:document/mysql/ 定稿 → 其余四方言脚本 → 迁移(跨环境时)
3) 破坏性变更(改名/删字段/改枚举值)必须走版本化说明 + 前端同步 +
黄金样本更新,禁止静默变更
4) 架构红线复查:绕过 dao / 手写租户条件 / 反向依赖 task / 超 15 导出的 base /
未登记 tenantTables——任何一项都应打回