Files
ordo/README.md
T
0264408andCursor 8d08a2840b docs: sync package layout and REST with current API
Host examples and README still described the pre-split packages and omitted optional REST.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 11:45:23 +08:00

7.2 KiB
Raw Blame History

Ordo

轻量审批流程引擎。宿主通过 OrdoEngine 注册流程定义、发起实例、审批/驳回/转派/撤回/取消,并查询任务、实例与审计历史。引擎不绑定业务表单、用户体系或设计器 UI。可选 REST(ordo.rest.enabled)。业务数据放在 ProcessContext 里。

要求 Java 17+。当前版本 0.0.1-SNAPSHOT。

模块

模块 作用
ordo-api 公共模型与 OrdoEngine 端口
ordo-core 运行时(DefaultOrdoEngine / InMemoryOrdoEngine)
ordo-storage-jdbc JDBC 存储 + 按方言 Flyway 基线(PostgreSQL / MySQL)
ordo-spring-boot-starter Spring Boot 自动装配(JDBC + Flyway)
ordo-example 内存引擎示例

存储实现通过 dialect 层支持 PostgreSQL 与 MySQL(测试可用 H2 PostgreSQL 兼容模式)。Starter 不携带 JDBC 驱动,宿主自行加入 postgresql、mysql-connector-j 或 h2。Spring Boot 4 还需额外引入 spring-boot-starter-flyway,否则迁移不会跑。

能力

  • 线性或多步图:StepTransition + 内置谓词 / 宿主 RoutingCondition
  • 会签/或签:ApprovalPolicy.ALL / ANY(多候选人)
  • 结构化并行:kind: PARALLEL 块(一层、join ALL)
  • ACTION 步骤:事务提交后调用宿主 ActionHandler(可经 NamedAction 分发)
  • 发起人撤回:WITHDRAWN,待办任务 SKIPPED
  • 管理员/系统取消:cancel → CANCELLED,待办任务 SKIPPED(引擎不鉴权角色)
  • 任务转派:当前办理人 reassign,审计 TASK_REASSIGNED
  • 到期升级:步骤 due + processDue,审计 TASK_ESCALATED
  • 分页查询:任务 / 实例 / 流程定义
  • 审计时间线:ProcessEvent + queryHistory
  • 扩展点:AssigneeResolver、RoutingCondition、ActionHandler、NamedCondition、NamedAction、OrdoEventListener

开发计划:独立设计器(不进本仓库)。多租户 暂不在计划中。见 docs/roadmap.md。

详细用法(定义 JSON、扩展点、异常、查询、ACTION/审计语义)见 docs/usage.md。对外行为变更时同步更新该文档。

内存快速开始

<dependency>
    <groupId>com.jetlumen</groupId>
    <artifactId>ordo-core</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>
import com.jetlumen.ordo.api.OrdoEngine;
import com.jetlumen.ordo.api.definition.ApprovalStep;
import com.jetlumen.ordo.api.definition.ProcessDefinition;
import com.jetlumen.ordo.api.runtime.ProcessContext;
import com.jetlumen.ordo.core.InMemoryOrdoEngine;

OrdoEngine ordo = new InMemoryOrdoEngine();
ordo.publish(ProcessDefinition.linear("leave-request", "Leave request", List.of(
        ApprovalStep.single("manager", "Manager approval", "maria"),
        ApprovalStep.single("hr", "HR approval", "henry")
)));

ProcessInstance instance = ordo.start("leave-request", "alice",
        new ProcessContext(Map.of("requestId", "LEAVE-2026-001")));
ApprovalTask manager = ordo.findPendingTasksByInstanceId(instance.id()).get(0);
ordo.approve(manager.id(), "maria", "ok");

完整示例:ordo-example 的 LeaveRequestExample。

JSON 流程定义

