activiti 多实例任务
1.1.1. 前言
个人,那么当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:activiti="http://activiti.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="daling">
<process id="daling" name="name_daling" isExecutable="true" activiti:candidateStarterUsers="a,b,c,d">
<startEvent id="startevent1" name="Start"></startEvent>
<userTask id="usertask1" name="多实例任务" activiti:candidateUsers="shareniu1,shareniu2,shareniu3,shareniu4">
<multiInstanceLoopCharacteristics isSequential="true">
<loopCardinality>2</loopCardinality>
</multiInstanceLoopCharacteristics>
</userTask>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow2" sourceRef="usertask1" targetRef="endevent1"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_daling">
<bpmndi:BPMNPlane bpmnElement="daling" id="BPMNPlane_daling">
<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
<omgdc:Bounds height="35.0" width="35.0" x="180.0" y="150.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
<omgdc:Bounds height="55.0" width="105.0" x="370.0" y="90.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
<omgdc:Bounds height="35.0" width="35.0" x="650.0" y="130.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="215.0" y="167.0"></omgdi:waypoint>
<omgdi:waypoint x="422.0" y="145.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="475.0" y="117.0"></omgdi:waypoint>
<omgdi:waypoint x="667.0" y="130.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
个人审核。
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. 流程的部署
Deployment deploy = repositoryService2.createDeployment()
.category(category).addClasspathResource("demo1.bpmn").deploy();
1.1.2.1.2. 流程的启动
了,确实多任务就是参考这几个值的变化进行判断的。
次,所以我们看看ACT_RU_IDENTITYLINK还有一个任务,因为我们是并行处理的。
所以我们在结束新的任务看一下流程是不是真的结束了,如果结束了,那么我们循环次数的配置就是正确的。
1.1.2.1.4. 完成任务
String taskId="47502";
demo.getTaskService().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.
下面的代码详细的介绍通过条件的配置,具体的配置代码如下:
<?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:activiti="http://activiti.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="daling">
<process id="daling" name="name_daling" isExecutable="true" activiti:candidateStarterUsers="a,b,c,d">
<startEvent id="startevent1" name="Start"></startEvent>
<userTask id="usertask1" name="多实例任务" activiti:candidateUsers="shareniu1,shareniu2,shareniu3,shareniu4">
<multiInstanceLoopCharacteristics isSequential="false">
<loopCardinality>4</loopCardinality>
<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.25}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow2" sourceRef="usertask1" targetRef="endevent1"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_daling">
<bpmndi:BPMNPlane bpmnElement="daling" id="BPMNPlane_daling">
<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
<omgdc:Bounds height="35.0" width="35.0" x="180.0" y="150.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
<omgdc:Bounds height="55.0" width="105.0" x="371.0" y="140.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
<omgdc:Bounds height="35.0" width="35.0" x="660.0" y="150.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="215.0" y="167.0"></omgdi:waypoint>
<omgdi:waypoint x="371.0" y="167.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="476.0" y="167.0"></omgdi:waypoint>
<omgdi:waypoint x="660.0" y="167.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
1.1.4.1. 配置描述
<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.25}</completionCondition>
nrOfCompletedInstances、nrOfInstances 变量描述上面已经描述了,我们这里设置的条件是大于1/4的人完成任务,任务就结束了。下面我们代码部署流程,启动流程后进行测试:
ACT_RU_TASK表如下:
我们随便结束一个任务,看一下ACT_RU_TASK表变化。
个人,通过条件是1/4,所以任意一个人结束了,流程就结束了。这里我们测试的是并行,串行也是一样的,读者可以自行测试验证。
1.1.5. 动态的配置
上面的几种方式,我们定义xml的时候,循环的次数是固定写在xml中的,也就是说我们配置的是循环2次,那么所有的流程实例都是循环2次,这样就不灵活了,程序当然是灵活了比较好,所以在实际开发中,我们可以使用下面的这种方式操作,使程序更加的灵活。
程序的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:activiti="http://activiti.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="daling">
<process id="daling" name="name_daling" isExecutable="true" activiti:candidateStarterUsers="a,b,c,d">
<startEvent id="startevent1" name="Start"></startEvent>
<userTask id="usertask1" name="多实例任务" activiti:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="false" activiti:collection="assigneeList" activiti:elementVariable="assignee">
<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.25}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow2" sourceRef="usertask1" targetRef="endevent1"></sequenceFlow>
<userTask id="usertask2" name="User Task"></userTask>
<sequenceFlow id="flow3" sourceRef="startevent1" targetRef="usertask2"></sequenceFlow>
<sequenceFlow id="flow4" sourceRef="usertask2" targetRef="usertask1"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_daling">
<bpmndi:BPMNPlane bpmnElement="daling" id="BPMNPlane_daling">
<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
<omgdc:Bounds height="35.0" width="35.0" x="180.0" y="150.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
<omgdc:Bounds height="55.0" width="105.0" x="371.0" y="140.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
<omgdc:Bounds height="35.0" width="35.0" x="660.0" y="150.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
<omgdc:Bounds height="55.0" width="105.0" x="330.0" y="50.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="476.0" y="167.0"></omgdi:waypoint>
<omgdi:waypoint x="660.0" y="167.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
<omgdi:waypoint x="197.0" y="150.0"></omgdi:waypoint>
<omgdi:waypoint x="382.0" y="105.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
<omgdi:waypoint x="382.0" y="105.0"></omgdi:waypoint>
<omgdi:waypoint x="423.0" y="140.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
动态配置如下所示:
<userTask id="usertask1" name="多实例任务" activiti: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集合,注意这里是集合信息而不是字符串,所以程序的运行时候变量的赋值,如下所示:
个人审核。
5.<loopCardinality>2</loopCardinality> 循环2次结束。
6.<multiInstanceLoopCharacteristics isSequential="true"> 串行并行的配置。
7.
<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.25}</completionCondition> 完成条件的配置。
这里我们还可以得出一个结论:
如果使用串行方式操作nrOfActiveInstances 变量始终是1,因为并行的时候才会去+1操作。
1.1.7. 遗留点
上面的程序已经解决了常用的问题,关于会签、加签、减签、退签、权重配置、自定义通过条件配置(条件自定义通过)
这些问题,这个章节还没有具体的实现,关于这些问题,由于本章内容有限,我们就后续章节讲解吧。
未完待续...
分享牛,分享、我们是快乐的。
activiti 多实例任务的更多相关文章
- 工作流学习——Activiti流程实例、任务管理四步曲 (zhuan)
http://blog.csdn.net/zwk626542417/article/details/46646565 ***************************************** ...
- Activiti 流程实例、任务、执行对象及相关的表
一个流程中,流程实例只有一个,执行对象可以有多个(如果存在分支和聚合) SELECT * FROM activiti.act_ru_execution a; #正在执行的执行对象表 SELECT * ...
- Activiti流程实例管理
1.启动流程 在完成了流程定义部署后,就要启动流程实例了. /** * 1 启动流程 * 当流程到达一个节点时,会在act_ru_execution表中产生1条数据 * 如果当前节点是用户任务节点,这 ...
- Activiti配置实例以及Spring集成配置
public class TestDB { public static void main(String[] args) { //1. 创建Activiti配置对象的实例 ProcessEngineC ...
- Activiti学习之 多实例实现会签功
转: Activiti学习之 多实例实现会签功能 2014年11月26日 11:27:11 程诺 阅读数:26185 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog ...
- Activiti 多个并发子流程的应用
多个部门发起资金计划,最后统一到财务部审批,每个部门发起资金计划是一个子流程,财务部审批是多个部门的计划同时审批,审批完成后,再提交上级领导审批. 流程如下: 要解决以上问题,需要实现多个子流程并行处 ...
- 最近学习工作流 推荐一个activiti 的教程文档
全文地址:http://www.mossle.com/docs/activiti/ Activiti 5.15 用户手册 Table of Contents 1. 简介 协议 下载 源码 必要的软件 ...
- Activiti实现会签功能
一个任务需要多个角色进行审批或者表决,根据这些审批结果来决定流程的走向.实现以上任务,activiti已经提供了支持,可以使用BPMN规范的多实例活动来实现. 1.Activiti多实例: 多实例节点 ...
- 初识activiti
Activity工作流学习要点 1. 1个插件 在Eclipse中安装Activity插件,让你可以在Eclipse中绘制Activity工作流图 2. 1个引擎 ProcessEngine对象,Ac ...
随机推荐
- 重拾Python(5):数据读取
本文主要对Python如何读取数据进行总结梳理,涵盖从文本文件,尤其是excel文件(用于离线数据探索分析),以及结构化数据库(以Mysql为例)中读取数据等内容. 约定: import numpy ...
- Python更新pip出现错误解决方法
Python更新pip出现错误解决方法 更新pip python -m pip install --upgrade pip 查看时报错 解决方法 在命令栏(即win+r)输入:easy_install ...
- Java IO(三)
在Java IO提供的类中,除了前面介绍的RandomAccessFile类之外,还有一系列的io操作类. 主要分为两大类.字符流和字节流.关系图如下: 在Java IO的操作中,很好的体现了Java ...
- python 网络爬虫(一)爬取天涯论坛评论
我是一个大二的学生,也是刚接触python,接触了爬虫感觉爬虫很有趣就爬了爬天涯论坛,中途碰到了很多问题,就想把这些问题分享出来, 都是些简单的问题,希望大佬们以宽容的眼光来看一个小菜鸟
- [USACO 04OPEN]MooFest
Description 约翰的N 头奶牛每年都会参加“哞哞大会”.哞哞大会是奶牛界的盛事.集会上的活动很多,比如堆干草,跨栅栏,摸牛仔的屁股等等.它们参加活动时会聚在一起,第i 头奶牛的坐标为Xi,没 ...
- 【BZOJ1483】【HNOI2009】梦幻布丁
题意:n个连续的点,有若干种颜色,每个颜色会因为某些操作变为另一种颜色,动态查询颜色段数. 解题思路:对每个颜色开一棵平衡树启发式合并应该是最裸的想法,但是我们有更优的! 考虑对每个颜色利用链表储存它 ...
- Java并发编程之并发工具类
CountDownLatch CountDownLatch可以用于一个或多个线程等待其他线程完成操作. 示例代码 private static CountDownLatch c = new Count ...
- 【OCP|052】OCP最新题库解析(052)--小麦苗解答版
[OCP|052]OCP最新题库解析(052)--小麦苗解答版 OCP最新题库解析历史连接(052):http://mp.weixin.qq.com/s/bUgn4-uciSndji_pUbLZfA ...
- PTA 邻接表存储图的广度优先遍历(20 分)
6-2 邻接表存储图的广度优先遍历(20 分) 试实现邻接表存储图的广度优先遍历. 函数接口定义: void BFS ( LGraph Graph, Vertex S, void (*Visit)(V ...
- 深入以太坊智能合约 ABI
开发 DApp 时要调用在区块链上的以太坊智能合约,就需要智能合约的 ABI.本文希望更多了解 ABI,如为什么需要 ABI?如何解读 Ethereum 的智能合约 ABI?以及如何取得合约的 ABI ...