当前位置: 首页 > news >正文

别再只会用Assignee了!用Activiti7多实例搞定会签与或签的完整配置流程

Activiti7多实例实战:从会签到或签的进阶审批配置指南

当审批流程从单人决策转向集体决策时,工作流引擎的配置复杂度会呈指数级上升。想象这样一个场景:某跨国企业的采购申请需要经过三个区域负责人的联合审批,其中任意两位同意即可生效;或者紧急报销流程只需获得财务部门任意一位主管的批准就能进入下一环节。这类需求在Activiti7中可以通过多实例任务(Multi-Instance Task)优雅实现,但90%的中级开发者都会在Completion Condition表达式或Collection变量传递环节踩坑。

1. 多实例任务的核心架构解析

多实例任务本质上是BPMN 2.0规范中的一种特殊活动类型,它允许单个任务节点在运行时动态创建多个实例。与简单的Assignee分配不同,这种机制为复杂审批场景提供了三种关键控制维度:

执行模式选择

  • 顺序执行(Sequential=true):适用于需要层级审批的场景,如先部门经理后总监
  • 并行执行(Sequential=false):适用于同级多人同时审批,如委员会投票

参与者配置矩阵

配置项作用域示例值注意事项
Collection流程变量${approveUserList}必须实现java.util.List接口
Element Variable元素变量member与Assignee表达式保持一致
Loop Cardinality固定数量3与Collection互斥

完成条件的三层控制体系

  1. 数量阈值${nrOfCompletedInstances >= 2}
  2. 比例控制${nrOfCompletedInstances/nrOfInstances > 0.6}
  3. 自定义逻辑:通过DelegateExecution注入业务判断
// Spring Boot中的多实例流程启动示例 @RestController @RequestMapping("/process") public class MultiInstanceController { @Autowired private RuntimeService runtimeService; @PostMapping("/start") public String startProcess(@RequestBody ApproveRequest request) { Map<String, Object> variables = new HashMap<>(); variables.put("approveUserList", request.getApprovers()); variables.put("minApproves", request.getMinApproves()); ProcessInstance instance = runtimeService.startProcessInstanceByKey( "multiInstanceProcess", variables ); return instance.getId(); } }

2. 会签模式的深度配置实战

会签(即"与签")是多人必须全部或部分完成审批才能使流程继续的典型场景。某电商平台的退款审核系统曾因错误配置导致2000多笔订单卡在审批环节,根本原因正是Completion Condition表达式与业务规则不匹配。

比例通过型会签的黄金配置法则

  1. 在BPMN设计器中设置Multi-Instance类型为Parallel
  2. Collection填写流程变量名如${approveUserList}
  3. Completion Condition填入比例公式:
    ${nrOfCompletedInstances/nrOfInstances >= 0.7}

动态阈值实现方案

<multiInstanceLoopCharacteristics isSequential="false" activiti:collection="${approveUserList}" activiti:elementVariable="approver"> <completionCondition>${nrOfCompletedInstances >= minApproves}</completionCondition> </multiInstanceLoopCharacteristics>

审批结果聚合的三种模式对比

  1. 乐观模式(任一通过):

    # 历史任务记录示例 SELECT * FROM act_hi_taskinst WHERE PROC_INST_ID_ = '1001' AND DELETE_REASON_ IS NULL;
  2. 悲观模式(全员通过):

    // 在DelegateTask中校验历史审批结果 List<HistoricTaskInstance> histories = historyService .createHistoricTaskInstanceQuery() .processInstanceId(execution.getProcessInstanceId()) .list(); long rejects = histories.stream() .filter(h -> "REJECT".equals(h.getVariable("result"))) .count(); if(rejects > 0) { execution.setVariable("approved", false); }
  3. 混合模式(自定义规则):

    -- 数据库级别验证(Oracle示例) SELECT SUM(CASE WHEN VAR_TEXT_ = 'APPROVE' THEN 1 ELSE 0 END) approves, COUNT(*) total FROM ACT_HI_VARINST WHERE PROC_INST_ID_ = '1001' AND NAME_ = 'approvalResult'

3. 或签模式的特殊处理技巧

或签(即"或签")的特点是任一处理人完成操作即可推动流程,但实际业务中往往需要区分"通过"和"拒绝"两种操作结果。某金融机构的贷款审批系统就曾因未处理拒绝场景导致错误放款。

基础或签配置

Completion Condition: ${nrOfCompletedInstances >= 1}

增强型或签实现方案

  1. 在任务完成时注入决策结果:

    taskService.complete(taskId, Variables.putValue("decision", "REJECT") );
  2. 配置边界事件捕获拒绝:

    <boundaryEvent id="rejectEvent" attachedToRef="approvalTask"> <messageEventDefinition messageRef="rejectMsg" /> </boundaryEvent>
  3. 使用执行监听器清理残余实例:

    public class CancelInstancesListener implements ExecutionListener { @Override public void notify(DelegateExecution execution) { runtimeService.createExecutionQuery() .activityId("approvalTask") .list() .forEach(e -> runtimeService.deleteExecution(e.getId())); } }

