# 元数据管理服务（`xlyManage`）

`xlyManage` 模块是 **BACK 配置器背后的 service 层**。PM 在系统模块配置、界面显示内容配置、数据表内容配置、系统权限配置、系统常量配置、用户信息配置、Mysql脚本配置等页面点击修改 / 新增 / 删除时，请求会先落到 `xlyEntry/.../web/systemweb/` 下的某个 `Gds*Controller`，再委托给 `xlyManage/src/main/java/com/xly/service/systeminfo/impl/` 下的 `Gds*ServiceImpl`。

这些 service 是框架的**元数据 CRUD 主干**：它们拥有每张 `gds*` 表的读写逻辑。运行时（[切片 1](../../slices/01-hello-world.md)、[runtime.md](runtime.md)）负责**读取**元数据；`xlyManage` 负责**写入**元数据。

## 服务总览

| Service | 行数 | 拥有内容 | BACK 页面 |
|---|---:|---|---|
| `GdsmoduleServiceImpl` | 729 | `gdsmodule`（模块）、`gdsroute`（URL 白名单）、模块树 CRUD | 系统模块配置 |
| `GdsconfigformServiceImpl` | 878 | `gdsconfigformmaster`、`gdsconfigformslave`、`gdsconfigformcustomslave`、`gdsconfigformpersonalize`（表单定义 + 每租户覆盖） | 界面显示内容配置 |
| `GdsconfigtbServiceImpl` | 555 | `gdsconfigtbmaster`、`gdsconfigtbslave`（虚拟表定义） | 数据表内容配置 |
| `SqlScriptsServiceImpl` | 489 | BACK 中编写的 DDL / proc / view 脚本；使用 [`templesql/`](sql-templates.md) 模板 | Mysql脚本配置 |
| `GdsjurisdictionServiceImpl` | 362 | `gdsjurisdiction`（每模块动作**目录**；见[权限](../builder/permissions.md)） | 系统权限配置 + 配置流程的一部分 |
| `GdsparameterServiceImpl` | 319 | `gdsparameter`（系统级参数） | 参数页面 |
| `GdsformconstServiceImpl` | 243 | `gdsformconst`（每表单常量：标签、默认文本）。切片 1 锚点表。 | 系统常量配置 |
| `GdslogininfoServiceImpl` | 221 | `sftlogininfo*` 表族（用户 / 登录 / 用户组目录） | 用户信息配置 |
| `SysbrandsServiceImpl` | 125 | `sysbrands`（加工商 / 租户主数据） | 租户管理 |
| `CommonServiceImpl` | 56 | 其他 service 共用 helper | n/a |

合计约 4000 行元数据 CRUD 逻辑，这是框架运行时里相当大的部分，之前 Wiki 没有覆盖。

## 方法形状约定

每个 `Gds*Service` 基本都遵循同一个五方法形状：

```java
Feedback<Map<String,Object>> getXxx(Map<String, Object> params);       // 列表 / 分页读取
Feedback<Map<String,Object>> getXxxBysId(Map<String, Object> params);  // 单行读取
Feedback<Map<String,Object>> addXxx(Map<String, Object> params);       // 插入
Feedback<Map<String,Object>> updateXxx(Map<String, Object> params);    // 更新
Feedback<Map<String,Object>> deleteXxx(Map<String, Object> params);    // 删除（常见为 bInvalid 软删）
```

对应 `Gds*Controller` 的 endpoint 方法也几乎逐字镜像这个形状。因此 BACK 管理接口面本质上是一个薄 pass-through：controller 在 `xlyEntry/.../systemweb/`，service 在 `xlyManage/.../systeminfo/impl/`。这和运行时侧相反：运行时由一个通用 `BusinessBaseController` 处理任意表上的业务数据 CRUD；这里每类框架元数据 CRUD 都有自己的 controller + service 对。

## 值得注意的细节