{
  "id": "leave-request-routed",
  "name": "Leave request",
  "steps": [
    { "id": "notify-submitted", "name": "Notify submitted", "kind": "ACTION", "action": "leave-submitted-mail" },
    { "id": "manager", "name": "Manager approval", "candidates": ["maria"], "policy": "ANY" },
    { "id": "hr", "name": "HR approval", "candidates": ["henry"], "policy": "ANY" },
    { "id": "notify-approved", "name": "Notify approved", "kind": "ACTION", "action": "leave-approved-mail" }
  ],
  "transitions": [
    { "from": "notify-submitted", "to": "manager" },
    { "from": "manager", "to": "hr", "when": { "gt": ["days", 3] }, "priority": 0 },
    { "from": "manager", "to": "notify-approved", "priority": 1 },
    { "from": "hr", "to": "notify-approved" },
    { "from": "notify-approved", "to": null }
  ]
}
  • kind 默认 APPROVAL;ACTION 用 "action" 作为 handler 查找键;PARALLEL 用 branches(结构化并行块,见 docs/usage.md)。
  • 带 when 的边先按 priority 匹配,都未命中再走无条件边;to: null 表示结束。
  • 代码侧可用 ProcessDefinitionParser.fromJson(...)(com.jetlumen.ordo.api.definition)。

Spring Boot

<dependency>
    <groupId>com.jetlumen</groupId>
    <artifactId>ordo-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

需要 DataSource。存在 DataSource 且 ordo.enabled 不为 false 时装配 JDBC 引擎。REST 另需宿主的 Web starter,且 ordo.rest.enabled=true。

ordo:
  enabled: true
  jdbc:
    dialect:     # 可选 postgresql / mysql;空则按 DataSource 探测
  definitions:
    location: classpath*:ordo/*.json   # 默认值;启动时 publish 加载
  due:
    poll-ms: 0   # >0 时轮询 processDue
  rest:
    enabled: false
    base-path: /ordo

宿主提供 Bean 即可覆盖默认值:

Bean 默认
AssigneeResolver 候选人即办理人
NamedCondition / NamedAction 可多个;无对应门面时按 key 分发
RoutingCondition 无具名 condition 时始终匹配;有则未知 ref 为 false
ActionHandler 无具名 action 时空操作;有则未知 key 抛错
OrdoCatalog REST 打开时从 Named* 投影;assignees 空
OrdoEventListener 可注册多个,提交后按顺序调用

运行时约定

办理人 必须等于任务 assignee,否则 UnauthorizedTaskOperationException(approve / reject / reassign)。
转派 只改 PENDING 任务的 assignee,不推进步骤。
撤回 仅发起人可操作,且实例须为 RUNNING。
取消 cancel 任意非空 actor,实例须为 RUNNING;谁能调用由宿主决定。

实例状态:RUNNING / APPROVED / REJECTED / WITHDRAWN / CANCELLED。
任务状态:PENDING / APPROVED / REJECTED / SKIPPED。

ACTION 在审批事务提交之后执行。失败只记 FAILED、打日志、发 ACTION_FAILED,不回滚已生效审批、不阻塞后续步骤。可重试策略留给宿主(listener 或 queryActionExecutions)。

历史 queryHistory(instanceId, page) 按时间升序。事件类型包括实例起止、任务创建/审批/跳过/转派、ACTION 成败。
OrdoEventListener.onEvent 在提交后派发;单个 listener 抛错不影响流程和其他 listener。

查询

ordo.queryTasks(TaskQuery.any().withAssignee("maria").withStatus(TaskStatus.PENDING),
        PageRequest.of(0, 20));
ordo.queryInstances(InstanceQuery.any().withInitiator("alice"), PageRequest.of(0, 20));
ordo.queryDefinitions(PageRequest.of(0, 20));
ordo.queryHistory(instanceId, PageRequest.of(0, 50));
ordo.queryActionExecutions(instanceId, PageRequest.of(0, 20));

任务/实例列表默认最新优先;历史与 ACTION 执行记录按发生时间升序。

构建

mvn -pl ordo-api,ordo-core,ordo-storage-jdbc,ordo-spring-boot-autoconfigure,ordo-spring-boot-starter install

先 install 再给外部工程(如宿主应用)引用。