基于camunda如何实现会签流程:camunda会签流程配置与原理解析

一、背景

市场上比较有名的开源流程引擎有osworkflow、jbpm、activiti、flowable、camunda。由于jbpm、activiti、flowable这几个流程引擎出现的比较早,国内人用的比较多,大家对camunda流程引擎认识的不多,实际上camunda在功能上、稳定性、性能、轻量化方面均比jbpm、activiti、flowable优秀。中国人使用业务流程,“会签”是一个最常用的流程操作,那么如何基于camunda实现会签流程,会签背后的流程引擎执行原理是什么,笔者希望通过这篇文章给正在研究camunda的同学参考,抛砖引玉。

二、什么是会签

会签: 在流程业务管理中,任务是通常都是由一个人去处理的,而多个人同时处理一个任务,这种任务我们称之为会签任务。

1、按照会签执行的顺序:

a)串行会签:串行会签也叫顺序会签,指按照提交流程处理人的次序user1、user2、user3依次接收待办任务,并按顺序处理流程。

b) 并行会签:指user1、user2、user3同时接收到流程待办任务,并行处理。

2、按照会签通过的比例:

a) 全部通过:会签人全部审批通过表决后,会签通过。

b) 按数量通过:达到一定数量的通过表决后,会签通过。

c) 按比例通过:达到一定比例的通过表决后,会签通过。

d) 一票通过:只要有一个表决通过的,会签通过。

e) 一票否决:只要有一个表决时否定的,会签通过。

以下介绍基于camunda流程引擎如何实现会签,并详细解析流程引擎运行的原理。

三、安装camunda BPM

首先完成camunda流程引擎的部署和camunda流程设计器的部署,并新建三个用户user1、user2、user3,为设计会签流程准备。详细操作见:《Camunda流程引擎快速入门——Hello World示例》, lowcode.blog.csdn.net/a



四、设计会签流程图

1、画流程图,设置一个会签节点

Camunda实现会签是基于多实例任务,将节点设置成多实例,主要通过在UserTask节点的属性上配置。选则一个用户任务在下面的属性中选择Multil instance,可以看到有两种图标,分别表示串行会签和并行会签。





2、会签参数设置

主要参数配置说明:

  • loop cardinality:循环基数。可选项。可以直接填整数,表示会签的人数。
  • Collection:集合。可选项。会签人数的集合,通常为list,和loop cardinality二选一。
  • Element variable:元素变量。选择Collection时必选,为collection集合每次遍历的元素。
  • Completion condition:完成条件。可选。比如设置一个人完成后会签结束,那么其他人的代办任务都会消失。



设置完成后,会签节点的代码片段:

    <bpmn:userTask id="Activity_1udxyrq" name="会签" camunda:assignee="${assignee}">
      <bpmn:incoming>Flow_1258z36</bpmn:incoming>
      <bpmn:outgoing>Flow_0248t03</bpmn:outgoing>
      <bpmn:multiInstanceLoopCharacteristics camunda:collection="assigneeList" camunda:elementVariable="assignee" />
</bpmn:userTask>

3、配置流程处理人

需要注意的是,右侧的Assignee,Candidate Users,Candidate Groups,分别表示按照负责人/候选用户/候选组。

采用Assignee,填写上一步中的Element Variable字段的内容,即可获取当前审批人,注意是动态变量,${}格式,即会签人Collection中遍历的每一个人赋值给该变量。




4、配置流程监听事件

为了更好的实现会签可以结合流程节点监听功能Listener处理,监听种类有Java class、Expression、Delegate expression、script,文本为了简单,使用script配置会签处理人。

如何使用groovy script,详细请参考camunda官方文档: docs.camunda.org/manual




设置完成后,executionListener的配置片段如下:

  <bpmn:extensionElements>
        <camunda:executionListener event="start">
          <camunda:script scriptFormat="groovy">def userList = ['user1', 'user2', 'user3'];execution.setVariable("assigneeList", userList);</camunda:script>
        </camunda:executionListener>
      </bpmn:extensionElements>

5、完整的BPMN流程文件

完整的BPMN流程模型文件:

<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_1lsa7z1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.8.1" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.15.0">
  <bpmn:process id="Process_1n6xfcx" name="测试验证流程1" isExecutable="true" camunda:versionTag="1.0">
    <bpmn:startEvent id="StartEvent_1">
      <bpmn:outgoing>Flow_153mh25</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:sequenceFlow id="Flow_153mh25" sourceRef="StartEvent_1" targetRef="Activity_18krv16" />
    <bpmn:sequenceFlow id="Flow_1258z36" sourceRef="Activity_18krv16" targetRef="Activity_1udxyrq" />
    <bpmn:sequenceFlow id="Flow_0248t03" sourceRef="Activity_1udxyrq" targetRef="Activity_0neq0ra" />
    <bpmn:endEvent id="Event_00b1j9n">
      <bpmn:incoming>Flow_0ucs2b7</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="Flow_0ucs2b7" sourceRef="Activity_0neq0ra" targetRef="Event_00b1j9n" />
    <bpmn:userTask id="Activity_18krv16" name="申请">
      <bpmn:extensionElements>
        <camunda:executionListener event="start">
          <camunda:script scriptFormat="groovy">def userList = ['user1', 'user2', 'user3'];execution.setVariable("assigneeList", userList);</camunda:script>
        </camunda:executionListener>
      </bpmn:extensionElements>
      <bpmn:incoming>Flow_153mh25</bpmn:incoming>
      <bpmn:outgoing>Flow_1258z36</bpmn:outgoing>
    </bpmn:userTask>
    <bpmn:userTask id="Activity_1udxyrq" name="会签" camunda:assignee="${assignee}">
      <bpmn:incoming>Flow_1258z36</bpmn:incoming>
      <bpmn:outgoing>Flow_0248t03</bpmn:outgoing>
      <bpmn:multiInstanceLoopCharacteristics camunda:collection="assigneeList" camunda:elementVariable="assignee" />
    </bpmn:userTask>
    <bpmn:userTask id="Activity_0neq0ra" name="审批" camunda:assignee="user2">
      <bpmn:incoming>Flow_0248t03</bpmn:incoming>
      <bpmn:outgoing>Flow_0ucs2b7</bpmn:outgoing>
    </bpmn:userTask>
  </bpmn:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1n6xfcx">
      <bpmndi:BPMNEdge id="Flow_0ucs2b7_di" bpmnElement="Flow_0ucs2b7">
        <di:waypoint x="690" y="117" />
        <di:waypoint x="752" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0248t03_di" bpmnElement="Flow_0248t03">
        <di:waypoint x="530" y="117" />
        <di:waypoint x="590" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_1258z36_di" bpmnElement="Flow_1258z36">
        <di:waypoint x="370" y="117" />
        <di:waypoint x="430" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_153mh25_di" bpmnElement="Flow_153mh25">
        <di:waypoint x="215" y="117" />
        <di:waypoint x="270" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
        <dc:Bounds x="179" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_00b1j9n_di" bpmnElement="Event_00b1j9n">
        <dc:Bounds x="752" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_068boyx_di" bpmnElement="Activity_18krv16">
        <dc:Bounds x="270" y="77" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_10kl1f8_di" bpmnElement="Activity_1udxyrq">
        <dc:Bounds x="430" y="77" width="100" height="80" />
      </bpmndi:BPMNShape>