给前端
toast
的
message
只放用户能看懂的中文;动作 / 状态的内部 code、堆栈等技术细节不进
message
,由访问日志承载。本规范是必须遵守的跨模块约定,新功能照做。
message 面向用户、诊断面向开发,两者分离。
前端往往直接把后端业务异常的
message
弹给最终用户。如果
message
里夹着
complete
/
status
/
action
这类内部术语,用户看不懂,会误以为系统异常或数据没保存。
complete
动作,后端返回
"当前任务状态不支持动作【complete】"
。用户合理的预期是看到
"任务已完成,请勿重复提交"
这类人话。
因此约定:
用户看友好中文(
message
),开发排查看访问日志(
infra_api_access_log
里有原始 code、入参、堆栈)。
两条信息流互不污染。
整套方案
零新表、framework 零改动
,纯在
rdms-project
域内:一个解析器组件 + 错误码文案模板改造 + service 接入。
StatusActionTextResolver
位置:
rdms-project-boot · service/status/StatusActionTextResolver.java
(
@Component
)。把动作 / 状态的 code 翻成中文展示名,供错误文案使用。
| 方法 | 作用 | 查不到 / 空入参 |
|---|---|---|
actionName(objectType, actionCode) |
动作中文名 |
回退原
actionCode
,不抛错
|
statusName(objectType, statusCode) |
状态中文名 |
回退原
statusCode
,不抛错
|
rdms_object_status_transition.action_name
,状态名取自
rdms_object_status_model.status_name
。运维在状态机表里配新动作 / 新状态,文案自动生效,
不用改代码发版
。
错误码定义时,文案就留中文名占位,由 service 在抛错前用 resolver 填入。例如:
// 个人事项 —— 正面样板
ErrorCode PERSONAL_ITEM_STATUS_ACTION_NOT_ALLOWED =
new ErrorCode(1_008_008_004, "当前个人事项为「{}」状态,不支持「{}」操作");
抛出前:
exception(PERSONAL_ITEM_STATUS_ACTION_NOT_ALLOWED, resolver.statusName(...), resolver.actionName(...))
—— 占位填的是中文名,不是裸 code。
状态机校验失败抛错时,先经 resolver 翻译再返回的 service:
ProductRequirementServiceImpl
(产品需求)
PersonalItemServiceImpl
(个人事项)
ProjectTaskServiceImpl
(任务)
ProductServiceImpl
(产品)
ProjectExecutionServiceImpl
(执行)
ProjectServiceImpl
(项目)
ProjectRequirementServiceImpl
(项目需求)
StatusActionTextResolver
。
PERSONAL_ITEM_STATUS_ACTION_NOT_ALLOWED
),
不要把 code 直接嵌进文案
。
actionName / statusName
把 code 翻成中文名再填占位。
rdms_object_status_model
/
rdms_object_status_transition
配好
status_name
/
action_name
,resolver 即自动生效。
除"状态机动作 / 状态翻中文"外,凡
message
会被前端直接展示,
以下技术 token 一律不得出现在 message 里
,只能进日志(
log.warn
/
infra_api_access_log
):
| 禁止外泄 | 反例 | 正确做法 |
|---|---|---|
| 数据库表名 / 列名 |
"未在
system_role
找到"
|
"…未配置,请联系管理员" |
| 权限码 / 内部标记 |
"操作权限【
project:project:update
】"、"【
member
】"
|
"您没有此项操作权限,请联系管理员" |
| 动作 / 状态 code |
"不支持动作【
complete
】"
|
resolver 翻中文名(见 §2) |
| 类名 / 字段名 / 堆栈 |
"
NullPointerException at ...
"
|
友好提示,异常进日志 |
OvertimeApplicationServiceImpl
已注入 resolver,文案对齐其它域「当前加班申请为「{}」状态,不支持「{}」操作」。
Project/ProductObjectPermissionService
已去占位、权限码改
log.warn
;错误码文案改"您没有该项目/产品的此项操作权限,请联系管理员"。
PRODUCT/PROJECT_INTERNAL_ROLE_NOT_CONFIGURED
两条已去掉
system_role
。
OvertimeApplicationServiceImplTest
(2 用例,
mvn test
通过):验证状态机「动作不允许 / 缺原因」抛错时,
message
填的是
StatusActionTextResolver
翻出的中文名、不外泄英文动作 / 状态 code。属 Mockito 单测(mock resolver),覆盖的是 service 层「填中文名而非裸
code」这条契约;resolver 自身的 DB 翻译由
StatusActionTextResolverTest
覆盖。真实 DB 状态机表是否配齐
status_name
/
action_name
的端到端校验仍依赖运行时,不在单测范围。
infra_api_access_log
(访问日志,留原始 code / 入参 / 堆栈)。
CLAUDE.md · 接口语义
章节留有指向本文档的红线指针。