或签场景下的数据一致性挑战

  • ACT_RU_TASK表:未完成任务需手动清理
  • ACT_HI_TASKINST表:通过DELETE_REASON_字段区分自然完成与强制终止
  • 业务数据同步:建议采用SAGA模式补偿事务

4. 生产环境中的性能优化策略

当审批人员规模超过50人时,原生多实例实现可能遇到性能瓶颈。某政务审批平台在接入300+部门时,流程实例启动时间达到了不可接受的8秒。

索引优化方案

-- MySQL性能优化示例 ALTER TABLE ACT_RU_IDENTITYLINK ADD INDEX idx_task_assignee (TASK_ID_, TYPE_, USER_ID_); ALTER TABLE ACT_RU_VARIABLE ADD INDEX idx_proc_inst_name (PROC_INST_ID_, NAME_);

批量处理模式

// 使用Bulk API处理大规模审批人 List<String> approvers = getHugeApproverList(); // 500+人 runtimeService.createProcessInstanceBuilder() .processDefinitionKey("massApproval") .variable("approveUserList", approvers) .variable("batchSize", 100) .addExtensionElement(new BatchConfigElement()) .executeAsync();

缓存层设计要点

  1. 使用Redis缓存流程定义:

    # application.yml配置 activiti: process-definition-cache: enabled: true max-size: 1000 expire-after-write: 1h
  2. 审批人列表分片加载:

    @Cacheable(value = "approvers", key = "#deptId") public List<String> getDepartmentApprovers(String deptId) { // 数据库查询 }
  3. 历史决策结果预加载:

    /* MyBatis映射示例 */ <select id="getApprovalTrend" resultType="ApprovalStat"> SELECT APPROVER, COUNT(*) total FROM BIZ_APPROVAL_HISTORY WHERE PROCESS_DEF_ID = #{defId} GROUP BY APPROVER </select>

在大型制造业集团的采购系统中,通过组合使用这些优化策略,成功将200人规模的会签流程实例启动时间从12秒降低到1.8秒,任务分配耗时从5秒降至400毫秒。关键点在于:提前识别Collection变量的数据规模,对超百人场景采用分批加载机制;对高频使用的流程定义启用二级缓存;在历史数据查询上建立适当的索引策略。

http://www.jsqmd.com/news/971828/

相关文章:

  • 信创环境避坑实录:在飞腾2000+银河麒麟V10上,我这样搞定了Docker 19.03.9和达梦8.1
  • 深圳装修对比3家实测,RERA源木匠心,5000平方工厂秒杀外包贴牌 - 产品测评官
  • 从航海图到手机地图:聊聊墨卡托投影如何统治了我们的数字世界
  • 实战避坑:从零到一开发你的第一个PDMS PML图形界面(Form)插件
  • 2026年阻燃采光瓦选购指南,潍坊泰霖建材的优势 - mypinpai
  • 《Python 入门到进阶完整学习笔记 | 基础语法 + 容器 + 函数 + 面向对象》
  • LosslessCut:5分钟掌握无损视频剪辑,告别画质损失的终极解决方案
  • Word VBA调试时文件被锁死?教你用On Error GoTo跳过4198错误(附完整代码)
  • 终极Boot Camp驱动解决方案:Brigadier如何让Mac用户告别驱动烦恼
  • Nginx黑白名单进阶玩法:告别手动配置,用Lua+Redis实现动态封禁恶意IP
  • 模板驱动文档自动化:告别重复劳动的确定性交付方案
  • 音频处理实战:用Python快速设计Butterworth滤波器并可视化幅频曲线(附Jupyter Notebook)
  • 深度解析10款降AIGC工具:帮你锁定达标神器
  • 【PC】Alger 5.1.0[特殊字符]高颜值开源音乐软件⭐可批量下载
  • 别再死记叉乘公式了!用Python和NumPy玩转向量的反对称矩阵表示
  • 别再混淆了!一文讲清SAP WM里SU、HU和Quant的区别与联系(含配置点检查)
  • 靠谱的邢台成人高考学校
  • 从输入法到语音识别:聊聊马尔可夫链在我们身边的那些“隐形”应用
  • F28335 DSP连接AD7606采集8路信号,从硬件接线到代码调试的完整避坑记录
  • 2026年新疆闪灵GEO搜索推广口碑如何? - mypinpai
  • 好用的 GEO 优化线上推广品牌哪家强 - mypinpai
  • SuperMap iDesktop实战:当CAD数据没有坐标系信息时,如何一步步完成投影转换?
  • GPU显存稳定性测试终极指南:6分钟发现隐藏硬件故障
  • Gunicorn:Python WSGI HTTP 服务器
  • Hi3861 WiFi开发避坑指南:从STA连接到AP热点创建的完整流程与常见错误码解析
  • 别再让服务器被冲垮了!手把手教你用Nginx的limit_req和limit_conn给接口上把锁
  • Foreman:服务器生命周期管理
  • 高级语法与特性
  • 告别Electron?我用Flutter 3.0给Windows 11开发了个不到20MB的桌面应用
  • 图嵌入与谱半径极值问题研究