工作流 Flowable 全流程


一,管理员创建流程分类

在正式设计复杂的业务流程之前,我们需要先为它们建立一个"文件夹体系"。流程分类(Category)的作用就是对不同业务域(如人事、财务、行政)的流程进行逻辑隔离与归纳。

1. 业务交互流程

这一步是整个 BPM 系统的入口。管理员的操作路径非常直观:

  • 操作入口:登录后台管理系统,进入【工作流】->【流程分类】菜单。
  • 输入信息:点击"新增"按钮,填写分类的基础元数据。
  • 分类名称 (name) :展示给用户看的名字,例如 Test03(或"人事考勤")。
  • 分类编码 (code) :系统内部识别的唯一标识,例如 Test03(或 hr_attendance)。
  • 排序 (sort) :决定该分类在列表中的显示顺序,例如 3
2. 前后端数据流转

当管理员点击"确定"后,数据在系统内部经历了一次标准的 CRUD:

  • 前端请求 (Request)
    前端封装表单数据,发起 POST 请求至 /bpm/category/create 接口。
json 复制代码
// 请求载荷示例
{
  "name": "Test03",
  "code": "Test03",
  "sort": 3
}
  • 后端处理 (Processing)

    Controller 层接收请求后,下沉至 Service 层进行核心校验。

  • 唯一性检查 :这是最关键的业务规则。系统会查询 bpm_category 表,确保传入的 namecode 在全表中是唯一的。如果已存在,直接抛出异常,防止数据冲突。

  • 持久化:校验通过后,后端将数据封装为 Entity 对象。

  • 数据库落地 (Database)

    最终,一条新的记录被插入到业务表 bpm_category 中。

注意 :bpm_category是 业务扩展表,而非 Flowable 的原生表。Flowable 虽然也有 Category 字段,但为了实现更复杂的层级管理和元数据控制,我们通常维护一张独立的分类表。


二,管理员创建流程表单

在定义了流程分类后,下一步是构建流程流转中承载数据的容器------流程表单。本环节通过低代码形式,将业务需求转化为系统可识别的数据结构。

1. 可视化表单设计

管理员进入后台管理系统,通过内置的表单设计器进行可视化配置。在此场景中,管理员创建了一个名为"请假表单"的业务单据,并拖拽配置了两个核心组件:

  • 请假原因:单行文本输入框。
  • 请假时间 :单行文本输入框(用于输入具体天数)。
    完成布局与属性配置后,点击保存触发提交。
2. 前后端交互协议

前端将可视化的配置结果转化为 JSON 数据结构,并通过 POST 请求发送至 /bpm/form/create 接口。请求载荷包含三个核心参数:

  • name (表单名称)

    标识表单的业务名称,此处为 "请假表单"

  • conf (全局配置)

    定义表单的整体样式与行为。

    • 样式参数 :如 "labelPosition": "right"(标签右对齐)、"labelWidth": "100px"(标签宽度)。
    • 按钮控制 :定义了 "submitBtn"(提交按钮)显示,而 "resetBtn"(重置按钮)隐藏。
  • fields (组件字段定义)

    这是表单的核心数据模型,以数组形式定义了具体控件的属性。

    • 组件一(请假原因) :字段标识为 field: "Fkkgmkfa5l8eabc",类型为 input,标题为 title: "请假原因"
    • 组件二(请假时间) :字段标识为 field: "Fl6ymkfbx7rrahc",类型为 input,标题为 title: "请假时间"

注意 :前端生成的随机字符串 ID(如 Fkkg...)是后续流程运行时存取具体业务值的唯一键(Key)。

3. 数据持久化存储

后端接收请求后,解析并校验参数,随后执行插入操作:

  • 目标表bpm_form(业务表单定义表)。

  • 存储逻辑

    • conffields 字段被序列化为 JSON 字符串 存储在对应的数据库列中。
    • 系统为该表单生成一个全局唯一的 id
  • 返回结果:返回创建成功状态。

