我们在使用Flowable 工作流引擎的时候,最常用的肯定是任务节点,因为在OA系统、审批系统、办公自动化系统中核心的处理就是流程的运转,在流程运转的时候,可能我们有这样的一个需求,在一个任务节点的时候,我们需要多个人对这个节点进行审批,比如实际中这样一个例子,假如是一个部门的投票,这个部门有5个人,那么当5个人都投票的时候大概分为如下几种:

1.部门所有人都去投票,当所有人都投票完成的时候,这个节点结束,流程运转到下一个节点。(所有的人都需要投票)

2.部门所有人都去投票,只要有任意2/3的人同意,这个节点结束,流程运转到下一个节点。(部分人投票只要满足条件就算完成)。

3.部门中有一个部门经理,只要部门经理投票过了,这个节点结束,流程运转到下一个节点(一票否决权)。

4.部门中根据职位不同,不同的人都不同的权重,当满足条件的时候,这个节点结束,流程运转到下一个节点。比如说所有的人员权重加起来是1,a有0.2的权重,其他的四个人分别是0.1的权重,我们可以配置权重达到0.3就可以走向下一个节点,换言之a的权重是其他人的2倍,那就是a的投票相当于2个人投票。这种需求还是很常见的。

5.部门所有人都去投票,a投票结束到b,b开始投票结束到c,一直如此,串行执行。最终到最后一个人再统计结果,决定流程的运转。

上面的五种情况,我们可以提取出来一些信息,我们的activiti 工作流引擎,必须支持如下功能,才能满足上面的需求:

1.任务节点可以配置自定义满足条件。

2.任务节点必须支持串行、并行。

3.任务节点必须支持可以指定候选人或者候选组。

4.任务节点必须支持可以循环的次数。

5.任务节点必须支持可以自定义权重。

6.任务节点必须支持加签、减签。(就是动态的修改任务节点的处理人)

因为实际上的需求可能比上面的几种情况更加的复杂,上面的6个满足条件,工作流支持前4个,后面的2个条件是不支持的,所以我们必须要扩展activiti 工作流引擎才能使用5、6等的功能。下面我们将详细的介绍前四种条件的使用,在掌握基本使用之后,我们在后面的章节中将详细的介绍,5、6这两种功能以及可能更加复杂的操作。

1.1.2. 串行、并行配置

为了演示如何使用,我们采用由浅入深的使用,结合流程图、流程定义xml、以及代码和数据库的变化来阐释每一个配置的使用以及含义。

流程的详细定义如下图所示:

 

流程的详细定义xml如下:

<?xml version="1.0" encoding="UTF-8"?>

<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef">

<process id="multiInstance" name="multiInstance" isExecutable="true">

<documentation>multiInstance</documentation>

<startEvent id="startEvent1"></startEvent>

<userTask id="A" name="多实例测试" flowable:candidateUsers="shareniu1,shareniu2,shareniu3,shareniu4" xmlns:shareniu="http://www.shareniu.com/" shareniu:shareniuext="" shareniu:shareniuextboolen="false">

<multiInstanceLoopCharacteristics isSequential="true">

<loopCardinality>2</loopCardinality>

</multiInstanceLoopCharacteristics>

</userTask>

<sequenceFlow id="sid-6D482A8A-F796-4E2B-AB2C-ABBFD2DA428D" sourceRef="startEvent1" targetRef="A"></sequenceFlow>

<userTask id="shareniu-B" name="shareniu-B" xmlns:shareniu="http://www.shareniu.com/" shareniu:shareniuext="" shareniu:shareniuextboolen="false"></userTask>

<sequenceFlow id="sid-BA8FC337-40DC-493B-805C-F213B7C4A17D" sourceRef="A" targetRef="shareniu-B"></sequenceFlow>

<endEvent id="sid-4AC81F5B-49F8-4135-B68E-1C182D004080"></endEvent>

<sequenceFlow id="sid-DF962BB4-EA4C-4D86-9A91-214EB2EC1A47" sourceRef="shareniu-B" targetRef="sid-4AC81F5B-49F8-4135-B68E-1C182D004080"></sequenceFlow>

</process>

<bpmndi:BPMNDiagram id="BPMNDiagram_multiInstance">

<bpmndi:BPMNPlane bpmnElement="multiInstance" id="BPMNPlane_multiInstance">

<bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">

