验证状态:已源码核验、未联调;适用基线:Web
7fe6dd10、services89bd222c;核验日期:2026-09-12
新增一条翻译词条。当前 Web 翻译新增页提交本操作。自然键(language+namespace+key)重复时服务端以业务错误拒绝,不做 upsert。
| 页面/功能 | 角色或空间分支 | 调用证据 |
|---|---|---|
| 翻译新增页提交 | 当前 $spaceId;前端入口要求 administrator 或 configuration-translation:create(route.tsx:26-29);后端同串(TranslationController.java:55) |
app/routes/($lng).$spaceId.configuration.translation.add/route.tsx:59,88 |
| 项 | 值 |
|---|---|
| operationId | http-post-main-service-system-api-configuration-translation-save-ab056553 |
| method + path | POST /main-service/system-api/configuration/translation/save |
| base URL | 当前 Web 使用同源相对 URL |
| headers | Content-Type: application/json;Authorization: Bearer <token> |
| 序列化 | object body 由公共 wrapper 执行 JSON.stringify |
需要有效登录态,并满足 administrator 角色或 configuration-translation:create。写操作走租户拦截器,tenant_id 由服务端当前租户上下文填充(INSERT fill),请求中的租户字段不决定归属。认证与空间。
| JSON 路径/参数 | JSON 类型 | 位置 | 必填 | 可空 | 默认值 | 枚举/范围/单位 | 说明 | 字段证据 |
|---|---|---|---|---|---|---|---|---|
translationId |
string | body | 否 | 否 | Web 端生成 nanoid 去杠去下划线;服务端 IdType.ASSIGN_UUID 兜底 |
≤32 字符 | 主键;Web 新增页总是显式生成(route.tsx:74-81) | TranslationSaveRequestDTO.java;Translation.java @TableId(ASSIGN_UUID);app/.common/lib/strings.ts:50 stringLiteNanoId |
language |
string | body | 是 | 否 | 无 | 1..128;服务端可按 languageMap 配置映射 |
语言 | TranslationSaveRequestDTO.java @NotBlank @Size(max=128) |
namespace |
string | body | 是 | 否 | 无 | 1..128 | 命名空间 | 同上 |
key |
string | body | 是 | 否 | 无 | ≥1 | 词条键 | 同上 |
value |
string | body | 是 | 否 | 无 | ≥1 | 词条值 | 同上 |
revision |
number | body | 否 | 是 | null |
— | 随 save 复制写入;无乐观锁作用 | 同上;TranslationService.save BeanUtils.copyProperties |
服务端先以自然键 count 查重,existsCount > 0 抛 ApiException("Translation exists")(TranslationController.java:59-69);随后 save 实际执行 MyBatis-Plus saveOrUpdate(TranslationService.java:31-40)。返回值恒为 true(「无异常完成即成功」合同,注释明示分区触发器可能使成功 INSERT 报告 0 行)。
| JSON 路径 | JSON 类型 | 出现条件 | 可空 | 枚举/范围/单位 | 说明 | 字段证据 |
|---|---|---|---|---|---|---|
timestamp/status/error/localizedError/path |
同信封 | JSON 响应 | — | — | 成功 status=200、data=true |
gt-common-core/src/main/java/tech/gt/api/ApiResult.java |
extraData |
object | 成功 | 否 | — | 恒为 {} |
同上 |
data |
boolean | 业务成功 | 否 | true |
合同恒 true | TranslationController.java:71 |
副作用链:save 标注 @MyMessage(TRANSLATION_SAVE) 发布 JMS 消息(TranslationService.java:30),TranslationListener.save 消费后触发 requestPublishInNextRound,由 TranslationScheduling 批量刷新最终翻译视图(TranslationListener.java:52-60)。读端何时可见新词条取决于该异步刷新,非同步合同。
status=200 表示行已落库并已受理刷新请求;最终翻译视图的可见性是异步的(内存队列 + 定时批量,TranslationScheduling.java:37-46),不能以本操作返回判定视图已更新。
按已核验契约构造的示例,不是真实联调记录。
请求:
成功响应:
认证失败/权限失败/业务拒绝(自然键重复 Translation exists)/ 请求校验失败(@NotBlank/@Size)。重复提交同一自然键必然业务失败;重试前需先查询确认。前端节流 500ms(route.tsx:61)。
无长连接资源。成功后新增页导航回列表页(route.tsx:63-67)。
最终翻译视图的刷新时延、TranslationScheduling 批量参数(MAX_PENDING_TRANSLATIONS=10000、每轮 20 批、最长等待 6 秒)在目标环境的实际表现未联调核验(源码常量见 TranslationScheduling.java:39-43)。
仅完成双仓静态源码核验,未执行真实 HTTP、数据库或 JMS 联调。
| 结论 | 状态 | 仓库/基线 | 路径、符号及定位 | 内容指纹(脏文件) |
|---|---|---|---|---|
| Web 方法、路径、序列化与消费 | 已源码核验 | web 7fe6dd10 |
translationApi.ts:1 configurationTranslationSaveApi;add route.tsx:59,88 |
证据文件与 HEAD 一致 |
| 权限、输入、输出和完成语义 | 已源码核验 | services 89bd222c |
TranslationController.java:56 save(查重 :59-69);TranslationService.java:31-40 |
证据文件与 HEAD 一致 |
| 异步视图刷新链 | 已源码核验 | services 89bd222c |
TranslationListener.java:52-60;TranslationScheduling.java:37-46 |
证据文件与 HEAD 一致 |
| 真实部署联调 | 未执行 | — | 未发送请求、未连接数据库/JMS | — |