一、流程模型的核心概念

一个工作流由「流程定义」和「流程实例」组成。定义是模板,实例是某次具体执行。

概念说明
流程定义(Process)包含节点、连线、条件规则的静态模板
流程实例(Instance)基于定义创建的某次运行,含当前状态
节点(Node)流程中的步骤,如审批、抄送、条件判断
流转(Transition)节点之间的有向连接,可附带条件表达式
任务(Task)分配给具体用户或角色的待办事项

二、数据库表结构设计

采用「定义-实例-任务」三层模型,支持版本管理与流程历史追溯。

workflow_schema.sql
/* 流程定义 */
CREATE TABLE wf_process (
    id          BIGINT PRIMARY KEY,
    key         VARCHAR(64) NOT NULL,   /* 业务标识,如 "leave_approval" */
    name        VARCHAR(128),
    version     INT DEFAULT 1,
    definition  JSON NOT NULL,        /* 节点与连线的 JSON 描述 */
    is_active   BOOLEAN DEFAULT TRUE,
    created_at  DATETIME
);

/* 流程实例 */
CREATE TABLE wf_instance (
    id           BIGINT PRIMARY KEY,
    process_id   BIGINT NOT NULL,
    business_key VARCHAR(64),        /* 关联业务表主键 */
    status       VARCHAR(20),        /* RUNNING / COMPLETED / REJECTED */
    current_node VARCHAR(64),        /* 当前节点 ID */
    variables    JSON,               /* 流程变量,如 {"amount": 5000} */
    started_at   DATETIME,
    ended_at     DATETIME
);

/* 审批任务 */
CREATE TABLE wf_task (
    id          BIGINT PRIMARY KEY,
    instance_id BIGINT NOT NULL,
    node_id     VARCHAR(64) NOT NULL,
    assignee    BIGINT,              /* 具体处理人 */
    candidate_role BIGINT,           /* 候选角色(会签/或签) */
    action      VARCHAR(20),       /* APPROVE / REJECT / TRANSFER */
    comment     TEXT,
    created_at  DATETIME,
    completed_at DATETIME
);

三、节点类型与状态机驱动

每种节点类型对应一个处理器,核心逻辑是「接收事件 → 更新状态 → 计算下一个节点」。

workflow_engine.java(伪代码)
public interface NodeHandler {
    List<String> execute(WfInstance instance, WfNode node, ActionRequest req);
}

/* 审批节点:根据或签/会签策略决定流转 */
public class ApproveHandler implements NodeHandler {
    public List<String> execute(WfInstance inst, WfNode node, ActionRequest req) {
        if (node.getStrategy() == Strategy.ANY) {       /* 或签:一人通过即过 */
            return List.of(node.getNextNodeId(req.getAction()));
        } else if (node.getStrategy() == Strategy.ALL) { /* 会签:全部通过才过 */
            int total = taskService.countPending(inst.getId(), node.getId());
            if (total == 1) {  /* 最后一个审批人 */
                return List.of(node.getNextNodeId("APPROVE"));
            }
            return List.of();  /* 继续等待其他人 */
        }
        /* 依次审批:按预设顺序触发下一个处理人 */
        String nextAssignee = node.getNextAssignee(inst);
        taskService.createTask(inst.getId(), node.getId(), nextAssignee);
        return List.of();
    }
}

四、条件分支与表达式引擎

流程连线可附带条件,如「金额 > 5000 走经理审批,否则走自动审批」。使用轻量级表达式引擎(如 Aviator、QLExpress 或自研)解析。

condition.json(流程定义片段)
{
  "transitions": [
    {
      "from": "submit",
      "to": "manager_approve",
      "condition": "${amount > 5000 || days > 3}"
    },
    {
      "from": "submit",
      "to": "auto_approve",
      "condition": "${amount <= 5000 && days <= 3}"
    }
  ]
}
安全提示: 表达式引擎必须做沙箱隔离,禁止调用 System.exit、文件 IO 等危险操作。建议白名单化可用函数与变量。

五、自动化动作:审批后的连锁反应

流程节点可配置「通过后自动执行」的动作,如发送通知、更新业务状态、调用外部 API。

auto_action.java(伪代码)
public interface AutoAction {
    void run(WfInstance instance, Map<String, Object> params);
}

/* 实现示例 */
public class SendNotificationAction implements AutoAction {
    public void run(WfInstance inst, Map<String, Object> p) {
        String tmpl = (String) p.get("template");
        Long userId = (Long) p.get("toUser");
        notifyService.send(userId, render(tmpl, inst.getVariables()));
    }
}

六、版本管理与流程迁移

已发布的流程定义不应直接修改,而是创建新版本。运行中的实例继续使用旧版本,新实例使用最新版本。这样可避免正在审批的流程因规则变更而异常中断。

七、总结

工作流引擎的设计要点:状态机驱动保证流转确定性,节点策略支持或签/会签/依次审批,条件表达式实现灵活分支,自动化动作打通业务系统,版本管理保障运行稳定性。这些机制组合在一起,才能支撑企业复杂的业务流程需求。