<omgdc:Bounds height="30.0" width="30.0" x="100.0" y="130.0"></omgdc:Bounds>

</bpmndi:BPMNShape>

<bpmndi:BPMNShape bpmnElement="A" id="BPMNShape_A">

<omgdc:Bounds height="80.0" width="100.0" x="165.0" y="105.0"></omgdc:Bounds>

</bpmndi:BPMNShape>

<bpmndi:BPMNShape bpmnElement="shareniu-B" id="BPMNShape_shareniu-B">

<omgdc:Bounds height="80.0" width="100.0" x="315.0" y="120.0"></omgdc:Bounds>

</bpmndi:BPMNShape>

<bpmndi:BPMNShape bpmnElement="sid-4AC81F5B-49F8-4135-B68E-1C182D004080" id="BPMNShape_sid-4AC81F5B-49F8-4135-B68E-1C182D004080">

<omgdc:Bounds height="28.0" width="28.0" x="442.0" y="146.0"></omgdc:Bounds>

</bpmndi:BPMNShape>

<bpmndi:BPMNEdge bpmnElement="sid-DF962BB4-EA4C-4D86-9A91-214EB2EC1A47" id="BPMNEdge_sid-DF962BB4-EA4C-4D86-9A91-214EB2EC1A47">

<omgdi:waypoint x="414.9499999999902" y="160.0"></omgdi:waypoint>

<omgdi:waypoint x="442.0" y="160.0"></omgdi:waypoint>

</bpmndi:BPMNEdge>

<bpmndi:BPMNEdge bpmnElement="sid-BA8FC337-40DC-493B-805C-F213B7C4A17D" id="BPMNEdge_sid-BA8FC337-40DC-493B-805C-F213B7C4A17D">

<omgdi:waypoint x="264.95000000000005" y="145.0"></omgdi:waypoint>

<omgdi:waypoint x="290.0" y="145.0"></omgdi:waypoint>

<omgdi:waypoint x="290.0" y="160.0"></omgdi:waypoint>

<omgdi:waypoint x="314.99999999998477" y="160.0"></omgdi:waypoint>

</bpmndi:BPMNEdge>

<bpmndi:BPMNEdge bpmnElement="sid-6D482A8A-F796-4E2B-AB2C-ABBFD2DA428D" id="BPMNEdge_sid-6D482A8A-F796-4E2B-AB2C-ABBFD2DA428D">

<omgdi:waypoint x="129.94999817301806" y="145.0"></omgdi:waypoint>

<omgdi:waypoint x="165.0" y="145.0"></omgdi:waypoint>

</bpmndi:BPMNEdge>

</bpmndi:BPMNPlane>

</bpmndi:BPMNDiagram>

</definitions>

<xml配置文件的部分含义如下:

1.flowable:candidateUsers="shareniu1,shareniu2,shareniu3,shareniu4" 这个节点可以4个人审核。

2.<loopCardinality>2</loopCardinality> 循环2次结束。

3.<multiInstanceLoopCharacteristics isSequential="true"> 串行并行的配置。

1.1.2.1. 串行的配置

修改<multiInstanceLoopCharacteristics isSequential="true"> 中的isSequential为true是串行,isSequential为false是并行。我们测试串行。下面的代码展示启动流程因为是以一个节点所以部署启动后,直接进入多实例任务。

1.1.2.1.1. 流程的部署

@Test

public void addBytes() {

byte[] bytes = IoUtil.readInputStream(

ProcessengineTest.class.getClassLoader()

.getResourceAsStream("com/shareniu/shareniu_flowable_study/bpmn/ch3/multiInstance.bpmn20.xml"),

"multiInstance.bpmn20.xml");

String resourceName = "multiInstance.bpmn";

Deployment deployment = repositoryService.createDeployment().addBytes(resourceName, bytes).deploy();

System.out.println(deployment);

}

1.1.2.1.2. 流程的启动

@Test

public void startProcessInstanceByKey() {

String processDefinitionKey = "multiInstance";

ProcessInstance startProcessInstanceByKey = runtimeService.startProcessInstanceByKey(processDefinitionKey);

System.out.println(startProcessInstanceByKey);

}

我们按照上面的步骤启动一个流程看一下数据库的变化。

ACT_RU_TASK表的数据有了如下图所示:

ACT_RU_IDENTITYLINK表的数据有了如下图所示:

ACT_RU_IDENTITYLINK权限表中,确实把我们设置的人员信息设置进去了,shareniu1,shareniu2,shareniu3,shareniu4现在就有代办信息了。

ACT_RU_VARIABLE表的数据有了如下图示:

上面重要的变量需要解释一下,要不然还真不好理解,多任务是怎么运转的。

1.nrOfInstances  实例总数。

2.nrOfCompletedInstances  当前还没有完成的实例 nr是number单词缩写 。

3.loopCounter 已经循环的次数。

4.nrOfActiveInstances 已经完成的实例个数。

下面我们结束一个任务看一下,流程走到那个节点了。

1.1.2.1.3. 完成任务

@Test

public void complete() {

String taskId="15011";

taskService.complete(taskId);

}

接下来看一下数据库表的变化。

ACT_RU_VARIABLE表的数据有了如下图所示:

上面我们仔细的发现,可以看到

nrOfCompletedInstances、loopCounter、nrOfActiveInstances都加1了,确实多任务就是参考这几个值的变化进行判断的。

因为我们设置了循环2次,所以我们看看ACT_RU_IDENTITYLINK还有一个任务,因为我们是并行处理的。

所以我们在结束新的任务看一下流程是不是真的结束了,如果结束了,那么我们循环次数的配置就是正确的。

1.1.2.1.4. 完成任务

@Test

public void complete() {

String taskId="17502";

taskService.complete(taskId);

}

下面看一下ACT_RU_TASK,里面没有任务信息了,所以侧面证明循环次数的配置就是正确的。

接下来我们测试并行任务。除了isSequential="false",其他的配置是一样的。

1.1.2.2. 并行的配置测试

除了isSequential="false",其他的配置跟上面的串行是一样一样的。

重新部署测试,部署后我们启动一个新的流程测试。

ACT_RU_TASK表如下:

一次性的有2个任务需要处理,因为我们循环的是2次,所以直接就是2个。

ok串行、并行就讲解到这里。

1.1.3. 串行、并行总结

我们配置的是循环2次,看以看到不管是并行还是串行,两个代办任务结束之后,流程直接跳转到下一个状态,但是

我们并没有配置结束条件,所以上面的例子,也可以看出来,如果不配置默认的通过条件,则默认条件是1,后面的源码章节会给大家说明这一点的。

1.1.4. 通过条件的配置

在上面的串行、并行实例中,我们没有设置通过条件,但是程序按照配置的循环的次数,然后跳转到了下一个状态,可以侧面印证,如果不配置通过条件则默认值就是1.

下面的代码详细的介绍通过条件的配置,具体的配置代码如下:

<process id="multiInstance" name="multiInstance"

isExecutable="true">

<documentation>multiInstance</documentation>

<startEvent id="startEvent1"></startEvent>

<userTask id="A" name="多实例测试"

flowable:candidateUsers="shareniu1,shareniu2,shareniu3,shareniu4">

<multiInstanceLoopCharacteristics

isSequential="true">

<loopCardinality>4</loopCardinality>

<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.25}</completionCondition>

</multiInstanceLoopCharacteristics>

</userTask>

<sequenceFlow

id="sid-6D482A8A-F796-4E2B-AB2C-ABBFD2DA428D" sourceRef="startEvent1"

targetRef="A"></sequenceFlow>

<userTask id="shareniu-B" name="shareniu-B"

xmlns:shareniu="http://www.shareniu.com/" shareniu:shareniuext=""

shareniu:shareniuextboolen="false"></userTask>

<sequenceFlow

id="sid-BA8FC337-40DC-493B-805C-F213B7C4A17D" sourceRef="A"

targetRef="shareniu-B"></sequenceFlow>

<endEvent id="sid-4AC81F5B-49F8-4135-B68E-1C182D004080"></endEvent>

<sequenceFlow

id="sid-DF962BB4-EA4C-4D86-9A91-214EB2EC1A47" sourceRef="shareniu-B"

targetRef="sid-4AC81F5B-49F8-4135-B68E-1C182D004080"></sequenceFlow>

</process>

1.1.4.1. 配置描述

<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.25}</completionCondition>

nrOfCompletedInstances、nrOfInstances 变量描述上面已经描述了,我们这里设置的条件是大于1/4的人完成任务,任务就结束了。下面我们代码部署流程,启动流程后进行测试:

ACT_RU_TASK表如下:

我们随便结束一个任务,看一下ACT_RU_TASK表变化。

@Test

public void complete() {

String taskId="40003";

taskService.complete(taskId);

}

执行上面的代码,我们很神奇的发现,ACT_RU_TASK表中的其他任务没有了,因为我们配置了4个人,通过条件是1/4,所以任意一个人结束了,流程就结束了。这里我们测试的是并行,串行也是一样的,读者可以自行测试验证。

1.1.5. 动态的配置

上面的几种方式,我们定义xml的时候,循环的次数是固定写在xml中的,也就是说我们配置的是循环2次,那么所有的流程实例都是循环2次,这样就不灵活了,程序当然是灵活了比较好,所以在实际开发中,我们可以使用下面的这种方式操作,使程序更加的灵活。

程序的xml配置如下所示:

  1. <process id="multiInstance" name="multiInstance"

    isExecutable="true">

    <documentation>multiInstance</documentation>

    <startEvent id="startEvent1"></startEvent>

    <userTask id="A" name="多实例测试" flowable:assignee="${assignee}">

    <multiInstanceLoopCharacteristics

    isSequential="false" flowable:collection="assigneeList"

    flowable:elementVariable="assignee">

    <completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.25}

    </completionCondition>

    </multiInstanceLoopCharacteristics>

    </userTask>

    <sequenceFlow

    id="sid-6D482A8A-F796-4E2B-AB2C-ABBFD2DA428D" sourceRef="startEvent1"

    targetRef="A"></sequenceFlow>

    <userTask id="shareniu-B" name="shareniu-B"

    xmlns:shareniu="http://www.shareniu.com/" shareniu:shareniuext=""

    shareniu:shareniuextboolen="false"></userTask>

    <sequenceFlow

    id="sid-BA8FC337-40DC-493B-805C-F213B7C4A17D" sourceRef="A"

    targetRef="shareniu-B"></sequenceFlow>

    <endEvent id="sid-4AC81F5B-49F8-4135-B68E-1C182D004080"></endEvent>

    <sequenceFlow

    id="sid-DF962BB4-EA4C-4D86-9A91-214EB2EC1A47" sourceRef="shareniu-B"

    targetRef="sid-4AC81F5B-49F8-4135-B68E-1C182D004080"></sequenceFlow>

    </process>

动态配置如下所示:

<userTask id="usertask1" name="多实例任务" flowable:assignee="${assignee}">

<multiInstanceLoopCharacteristics isSequential="false" activiti:collection="assigneeList" activiti:elementVariable="assignee">

<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.25}</completionCondition>

</multiInstanceLoopCharacteristics>

</userTask>

参数说明:

activiti:assignee="${assignee}"

activiti:elementVariable="assignee" 多实例任务依赖上面的配置${assignee}

activiti:collection="assigneeList"

三个参数结合决定了,当前节点的处理人来自assigneeList集合,注意这里是集合信息而不是字符串,所以程序的运行时候变量的赋值,如下所示:

@Test

public void startProcessInstanceByKey() {

Map<String, Object> vars = new HashMap<>();

String[] v = { "shareniu1", "shareniu2", "shareniu3", "shareniu4" };

vars.put("assigneeList", Arrays.asList(v));

String processDefinitionKey = "multiInstance";

ProcessInstance startProcessInstanceByKey = runtimeService.startProcessInstanceByKey(processDefinitionKey,

vars);

Sys

ok了,测试一下,确实程序如预期的所示,大功告成。

1.1.6. 总结

参数的使用总结

4.flowable:candidateUsers="shareniu1,shareniu2,shareniu3,shareniu4" 这个节点可以4个人审核。

5.<loopCardinality>2</loopCardinality> 循环2次结束。

6.<multiInstanceLoopCharacteristics isSequential="true"> 串行并行的配置。

<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.25}</completionCondition> 完成条件的配置。

这里我们还可以得出一个结论:

如果使用串行方式操作nrOfActiveInstances 变量始终是1,因为并行的时候才会去+1操作。

1.1.7. 遗留点

上面的程序已经解决了常用的问题,关于会签、加签、减签、退签、权重配置、自定义通过条件配置(条件自定义通过)