此步骤生成的 formId 至关重要,它将在下一章"创建流程模型"时被引用,从而实现"流程定义"与"业务表单"的物理绑定。


三,管理员创建流程模型

在完成了分类与表单的创建后,核心环节便是构建流程模型。此步骤旨在定义业务流转的逻辑规则(BPMN 图),并将前两章创建的分类与表单进行物理绑定。

1. 模型配置与可视化设计

管理员在后台管理系统中新建流程模型,操作分为两个维度:

  • 元数据配置

    • 基本信息 :定义流程名称为 请假流程,唯一标识 Key 设为 leave,并归属到 Test03 分类下。
    • 表单绑定 :选择上一章创建的"请假表单",系统在后端记录该表单的唯一标识 formId=41
  • BPMN 图形设计

    • 进入流程设计器(Modeler),绘制标准的 BPMN 2.0 流程图。
    • 配置起始节点(StartEvent),确保其关联了上述请假表单(用于发起流程时渲染)。
    • 绘制结束节点(EndEvent)以构成闭环,并点击保存。
2. 数据传输协议

前端将配置元数据与图形数据合并,通过 POST 请求发送至 /bpm/model/create 接口。核心载荷(Payload)包含:

  • 元数据name="请假流程", key="leave", category="Test03", formId=41。
  • 图形数据bpmnXml(由设计器生成的标准 XML 字符串)。
3. 后端处理与双表存储

后端接收请求后,首先校验模型 Key 的合法性及唯一性。校验通过后,通过 Flowable 原生的 RepositoryService 执行两步核心存储操作,分别涉及模型元数据表通用字节资源表

  • 步骤一:存储模型元数据 (ACT_RE_MODEL)

    调用 repositoryService.saveModel(model) 初始化模型记录。

    • KEY_ / NAME_ / CATEGORY_:直接映射传入的基本信息。
    • META_INFO_ (关键扩展) :由于 Flowable 原生模型表没有 formId 字段,框架将 formId: 41 以及描述信息封装为 JSON 字符串,存储在此字段中。这是实现"流程-表单"绑定的关键。
  • 步骤二:存储模型源文件 (ACT_GE_BYTEARRAY)

    调用 repositoryService.addModelEditorSource(id, bytes) 处理 BPMN XML 数据。

    • 数据转换 :将前端传来的 bpmnXml 字符串转换为 UTF-8 字节流。
    • 持久化 :将字节流作为一条记录插入 ACT_GE_BYTEARRAY 表。此表专门用于存储二进制大对象(BLOB)。
    • 建立关联 :Flowable 自动将新生成的字节记录 ID 回填至 ACT_RE_MODEL 表的 EDITOR_SOURCE_VALUE_ID_ 字段。

这是为您总结的第四章内容。这一章是流程设计走向流程运行的分水岭,技术密度较高。

我对您提供的步骤进行了核心优化,特别是在数据隔离 (草稿 vs 定稿)和扩展元数据存储方面做了更严谨的技术表述。


四,版本化与发布------管理员部署流程模型

流程模型在"部署"之前,仅仅是存储在数据库中的静态设计草稿。部署操作是将设计草稿转化为引擎可执行代码(ProcessDefinition)的关键步骤,同时涉及严格的版本控制与数据快照机制。

1. 部署触发与完整性校验

管理员在流程模型列表中选择"请假流程",点击【发布】按钮。

  • 接口交互 :前端通过 POST 请求调用 /bpm/model/deploy 接口,仅需传输模型主键 id
  • 前置校验 :后端根据 id 查询 ACT_RE_MODEL 表获取模型元数据及 XML 源码。系统调用 Flowable 校验器(BPMN Validator)对 XML 进行语法分析,检查是否存在游离节点、缺失的起始/结束事件或不合法的连线逻辑。
2. 核心部署:Flowable 引擎的三表联动

