# 系统参数(SysParams)使用规范 ## 适用范围 - 需要读取或写入 `sys_params` 表中的系统参数时,使用本文。 - 需要给某一个固定参数提供独立业务 API,但底层仍保存到 `sys_params` 时,使用本文。 ## 现有落点 - 表结构:`model/system/sys_params.go` - Service:`service/system/sys_params.go` - API:`api/v1/system/sys_params.go` - Router:`router/system/sys_params.go` ## 现有接口 - 实际完整路径 = `/sysParams/...`。 - 如果环境把 `router-prefix` 配成 `/api`,则完整路径就是 `/api/sysParams/...`。 - 当前仓库 `config.yaml` 中 `router-prefix` 默认值为空字符串;不要把 `/api` 写死为项目事实。 - 这组路由在 `initialize/router.go` 中挂到 `PrivateGroup`,默认需要鉴权。 - `GET /sysParams/getSysParam?key=xxx`:按 `key` 读取单条参数。 - `GET /sysParams/getSysParamsList`:分页读取参数列表。 - `POST /sysParams/createSysParams`:创建参数。 - `PUT /sysParams/updateSysParams`:按 `ID` 更新参数。 - `DELETE /sysParams/deleteSysParams`:按 `ID` 删除参数。 - 结论:这组接口适合“通用参数管理页”,不适合业务围绕某一个固定参数直接做长期读写。 ## 强制规则 - 后端代码禁止通过 HTTP 反调自己的 `/sysParams` 接口;统一在 `Service` 层直接调用 `service.ServiceGroupApp.SystemServiceGroup.SysParamsService`。 - `API` 层禁止直接操作 `global.GVA_DB`。 - `Value` 是字符串存储;简单值可直接存字符串,结构化配置必须由业务 `Service` 负责 `json.Marshal` / `json.Unmarshal`。 - 不要把 `sys_params` 的 `ID` 暴露给前端,作为某个固定配置的长期主键。 - 固定配置统一按 `key` 识别;`key` 必须稳定、唯一、可读,建议使用 `.`,例如 `device.runtimeConfig`。 - 参数不存在时必须显式处理:返回业务错误、初始化默认值、或创建后再返回;禁止静默吞掉。 - 通用参数管理页面可以直接调用 `/sysParams`;具体业务页面优先调用该业务自己的独立 API。 - 参数属于某个业务模块时,落点放到该业务模块;只有平台级通用参数才继续放在 `system` 模块。 ## 代码内直接读取 - 读取动作统一放在 `service/`。 - 调用入口: ```go param, err := service.ServiceGroupApp.SystemServiceGroup.SysParamsService.GetSysParam("device.runtimeConfig") ``` - `param.Value` 就是最终存储值。 - 如果 `Value` 存的是 JSON,必须先反序列化为业务结构体,再继续使用。 ```go package device import ( "encoding/json" "github.com/flipped-aurora/gin-vue-admin/server/service" ) type RuntimeConfig struct { Enable bool `json:"enable"` Mode string `json:"mode"` } func (s *DeviceService) GetRuntimeConfig() (RuntimeConfig, error) { param, err := service.ServiceGroupApp.SystemServiceGroup.SysParamsService.GetSysParam("device.runtimeConfig") if err != nil { return RuntimeConfig{}, err } var cfg RuntimeConfig if err = json.Unmarshal([]byte(param.Value), &cfg); err != nil { return RuntimeConfig{}, err } return cfg, nil } ``` ## 代码内直接写入 - 当前 `SysParamsService` 没有“按 `key` 直接写入”的现成能力。 - 现在只有 `CreateSysParams`、`UpdateSysParams`、`GetSysParam`。 - 这意味着:业务写入固定参数时,必须先按 `key` 查询,再决定 `create` 还是 `update`。 - 这段逻辑必须收口到业务 `Service`,不要放在 `API`,也不要交给前端拼 `ID`。 ```go package device import ( "encoding/json" "errors" "github.com/flipped-aurora/gin-vue-admin/server/model/system" "github.com/flipped-aurora/gin-vue-admin/server/service" "gorm.io/gorm" ) const runtimeConfigKey = "device.runtimeConfig" func (s *DeviceService) SaveRuntimeConfig(cfg RuntimeConfig) error { valueBytes, err := json.Marshal(cfg) if err != nil { return err } sysParamsSvc := service.ServiceGroupApp.SystemServiceGroup.SysParamsService param, err := sysParamsSvc.GetSysParam(runtimeConfigKey) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return sysParamsSvc.CreateSysParams(&system.SysParams{ Name: "设备运行配置", Key: runtimeConfigKey, Value: string(valueBytes), Desc: "device 模块运行配置", }) } return err } param.Value = string(valueBytes) param.Name = "设备运行配置" param.Desc = "device 模块运行配置" return sysParamsSvc.UpdateSysParams(param) } ``` ## 什么时候必须写独立 API - 前端只关心某一个固定参数,不应该先查列表、拿 `ID`、再更新时。 - 参数值是 JSON,需要强类型请求体和响应体时。 - 这个参数有明确业务语义,例如“设备运行配置”“首页配置”“第三方回调配置”时。 - 该参数需要单独做权限控制、默认值处理、字段校验、审计说明时。 ## 独立 API 规范 - 独立 API 仍按 `Router → API → Service → GORM → Database` 分层实现。 - 底层存储仍使用 `sys_params`;不要因为一个配置项就单独建表,除非它已经演变成独立业务实体。 - 对外接口暴露业务语义,不暴露 `sys_params` 的 `ID`、通用 CRUD 细节。 - `Service` 负责固定 `key`、处理 JSON 转换、决定 create/update、处理不存在时的策略。 - 参数属于业务模块时,文件落点统一为 `model//request`、`model//response`、`service/`、`api/v1/`、`router/`。 - 新增业务路由统一注册到 `initialize/router_biz.go`。 ## 推荐落地方式 - 对外提供两个独立接口即可:一个“获取配置”,一个“保存配置”。 - 接口名使用业务语义,不使用 `sysParams` 命名。 - 示例接口:`GET /deviceConfig/getRuntimeConfig`、`PUT /deviceConfig/updateRuntimeConfig`。 - `GET` 接口返回业务结构体。 - `PUT` 接口接收业务结构体。 - 底层统一在 `service/device` 中转成 `sys_params.value` 的 JSON 字符串。 ## 禁止事项 - 禁止在业务代码里直接写 SQL 操作 `sys_params`,绕开现有 `Service` 分层。 - 禁止在业务 `API` 中直接处理 `sys_params` 的 `ID`。 - 禁止让前端把一个固定配置当成“参数管理列表中的某一行”去长期维护。 - 禁止把结构化 JSON 配置直接裸透传为字符串给业务页面,除非该页面本身就是通用参数管理页。