别再手动抄送了!用Activiti7多实例搞定会签审批,附赠SpringBoot集成避坑指南

发布时间:2026/6/8 18:16:14

别再手动抄送了!用Activiti7多实例搞定会签审批,附赠SpringBoot集成避坑指南 Activiti7会签审批实战告别低效抄送用多实例重构企业审批流当审批单在OA系统中流转时你是否还在为以下场景头疼财务报销需要部门全员确认却要手动勾选十几个抄送人项目立项必须获得三位总监联签但系统只能逐个串行审批紧急请假需要任意一位经理快速审批却因流程设计被迫等待固定审批人。这些传统审批流程中的人工接力赛正在吞噬企业运营效率。1. 会签与或签重新定义审批协作模式会签Approval Meeting和或签Or Approval是工作流引擎中两种典型的多人协作审批模式。前者要求指定范围内一定数量的审批人达成共识后者则只需任意一位审批人处理即可推进流程。这两种模式在Activiti7中均通过**多实例活动Multi-Instance Activity**实现但配置策略和适用场景截然不同。表会签与或签的核心差异对比特征会签模式或签模式完成条件需满足预设人数/比例任意一人处理即完成典型应用部门预算审批、项目立项紧急请假、故障处理并行性可配置并行/串行通常并行执行结果处理支持投票统计首个响应者决定流向系统负载较高需跟踪多实例状态较低单实例完成即结束在技术实现层面这两种模式共享相同的底层机制——都通过BPMN 2.0规范的multiInstanceLoopCharacteristics元素实现。关键区别仅体现在completionCondition属性的表达式配置上!-- 会签示例超过半数同意即通过 -- userTask idgroupApproval name部门会签 multiInstanceLoopCharacteristics isSequentialfalse collectionapprovers elementVariableapprover completionCondition${nrOfCompletedInstances/nrOfInstances 0.5}/completionCondition /multiInstanceLoopCharacteristics /userTask !-- 或签示例任意一人处理即完成 -- userTask idurgentApproval name紧急审批 multiInstanceLoopCharacteristics isSequentialfalse collectionmanagers elementVariablemanager completionCondition${nrOfCompletedInstances 1}/completionCondition /multiInstanceLoopCharacteristics /userTask2. 会签实现四步法从设计到部署2.1 BPMN可视化配置在Activiti Modeler中创建会签节点时需要关注以下核心属性配置多实例类型选择Parallel实现并行会签审批人同时收到任务选择Sequential实现串行会签按列表顺序逐个审批参与者集合通过collection属性指定审批人列表变量名如${approvers}元素变量设置临时变量名存储当前审批人通常与任务Assignee占位符一致完成条件使用预定义变量编写UEL表达式${nrOfCompletedInstances nrOfInstances}全员通过${nrOfCompletedInstances 2}至少两人同意${nrOfCompletedInstances/nrOfInstances 0.6}超过60%同意图会签节点在流程设计器中的典型配置界面注此处应插入配置截图展示Loop cardinality、Completion condition等字段的填写示例2.2 动态参与者配置审批人列表的注入时机和方式直接影响会签的灵活性。推荐三种实践方案方案一启动时静态注入// 流程启动时传入审批人列表 MapString, Object variables new HashMap(); variables.put(approvers, Arrays.asList(user1, user2, user3)); runtimeService.startProcessInstanceByKey(meetingApproval, variables);方案二运行时动态查询// 通过监听器动态设置参与者 public class DynamicApproverListener implements TaskListener { Override public void notify(DelegateTask task) { String deptId (String) task.getVariable(applyDept); ListString approvers departmentService.findApprovers(deptId); task.setVariable(approvers, approvers); } }方案三混合模式固定动态// 合并固定审批人和动态查询结果 ListString fixedApprovers Arrays.asList(CFO, CTO); ListString dynamicApprovers projectService.getProjectStakeholders(projectId); ListString allApprovers Stream.concat(fixedApprovers.stream(), dynamicApprovers.stream()).collect(Collectors.toList()); variables.put(approvers, allApprovers);2.3 完成条件进阶策略除基础的数量条件外实际业务往往需要更复杂的完成逻辑权重投票场景!-- 不同审批人拥有不同票权 -- completionCondition ${(voteResults[director] ? 3 : 0) (voteResults[manager] ? 2 : 0) (voteResults[staff] ? 1 : 0) 5} /completionCondition自定义条件类public class CustomCompletionCondition implements JavaDelegate { public void execute(DelegateExecution execution) { boolean isRejected (boolean) execution.getVariable(globalReject); int agreeCount ((List)execution.getVariable(voteResults)) .stream().filter(r - agree.equals(r)).count(); execution.setVariable(meetingPassed, !isRejected agreeCount 1); } }2.4 会签结果聚合多实例任务完成后通常需要汇总各审批意见。通过execution.getVariableLocal()可获取实例级变量// 在流程后续节点中收集会签结果 ListMapString, Object allComments new ArrayList(); for (String approver : approvers) { MapString, Object comment taskService.getVariableLocal( taskService.createTaskQuery() .processInstanceId(processInstanceId) .taskAssignee(approver) .singleResult().getId(), approvalComment); allComments.add(comment); }3. SpringBoot集成实战与避坑指南3.1 自动配置陷阱当SpringBoot遇到Activiti7时这些配置项最容易出问题# 必须关闭自动部署校验否则修改BPMN后需重启 spring.activiti.check-process-definitionsfalse # 建议使用新事务管理器避免会签任务卡死 spring.activiti.async-executor-activatetrue spring.activiti.async-executor-thread-pool-size103.2 变量传递黑洞会签任务中变量作用域的特殊性常导致意外// 错误示范直接设置全局变量其他审批人看不到 taskService.setVariable(taskId, comment, 同意); // 正确做法使用setVariableLocal设置实例级变量 taskService.setVariableLocal(taskId, privateComment, 建议补充材料);表Activiti变量作用域对照方法作用域多实例可见性runtimeService.setVariable流程实例所有节点可见taskService.setVariable任务仅当前任务可见taskService.setVariableLocal任务实例多实例中各任务独立3.3 事务一致性方案会签任务并行执行时需要考虑事务隔离问题。推荐采用Saga模式Transactional public void completeApproval(String taskId, ApprovalVO vo) { // 1. 记录审批操作本地事务保证 approvalRecordRepository.save(convertToEntity(vo)); // 2. 发送领域事件异步补偿 eventPublisher.publishEvent(new ApprovalEvent( taskId, vo.getComment(), vo.isAgree())); // 3. 完成任务最后执行 taskService.complete(taskId, Collections.singletonMap(approvalResult, vo.isAgree())); }3.4 性能优化策略大规模会签场景下这些优化手段能显著提升性能批量任务查询避免N1查询问题// 低效做法 for (String approver : approvers) { Task task taskService.createTaskQuery() .taskAssignee(approver).singleResult(); } // 高效做法 ListTask tasks taskService.createTaskQuery() .processInstanceId(processInstanceId) .taskAssigneeIds(approvers) .list();启用历史级别优化# 只记录必要的历史数据 spring.activiti.history-levelaudit异步日志处理Bean public AsyncLogListener asyncLogListener() { return new AsyncLogListener(executor); }4. 企业级会签场景深度解析4.1 层级审批矩阵式会签对于需要跨部门联动的审批场景可采用分层会签设计process idmatrixApproval startEvent idstart/ !-- 第一层部门内会签 -- userTask iddeptApproval name部门审批 multiInstanceLoopCharacteristics collection${deptApprovers} elementVariableapprover completionCondition${nrOfCompletedInstances 2}/completionCondition /multiInstanceLoopCharacteristics /userTask !-- 第二层跨部门会签 -- userTask idcrossDeptApproval name跨部门会签 multiInstanceLoopCharacteristics collection${crossDeptApprovers} elementVariableapprover completionCondition${nrOfCompletedInstances nrOfInstances}/completionCondition /multiInstanceLoopCharacteristics /userTask endEvent idend/ /process4.2 动态路由条件化或签结合网关实现智能路由的或签流程sequenceFlow idtoHR sourceRefapprovalGateway targetRefhrApproval conditionExpression xsi:typetFormalExpression ${firstApprover.department HR} /conditionExpression /sequenceFlow sequenceFlow idtoFinance sourceRefapprovalGateway targetReffinanceApproval conditionExpression xsi:typetFormalExpression ${firstApprover.department Finance} /conditionExpression /sequenceFlow4.3 混合模式会签或签组合复杂审批链的典型结构示例开始 → [预算会签]3人至少2人同意 → [技术或签]任意架构师 → [CFO审批]单人 → [终审会签]全部董事 → 结束对应的BPMN片段userTask idfinalApproval name董事会终审 multiInstanceLoopCharacteristics isSequentialtrue collection${boardMembers} elementVariablemember completionCondition ![CDATA[ ${nrOfCompletedInstances nrOfInstances || nrOfRejectedInstances 1} ]] /completionCondition /multiInstanceLoopCharacteristics /userTask4.4 异常处理会签超时与干预对于可能陷入僵局的会签任务需要设计熔断机制Scheduled(fixedDelay 3600000) public void monitorStuckApprovals() { ListProcessInstance instances runtimeService.createProcessInstanceQuery() .activityId(groupApproval) .startedBefore(new Date(System.currentTimeMillis() - 48 * 3600000)) .list(); instances.forEach(instance - { runtimeService.setVariable(instance.getId(), forceComplete, true); runtimeService.trigger(instance.getId()); }); }在BPMN中配置相应的边界事件boundaryEvent idtimeoutEvent attachedToRefgroupApproval timerEventDefinition timeDurationPT48H/timeDuration /timerEventDefinition /boundaryEvent

相关新闻