校验通过后,后端调用 Flowable 原生接口 repositoryService.createDeployment()...deploy() 执行部署。这是一个原子性事务,底层数据库发生如下级联变化:

  • 生成部署档案 (ACT_RE_DEPLOYMENT)
    插入一条新记录,生成全局唯一的 DEPLOYMENT_ID_。该记录标识了本次发布的版本快照时间与名称。
  • 固化资源文件 (ACT_GE_BYTEARRAY)
    引擎将模型草稿中的 XML 源码复制 一份,作为不可变的资源文件插入此表,并将 DEPLOYMENT_ID_ 关联到上一条记录。

技术修正:此处实现了"设计"与"运行"的物理隔离。即便后续管理员修改了模型草稿(Model),也不会影响已部署运行的资源文件。

  • 生成流程定义 (ACT_RE_PROCDEF)
    引擎解析 XML 结构,提取流程规则,插入一条流程定义记录。
  • 版本控制 :引擎自动查询该 Key(leave)的历史版本,将 VERSION_ 字段设为"最大版本号 + 1"。
  • 状态关联 :该记录同时关联上述的 DEPLOYMENT_ID_ 和资源文件名称。
3. 扩展元数据存储 (bpm_process_definition_info)

由于 Flowable 原生的 ACT_RE_PROCDEF 表结构固定,无法存储业务框架特有的配置(如关联的 formId、自定义图标、描述等)。

系统在此步执行扩展逻辑:从 ACT_RE_MODELMETA_INFO_ 中提取表单 ID 等信息,结合新生成的 processDefinitionId,插入到自定义扩展表 bpm_process_definition_info 中。这确保了流程定义与业务表单在运行时的强绑定。

4. 模型状态回写

部署的最后一步是更新设计草稿的状态。系统将新生成的 deploymentId 回写到 ACT_RE_MODEL 表的 DEPLOYMENT_ID_ 字段。

  • 字段非空:表示该模型已发布,且指向最新的部署版本。
  • 逻辑闭环:至此,流程模型完成了从"设计态"到"运行态"的转化,具备了发起流程实例的能力。
5. 深入解析:设计态与运行态的资源隔离(ACT_GE_BYTEARRAY 实例分析)

在执行部署操作后,若观察底层的通用字节资源表 ACT_GE_BYTEARRAY,会发现同一个"请假流程"存在两类截然不同的 XML 资源记录。这并非数据冗余,而是 Flowable 架构中为了实现"设计态"与"运行态"物理隔离而设计的核心机制。

我们将第三章(创建模型)与第四章(部署模型)产生的两条关键记录进行对比分析(参考数据库实例数据):

第一类记录:设计态源文件(Editor Source)

  • 来源 :产生于第三章"创建流程模型" ,对应 repositoryService.saveModel 操作。

  • 实例特征

    • NAME_ :固定为 source。这是 Flowable 设计器专用的标识,代表这是"设计草稿"。
    • DEPLOYMENT_ID_(Null)。关键特征。因为它是草稿,尚未发布,所以不关联任何部署记录。
    • REV_7(示例值)。高版本号表明管理员在设计器中点击了 7 次保存。
  • 技术含义 :这条记录是可变的。它仅供前端流程设计器(Model Editor)回显和编辑使用。无论管理员如何修改这条记录,都不会影响线上正在运行的业务。

第二类记录:运行态定义文件(Deployment Resource)

  • 来源 :产生于第四章"部署流程模型" ,对应 repositoryService.deploy 操作。

  • 实例特征

    • NAME_ :变更为具体的资源名称 leave.bpmn (格式通常为 流程Key + .bpmn)。
    • DEPLOYMENT_ID_7e7559db... (示例值)。有具体值,指向 ACT_RE_DEPLOYMENT 表的一条部署记录。
    • REV_1。永远为 1。
  • 技术含义 :这条记录是不可变的快照 。部署动作发生时,引擎读取了上述的 source 草稿,将其转化为标准的 BPMN 2.0 XML 格式,并复制 一份作为永久归档插入此表。流程引擎(Process Engine)在流转任务时,只读取这条记录,完全忽略 source 记录。


