369 lines
16 KiB
Markdown
369 lines
16 KiB
Markdown
# 系统配置模型
|
||
|
||
<cite>
|
||
**本文引用的文件**
|
||
- [internal/model/system_config.go](file://internal/model/system_config.go)
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go)
|
||
- [internal/repository/system_config_repository_test.go](file://internal/repository/system_config_repository_test.go)
|
||
- [internal/types/common.go](file://internal/types/common.go)
|
||
- [pkg/config/config.go](file://pkg/config/config.go)
|
||
- [pkg/config/manager.go](file://pkg/config/manager.go)
|
||
- [scripts/check-env.sh](file://scripts/check-env.sh)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [引言](#引言)
|
||
2. [项目结构](#项目结构)
|
||
3. [核心组件](#核心组件)
|
||
4. [架构总览](#架构总览)
|
||
5. [详细组件分析](#详细组件分析)
|
||
6. [依赖关系分析](#依赖关系分析)
|
||
7. [性能考量](#性能考量)
|
||
8. [故障排查指南](#故障排查指南)
|
||
9. [结论](#结论)
|
||
10. [附录](#附录)
|
||
|
||
## 引言
|
||
本文件围绕系统配置模型进行系统性说明,重点聚焦于 SystemConfig 结构体的设计与应用,涵盖:
|
||
- 键值配置存储机制与配置类型(ConfigType:STRING/INTEGER/BOOLEAN/JSON)的枚举定义与值序列化策略
|
||
- IsPublic 标志位如何控制前端可访问的配置项(站点名称、注册开关、维护模式等)
|
||
- SystemConfigPublicResponse 响应结构的字段映射逻辑与敏感配置与公开配置的分离原则
|
||
- 关于配置项版本管理、变更审计与缓存策略的建议
|
||
- 如何安全地读取与更新系统参数,避免配置注入风险
|
||
|
||
## 项目结构
|
||
系统配置模型位于内部模型层与仓库层,配合通用类型与配置加载模块共同构成完整的配置体系。下图展示了与系统配置模型直接相关的文件与职责划分。
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "模型层"
|
||
M1["internal/model/system_config.go<br/>定义 SystemConfig 与 SystemConfigPublicResponse"]
|
||
end
|
||
subgraph "仓库层"
|
||
R1["internal/repository/system_config_repository.go<br/>提供配置查询与更新接口"]
|
||
R2["internal/repository/system_config_repository_test.go<br/>测试查询条件、公开配置逻辑与更新逻辑"]
|
||
end
|
||
subgraph "类型与响应"
|
||
T1["internal/types/common.go<br/>定义 SystemConfigResponse 等通用响应类型"]
|
||
end
|
||
subgraph "配置加载"
|
||
C1["pkg/config/config.go<br/>应用运行时配置加载与环境变量覆盖"]
|
||
C2["pkg/config/manager.go<br/>全局配置实例管理"]
|
||
S1["scripts/check-env.sh<br/>环境变量检查脚本"]
|
||
end
|
||
M1 --> R1
|
||
R1 --> C1
|
||
T1 -.-> M1
|
||
C1 --> C2
|
||
S1 --> C1
|
||
```
|
||
|
||
图表来源
|
||
- [internal/model/system_config.go](file://internal/model/system_config.go#L1-L42)
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L1-L58)
|
||
- [internal/repository/system_config_repository_test.go](file://internal/repository/system_config_repository_test.go#L1-L145)
|
||
- [internal/types/common.go](file://internal/types/common.go#L208-L215)
|
||
- [pkg/config/config.go](file://pkg/config/config.go#L108-L133)
|
||
- [pkg/config/manager.go](file://pkg/config/manager.go#L1-L63)
|
||
- [scripts/check-env.sh](file://scripts/check-env.sh#L1-L61)
|
||
|
||
章节来源
|
||
- [internal/model/system_config.go](file://internal/model/system_config.go#L1-L42)
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L1-L58)
|
||
- [internal/types/common.go](file://internal/types/common.go#L208-L215)
|
||
- [pkg/config/config.go](file://pkg/config/config.go#L108-L133)
|
||
- [pkg/config/manager.go](file://pkg/config/manager.go#L1-L63)
|
||
- [scripts/check-env.sh](file://scripts/check-env.sh#L1-L61)
|
||
|
||
## 核心组件
|
||
- SystemConfig:系统配置的持久化模型,包含键、值、类型、描述、是否公开、创建与更新时间等字段;通过 GORM 映射到 system_config 表。
|
||
- ConfigType:配置类型枚举,支持 STRING、INTEGER、BOOLEAN、JSON 四种类型。
|
||
- IsPublic:布尔标志位,决定该配置是否可被前端获取。
|
||
- SystemConfigPublicResponse:面向前端的公开配置响应结构,包含站点名称、站点描述、注册开关、维护模式、公告等字段。
|
||
- SystemConfigRepository:提供按键查询、获取公开配置、获取全部配置、更新配置与更新配置值等操作。
|
||
- SystemConfigResponse:通用系统配置响应类型(与公开响应不同,包含更多业务参数)。
|
||
|
||
章节来源
|
||
- [internal/model/system_config.go](file://internal/model/system_config.go#L7-L41)
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L11-L57)
|
||
- [internal/types/common.go](file://internal/types/common.go#L208-L215)
|
||
|
||
## 架构总览
|
||
系统配置模型遵循“模型-仓库-服务-控制器”的分层设计。配置读写通过仓库层封装数据库访问,对外暴露简洁的接口;公开配置通过 IsPublic 进行过滤,确保敏感信息不泄露给前端。
|
||
|
||
```mermaid
|
||
graph TB
|
||
Client["前端/管理端"] --> API["控制器/服务层"]
|
||
API --> Repo["SystemConfigRepository"]
|
||
Repo --> Model["SystemConfig 模型"]
|
||
Repo --> DB["数据库 system_config 表"]
|
||
API --> PublicResp["SystemConfigPublicResponse"]
|
||
API --> CommonResp["SystemConfigResponse"]
|
||
```
|
||
|
||
图表来源
|
||
- [internal/model/system_config.go](file://internal/model/system_config.go#L18-L41)
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L11-L57)
|
||
- [internal/types/common.go](file://internal/types/common.go#L208-L215)
|
||
|
||
## 详细组件分析
|
||
|
||
### SystemConfig 结构体与配置类型
|
||
- 字段说明
|
||
- Key:配置键,唯一索引,用于标识具体配置项。
|
||
- Value:配置值,以字符串形式存储,配合 Type 决定解析方式。
|
||
- Type:配置类型,枚举 STRING/INTEGER/BOOLEAN/JSON。
|
||
- IsPublic:是否公开,true 时可在公开接口中返回给前端。
|
||
- Description、CreatedAt、UpdatedAt:元信息与时间戳。
|
||
- 表名映射:TableName 返回 system_config,用于 GORM 自动迁移与查询。
|
||
- 配置类型与序列化策略
|
||
- STRING:直接以字符串存储,适合文本类配置。
|
||
- INTEGER:字符串存储,需要在读取后转换为整数。
|
||
- BOOLEAN:字符串存储,需要在读取后转换为布尔值。
|
||
- JSON:字符串存储,需要在读取后进行 JSON 解析,支持复杂结构。
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class SystemConfig {
|
||
+int64 id
|
||
+string key
|
||
+string value
|
||
+string description
|
||
+ConfigType type
|
||
+bool is_public
|
||
+time created_at
|
||
+time updated_at
|
||
+TableName() string
|
||
}
|
||
class ConfigType {
|
||
<<enumeration>>
|
||
"STRING"
|
||
"INTEGER"
|
||
"BOOLEAN"
|
||
"JSON"
|
||
}
|
||
SystemConfig --> ConfigType : "使用"
|
||
```
|
||
|
||
图表来源
|
||
- [internal/model/system_config.go](file://internal/model/system_config.go#L7-L32)
|
||
|
||
章节来源
|
||
- [internal/model/system_config.go](file://internal/model/system_config.go#L7-L32)
|
||
|
||
### 公开配置响应 SystemConfigPublicResponse 的字段映射
|
||
- 字段含义
|
||
- site_name:站点名称
|
||
- site_description:站点描述
|
||
- registration_enabled:注册开关
|
||
- maintenance_mode:维护模式
|
||
- announcement:公告
|
||
- 映射原则
|
||
- 仅来源于 IsPublic 为 true 的配置项,避免敏感配置泄露。
|
||
- 字段名与 JSON 序列化标签一一对应,便于前端消费。
|
||
- 分离原则
|
||
- 敏感配置(如密钥、内部开关)应设置 IsPublic=false,不在公开响应中出现。
|
||
- 公开配置(如站点名称、注册开关、维护模式、公告)应设置 IsPublic=true。
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class SystemConfigPublicResponse {
|
||
+string site_name
|
||
+string site_description
|
||
+bool registration_enabled
|
||
+bool maintenance_mode
|
||
+string announcement
|
||
}
|
||
```
|
||
|
||
图表来源
|
||
- [internal/model/system_config.go](file://internal/model/system_config.go#L34-L41)
|
||
|
||
章节来源
|
||
- [internal/model/system_config.go](file://internal/model/system_config.go#L34-L41)
|
||
|
||
### 仓库层接口与流程
|
||
- GetSystemConfigByKey(key):根据键查询配置,若记录不存在返回空而非错误。
|
||
- GetPublicSystemConfigs():仅返回 IsPublic=true 的配置集合。
|
||
- GetAllSystemConfigs():返回全部配置(供管理员使用)。
|
||
- UpdateSystemConfig(config):保存配置(含类型与值)。
|
||
- UpdateSystemConfigValue(key, value):仅更新值字段。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant Client as "调用方"
|
||
participant Repo as "SystemConfigRepository"
|
||
participant DB as "数据库"
|
||
Client->>Repo : GetPublicSystemConfigs()
|
||
Repo->>DB : 查询 where is_public = true
|
||
DB-->>Repo : 返回公开配置列表
|
||
Repo-->>Client : 返回公开配置
|
||
Client->>Repo : UpdateSystemConfigValue(key, value)
|
||
Repo->>DB : Model(...).Where("key = ?").Update("value", value)
|
||
DB-->>Repo : 更新成功
|
||
Repo-->>Client : 返回 nil
|
||
```
|
||
|
||
图表来源
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L25-L57)
|
||
|
||
章节来源
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L11-L57)
|
||
|
||
### 配置读取与序列化策略
|
||
- 读取流程
|
||
- 使用 GetSystemConfigByKey(key) 获取配置。
|
||
- 根据 Type 对 Value 进行类型化解析:
|
||
- STRING:直接使用字符串。
|
||
- INTEGER:解析为整数。
|
||
- BOOLEAN:解析为布尔值。
|
||
- JSON:解析为结构体或 map。
|
||
- 序列化策略
|
||
- 公开响应使用 SystemConfigPublicResponse,仅包含 IsPublic=true 的字段映射。
|
||
- 非公开配置不参与公开响应序列化。
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start(["开始"]) --> Load["GetSystemConfigByKey(key)"]
|
||
Load --> Found{"找到记录?"}
|
||
Found --> |否| ReturnNil["返回空配置"]
|
||
Found --> |是| ParseType["根据 Type 解析 Value"]
|
||
ParseType --> STRING["STRING:直接使用字符串"]
|
||
ParseType --> INTEGER["INTEGER:解析为整数"]
|
||
ParseType --> BOOLEAN["BOOLEAN:解析为布尔值"]
|
||
ParseType --> JSON["JSON:解析为结构体/字典"]
|
||
STRING --> End(["结束"])
|
||
INTEGER --> End
|
||
BOOLEAN --> End
|
||
JSON --> End
|
||
ReturnNil --> End
|
||
```
|
||
|
||
图表来源
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L11-L23)
|
||
- [internal/model/system_config.go](file://internal/model/system_config.go#L7-L15)
|
||
|
||
章节来源
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L11-L23)
|
||
- [internal/model/system_config.go](file://internal/model/system_config.go#L7-L15)
|
||
|
||
### 公开配置逻辑与测试验证
|
||
- 公开配置查询逻辑
|
||
- GetPublicSystemConfigs() 仅返回 IsPublic=true 的配置,确保敏感配置不被泄露。
|
||
- 测试覆盖点
|
||
- 查询条件验证:键非空才视为有效。
|
||
- 公开配置逻辑:仅包含 IsPublic=true 的配置。
|
||
- 更新值逻辑:键非空即允许更新,空值亦可接受。
|
||
- 错误处理:记录不存在时返回空而非错误。
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
QStart(["查询入口"]) --> BuildQuery["构建查询:where is_public = true"]
|
||
BuildQuery --> Exec["执行查询"]
|
||
Exec --> Result{"查询结果"}
|
||
Result --> |存在| Filter["过滤 IsPublic=true"]
|
||
Result --> |不存在| NotFound["返回空集合"]
|
||
Filter --> Return["返回公开配置集合"]
|
||
NotFound --> Return
|
||
```
|
||
|
||
图表来源
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L25-L33)
|
||
- [internal/repository/system_config_repository_test.go](file://internal/repository/system_config_repository_test.go#L51-L78)
|
||
|
||
章节来源
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L25-L33)
|
||
- [internal/repository/system_config_repository_test.go](file://internal/repository/system_config_repository_test.go#L1-L145)
|
||
|
||
### 安全与注入防护
|
||
- 输入校验
|
||
- 键非空校验:更新与查询均要求键非空,防止空键导致的异常行为。
|
||
- 值可为空:允许空值,但需结合业务语义判断有效性。
|
||
- 类型约束
|
||
- 通过 Type 字段强制约束 Value 的解析方式,避免任意字符串被错误解读。
|
||
- 敏感信息隔离
|
||
- 通过 IsPublic=false 隐藏敏感配置,仅在管理员通道可见。
|
||
- 环境变量安全
|
||
- 应用配置加载来自环境变量,建议使用强口令与密钥,脚本会提示 JWT 密钥长度不足的风险。
|
||
|
||
章节来源
|
||
- [internal/repository/system_config_repository_test.go](file://internal/repository/system_config_repository_test.go#L80-L116)
|
||
- [scripts/check-env.sh](file://scripts/check-env.sh#L52-L61)
|
||
- [pkg/config/config.go](file://pkg/config/config.go#L238-L305)
|
||
|
||
## 依赖关系分析
|
||
- 模型依赖
|
||
- SystemConfig 依赖 GORM 标签进行数据库映射。
|
||
- SystemConfigPublicResponse 依赖 JSON 标签进行序列化。
|
||
- 仓库依赖
|
||
- 依赖数据库连接(MustGetDB),通过 where 条件实现键查询与公开筛选。
|
||
- 类型依赖
|
||
- SystemConfigResponse 与 SystemConfigPublicResponse 分别服务于不同场景的响应结构。
|
||
- 配置加载依赖
|
||
- 应用配置加载与环境变量覆盖,确保运行时参数可控且可审计。
|
||
|
||
```mermaid
|
||
graph LR
|
||
Model["SystemConfig 模型"] --> Repo["SystemConfigRepository"]
|
||
Repo --> DB["数据库"]
|
||
PublicResp["SystemConfigPublicResponse"] --> API["控制器/服务层"]
|
||
CommonResp["SystemConfigResponse"] --> API
|
||
Cfg["pkg/config/config.go"] --> API
|
||
CfgMgr["pkg/config/manager.go"] --> Cfg
|
||
```
|
||
|
||
图表来源
|
||
- [internal/model/system_config.go](file://internal/model/system_config.go#L18-L41)
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L11-L57)
|
||
- [internal/types/common.go](file://internal/types/common.go#L208-L215)
|
||
- [pkg/config/config.go](file://pkg/config/config.go#L108-L133)
|
||
- [pkg/config/manager.go](file://pkg/config/manager.go#L1-L63)
|
||
|
||
章节来源
|
||
- [internal/model/system_config.go](file://internal/model/system_config.go#L18-L41)
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L11-L57)
|
||
- [internal/types/common.go](file://internal/types/common.go#L208-L215)
|
||
- [pkg/config/config.go](file://pkg/config/config.go#L108-L133)
|
||
- [pkg/config/manager.go](file://pkg/config/manager.go#L1-L63)
|
||
|
||
## 性能考量
|
||
- 查询优化
|
||
- 为 key 建立唯一索引,提升按键查询效率。
|
||
- 为 is_public 建立索引,加速公开配置筛选。
|
||
- 缓存策略建议
|
||
- 公开配置可引入只读缓存(如 Redis),定期刷新,降低数据库压力。
|
||
- 对频繁读取的配置项(如站点名称、注册开关、维护模式)设置短 TTL,平衡一致性与性能。
|
||
- 更新策略
|
||
- 批量更新时使用 UpdateSystemConfigValue,避免不必要的字段变更导致的冗余日志与锁竞争。
|
||
- 版本与审计
|
||
- 建议引入配置版本号字段与审计日志,记录每次变更的时间、操作者与变更内容,便于回溯与合规。
|
||
|
||
## 故障排查指南
|
||
- 记录不存在
|
||
- GetSystemConfigByKey(key) 在记录不存在时返回空而非错误,调用方需显式判空。
|
||
- 公开配置为空
|
||
- 若 GetPublicSystemConfigs() 返回空,检查是否正确设置 IsPublic=true 或数据库中是否存在公开配置。
|
||
- 更新失败
|
||
- UpdateSystemConfigValue(key, value) 要求键非空;若更新无效,确认键是否存在且值合法。
|
||
- 类型解析错误
|
||
- 根据 Type 对 Value 进行解析;若解析失败,检查配置值格式与类型是否匹配。
|
||
- 环境变量问题
|
||
- 使用脚本检查关键环境变量是否缺失或过短(如 JWT 密钥长度),及时修正。
|
||
|
||
章节来源
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L11-L23)
|
||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L25-L57)
|
||
- [internal/repository/system_config_repository_test.go](file://internal/repository/system_config_repository_test.go#L119-L145)
|
||
- [scripts/check-env.sh](file://scripts/check-env.sh#L1-L61)
|
||
|
||
## 结论
|
||
SystemConfig 模型通过统一的键值存储与类型约束,实现了灵活而安全的系统配置管理。借助 IsPublic 标志位与公开响应结构,系统在保证功能可用的同时,严格隔离了敏感配置。结合缓存、版本与审计策略,可进一步提升系统的稳定性与可运维性。建议在生产环境中严格执行输入校验、类型解析与注入防护,并建立完善的变更审计流程。
|
||
|
||
## 附录
|
||
- 常用配置键建议
|
||
- 站点名称:site_name(IsPublic=true)
|
||
- 站点描述:site_description(IsPublic=true)
|
||
- 注册开关:registration_enabled(IsPublic=true)
|
||
- 维护模式:maintenance_mode(IsPublic=true)
|
||
- 公告:announcement(IsPublic=true)
|
||
- 管理员专用:secret_key、internal_switch(IsPublic=false) |