后端 LiteFlow 使用与开发规范¶
📄 创建: 李锦鹏 2026-08-17
文档版本:1.0
适用范围:
tpm-backend中所有接入 LiteFlow 规则编排的业务模块,以及公共 SDKbams-flow提供的 LiteFlow 封装能力。本文以当前代码、规则 XML 和
bams-flowSDK 源码为准,说明 LiteFlow 的架构分层、核心概念、 编写规范、配置方式、规则发布与版本管理、事务并发以及故障排查方式。
1. 概述¶
TPM 后端使用 LiteFlow 承担「业务规则编排 / 状态机流转」职责,而审批工作流由 Warm-Flow 承担。两者统一封装在公共 SDK cn.cnbm.bams:bams-flow 中,宿主业务(如润滑计划、润滑工单)不直接依赖 LiteFlow 原生 API,而是通过 SDK 暴露的 版本化执行器、模板服务、链查找服务、实例仓库 和 类型化节点基类 完成业务流转。
核心特征:
- 多工厂、多模板、多版本:同一套规则模板可为不同工厂发布不同版本,版本不可变。
- 规则数据库化:规则 XML 统一保存在
sys_liteflow表,ACTIVE记录是当前版本的唯一数据源, 不再使用本地 XML 资源映射或 Rediscurrent指针。 - 固定版本实例:首次执行后业务表保存
instanceId,后续动作通过 Redis 实例恢复固定版本, 保证「流程进行中」不会因切换 ACTIVE 版本而中途改变规则。 - 业务状态由节点计算、事务服务统一落库:LiteFlow 节点只做「状态校验 + 状态迁移 + 变更意图输出」, 数据库提交由业务 FlowService 在 Spring 事务中原子完成。
- 乐观并发控制:数据库更新始终带「原状态」条件,避免并发请求互相覆盖。
2. 整体架构与依赖¶
2.1 依赖关系¶
tpm-backend-service
└── cn.cnbm.bams:bams-flow (SDK 封装层)
├── LiteFlow Starter (com.yomahub.liteflow)
├── LiteFlow Redis Rule-DB Provider
└── Warm-Flow Starter (审批工作流,与本文关系较小)
tpm-backend-service/pom.xml 引入:
SDK 源码位置(不在 tpm-backend 仓库内):
2.2 SDK 核心包结构¶
cn.cnbm.bams.flow
├── config
│ ├── BamsFlowProperties # bams.flow.* 配置
│ ├── LiteFlowRuleDbProperties # liteflow.rule-db.* 配置
│ └── FlowAutoConfiguration # 按开关条件注册封装 Bean
├── lite
│ ├── entity
│ │ └── SysLiteFlow # sys_liteflow 表实体
│ ├── instance
│ │ ├── BamsLiteFlowInstance # 业务实例元数据(归属 + 版本)
│ │ ├── BamsLiteFlowInstanceRepository # 实例仓库 SPI
│ │ └── RedisBamsLiteFlowInstanceRepository # 默认 Redis 实现
│ ├── mapper
│ │ └── SysLiteFlowMapper # MyBatis-Plus Mapper
│ ├── node
│ │ ├── BamsTypedNodeComponent<C> # 类型安全节点基类
│ │ ├── BamsHumanConfirmationContext # 人工确认上下文契约
│ │ └── BamsHumanConfirmationNode # 公共布尔节点 flowHumanConfirmation
│ ├── runtime
│ │ ├── BamsVersionedFlowRequest # 一次版本化规则执行请求
│ │ ├── BamsVersionedFlowResult # 一次版本化规则执行结果
│ │ ├── BamsVersionedLiteFlowExecutor # 版本化执行器接口
│ │ ├── BamsVersionedLiteFlowExecutorImpl
│ │ ├── BamsLiteFlowChainService # chain 查找 + Rule-DB 候选加载
│ │ └── BamsLiteFlowChainServiceImpl
│ └── service
│ ├── BamsLiteFlowService # 原生 FlowExecutor 薄封装
│ ├── BamsLiteFlowTemplateService # currentVersion / versionedChain
│ ├── BamsLiteFlowActiveTemplateService # ACTIVE 查询 / 激活
│ ├── BamsLiteFlowRulePublisherService # 数据库 XML 发布 / 激活
│ └── SysLiteFlowService
2.3 业务侧包结构(tpm-backend-service)¶
cn.cnbm.bams.ems.service.flow
├── support
│ └── AbstractVersionedRuleFlowService<E, C, A> # 版本化规则调用模板方法
├── constant
│ ├── EmLubricationPlanFlowConstants
│ └── EmLubricationOrderFlowConstants
└── lubrication
├── EmLubricationPlanFlowAction
├── EmLubricationPlanFlowCommand
├── EmLubricationPlanFlowService
├── EmLubricationOrderFlowAction
├── EmLubricationOrderFlowService
├── context
│ ├── EmLubricationPlanFlowContext
│ └── EmLubricationOrderFlowContext
└── node
├── EmLubricationPlanFlowNodeSupport
├── EmLubricationPlanSubmitEffectiveNode
├── EmLubricationPlanSubmitForApprovalNode
├── EmLubricationPlanApproveNode
├── EmLubricationPlanRejectNode
├── EmLubricationPlanCompleteDispatchNode
├── EmLubricationOrderFlowNodeSupport
├── EmLubricationOrderCreateAssignedNode
├── EmLubricationOrderCreatePendingClaimNode
├── EmLubricationOrderClaimNode
├── EmLubricationOrderStartNode
├── EmLubricationOrderSubmitNode
├── EmLubricationOrderAcceptNode
└── EmLubricationOrderRejectAcceptanceNode
3. 核心概念与术语¶
| 术语 | 含义 | 示例 |
|---|---|---|
| 规则模板 templateCode | 某类业务的规则模板编码,全局稳定 | lubrication-plan、lubrication-order |
| 规则版本 version | 模板的不可变版本,格式v[0-9]+ |
v1、v3 |
| 基础 chain baseChainId | XML 中未加任何后缀的 chain 名,业务代码只使用它 | lubricationPlanCreate |
| 版本化 chainId | 基础 chain + 工厂 + 模板 + 版本拼出的最终 chain | 见第 7 节 |
| 业务实例 instanceId | 首次规则成功执行后由 LiteFlowrequestId 建立并持续沿用的 ID |
1b810ee... |
| 固定版本 | 实例绑定后不再改变的规则版本 | 首次绑定的v3 |
| 动作 action | 业务语义上的一个流程操作,映射到一个基础 chain | SUBMIT、APPROVAL |
| 上下文 context | 单次规则执行的业务数据载体 | EmLubricationPlanFlowContext |
| 节点 node | 一个@LiteflowComponent,只负责一条状态迁移 |
lubPlanApprove |
| 定义链 definition chain | 只描述状态顺序、不参与流转、供前端读取的 chain | lubricationPlanDefinition |
| 人工确认节点 | SDK 提供的公共布尔节点,用于 IF 分支 | flowHumanConfirmation |
4. 配置规范¶
4.1 配置位置¶
两处应保持一致。
4.2 完整配置示例¶
bams:
flow:
# bams-flow 模块总开关
enabled: true
# 注册 Warm-Flow 审批流封装服务
warm-flow-enabled: true
# 注册 LiteFlow 规则编排封装服务
lite-flow-enabled: true
# 业务实例 Redis Key 前缀;完整 Key = 前缀 + templateCode + ":" + instanceId
key: 'tpm:liteflow:instance:'
liteflow:
# LiteFlow 引擎开关(由 LiteFlow Starter 读取)
enable: true
rule-db:
# 是否启用 Redis Rule-DB 与数据库多版本发布能力
enabled: true
# 规则应用编码,必须与 sys_liteflow.app_code 一致
application-name: tpm-admin
redis:
address: redis://${spring.data.redis.host}:${spring.data.redis.port:6379}
username: ${spring.data.redis.username:}
password: ${spring.data.redis.password:}
database: ${spring.data.redis.database:0}
key-prefix: bams-liteflow
key-hash-tag: ${LITEFLOW_REDIS_KEY_HASH_TAG:}
sync:
poll-seconds: 3 # 增量变更轮询周期
reconcile-seconds: 60 # 全量校准周期
4.3 配置项说明¶
| 配置项 | 默认值 | 含义 |
|---|---|---|
bams.flow.enabled |
true |
bams-flow 模块总开关,关闭后不注册封装 Bean |
bams.flow.warm-flow-enabled |
true |
是否注册BamsWarmFlowService |
bams.flow.lite-flow-enabled |
true |
是否注册BamsLiteFlowService 及公共人工确认节点 |
bams.flow.key |
bams:liteflow:instance: |
业务实例 Redis Key 前缀 |
liteflow.enable |
LiteFlow 默认 | LiteFlow 引擎开关 |
liteflow.rule-db.enabled |
false |
是否启用 Rule-DB 及数据库多版本能力,必须显式 true |
liteflow.rule-db.application-name |
spring.application.name,兜底 admin |
应用隔离编码,同时用于查询sys_liteflow |
liteflow.rule-db.redis.address |
无 | Redis Publisher 地址 |
liteflow.rule-db.redis.key-prefix |
bams-liteflow |
官方 Rule-DB 规则正文/索引/同步数据 Key 前缀 |
liteflow.rule-db.redis.key-hash-tag |
空 | Redis Cluster 下统一 hash tag |
liteflow.rule-db.sync.poll-seconds |
Provider 默认 | 增量变更轮询周期 |
liteflow.rule-db.sync.reconcile-seconds |
Provider 默认 | 全量校准周期 |
注意:
bams.flow.key(业务实例 Key)与liteflow.rule-db.redis.key-prefix(官方 Rule-DB Key)是两个不同命名空间,不要混淆。Redis 连接参数必须与spring.data.redis.*保持一致。
5. 数据库表结构¶
5.1 sys_liteflow(规则模板表)¶
DDL 由 bams-flow SDK 提供(db/migration/V1.6.0__sys_liteflow.sql、V1.6.1__remove_sys_liteflow_deleted.sql):
| 字段 | 类型 | 说明 |
|---|---|---|
id |
VARCHAR(20) | 主键 |
app_code |
VARCHAR(64) | 规则所属应用编码,与liteflow.rule-db.application-name 一致 |
corp_code |
VARCHAR(32) | 工厂编码 |
template_code |
VARCHAR(64) | 业务规则模板编码 |
version |
VARCHAR(32) | 不可变版本,v[0-9]+ |
xml_content |
TEXT | LiteFlow EL XML 原文 |
status |
VARCHAR(16) | DRAFT / PUBLISHED / ACTIVE / DISABLED |
publisher |
VARCHAR(20) | 发布人 |
created_by / created_time / updated_by / updated_time |
— | 审计字段 |
约束:
UNIQUE KEY (app_code, corp_code, template_code, version)
KEY (app_code, corp_code, template_code, status)
说明:
sys_liteflow已移除deleted逻辑删除字段,生命周期完全由status表达。 同一app_code + corp_code + template_code下同时只有一个ACTIVE版本。
5.2 业务表流程字段¶
以润滑计划 / 润滑工单为例,业务表需要新增:
| 字段 | 含义 |
|---|---|
plan_status / status |
业务状态编码(如0、1、2...) |
instance_id |
LiteFlow 首次执行建立的固定实例 ID |
is_enabled |
(计划)启停标记,1 启用、0 停用 |
corp_code |
工厂编码,用于选择规则模板版本 |
业务状态编码必须集中在状态枚举中,禁止散落字符串。
6. 业务状态枚举规范¶
6.1 润滑计划 EmLubricationPlanStatus¶
| 编码 | 枚举 | 名称 | 说明 |
|---|---|---|---|
0 |
DRAFT |
编制中 | 初始状态,唯一允许编辑 |
1 |
REJECTED |
已驳回 | 审批驳回,允许修改后重新提交 |
2 |
PENDING_APPROVAL |
待审批 | 等待审批 |
3 |
PENDING_DISPATCH |
待派工 | 审批通过后等待派工 |
4 |
EXECUTING |
执行中 | 派工完成 / 直接生效的终态,isEnabled=1 |
5 |
DISABLED |
已停用 | 人工停用(由服务在定义链解析后统一追加) |
6.2 润滑工单 EmLubricationOrderStatus¶
| 编码 | 枚举 | 名称 |
|---|---|---|
0 |
PENDING_CLAIM |
待领取 |
1 |
PENDING_LUBRICATION |
待润滑 |
2 |
LUBRICATING |
润滑中 |
3 |
PENDING_ACCEPTANCE |
待验收 |
4 |
COMPLETED |
已完成 |
6.3 枚举编写规范¶
- 每个状态枚举同时定义
code(数据库值)与displayName(中文名称)。 - 提供
fromCode(String)统一解析,非法编码抛IllegalArgumentException。 - 禁止在业务代码中直接写状态字符串或数字。
7. 版本化 Chain ID 规则¶
版本化 chain ID 由 BamsLiteFlowTemplateService.versionedChain(...) 生成,分隔符固定为 双下划线 __(Redis Rule-DB 禁止冒号和空白)。
7.1 生成规则¶
| 场景 | 结果格式 | 示例 |
|---|---|---|
| 完整作用域 | baseChainId__corpCode__templateCode__version |
lubricationPlanCreate__120101__lubrication-plan__v3 |
无templateCode(历史实例) |
baseChainId__version |
lubricationPlanCreate__v3 |
无corpCode(历史实例) |
baseChainId__templateCode__version |
lubricationPlanCreate__lubrication-plan__v3 |
version = legacy(XML 配置模式) |
baseChainId |
lubricationPlanCreate |
7.2 校验规则¶
version必须匹配v[0-9]+。corpCode/templateCode/baseChainId只能包含[A-Za-z0-9_.-]+(不能有冒号、空白)。- 业务代码和 XML 只使用基础 chain 名,禁止手工拼接版本化 chain ID,统一由 SDK 生成。
8. 规则执行核心流程(模板方法)¶
SDK 的 BamsVersionedLiteFlowExecutorImpl.execute(...) 固定执行:
- 解析版本:无
instanceId→ 取currentVersion(ACTIVE);有instanceId→ 从 Redis 实例恢复固定版本并校验归属。 - 生成版本化 chain 并查找;不存在时:
optionalChain=true→ 返回executed=false;- 否则抛
IllegalStateException。 - 执行 chain,校验引擎
isSuccess与requestId。 - 建立实例:首次用
requestId作为instanceId,后续沿用原实例,返回BamsVersionedFlowResult。
业务侧 AbstractVersionedRuleFlowService(tpm-backend)以模板方法固定调用顺序:
构造 BamsVersionedFlowRequest
→ executor.execute(request, context)
→ 若 executed=false → handleUnexecutedRule(...) (仅可选链进入)
→ validateExecutionResult(...) (业务结果校验)
→ persistExecutionResult(...) (原子落库)
→ flowInstanceRepository.save(execution.instance())(保存固定版本实例)
→ afterExecution(...) (领域日志)
抽象方法 / 可覆盖钩子:
| 方法 | 必填 | 职责 |
|---|---|---|
getBusinessId(E) |
是 | 业务主键 |
getFlowInstanceId(E) |
是 | 已绑定实例 ID,首次为 null |
getCorpCode(E) |
是 | 工厂编码 |
getTemplateCode() |
是 | 模板编码 |
getChainId(A) |
是 | 动作 → 基础 chain |
getActionDisplayName(A) |
是 | 动作中文名(日志/异常) |
validateExecutionResult(...) |
是 | 校验节点是否产生合法状态变化 |
persistExecutionResult(...) |
是 | 带原状态条件原子落库 |
isOptionalChain(A) |
否 | 默认false |
handleUnexecutedRule(...) |
否 | 默认抛异常 |
afterExecution(...) |
否 | 默认空实现 |
9. 业务 FlowService 编写规范¶
每个接入 LiteFlow 的业务需要提供一个 FlowService,继承 AbstractVersionedRuleFlowService<E, C, A>。
9.1 结构模板¶
@Slf4j
@Service
public class XxxFlowService extends AbstractVersionedRuleFlowService<
XxxEntity, XxxFlowContext, XxxFlowAction> {
// 仅注入领域服务,公共执行器/实例仓库通过 super 传入
public XxxFlowService(
BamsVersionedLiteFlowExecutor versionedFlowExecutor,
BamsLiteFlowInstanceRepository flowInstanceRepository,
XxxService xxxService) {
super(versionedFlowExecutor, flowInstanceRepository);
this.xxxService = xxxService;
}
@Transactional(rollbackFor = Exception.class)
public XxxEntity execute(String id, XxxFlowAction action, Boolean input) {
validateRequest(id, action, input);
XxxEntity entity = loadRequiredEntity(id);
XxxFlowContext context = createContext(entity, input);
return executeVersionedRule(entity, action, context);
}
// ...实现抽象方法
}
9.2 规范要点¶
- 入口方法必须
@Transactional(rollbackFor = Exception.class),保证状态落库与子表业务在同一事务。 - 以数据库快照为准:执行前重新
getById,禁止使用请求体中可被篡改的字段判断流程。 - 动作入参显式传递:审批结果、派工人员等通过命令对象或明确参数传入,禁止
Consumer<Context>隐式修改上下文。 - 工厂编码必须来自数据库快照或登录会话,不能由请求体任意指定。
- 原状态作为并发更新条件,更新失败抛「状态已被其他请求修改」。
- 领域日志统一记录
businessId / instanceId / action / 原状态 -> 目标状态。 - 新建后 chain 若允许省略,重写
isOptionalChain返回true,并重写handleUnexecutedRule给出明确语义(如保持原状态)。
10. 动作枚举规范¶
动作枚举同时定义基础 chain ID 与中文名称:
@Getter
public enum XxxFlowAction {
CREATE("xxxCreate", "创建"),
SUBMIT("xxxSubmit", "提交"),
APPROVAL("xxxApproval", "审批");
// ...
}
- 一个动作对应一个基础 chain。
- 审批通过 / 驳回是同一动作的不同结果分支,通过上下文人工结果区分,不拆成两个动作。
- 动作名称用于日志和异常提示,保持中文可读。
10.1 现有动作映射¶
润滑计划 EmLubricationPlanFlowAction
| 动作 | 基础 chain | 是否可选 |
|---|---|---|
CREATE |
lubricationPlanCreate |
是(未配置保持编制中) |
SUBMIT |
lubricationPlanSubmit |
否 |
APPROVAL |
lubricationPlanApproval |
否 |
COMPLETE_DISPATCH |
lubricationPlanCompleteDispatch |
否 |
润滑工单 EmLubricationOrderFlowAction
| 动作 | 基础 chain |
|---|---|
CREATE |
lubricationOrderCreate |
CLAIM |
lubricationOrderClaim |
SAVE |
lubricationOrderSave |
SUBMIT |
lubricationOrderSubmit |
ACCEPTANCE |
lubricationOrderAcceptance |
11. 上下文(Context)编写规范¶
上下文是一次规则执行的业务数据载体,同时是并发控制与人工确认的契约。
11.1 规范要点¶
- 使用
@Data(Lombok),按领域独立建模。 - 需要人工确认(审批/验收/派工)的上下文实现 SDK 接口
BamsHumanConfirmationContext,提供getHumanConfirmed()。 - 固定携带:
- 业务主键(
planId/orderId) corpCodeoriginalStatus(执行前数据库状态,作为并发条件)currentStatus(节点在内存中逐步推进的状态)humanConfirmed(人工结果,true/false已处理,null等待)- 提供
transition(expectedStatus, targetStatus)执行受约束的状态迁移,当前状态不符时抛IllegalStateException,节点只能通过它推进状态,禁止直接setCurrentStatus绕过校验 (除非是 CREATE 起点等确需显式声明的场景)。 - 节点需要额外持久化业务字段时,通过变更意图标志表达(如
planEnableRequested、lubricationUsersUpdateRequested),由事务服务统一应用,节点不直接操作数据库。
11.2 示例(润滑计划上下文)¶
@Data
public class EmLubricationPlanFlowContext implements BamsHumanConfirmationContext {
private String planId;
private String corpCode;
private Boolean humanConfirmed;
private EmLubricationPlanStatus originalStatus;
private EmLubricationPlanStatus currentStatus;
private String lubricationUserIds;
private String lubricationUserNames;
private boolean lubricationUsersUpdateRequested;
private boolean planEnableRequested;
public void transition(EmLubricationPlanStatus expected, EmLubricationPlanStatus target) {
if (currentStatus != expected) {
throw new IllegalStateException("...当前为“" + currentStatus.getDisplayName()
+ "”,不能执行要求“" + expected.getDisplayName() + "”状态的规则");
}
currentStatus = target;
}
public void requestPlanEnable() { this.planEnableRequested = true; }
public void requestLubricationUsersUpdate() { this.lubricationUsersUpdateRequested = true; }
// prepareDispatch(...) 供派工入口设置输入并置 humanConfirmed=true
}
12. 节点(Node)编写规范¶
12.1 节点基类¶
每个业务提供一个节点基类,向 SDK 声明上下文类型:
public abstract class XxxFlowNodeSupport extends BamsTypedNodeComponent<XxxFlowContext> {
protected XxxFlowNodeSupport() {
super(XxxFlowContext.class);
}
}
SDK 的 BamsTypedNodeComponent<C> 统一完成 getRequestData() 空值与类型校验, 业务节点通过 context() 获取类型安全的上下文。
12.2 节点类规范¶
- 使用
@LiteflowComponent(value = "...", name = "中文名")声明稳定且唯一的组件 ID。 - 一个节点只描述一条状态边(一个
transition)。 - 重写
process()只做「读取输入 → 校验前置状态 → 迁移状态 → 输出变更意图」, 禁止在节点内直接读写数据库。 - 需要人工判断时,业务 XML 使用 SDK 公共节点
flowHumanConfirmation,不重复声明。
12.3 现有节点组件 ID 清单¶
润滑计划
| 组件 ID | 迁移 |
|---|---|
lubPlanSubmitEffective |
DRAFT -> EXECUTING,requestPlanEnable |
lubPlanSubmitForApproval |
DRAFT -> PENDING_APPROVAL 或 REJECTED -> PENDING_APPROVAL |
lubPlanApprove |
PENDING_APPROVAL -> PENDING_DISPATCH |
lubPlanReject |
PENDING_APPROVAL -> REJECTED |
lubPlanCompleteDispatch |
PENDING_DISPATCH -> EXECUTING,校验人员并 requestLubricationUsersUpdate + requestPlanEnable |
润滑工单
| 组件 ID | 迁移 |
|---|---|
lubOrderCreateAssigned |
PENDING_CLAIM -> PENDING_LUBRICATION |
lubOrderCreatePendingClaim |
声明PENDING_CLAIM(创建初始态) |
lubOrderClaim |
PENDING_CLAIM -> PENDING_LUBRICATION |
lubOrderStart |
PENDING_LUBRICATION -> LUBRICATING |
lubOrderSubmit |
LUBRICATING -> PENDING_ACCEPTANCE |
lubOrderAccept |
PENDING_ACCEPTANCE -> COMPLETED |
lubOrderRejectAcceptance |
PENDING_ACCEPTANCE -> LUBRICATING |
SDK 公共节点
| 组件 ID | 类型 | 说明 |
|---|---|---|
flowHumanConfirmation |
布尔节点 | 读取BamsHumanConfirmationContext.getHumanConfirmed(),用于 IF 分支 |
13. 规则 XML 编写规范¶
13.1 XML 位置与性质¶
这些文件是规则源模板,不是线上运行时规则。运行时以 sys_liteflow.xml_content 中当前工厂的 ACTIVE 版本为准,通过 SDK 发布服务写入数据库并发布到 Redis Rule-DB。
13.2 定义链(必需)¶
每个版本必须声明一个定义链,只描述状态展示顺序,不参与业务流转:
<chain name="lubricationPlanDefinition">
THEN(
lubPlanReject.data('{"statusCode":"1"}'),
lubPlanSubmitForApproval.data('{"statusCode":"2"}'),
lubPlanApprove.data('{"statusCode":"3"}'),
lubPlanCompleteDispatch.data('{"statusCode":"4"}')
);
</chain>
要求:
- 字段名必须是
statusCode。 - 值必须是状态枚举支持的编码。
- 顺序必须与实际业务流转一致。
- 服务自动在首位追加初始状态(如
DRAFT),并在末尾追加公共状态(如DISABLED), 定义链只配置业务中间/终态。 - 定义链至少包含一个非初始状态节点。
13.3 动作链¶
<chain name="lubricationPlanCreate">
THEN(lubPlanSubmitForApproval);
</chain>
<chain name="lubricationPlanApproval">
IF(flowHumanConfirmation, lubPlanApprove, lubPlanReject);
</chain>
- 动作链名使用基础 chain ID。
- 人工确认用
IF(flowHumanConfirmation, 通过节点, 驳回节点)。 flowHumanConfirmation为true走成功分支,false走 ELSE 分支,null会抛异常 (表示尚未获得人工结果)。CREATEchain 可省略;其余动作 chain 缺失时执行器直接报错。
13.4 XML 示例:润滑工单(派工审批型)¶
<flow>
<chain name="lubricationOrderDefinition">
THEN(
lubOrderCreateAssigned.data('{"statusCode":"1"}'),
lubOrderStart.data('{"statusCode":"2"}'),
lubOrderSubmit.data('{"statusCode":"3"}'),
lubOrderAccept.data('{"statusCode":"4"}')
);
</chain>
<chain name="lubricationOrderCreate">
THEN(lubOrderCreateAssigned);
</chain>
<chain name="lubricationOrderSave">
THEN(lubOrderStart);
</chain>
<chain name="lubricationOrderSubmit">
THEN(lubOrderSubmit);
</chain>
<chain name="lubricationOrderAcceptance">
IF(flowHumanConfirmation, lubOrderAccept, lubOrderRejectAcceptance);
</chain>
</flow>
14. 规则发布与版本管理规范¶
14.1 运行时规则来源¶
运行时按以下条件从 sys_liteflow 读取当前激活版本:
app_code = liteflow.rule-db.application-name
corp_code = 当前工厂
template_code = 业务模板编码
status = ACTIVE
14.2 SDK 发布服务¶
BamsLiteFlowRulePublisherService rulePublisher; // 发布
BamsLiteFlowActiveTemplateService activeTemplate; // 激活/查询
核心方法:
| 方法 | 说明 |
|---|---|
publishXml(corpCode, templateCode, version, xmlContent) |
解析 XML 并逐条 chain 发布到 Rule-DB |
publishXml(appName, corpCode, templateCode, version, xmlContent) |
指定应用作用域发布 |
hasActiveVersion(corpCode, templateCode) |
是否存在 ACTIVE 版本 |
activateVersion(corpCode, templateCode, version) |
激活指定版本 |
findActive / requiredActive |
查询 ACTIVE 模板 |
14.3 发布与激活流程¶
- 选择目标工厂
corpCode与模板templateCode。 - 确定新的不可变版本
version(如v4),不要覆盖已有版本内容。 publishXml(...)发布 XML;每条 chain 以expectedVersion=0发布,Redis 已存在同 ID 时 官方 Lua 原子拒绝,从而保证版本不可变。activateVersion(...)激活:将目标版本置为ACTIVE,同时把同一作用域旧ACTIVE降级为PUBLISHED(事务内完成)。- 等待至少一个轮询周期(当前
poll-seconds=3秒)。 - 通过查询接口 / SQL 核对 ACTIVE 版本,再新建测试数据验证真实动作链。
14.4 版本切换约束¶
- 只有尚未建立实例的新业务绑定新 ACTIVE 版本。
- 已有
instanceId的业务必须继续使用原版本,避免流程中途规则变化。 - 禁止普通 SQL 直接覆盖历史版本
xml_content,会破坏版本不可变约束。
14.5 只读核对 SQL¶
SELECT app_code, corp_code, template_code, version, status
FROM sys_liteflow
WHERE app_code = 'tpm-admin'
AND corp_code = '120101'
AND template_code = 'lubrication-plan'
ORDER BY version DESC;
15. 事务、并发与 Redis 实例¶
15.1 事务与原子落库¶
- 保存主表、子表与 CREATE 规则处于同一 Spring 事务调用链。
- 持久化使用原状态作为更新条件:
UPDATE em_lubrication_plan
SET plan_status = :targetStatus, instance_id = :instanceId, ...
WHERE id = :planId AND plan_status = :originalStatus;
- 更新行数为 0 时抛「状态已被其他请求修改,请刷新后重试」,实现乐观并发控制。
- 先更新数据库、再写 Redis;Redis 写失败会触发数据库事务回滚。
15.2 Redis 业务实例¶
首次规则成功后,业务表保存 instance_id,同时 Redis 写入:
示例:
值为 JSON:
{
"instanceId": "1b810ee1492a4db1b2fa1291f2134bec",
"applicationName": "tpm-admin",
"id": "2086710739068497921",
"corpCode": "120101",
"templateCode": "lubrication-plan",
"version": "v3"
}
后续动作会校验 id、corpCode、templateCode、version 归属。Redis 数据丢失或归属不一致时 服务拒绝流转,不会自动切换到工厂最新版本。
因此以下运维动作必须将实例 Key 空间作为业务数据处理:
- Redis 清库或迁移;
- Redis database 切换;
bams.flow.key前缀变更;- 跨环境复制业务数据。
16. 现有业务示例对照¶
16.1 润滑计划(审批型)¶
创建 → DRAFT -> PENDING_APPROVAL
审批通过 → PENDING_APPROVAL -> PENDING_DISPATCH
审批驳回 → PENDING_APPROVAL -> REJECTED
派工完成 → PENDING_DISPATCH -> EXECUTING(isEnabled=1)
16.2 润滑计划(direct 型)¶
16.3 润滑工单(派工审批型)¶
创建 → PENDING_LUBRICATION
首次保存 → PENDING_LUBRICATION -> LUBRICATING
提交 → LUBRICATING -> PENDING_ACCEPTANCE
验收通过 → PENDING_ACCEPTANCE -> COMPLETED
验收不通过 → PENDING_ACCEPTANCE -> LUBRICATING
16.4 润滑工单(领取直办型)¶
创建 → PENDING_CLAIM
领取 → PENDING_CLAIM -> PENDING_LUBRICATION
首次保存 → PENDING_LUBRICATION -> LUBRICATING
提交 → LUBRICATING -> PENDING_ACCEPTANCE
验收通过/不通过 → 同派工审批型
17. API 接口清单¶
统一网关前缀 /tpm-api。
17.1 润滑计划 /em/EmLubricationPlan¶
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /flow/current-rule-nodes |
查询当前工厂规则节点 |
| POST | /flow/submit |
提交审批 |
| POST | /flow/approval |
审批结果(工作流待接入) |
| POST | /flow/complete-dispatch |
派工完成 |
| POST | /saveOrUpdateWithDetails |
新增/修改(新建触发 CREATE) |
| POST | /getDetailById |
详情查询 |
| POST | /batchEnable / /batchDisable |
启停 |
17.2 润滑工单 /em/EmLubricationOrder¶
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /flow/claim |
领取工单(当前登录人) |
| POST | /flow/submit |
提交验收 |
| POST | /flow/acceptanceInfo |
提交验收信息 |
| POST | /saveOrUpdateWithDetails |
新增/修改(新建触发 CREATE,待润滑触发 SAVE) |
| POST | /getDetailById |
详情查询 |
18. 开发约束与反模式¶
18.1 新增业务接入 LiteFlow 的步骤¶
- 定义状态枚举(
code+displayName+fromCode)。 - 定义动作枚举(基础 chain + 中文名)。
- 定义流程常量类(
TEMPLATE_CODE、DEFINITION_CHAIN、STATUS_CODE_FIELD)。 - 定义上下文(实现
BamsHumanConfirmationContext,含originalStatus/currentStatus/transition)。 - 编写节点基类与各单一状态迁移节点。
- 编写 FlowService 继承
AbstractVersionedRuleFlowService,实现动作映射、结果校验、原子落库。 - 编写 XML(定义链 + 动作链),作为规则源模板。
- 通过 SDK 发布服务发布并激活版本。
- 控制器只做参数校验并转发 FlowService,不在控制器里拼流程逻辑。
18.2 反模式(禁止)¶
- 禁止在业务代码或 XML 中手工拼接版本化 chain ID。
- 禁止在节点内直接读写数据库。
- 禁止使用
Consumer<Context>隐式修改上下文。 - 禁止重新引入
ruleVersion字段形成重复状态源(实例已保存版本)。 - 禁止通过普通 SQL 覆盖历史版本
xml_content。 - 禁止用请求体字段决定工厂或流程状态,工厂必须来自会话/数据库快照。
- 禁止把「保存/提交」等两个动作塞进一个接口的
saveFlag隐式推进。 - 禁止为 direct 规则配置无业务意义的「跳过审批/派工」中间节点。
19. 故障排查¶
| 现象 | 主要原因 | 处理 |
|---|---|---|
| 规则执行后状态未落库 | 节点未迁移状态,或 chain 与当前状态不符 | 检查 XML chain 与节点前置状态 |
| 提示「状态已被其他请求修改」 | 并发已先变更状态 | 刷新详情后重试,不要重放旧状态 |
| 提示「规则未产生状态变化」 | 节点没有调用transition |
检查节点逻辑 |
| 提示「LiteFlow 业务实例不存在」 | Redis Key 丢失、前缀或 database 变更 | 核对instance_id、bams.flow.key 与 Redis |
| 提示「归属不一致」 | 计划/工单与实例的工厂、模板、主键不一致 | 核对数据迁移与复制 |
| 修改 XML 后行为未变 | 只改了 resources,未发布 ACTIVE | 发布新版本并等待轮询 |
| 当前规则节点返回旧版本 | ACTIVE 指针、appCode、corpCode 不匹配 | 核对sys_liteflow 与配置 |
提示缺少statusCode |
定义链节点缺少data 或 JSON 非法 |
为每个定义节点配置合法{"statusCode":"..."} |
| 更新后子项消失 | 全量同步被当成增量 | 查询详情后回传全部需保留子项 |
20. 附录:关键类速查¶
SDK 关键类¶
| 类 | 作用 |
|---|---|
BamsVersionedLiteFlowExecutor |
版本化规则执行入口 |
BamsVersionedFlowRequest / BamsVersionedFlowResult |
请求/结果不可变模型 |
BamsLiteFlowTemplateService |
currentVersion / versionedChain |
BamsLiteFlowChainService |
chain 查找 + Rule-DB 候选加载 |
BamsLiteFlowInstanceRepository |
固定版本实例 SPI(默认 Redis) |
BamsLiteFlowRulePublisherService |
数据库 XML 发布 / 激活 |
BamsLiteFlowActiveTemplateService |
ACTIVE 查询 / 版本激活 |
BamsTypedNodeComponent<C> |
类型安全节点基类 |
BamsHumanConfirmationContext / BamsHumanConfirmationNode |
人工确认契约与公共节点 |
业务关键类¶
| 类 | 作用 |
|---|---|
AbstractVersionedRuleFlowService<E, C, A> |
版本化规则调用模板方法 |
XxxFlowAction |
动作 → 基础 chain 映射 |
XxxFlowCommand |
不可变执行命令 |
XxxFlowContext |
单次规则执行上下文 |
XxxFlowNodeSupport |
业务节点基类 |
XxxFlowService |
业务规则编排服务 |
常量与命名¶
| 项 | 约定 |
|---|---|
| 模板编码 | 小写短横线,如lubrication-plan |
| 定义链 | 业务名 +Definition,如 lubricationPlanDefinition |
| 状态字段 | statusCode |
| 版本 | v[0-9]+ |
| chain 分隔符 | __(双下划线) |
| 实例 Key | {bams.flow.key}{templateCode}:{instanceId} |