五,实例初始化------员工发起流程

在流程模型部署上线后,业务流转的实质性阶段始于"流程实例(Process Instance)"的创建。本章阐述员工提交申请时,系统如何将静态的流程定义转化为动态的运行数据。

1. 业务交互与数据封装

员工在后台管理系统前端访问已部署的"请假流程"入口。

  • 表单渲染 :前端根据第二章定义的 JSON 配置渲染动态表单,员工填写业务数据:请假原因="看病",请假时间="3"。
  • 提交动作:点击"发起"按钮,触发提交逻辑。
2. 接口协议与载荷定义

前端封装请求参数,发送 POST 请求至 /bpm/process-instance/create。请求载荷(Payload)包含两个核心要素:

  • processDefinitionId :指向具体的流程定义版本 ID(如 leave:1:7e82...),确保基于正确的版本发起。
  • variables:将表单业务数据封装为键值对 Map。
json 复制代码
{
  "Fkkgmkfa...": "看病", // Key为表单设计时生成的随机字段ID
  "Fl6ymkfb...": "3"
}
3. 后端预处理(业务层)

后端 Service 层接收请求后,在调用引擎之前执行一系列业务校验与数据增强:

  • 定义校验 :根据 processDefinitionId 查询 ACT_RE_PROCDEF 表,确认流程定义处于激活(Active)状态。
  • 权限与合法性校验:验证发起用户是否具备该流程的发起权限,并校验传入参数的格式合法性。
  • 上下文增强 :向 variables 中注入系统级内置变量,例如:
    • PROCESS_START_USER_ID: 发起人 ID。
    • PROCESS_STATUS: 初始化为"审批中"。
4. 引擎核心执行(持久化层)

业务层构建 ProcessInstanceBuilder 并调用 .start() 方法。此操作是一个原子性事务,触发 Flowable 引擎执行节点流转多表级联写入

关键数据库操作:

  • A. 初始化执行流 (ACT_RU_EXECUTION)

    引擎并非只插入一条记录,通常会生成两条记录以构建执行树:

    • 根执行流 (Root Execution) :代表流程实例本身。ID_PROC_INST_ID_ 相同,PARENT_ID_ 为空。
    • 子执行流 (Child Execution) :代表当前的执行指针。PARENT_ID_ 指向根执行流 ID,ACT_ID_ 指向当前停留的节点(如第一个用户任务)。
  • B. 变量持久化 (ACT_RU_VARIABLE)

    将增强后的 variables Map 扁平化存储。每一条键值对对应表中一行记录,外键 PROC_INST_ID_ 关联上述的根执行流 ID。

  • C. 身份链路绑定 (ACT_RU_IDENTITYLINK)

    引擎会向此表插入一条记录,标记当前用户为流程的 starter(发起人)。这对于后续查询"我发起的流程"至关重要。

  • D. 任务生成 (ACT_RU_TASK)

    引擎计算流程图路径,从 StartEvent 流转至第一个节点(假设为用户任务)。

    • 在表中插入一条新任务记录。
      • ASSIGNEE_ (办理人) :根据流程图配置(如 ${initiator} 或固定值)解析并填入具体用户 ID。
      • EXECUTION_ID_ :关联到上述的子执行流 ID(注意:是关联子执行流,而非根实例)。
  • E. 历史审计同步 (ACT_HI_*)
    start() 不仅操作运行时表(Runtime),会同步写入历史表以保证审计可追溯:

    • ACT_HI_PROCINST:记录流程实例开始时间。
    • ACT_HI_ACTINST:记录"开始节点"已完成,"用户任务节点"已开始。
    • ACT_HI_TASKINST:记录生成的第一个任务的历史存根。
    • ACT_HI_VARINST:记录变量的历史快照。

start() 操作标志着流程实例的正式诞生。此时,数据库中形成了完整的运行时数据结构(Execution Tree + Variables + Task),且首个审批节点的办理人已能在其"待办任务"列表中查询到该记录。


六,领导查看待办列表

