一,管理员创建流程分类
在正式设计复杂的业务流程之前,我们需要先为它们建立一个"文件夹体系"。流程分类(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表,确保传入的name和code在全表中是唯一的。如果已存在,直接抛出异常,防止数据冲突。 -
持久化:校验通过后,后端将数据封装为 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(业务表单定义表)。 -
存储逻辑:
conf和fields字段被序列化为 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_MODEL 的 META_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_指向当前停留的节点(如第一个用户任务)。
- 根执行流 (Root Execution) :代表流程实例本身。
-
B. 变量持久化 (
ACT_RU_VARIABLE)将增强后的
variablesMap 扁平化存储。每一条键值对对应表中一行记录,外键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 即可)
- SQL 映射 :
-
active():- SQL 映射 :
AND SUSPENSION_STATE_ = 1。 - 含义:仅查询激活状态的任务,过滤掉被挂起(Suspended)的任务。
- SQL 映射 :
-
includeProcessVariables():- SQL 映射 :
LEFT JOIN ACT_RU_VARIABLE ...。 - 含义:这是一个关键的性能优化操作。它指示引擎在查询任务的同时,通过**预加载(Eager Loading)**的方式一次性拉取关联的流程变量(如请假原因、请假天数)。这避免了后续遍历任务列表时产生 "N+1" 次查询数据库的问题。
- SQL 映射 :
-
orderByTaskCreateTime().desc():- SQL 映射 :
ORDER BY CREATE_TIME_ DESC。 - 含义:按任务创建时间倒序排列,确保最新的待办显示在最前。
- SQL 映射 :
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插入一条新记录(无结束时间),标志着下一环节审计追踪的开始。
- 节点实例化 :若目标节点仍为 UserTask,引擎向