- **`GdsconfigformServiceImpl` 最大**，因为它拥有四张强耦合表（form-master、form-slave、customslave、personalize）以及 **DDL 脚本生成**流程。`getFormslaveScriptSqlPro`、`getMasterSlaveScriptSqlPro` 等方法会生成工程师可应用到物理表上的 SQL，用于新增字段。这让定制覆盖模型（[切片 4](../../slices/04-custom-field.md)）端到端可用：BACK 配置器也能生成覆盖所暗示的 schema migration SQL。
- **`GdsmoduleServiceImpl` 包含 `getModuleTreePro`**，这是 SPA 登录后调用的模块树解析（实时 trace 中第一个 `/gdsmodule/getModuleTreePro` 请求）。版本可见性（[切片 2](../../slices/02-multi-tenancy.md)）最终由许可证产出的 `sVerifyLicense` 模块 id 列表控制，而不是直接按 `sVersionFlowId` 条件过滤。
- **`SqlScriptsServiceImpl`** 把 [`templesql/`](sql-templates.md) 脚手架接到 BACK 脚本编写页面。工程师填写占位规格后，service 会生成可编译的 proc / view body，并在连接的 schema 上执行。
- **`GdsjurisdictionServiceImpl` 写动作*目录***；`sysjurisdiction`（每用户授权表）由其他路径写入（`xlyBusinessService` 的权限管理流程）。目录 vs 授权的区别见[如何设置权限](../builder/permissions.md)。
- **`SysbrandsServiceImpl`** 写租户主数据（`sysbrands` + `sBrandsId` 行）；新租户初始化基本就是这里插入一行，再种子化元数据。

## 缓存失效钩子点

这些 service 的写方法直接带有自己的 `@CacheEvict` 注解（例如 `GdsmoduleServiceImpl.java:96` 的 `addGdsmodule` 会清理 9 个 cache region）。这就是 BACK 中的元数据编辑能立即在各节点生效的原因：共享 Redis 缓存（RedisCacheManager，见 [cache-invalidation.md](cache-invalidation.md)）会在写事务提交时清理相关 region。这里**没有 JMS 扇出用于清缓存**，这是常见误解，缓存失效页已有详细说明。（业务数据通过 `BusinessBaseServiceImpl` 写入时走另一条 `BusinessCleanRedisData.delCleanRedisData*` 分发路径；两条路径都在缓存失效页说明。）

## `xlyManage` 不包含什么

- **业务数据 CRUD。** 那是通用 `BusinessBaseController` + `BusinessBaseServiceImpl` 路径（[runtime.md](runtime.md)、[切片 1](../../slices/01-hello-world.md)）。
- **API 元数据**（`sysapi`）。那是 `xlyApi` 自己的管理接口面；见[外部 API](../../api-reference/external.md)。
- **工作流元数据**（`gdsmoduleflow`、`act_*`、`biz_flow`）。那在 `xlyFlow`；见 [activiti.md](activiti.md)。

## 出问题时先看哪里

| 症状 | 优先查看 |
|---|---|
| BACK 对 `gdsconfigform*` 修改 / 新增返回“操作失败” | `GdsconfigformServiceImpl`，检查字段校验和匹配的 DDL 脚本生成路径 |
| 版本可见性显示了错误模块 | 菜单 / 模块树 SQL，以及 `VerifyLicense.getModelAllList()` / `sVerifyLicense`，确认允许的模块 id 列表 |
| BACK 脚本编写页面生成了错误 SQL | `SqlScriptsServiceImpl` + [templesql 脚手架](sql-templates.md) |
| 某模块缺少权限动作目录（BtnAdd / BtnUpd / …） | `GdsjurisdictionServiceImpl`，检查该 `sParentId` 下的行 |
| 用户能登录 BACK 但 FROUNT 为空 | `GdslogininfoServiceImpl`，检查 `sftlogininfo*` 连接表 |