流程实例发起后,任务流转至审批节点。此时,系统需要精准地将"任务"分发到对应审批人的工作台中。本章阐述系统如何通过身份上下文,从引擎中检索出属于当前用户的活跃任务。

1. 交互入口与请求上下文

领导一登录后台管理系统,进入【我的待办】菜单。

  • 接口协议 :前端发起 GET 请求至 /bpm/task/todo-page 接口。
  • 身份凭证 :请求头(Header)中携带了 Authorization: Bearer {token}。这是后端识别"当前是谁在查任务"的唯一凭证,避免了在 URL 参数中显式传递 UserID 带来的安全隐患。
2. 后端上下文解析

后端接口接收请求后,并非直接调用引擎,而是先进行上下文处理:

  • 身份提取 :通过安全框架(如 Spring Security)解析 Token,从 SecurityContextHolder 中获取当前登录用户的 ID(例如 User_Leader)。
  • 分页参数 :接收前端传递的分页参数(如 pageNo=1, pageSize=10),以便应对大量待办数据的场景。
3. 引擎查询与底层 SQL 构建

后端 Service 层构建 Flowable 的 TaskQuery 对象,执行核心查询逻辑。代码层面的 taskService.createTaskQuery()... 会被引擎翻译为复杂的 SQL 语句,涉及对 运行时任务表 (ACT_RU_TASK)运行时变量表 (ACT_RU_VARIABLE) 的联合操作。

关键查询链式调用如下:

  • taskAssignee(userId)

    • SQL 映射WHERE ASSIGNEE_ = 'User_Leader'
    • 含义:精准匹配分配给当前用户的任务。
    • (注:实际业务中常用 taskCandidateOrAssigned 以涵盖"候选人"模式,但此处按您描述的直接指派模式,使用 assignee 即可)
  • active()

    • SQL 映射AND SUSPENSION_STATE_ = 1
    • 含义:仅查询激活状态的任务,过滤掉被挂起(Suspended)的任务。
  • includeProcessVariables()

    • SQL 映射LEFT JOIN ACT_RU_VARIABLE ...
    • 含义:这是一个关键的性能优化操作。它指示引擎在查询任务的同时,通过**预加载(Eager Loading)**的方式一次性拉取关联的流程变量(如请假原因、请假天数)。这避免了后续遍历任务列表时产生 "N+1" 次查询数据库的问题。
  • orderByTaskCreateTime().desc()

    • SQL 映射ORDER BY CREATE_TIME_ DESC
    • 含义:按任务创建时间倒序排列,确保最新的待办显示在最前。
4. 数据转换与响应

引擎返回查询结果(List<Task>)后,后端不会直接将 Flowable 的原生实体返回给前端(因为包含大量引擎内部字段),而是进行对象转换(DTO/VO):

  • 基础映射:提取 Task ID, Name, CreateTime 等基础字段。
  • 变量注入 :从查询结果中提取 processVariables(如 {"Fkkg...": "看病", "Fl6y...": "3"}),并将其映射为前端可读的业务字段。
  • 流程定义关联 :通常还会根据 PROC_DEF_ID_ 关联查询流程定义名称("请假流程"),以便用户知道这是什么流程的任务。

最终,前端接收到包含业务数据的标准分页列表,渲染出领导看到的待办表格。


第七章:流转与驱动------领导审批待办任务

当领导对待办任务进行"通过"操作时,系统不仅要处理业务层面的审批意见与签名,还需驱动 Flowable 引擎完成核心的"节点跃迁":销毁当前任务,移动执行指针,并生成下一个任务节点。

1. 审批动作与接口协议

领导在任务详情页点击【通过】按钮,若业务场景配置了签名或审批意见,需同时提交相关数据。

  • 接口调用 :前端发送 PUT 请求至 /bpm/task/approve
  • 载荷参数
  • id: 任务唯一标识(如 d7d3cb54-f212...)。
  • reason: 审批意见(可选)。
  • signatureImage: 电子签名图片(取决于配置)。
  • nextAssignee: 指定的下一节点审批人(若流程配置为手动选择)。
