# 元数据管理服务(`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> getXxx(Map params); // 列表 / 分页读取 Feedback> getXxxBysId(Map params); // 单行读取 Feedback> addXxx(Map params); // 插入 Feedback> updateXxx(Map params); // 更新 Feedback> deleteXxx(Map 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*` 连接表 |