flowable 任务节点多实例使用相关推荐

  1. 工作流-flowable 之驳回 多实例驳回 并行网关驳回 普通节点驳回到多实例

    6.4.0 新增加了驳回的方式,真是对中国式流程的一种福音呀,感谢flowable创始人. 再也不为开发驳回流程发愁了,网上那些视频和修改源码真的是demo级别的,不能商业用. 只有心如流水的学习才是 ...

  2. springboot集成flowable创建请假流程实例

    springboot如何集成flowable,如何部署flowable在线编辑器画bpm图以及bpm图的画法,我在上一篇博客中写了,这里直接上代码(源码地址:晚安/flowable_holiday ( ...

  3. Flowable工作流之多实例任务会签

    目录 1. 会签 2. 多实例任务会签 2.1. 绘制流程图 2.1.1. 多实例类型 2.1.2. 集合(多实例) 2.1.3. 元素变量(多实例) 2.1.4. 分配用户 2.1.5. 完成条件( ...

  4. Flowable 6.4 多实例会签 审批人设置、结果判断、会签后走向

    目前最新版的Flowable6.4,与旧版或Activiti有些许区别.由于关于Flowable的文章比较稀缺,遇到不少坑,特此记录. 参考文章:http://huan1993.iteye.com/b ...

  5. java正则截取xml节点_实例讲述Java使用正则表达式截取重复出现的XML字符串功能...

    Java使用正则表达式截取重复出现的XML字符串功能示例 本文实例讲述了Java使用正则表达式截取重复出现的XML字符串功能.分享给大家供大家参考,具体如下: public static void m ...

  6. 11gR2 RAC手动添加节点数据库实例

    两台服务器构成的Oracle 11gR2 RAC环境中,其中rac1服务器的私有网卡需要更换,所以在rac2服务器上使用dbca创建数据库的时候只创建了本节点的数据库实例(oracledb1).当ra ...

  7. mysql 5.7 单节点多实例_mysql5.7 多实例(第二篇)从节点数据异常

    前言: 大年初五,原计划撸一遍数据库监控的知识点,查看数据库时发现某一从节点数据不一致 1.查看节点状态   mysqld_multi report; 图1 2. 启动 所有节点   mysqld_m ...

  8. Flowable获取节点信息

    1.传入当前任务ID,和当前任务的一个选择条件值(测试后发现传入任何值都行) /*** 下一节点名称* @param taskId 流程id* @return*/public void findFlo ...

  9. flowable 并行节点跳转以及驳回

    bpmn流程图 <?xml version="1.0" encoding="UTF-8"?> <definitions xmlns=" ...

最新文章

  1. embed的名词_常见名词解释
  2. Android事件传递(分发)机制
  3. php设计模式--单例模式
  4. Dubbo学习总结(2)——Dubbo架构详解
  5. vs 2010 不显示解决方案文件
  6. 外媒:英特尔未来10年可能投资950亿美元在欧洲新建8家芯片厂
  7. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 图片:为图片添加圆角 (IE8 不支持)
  8. Oracle中使用DBMS_XPLAN查看执行计划的方法
  9. [CTBS]许可证过期之激活
  10. python爬虫与反爬虫
  11. Postman启动慢一直加载解决方案
  12. python 006 __ 小斌文档 | 特殊字符的使用
  13. 给定字符串1壹 2贰 3叁 4肆 5伍 6陆 7柒 8捌 9玖,输入对应的数字,输出对应的大写
  14. matlab编程刀尖频响,用半理论法预测主轴系统刀尖点频响函数
  15. 改变的不仅仅是货币——区块链技术的深层意义
  16. .NET开源工作流RoadFlow-表单设计-保存与发布
  17. 计算机与音乐结合论文,计算机毕业论文:浅谈计算机音乐技术在音乐教学中的应用...
  18. 根据年份与月份获取年、月、日
  19. 混合整数规划问题:Benders 解耦法
  20. js常用的几种for循环

热门文章

  1. anaconda如何卸载库_小白必看!Anaconda安装全攻略
  2. ubuntu安装好后常用软件安装和配置
  3. error: expected unqualified-id before 'public'
  4. 《MySQL 8.0.22执行器源码分析(1)——execute iterator一些记录》
  5. leetcode 47. 全排列 II 思考分析
  6. 肯德基收银系统模式_肯德基的完整形式是什么?
  7. 第五章 条件、循环及其他语句
  8. C++ STL 初步介绍01
  9. 详解list容器(应用+模拟实现)
  10. 【Java学习笔记三】抽象类与接口