2. 动态规则校验(基于 BPMN 扩展属性)

后端接收请求后,首先进行基础校验(任务是否存在、流程实例是否活跃)。随后,进入基于模型的动态校验逻辑

  • 获取节点定义 :根据任务的 taskDefinitionKey,从内存缓存的 BpmnModel 中定位到对应的 FlowElement 对象。
  • 解析扩展属性 :读取该节点配置的 extensionElements,检查是否存在自定义标签 signEnable
  • 强制校验 :若 signEnable=true,系统强制检查请求参数中是否包含 signatureImage。若缺失,直接抛出业务异常,拦截后续操作。这一机制实现了"配置驱动校验",无需硬编码。
3. 上下文准备:预设下一审批人

在触发流转前,系统需解决"下一棒交给谁"的问题。

  • 推理与设置 :根据前端传递的 nextAssignee 或业务规则,确定下一节点的受托人。
  • 变量持久化 :调用 runtimeService.setVariables(),将目标用户 ID 写入 ACT_RU_VARIABLE 表。
  • 目的 :Flowable 引擎在创建下一个任务时,会通过 UEL 表达式(如 ${approver})读取此变量作为新任务的 Assignee。
4. 引擎核心流转 (taskService.complete)

校验与参数准备完成后,调用 taskService.complete(taskId)。这是一个高度封装的原子操作,底层数据库发生剧烈的级联变化:

  • A. 任务销毁与归档 (Current Task)

    • 物理删除 :执行 DELETE 操作,从 ACT_RU_TASK 表中移除当前领导的待办记录。
    • 历史审计同步更新 ACT_HI_TASKINST 表,标记该任务状态为 completed,并记录 END_TIME_(结束时间)与 DURATION_(任务耗时)。
  • B. 路径计算与指针移动 (Navigation)

    • 读取模型:引擎从 Deployment Cache 中读取流程定义模型(无需每次查询数据库 XML),根据当前节点的"出口连线"计算目标节点。
    • 移动指针 :更新 ACT_RU_EXECUTION 表。
    • 将当前执行流的 ACT_ID_ 字段由"领导审批节点 ID"更新为"下一个节点 ID"。
    • (注:若遭遇并行网关,此处会涉及执行流的分裂或聚合操作)
  • C. 下一任务生成 (Next Task)

    • 节点实例化 :若目标节点仍为 UserTask,引擎向 ACT_RU_TASK 表执行 INSERT 操作,生成一条新的待办记录。
    • 属性填充 :新记录的 TASK_DEF_KEY_ 指向新节点 ID,ASSIGNEE_ 字段根据第 3 步预设的变量自动填充。
    • 历史同步 :同时向 ACT_HI_TASKINST 插入一条新记录(无结束时间),标志着下一环节审计追踪的开始。
相关推荐
焦糖玛奇朵婷2 小时前
就医陪诊小程序|从软件开发视角看实用度✨
java·大数据·jvm·算法·小程序
Yvonne爱编码2 小时前
深入剖析 Java 中的深拷贝与浅拷贝:原理、实现与最佳实践
java·开发语言
是三好2 小时前
Spring全家桶
java·后端·spring
西门吹雪分身2 小时前
JUC之线程中断
java
CSD资源分享2 小时前
Claude Code 国内API配置完整指南
java·windows·claude·claude code
索荣荣2 小时前
Java关键字终极指南:从入门到精通
java·开发语言
砚边数影2 小时前
线性回归实战(一):房价预测数据集入库KingbaseES,表结构设计
java·数据库·人工智能·深度学习·机器学习·线性回归·金仓数据库
李少兄2 小时前
IntelliJ IDEA 全局搜索完全指南:从高效使用到快捷键失效排查
java·intellij-idea·策略模式
空空kkk2 小时前
Spring、Spring MVC、SpringBoot的欢迎页配置
spring boot·spring·mvc