flowable 分支示例
flowable 分支示例
本文将介绍带有分支节点的flawable使用示例,在我们之前的文章中,我们已经介绍了Flowable无分支流程示例,如果你还没有阅读过,可以点击这里查看。
1.分支流程的概念:
在许多实际的业务场景中,我们可能会遇到需要根据不同的条件选择不同的处理流程的情况,这就是所谓的分支流程。在Flowable中,我们可以使用网关(Gateway)来实现这种分支流程。
以请假流程为例,假设一个员工需要请假,那么他首先需要找HR审批。如果请假天数不超过10天,那么HR的审批就足够了。但是,如果请假天数超过10天,那么就需要进一步找主管审批。这就形成了一个分支流程:根据请假天数的不同,选择不同的审批流程。
在这个例子中,”请假天数是否超过10天”就是一个分支条件,”找HR审批”和”找主管审批”就是两个分支流程。在Flowable中,我们可以使用网关来实现这个分支条件,然后根据条件的结果选择不同的流程进行处理。如图所示
2.Flowable实现分支流程
在Flowable中,我们可以使用网关(Gateway)来实现分支流程。网关是一种特殊的流程节点,它可以根据一定的条件来决定流程的走向。在我们的请假流程中,我们可以使用一个网关来决定是走HR审批流程,还是走主管审批流程。
Flowable中的网关主要有以下几种类型:
排他网关(Exclusive Gateway):也称为决策网关,它会根据条件选择一条分支执行,其他分支不执行。
并行网关(Parallel Gateway):它会同时启动所有的出口序列流,等所有的出口序列流都完成后,再汇聚到一起。
包含网关(Inclusive Gateway):它会根据条件启动一个或多个出口序列流,等所有启动的出口序列流都完成后,再汇聚到一起。
在我们的请假流程中,我们可以使用排他网关来实现分支流程。我们可以定义一个条件表达式,如果请假天数超过10天,那么走主管审批流程,否则走HR审批流程。
在Flowable中,我们可以使用BPMN 2.0的XML语言来定义流程。以下是一个简单的例子:
1
2
3
4
5
6
7
<bpmn:exclusiveGateway id="exclusiveGw" name="Exclusive Gateway" default="sequenceFlow1" />
<bpmn:sequenceFlow id="sequenceFlow1" sourceRef="exclusiveGw" targetRef="hrApproval">
<bpmn:conditionExpression xsi:type="tFormalExpression">${days <= 10}</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="sequenceFlow2" sourceRef="exclusiveGw" targetRef="managerApproval">
<bpmn:conditionExpression xsi:type="tFormalExpression">${days > 10}</bpmn:conditionExpression>
</bpmn:sequenceFlow>
3.完整的分支流程示例
这段代码是用于创建一个Flowable流程定义的。下面是对这段代码的详细解释:
- 首先,创建一个新的
Process
对象,并设置其ID和名称。1 2 3
Process process = new Process(); process.setId(createProcessDefinitionBranchDTO.getFlowName()); process.setName(createProcessDefinitionBranchDTO.getFlowName());
- 创建一个开始节点(
StartEvent
),并将其添加到流程中。1 2 3 4
StartEvent startEvent = new StartEvent(); startEvent.setId("StartEvent"+ UUID.randomUUID().toString().substring(0, 11)); startEvent.setName("开始"); process.addFlowElement(startEvent);
- 创建一个服务任务(
ServiceTask
),并将其添加到流程中。服务任务是一种特殊类型的任务,它代表了一个自动执行的步骤,比如调用一个Java类或者一个外部系统。1 2 3 4 5 6
ServiceTask startServiceTask = new ServiceTask(); startServiceTask.setId("StartServiceTask"+UUID.randomUUID().toString().substring(0,11)); startServiceTask.setName("提交"); startServiceTask.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_CLASS); startServiceTask.setImplementation(StartServiceTask.class.getName()); process.addFlowElement(startServiceTask);
- 创建一个序列流(
SequenceFlow
),并将其添加到流程中。序列流是流程中的箭头,它定义了流程的执行顺序。在这里,序列流从开始节点指向服务任务。1 2 3 4 5
SequenceFlow startServiceSequence = new SequenceFlow(); startServiceSequence.setId("StartServiceSequence"+UUID.randomUUID().toString().substring(0,11)); startServiceSequence.setSourceRef(startEvent.getId()); startServiceSequence.setTargetRef(startServiceTask.getId()); process.addFlowElement(startServiceSequence);
- 创建网关(
Gateway
),并将其添加到流程中。网关用于控制流程的分支和合并。这段代码根据输入的网关类型创建了相应的网关,并将其添加到了流程中。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Map<String, Gateway> gateways = new HashMap<>(); for (GatewayDefinitionDTO gatewayDTO : createProcessDefinitionBranchDTO.getGatewayDefinitionDTOS()) { Gateway gateway; if ("ExclusiveGateway".equals(gatewayDTO.getType())) { gateway = new ExclusiveGateway(); } else if ("ParallelGateway".equals(gatewayDTO.getType())) { gateway = new ParallelGateway(); } else { throw new IllegalArgumentException("Unsupported gateway type: " + gatewayDTO.getType()); } gateway.setId(gatewayDTO.getId()); // 使用前端提供的ID gateway.setName(gatewayDTO.getName()); process.addFlowElement(gateway); gateways.put(gatewayDTO.getId(), gateway); // 将网关添加到映射中 }
- 创建用户任务(
UserTask
),并将其添加到流程中。用户任务代表了需要人工完成的步骤。这段代码根据输入的节点信息创建了用户任务,并设置了多实例特性。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
for (ProcessNodeDefinitionDTO nodeDTO : createProcessDefinitionBranchDTO.getProcessNodeDefinitionDTOS()) { UserTask userTask = new UserTask(); userTask.setId(nodeDTO.getNodeId()); // 使用前端提供的ID userTask.setName(nodeDTO.getNodeName()); userTask.setAssignee("${" + nodeDTO.getNodeName() + "Assignee}"); MultiInstanceLoopCharacteristics loopCharacteristics = new MultiInstanceLoopCharacteristics(); loopCharacteristics.setSequential(false); loopCharacteristics.setInputDataItem(nodeDTO.getNodeName() + "Assignees"); loopCharacteristics.setElementVariable( nodeDTO.getNodeName() + "Assignee"); String completionCondition = nodeDTO.getNodeCategory() == 1 ? "${nrOfCompletedInstances == nrOfInstances}" : "${nrOfCompletedInstances >= 1}"; loopCharacteristics.setCompletionCondition(completionCondition); userTask.setLoopCharacteristics(loopCharacteristics); process.addFlowElement(userTask); }
创建结束节点(
EndEvent
),并将其添加到流程中。结束节点是流程的终点,每个流程都应该有一个或多个结束节点。1 2 3 4
EndEvent endEvent = new EndEvent(); endEvent.setId("endEvent"+UUID.randomUUID().toString().substring(0,11)); endEvent.setName("结束"); process.addFlowElement(endEvent);
- 创建序列流(
SequenceFlow
),并将其添加到流程中。这段代码根据输入的序列流信息创建了序列流,并将其添加到了流程中。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
for (SequenceFlowDefinitionDTO sequenceFlowDTO : createProcessDefinitionBranchDTO.getSequenceFlowDefinitionDTOS()) { SequenceFlow sequenceFlow = new SequenceFlow(); sequenceFlow.setId(sequenceFlowDTO.getId()); // 使用前端提供的ID // 判断并设置sourceRef if ("StartEvent".equals(sequenceFlowDTO.getSourceRef())){ sequenceFlow.setSourceRef(startServiceTask.getId()); } else { sequenceFlow.setSourceRef(sequenceFlowDTO.getSourceRef()); // 使用映射中的网关ID } // 判断并设置targetRef if ("EndEvent".equals(sequenceFlowDTO.getTargetRef())){ sequenceFlow.setTargetRef(endEvent.getId()); } else { sequenceFlow.setTargetRef(sequenceFlowDTO.getTargetRef()); // 使用映射中的用户任务ID } sequenceFlow.setConditionExpression(sequenceFlowDTO.getConditionExpression()); process.addFlowElement(sequenceFlow); }
- 创建BPMN模型(BpmnModel),并将流程添加到模型中。BPMN模型是流程定义的容器,它可以包含多个流程定义。最后,这段代码将创建的流程定义部署到Flowable引擎中。
1 2 3
BpmnModel bpmnModel = new BpmnModel(); bpmnModel.addProcess(process); deploy(bpmnModel, createProcessDefinitionBranchDTO);
4.无分支流程与分支流程比较
- 单条线流程(Sequential Flow):
这种流程中的任务按照一定的顺序依次执行,每个任务都有一个明确的前驱任务和后继任务。这种流程设计简单明了,适用于流程中的任务有明确的依赖关系,且不需要并行处理的场景。
A --> B --> C --> D
- 分支流程(Branching Flow):
这种流程中的某些任务可以并行执行,流程在某个点会分叉,分别进入不同的分支,每个分支可以独立执行,最后再在某个点汇合。这种流程设计灵活,适用于流程中的任务可以并行处理,或者需要根据条件选择执行不同任务的场景。1 2 3 4 5
A / \ B C \ / D