西安市城乡建设档案馆网站,免费高清logo图片在线生成,源码下载网站cms,网站开发项目需求书我们在使用工作流的时候#xff0c;常常有“流程退回”、“流程跳转”、“自由流”、“动态加签”等这样的需求。Camunda流程平台提供了这样的机制和接口#xff0c;虽然流程模型定义活动执行顺序的序列流#xff0c;但有时需要灵活地重新启动活动或取消正在运行的活动…我们在使用工作流的时候常常有“流程退回”、“流程跳转”、“自由流”、“动态加签”等这样的需求。Camunda流程平台提供了这样的机制和接口虽然流程模型定义活动执行顺序的序列流但有时需要灵活地重新启动活动或取消正在运行的活动进而可以实现中国特色的流程需求。文本重点讲如何使用camunda的API接口实现流程跳转、流程退回的需求另外还可能适用的场景有
实现中国特色流程操作包括退回申请人、退回上一步、任意退回、流程跳转、流程撤销、动态增加活动等修复必须重复或跳过某些步骤的流程实例将流程实例从一个版本的流程定义迁移到另一个版本测试可以跳过或重复活动以对单个工艺段进行孤立测试
比如云程低代码平台可以通过界面配置实现流程操作的特殊需求 在线体验系统http://www.yunchengxc.com
为了执行这样的操作流程引擎提供了通过RuntimeService.createProcessInstanceModification…或RuntimeService.createModification…输入的流程实例修改API。这个API允许通过使用fluent生成器在一个调用中指定多个修改指令。特别是可以
在activity活动之前开始执行在离开activity活动的序列流上开始执行取消正在运行的 Activity 实例取消给定activity活动的所有正在运行的实例使用每个指令设置变量
1、通过一个示例介绍如何动态修改流程实例
例如请考虑以下BPMN流程模型 该模型显示了处理贷款申请的简单流程。让我们假设一个贷款申请已经到达贷款申请已经过评估并且决定拒绝该申请。这意味着流程实例具有以下活动实例状态
ProcessInstanceDecline Loan Application
现在执行任务“拒绝贷款申请”的工作人员认识到评估结果中的错误并得出结论尽管如此该申请仍应被接受。虽然这种灵活性不是作为流程的一部分建模的但流程实例修改允许更正正在运行的流程实例。下面的API调用实现了这个技巧
ProcessInstance processInstance runtimeService.createProcessInstanceQuery().singleResult();
runtimeService.createProcessInstanceModification(processInstance.getId()).startBeforeActivity(acceptLoanApplication).cancelAllForActivity(declineLoanApplication).execute();
此命令首先在活动Accept Loan Application之前开始执行直到达到等待状态在本例中为用户任务的创建。之后它将取消活动“拒绝贷款申请”的运行实例。在工作人员的任务列表中“拒绝”任务已被删除并显示“接受”任务。生成的活动实例状态为
ProcessInstanceAccept Loan Application
假设在批准应用程序时必须存在一个名为approver的变量。这可以通过如下扩展修改请求来实现
ProcessInstance processInstance runtimeService.createProcessInstanceQuery().singleResult();
runtimeService.createProcessInstanceModification(processInstance.getId()).startBeforeActivity(acceptLoanApplication).setVariable(approver, joe).cancelAllForActivity(declineLoanApplication).execute();
添加的setVariable调用确保在启动活动之前提交指定的变量。
现在来看一些更复杂的案例。假设申请再次不正常并且“拒绝贷款申请”活动处于活动状态。现在工人意识到评估流程是错误的并希望完全重新启动。以下修改说明表示执行此任务的修改请求
可以启动子流程活动
ProcessInstance processInstance runtimeService.createProcessInstanceQuery().singleResult();
runtimeService.createProcessInstanceModification(processInstance.getId()).cancelAllForActivity(declineLoanApplication).startBeforeActivity(assessCreditWorthiness).startBeforeActivity(registerApplication).execute();
要从子流程的 start 事件开始请执行以下操作
ProcessInstance processInstance runtimeService.createProcessInstanceQuery().singleResult();
runtimeService.createProcessInstanceModification(processInstance.getId()).cancelAllForActivity(declineLoanApplication).startBeforeActivity(subProcessStartEvent).execute();
要启动子流程本身请执行以下操作
ProcessInstance processInstance runtimeService.createProcessInstanceQuery().singleResult();
runtimeService.createProcessInstanceModification(processInstance.getId()).cancelAllForActivity(declineLoanApplication).startBeforeActivity(evaluateLoanApplication).execute();
要启动流程的 start 事件请执行以下操作
ProcessInstance processInstance runtimeService.createProcessInstanceQuery().singleResult();
runtimeService.createProcessInstanceModification(processInstance.getId()).cancelAllForActivity(declineLoanApplication).startBeforeActivity(processStartEvent).execute();
1.1、流程跳转的实现方法
流程实例执行流程中经常遇到特殊业务需求需要跳过某些流程活动节点。为此您可以启动一个带有修改的流程实例并将令牌直接放在该流程实例中。
假设您想跳过子流程 Evaluate Loan Application 并测试网关 Application OK 使用您的流程变量您可以使用以下命令启动流程实例
ProcessInstance processInstance runtimeService.createProcessInstanceByKey(Loan_Application).startBeforeActivity(application_OK).setVariable(approved, true).execute();
此方法也可以用在JUnit测试中可以跳过前面流程部分仅仅关注要测试的流程活动。
2、操作语义
以下各节指定了流程实例修改的确切语义应阅读这些语义以便了解不同情况下的修改效果。如果没有另行说明以下示例将参考以下流程模型进行说明 2.1、修改指令类型
Fluent 流程实例修改生成器提供以下方法接口
startBeforeActivity(String activityId)startBeforeActivity(String activityId, String ancestorActivityInstanceId)startAfterActivity(String activityId)startAfterActivity(String activityId, String ancestorActivityInstanceId)startTransition(String transitionId)startTransition(String transition, String ancestorActivityInstanceId)cancelActivityInstance(String activityInstanceId)cancelTransitionInstance(String transitionInstanceId)cancelAllForActivity(String activityId)
2.1.1、在活动开始之前开始
ProcessInstanceModificationBuilder#startBeforeActivity(String activityId)
ProcessInstanceModificationBuilder#startBeforeActivity(String activityId, String ancestorActivityInstanceId)
通过startBeforeActivity在活动之前启动意味着在进入活动之前就开始执行。该指令尊重asyncBefore标志这意味着如果活动是asyncBeBefore则将创建作业。通常此指令从指定的活动开始执行流程模型直到达到等待状态。有关等待状态的详细信息请参阅“流程中的事务”文档。
2.1.2、活动后开始
ProcessInstanceModificationBuilder#startAfterActivity(String activityId)
ProcessInstanceModificationBuilder#startAfterActivity(String activityId, String ancestorActivityInstanceId)
通过startAfterActivity在活动之后启动意味着在活动的单个传出序列流上开始执行。该指令不考虑给定活动的asyncAfter标志。如果有多个传出序列流或者根本没有则指令失败。如果成功此指令将从序列流开始执行流程模型直到达到等待状态。
2.1.3、开始流转
ProcessInstanceModificationBuilder#startTransition(String transitionId)
ProcessInstanceModificationBuilder#startTransition(String transition, String ancestorActivityInstanceId)
通过startTransition启动转换转换为在给定的序列流上开始执行。当存在多个传出序列流时这可以与startAfterActivity一起使用。如果成功此指令将从序列流开始执行流程模型直到达到等待状态。
2.1.4、取消活动实例
ProcessInstanceModificationBuilder#cancelActivityInstance(String activityInstanceId)
cancelActivityInstance可以取消特定的活动实例。这可以是叶活动实例例如用户任务的实例也可以是层次结构中更高范围的实例例如子流程的实例。请参阅有关活动实例的详细信息—如何检索流程实例的活动实例。
2.1.5、取消转换实例
ProcessInstanceModificationBuilder#cancelTransitionInstance(String activityInstanceId)
转换实例表示即将以异步延续的形式进入/离开活动的执行流。已创建但尚未执行的异步延续作业表示为转换实例。cancelTransitionInstance可以取消这些实例。请参阅有关活动和转换实例的详细信息—如何检索流程实例的转换实例。
2.1.6、取消活动的所有活动实例
ProcessInstanceModificationBuilder#cancelAllForActivity(String activityId)
为了方便起见还可以通过指令cancelAllForActivity取消给定活动的所有活动和转换实例。
2.2、提供或设置变量
对于每个实例化指令即startBeforeActivity、startAfterActivity或startTransition都可以提交流程变量。API提供了方法
setVariable(String name, Object value)setVariables(MapString, Object variables)setVariableLocal(String name, Object value)setVariablesLocal(MapString, Object variables)
变量是在创建实例化所需的作用域之后、指定元素的实际执行开始之前设置的。这意味着在流程引擎历史记录中这些变量看起来不像是在执行startBefore和startAfter指令的指定活动期间设置的。在即将执行指令即进入活动等的执行上设置局部变量。
2.3、基于活动实例的 API
流程实例修改API基于活动实例。流程实例的活动实例树可以通过以下方法进行检索
ProcessInstance processInstance ...;
ActivityInstance activityInstance runtimeService.getActivityInstance(processInstance.getId());
ActivityInstance是一个递归数据结构上面方法调用返回的活动实例表示流程实例。ActivityInstance对象的ID可用于取消特定实例或用于实例化期间的祖先选择。
接口ActivityInstance具有方法getChildActivityInstances和getChildTransitionInstances以在活动实例树中进行深入搜索。例如假设活动“评估信用价值”和“注册申请”处于活动状态。然后活动实例树如下所示
ProcessInstanceEvaluate Loan ApplicationAssess Credit WorthinessRegister Application Request
在代码中可以按如下方式检索 Assess 和 Register 活动实例
ProcessInstance processInstance ...;
ActivityInstance activityInstance runtimeService.getActivityInstance(processInstance.getId());
ActivityInstance subProcessInstance activityInstance.getChildActivityInstances()[0];
ActivityInstance[] leafActivityInstances subProcessInstance.getChildActivityInstances();// leafActivityInstances has two elements; one for each activity
还可以直接检索给定活动的所有活动实例
ProcessInstance processInstance ...;
ActivityInstance activityInstance runtimeService.getActivityInstance(processInstance.getId());
ActivityInstance assessCreditWorthinessInstances activityInstance.getActivityInstances(assessCreditWorthiness)[0];
与活动实例相比转换实例并不表示活动的活动而是表示即将进入或即将离开的活动。当存在异步延续的作业但尚未执行时就会出现这种情况。对于活动实例可以使用getChildTransitionInstances方法检索子转换实例转换实例的API与活动实例的类似。
2.4、嵌套实例化
假设上面示例流程的一个流程实例其中活动“拒绝贷款申请”处于活动状态。现在我们提交指示以便在活动评估信用价值之前开始。应用此指令时流程引擎确保实例化所有尚未激活的父作用域。在这种情况下在启动活动之前流程引擎会实例化Evaluate Loan Application子流程。在活动实例树之前的位置
ProcessInstanceDecline Loan Application
现在是
ProcessInstanceDecline Loan ApplicationEvaluate Loan ApplicationAssess Credit Worthiness
除了实例化这些父作用域引擎还确保在这些作用域中注册事件订阅和作业。例如考虑以下流程 启动活动“评估信用价值”还会注册消息边界事件“收到的取消通知”的事件订阅以便可以通过这种方式取消子流程。
2.5、实例化的祖先选择
默认情况下启动活动会实例化所有尚未实例化的父作用域。当活动实例树如下时
ProcessInstanceDecline Loan Application
然后启动“评估信用价值”Assess Credit Worthiness会在以下更新的树中生成
ProcessInstanceDecline Loan ApplicationEvaluate Loan ApplicationAssess Credit Worthiness
子流程范围也已实例化。现在假设子流程已经实例化如下图所示
ProcessInstanceEvaluate Loan ApplicationAssess Credit Worthiness
再次启动 Assess Credit Worthiness 将在现有子流程实例的上下文中启动它因此生成的树为
ProcessInstanceEvaluate Loan ApplicationAssess Credit WorthinessAssess Credit Worthiness
如果您想避免这种行为而是想第二次实例化子流程则可以使用方法startBeforeActivityString activityIdString ancestorActivityInstanceId来提供祖先活动实例的id-类似的方法用于在活动之后启动和启动转换。参数ancestorActivityInstanceId采用当前活动的活动实例的id该活动实例属于要启动的活动的祖先活动。如果一个活动包含要启动的活动直接或间接与其间的其他活动一起那么它就是一个有效的祖先。
对于给定的祖先活动实例id祖先活动和要启动的活动之间的所有作用域都将被实例化而不管它们是否已经被实例化。在该示例中以下代码以流程实例作为根活动实例作为祖先启动活动“评估信用价值”
ProcessInstance processInstance ...;
ActivityInstance activityInstanceTree runtimeService.getActivityInstance(processInstance.getId());
runtimeService.createProcessInstanceModification(activityInstanceTree.getId()).startBeforeActivity(assessCreditWorthiness, processInstance.getId()).execute();
然后生成的活动实例树如下所示
ProcessInstanceEvaluate Loan ApplicationAssess Credit WorthinessEvaluate Loan ApplicationAssess Credit Worthiness
第二次启动了子流程。
2.6、取消传播
取消活动实例将传播到不包含其他活动实例的父活动实例。此行为可确保流程实例不会处于毫无意义的执行状态。这意味着当单个活动在子流程中处于活动状态并且该活动实例被取消时子流程也会被取消。请考虑以下活动实例树
ProcessInstanceDecline Loan ApplicationEvaluate Loan ApplicationAssess Credit Worthiness
取消“评估信用价值”的活动实例后树为
ProcessInstanceDecline Loan Application
如果所有指令都已执行并且没有活动活动实例则整个流程实例将被取消。在上面的示例中如果两个活动实例都被取消一个是评估信用价值另一个是拒绝贷款申请。
但是只有在执行完所有指令后才会取消流程实例。这意味着如果流程实例在两条指令之间没有活动活动实例则不会立即取消流程实例。例如假设活动“拒绝贷款申请”处于活动状态。活动实例树为
ProcessInstanceDecline Loan Application
尽管在执行取消指令后流程实例没有活动活动实例但以下修改操作将成功
ProcessInstance processInstance ...;
runtimeService.createProcessInstanceModification(processInstance.getId()).cancelAllForActivity(declineLoanApplication).startBeforeActivity(acceptLoanApplication).execute();
2.7、指令执行顺序
修改指令始终按提交顺序执行。因此以不同的顺序执行相同的指令可能会有所不同。请考虑以下活动实例树
ProcessInstanceEvaluate Loan ApplicationAssess Credit Worthiness
假设您的任务是取消“评估信用价值”的实例并启动活动“注册应用程序”。这两条指令有两种排序方式要么先执行取消要么先执行实例化。在前一种情况下代码如下所示
ProcessInstance processInstance ...;
runtimeService.createProcessInstanceModification(processInstance.getId()).cancelAllForActivity(assesCreditWorthiness).startBeforeActivity(registerApplication).execute();
由于取消传播子流程实例在执行取消指令时被取消仅在执行实例化指令时重新实例化。这意味着在执行修改后“评估贷款申请”子流程将出现一个不同的实例。与上一个实例关联的任何实体都已被删除例如变量或事件订阅。
相比之下请考虑首先执行实例化的情况
ProcessInstance processInstance ...;
runtimeService.createProcessInstanceModification(processInstance.getId()).startBeforeActivity(registerApplication).cancelAllForActivity(assesCreditWorthiness).execute();
由于实例化期间的默认祖先选择以及在这种情况下取消不会传播到子流程实例这一事实因此子流程实例在修改后与之前相同。将保留相关实体如变量和事件订阅。
2.8、使用中断/取消语义开始活动
流程实例修改尊重要启动的活动的任何中断或取消语义。特别是启动中断边界事件或中断事件子流程将取消/中断在中定义的活动。请考虑以下流程 假设活动“评估信用价值”当前处于活动状态。事件子流程可以使用以下代码启动
ProcessInstance processInstance ...;
runtimeService.createProcessInstanceModification(processInstance.getId()).startBeforeActivity(cancelEvaluation).execute();
由于“取消评估”子流程的启动事件正在中断因此它将取消“评估信用价值”的运行实例。当事件子流程的启动事件通过以下方式启动时也会发生同样的情况
ProcessInstance processInstance ...;
runtimeService.createProcessInstanceModification(processInstance.getId()).startBeforeActivity(eventSubProcessStartEvent).execute();
但是当位于事件子流程中的活动直接启动时不会执行中断。请考虑以下代码
ProcessInstance processInstance ...;
runtimeService.createProcessInstanceModification(processInstance.getId()).startBeforeActivity(notifyAccountant).execute();
生成的活动实例树将为
ProcessInstanceEvaluate Loan ApplicationAssess Credit WorthinessCancel EvaluationNotify Accountant
2.9、修改多实例活动实例
修改也适用于多实例活动。我们在下文中区分了多实例主体和内部活动。内部活动是实际活动具有流程模型中声明的ID。多实例主体是围绕此活动的一个范围在流程模型中不作为不同的元素表示。对于id为anActivityId的活动多实例主体按照约定具有id为anActivity id#multiInstanceBody。
有了这种区别就可以启动整个多实例主体也可以为正在运行的并行多实例活动启动单个内部活动实例。考虑以下流程模型 假设多实例活动处于活动状态并且有三个实例
ProcessInstanceContact Customer - Multi-Instance BodyContact CustomerContact CustomerContact Customer
以下修改将在同一多实例正文活动中启动“联系客户”活动的第四个实例
ProcessInstance processInstance ...;
runtimeService.createProcessInstanceModification(processInstance.getId()).startBeforeActivity(contactCustomer).execute();
生成的活动实例树为
ProcessInstanceContact Customer - Multi-Instance BodyContact CustomerContact CustomerContact CustomerContact Customer
流程引擎确保正确更新与多实例相关的变量nrOfInstances、nrOfActiveInstances和loopCounter。如果基于集合配置多实例活动则在执行指令时不考虑该集合并且不会为附加实例填充集合元素变量。这样的行为可以通过使用方法#setVariableLocal向集合元素变量提供实例化指令来实现。
现在考虑以下请求
ProcessInstance processInstance ...;
runtimeService.createProcessInstanceModification(processInstance.getId()).startBeforeActivity(contactCustomer#multiInstanceBody).execute();
这将再次启动整个多实例正文从而导致以下活动实例树
ProcessInstanceContact Customer - Multi-Instance BodyContact CustomerContact CustomerContact CustomerContact CustomerContact Customer - Multi-Instance BodyContact CustomerContact CustomerContact Customer
2.10、流程实例的异步修改
可以异步执行单个流程实例的修改。修改指令与同步修改相同Fluent Builder 的语法如下
Batch modificationBatch runtimeService.createProcessInstanceModification(processInstanceId).cancelActivityInstance(exampleActivityId:1).startBeforeActivity(exampleActivityId:2).executeAsync();
这将创建一个异步执行的修改批处理。 在执行单个流程实例的异步修改时不支持提供变量。
2.11、修改多个流程实例
当有多个流程实例满足特定条件时可以使用RuntimeService.createModification…一次修改它们。此方法允许指定应修改的流程实例的修改指令和ID。流程实例必须属于给定的流程定义。
fluent修改生成器提供了以下待提交的说明
startBeforeActivity(String activityId)startAfterActivity(String activityId)startTransition(String transitionId)cancelAllForActivity(String activityId)
可以通过提供一组流程实例 ID 或提供流程实例查询来选择流程实例进行修改。 也可以同时指定流程实例 ID 列表和查询。然后要修改的流程实例将是结果集的并集。
ProcessInstanceQuery processInstanceQuery runtimeService.createProcessInstanceQuery();runtimeService.createModification(exampleProcessDefinitionId).cancelAllForActivity(exampleActivityId:1).startBeforeActivity(exampleActivityId:2).processInstanceIds(processInstanceQuery).processInstanceIds(processInstanceId:1, processInstanceId:2).execute();
可以同步或异步执行多个流程实例的修改。
同步执行示例
runtimeService.createModification(exampleProcessDefinitionId).cancelAllForActivity(exampleActivityId:1).startBeforeActivity(exampleActivityId:2).processInstanceIds(processInstanceId:1, processInstanceId:2).execute();
异步执行示例
Batch batch runtimeService.createModification(exampleProcessDefinitionId).cancelAllForActivity(exampleActivityId:1).startBeforeActivity(exampleActivityId:2).processInstanceIds(processInstanceId:1, processInstanceId:2, processInstanceId:100).executeAsync();
2.12、跳过侦听器和输入/输出调用
可以跳过执行和任务侦听器的调用以及执行修改的事务的输入/输出映射。当在无法访问相关流程应用程序部署及其包含的类的系统上执行修改时这可能非常有用。可以使用修改生成器的execute方法boolean skipCustomListenersboolean skipIoMappings跳过Listener和ioMapping调用。
使用注释选项可以出于审核原因传递任意文本注释。
runtimeService.createProcessInstanceModification(processInstanceId).cancelAllForActivity(declineLoanApplication).startBeforeActivity(processStartEvent).annotation(Modified to resolve an error.).execute();
它将在用户操作日志中显示用于执行的修改。
2.13、健全性检查
流程实例修改是一个非常强大的工具允许随意启动和取消活动。因此很容易创建正常流程执行无法到达的情况。假设以下流程模型 假设活动“拒绝贷款审批”处于活动状态。经过修改后可以开始活动“评估信用价值”。在该活动完成后执行被困在加入的并行网关因为没有令牌会到达其他传入序列流从而激活并行网关。这是流程实例无法继续执行的最明显情况之一当然还有许多其他情况具体取决于具体的流程模型。
流程引擎无法检测到造成这种情况的修改。此API的用户有权进行修改使流程实例不会处于不需要的状态。然而流程实例修改也是修复这些情况的工具。
更详细请参考camunda官方文档
https://docs.camunda.org/manual/7.19/user-guide/process-engine/process-instance-modification/
流程会签实现思路和原理基于camunda如何实现会签camunda会签流程配置与原理解析_camunda 会签-CSDN博客