activiti5⼊门(四)流程图之六⼤构成元素
1、Events事件
2、Tasks任务(任务⽆法删除,只能结束。执⾏任务只要taskId即可,不需要当前⽤户,因为不排除⽤户离职的情况)
3、Gateways⽹关
4、Container容器
5、Connection连接
6、Artifacts说明
-----------------------------------------------------------
仅涉及Tasks任务的流程图实例:
根据⽤户查询当前任务:
StringurId=(String)sion().getAttribute("urId");这个urid和流程图xml格式中的activiti:assignee⼀致
List
如果我们在流程图⾥没有指定⽤户,⽽是⽤${urId}指定,那么最好每个urtask都要⽤不同的${xxx},因为如果相同,就说明这个
urTask是同⼀个⼈
那我们怎么⽤起来呢?
在流程启动的时候就要把它⽤进去:
Map
("urId","admin1");()...
rocessInstanceByKey(pdKey,bussinessId,map);
这样就在代码中指定了⽤户,这样每个流程实例都可能会有不同的⼈
注意,这⾥使⽤了bussinessId,这个值的作⽤,可以理解为它是另外⼀张业务表(⾮activiti表)的某个主键字段,这个字段会被很多其他
业务表引⽤,当我们查询act_hi_procinst表时就会⽤到BUSINESS_KEY_这个字段。不⽤查,⽤inessKey();即可
⽤户执⾏任务:
StringtaskId=ameter("taskId");
te(taskId);
可见只要知道任务id即可,不关⼼真正的⽤户是谁
每执⾏⼀次任务,act_ru_task表中不会增加⼀条数据,⽽是更新⼀条数据,且把ID都更新了,那原来那条数据保存在哪⾥?保存在
act_hi_taskinst中。
----------------------------------
ACT_RU_EXECUTION表中的executionID⼀般与流程实例ID相同,所以流程实例有多少条,他就有多少条,当⼀个流程⾛到某个节点,此时这个节点既有
urtask⼜有消息边界事件,那么ACT_RU_EXECUTION中会多出⼀个⼀条数据,假设ID为0001,这条数据的⽗ID是该流程,在act_ru_task表和
act_ru_event_subscr都会出现⼀条数据,表中的执⾏ID不再是流程ID,⽽是0001。正常情况下,执⾏任务ID和流程ID都是⼀致的。当存在不知道要⾛哪个时,
就会多出⼀条数据,即流程ID的延伸流程。出现这种情况如何获取执⾏ID?
Executionexecution=ExecutionQuery().messageEventSubscriptionName("全局消息名").singleResult();
eEventReceived("全局消息名",());//相当于执⾏了消息边界事件,没有执⾏urtask。
--------------------------
根据流程实例id查询当前任务(流程实例理解为譬如⼀张请假单)
List
-------------------
查询所有历史流程实例,涉及act_hi_procinst表
HistoryServicehistoryService=toryService();
List
HistoricProcessInstanceQuery().orderByProcessInstanceId().asc().list();
根据某历史流程实例id查询对应的历史任务(包括没有执⾏完的历史流程)涉及act_hi_taskinst表
HistoryServicehistoryService=toryService();
List
----------------------------------------------------
当urtask的⽤户为候选⼈时
例如xml中为activiti:candidateUrs="xxx1,xxx2,xxx13":指定候选⼈.(拉模式),
那么在⽤流程实例查询时是找不到指定⼈的,⼀定要有个指定⼈去认领任务才有⽤
TaskQuerytq=TaskQuery();
List
//迭代任务
for(Tasktask:candidateUrTaskLists){
//领取任务
((),urId);//领取任务时,也就是所谓的任务分配时,因为这个时候有assignee了
}
//根据任务的处理⼈查询任务
List
不重新获取,查的还是⽼数据,有种默认可重复读的感觉
-----------------------------------------------
当urtask的⽤户为候选组,且⽤了变量${group}时,那么在启动流程实例时,
("group","g1");//这⾥g1⽤字符串仅表⽰组名,不代表组员。因为业务中最后可能是根据⽤户名查找到组名,然后通过组名查找
到这个组的所有任务
rocessInstanceById(pdId,map);
查询组任务:
StringurId=(String)sion().getAttribute("urId");
Map
String[]arr={"a","b","c"};
List
("g1",asList);//这⾥只是模拟表⽰g1这个组有abc三个⽤户
Stringgroup=null;
for(Entry
List
if(ns(urId)){//根据⽤户找到⽤户所在组
group=();
}
}
List
if(group!=null){
taskLists1=TaskQuery().taskCandidateGroup(group).list();//根据⽤户所在组名找到所有任务
}
for(Tasktask:taskLists1){
((),urId);//第⼀个登录的⽤户将认领任务,同时这个组就不在有这个任务,即
taskCandidateGroup(group).list()将没有任务
}
List
的Assignee就是他了,它就能查到。没有领取任务的⽤户就查不到任务,除⾮是其它⾮组任务
ribute("taskLists",taskLists2);
uestDispatcher("/").forward(request,respon);
-----------------------------------------------------------
urTask的监听器
总共有4种:
create表⽰当创建任务时触发。
assignment表⽰当任务被分配后触发。
complete表⽰当任务完成后触发。
activiti中的表达式是${}形式,也有#{},后者在监听器中的表达式中有使⽤,也叫流程变量,在⼀个流程中有效。在启动流程时或在该
urtask之前要做好初始化。放map中。
要使⽤监听器,我们必须在流程图中找到urtask⾥⾯的listener,然后新建,指定我们⾃定义的监听器。我们写的监听器要实现
TaskListener。
以创建时定时器为例⼦:
publicclassCreateTaskListenerimplementsTaskListener{
privateExpressionname;//这个变量是在流程图中指定的,可以⽤来传⼊到java代码中
privateExpressionage;
@Override
publicvoidnotify(DelegateTaskdelegateTask){//DelegateTask称为委派任务
n("事件:"+ntName());
n(ue(delegateTask));//使⽤getValue的⽅法获取流程图中监听器的变量
n(ue(delegateTask));
//分配任务
StringurId=(String)ue(delegateTask);
ignee(urId);//分配任务到某个⼈
//分配完成后,分配监听器开始启动
}
delegateTask的api有很多,⽐如获取所有流程变量等。
除了java类型的定时器,还有#{}表达式,⽐如#{()}就是⼀个。我们创建⼀个Ur类实现Serializable,因为要存数据库,所以要
实现序列化。#{()}⾥⾯是能传参数的,⽐如#{(‘james’)}。他也分create、create和complete。它是怎么找到ur
的。⼀样在启动流程实例时,使⽤map,("ur",newUr());
除了,java,expression,还有与spring连⽤的delegateexpression委托表达式,以后会说。
urtask不仅仅有tasklistener,也有executionlistener,与tasklistener的区别是,后者只有两个阶段,start和end,start会⽐creat
还早。另外实现的监听接⼝不⼀样,后者是ExecutionListener。
监听器中获取引擎的⽅式:cution().getEngineServices()就是引擎(ProcessEngine)
taskUr中的表单我们很少⽤,它要配合监听器使⽤,为的是在监听器中能获取表单服务。但表单⼀般我们都有⾃⼰的表。
taskur⾥⾯还有⼀个多实例,即表⽰⼀个任务必须多个⽤户都做好后才能⾛到下⼀步。
有⼏个选项:
Sequential为true表⽰有顺序,必须⼀个⼀个做;为fal表⽰⽆顺序,⽤户不必等前⼀个⽤户。
collection是⼀个变量名,如urList。在流程启动时赋值,如
List
("admin1");
("admin2");
("admin3");
("admin4");
("admin5");
("urList",urList);
elementVariable是⼀个变量名(必须的),在assignee⽤${admin}这个表⽰后,在multiInstance中就能⽤admin代表${admin}了
completionCondition条件:⽐如有5个⼈完成,我现在只有三个⼈完成,我也算他任务完成,那就要⽤
${nrOfCompletedInstances/nrOfInstances>=0.6}表⽰。其中nrOfCompletedInstances和nrOfInstances是activiti在
act_ru_variable中⽣成的字段名,表⽰已完成实例和总实例。在流程图中我们不需要指定Loop,因为collection⾥⾯就能知道循环次数
-----------------------------------------------------------------------
其它任务类型:
ScriptTask脚本任务(⾃动触发),写⼀段javascript脚本
ServiceTask服务任务(⾃动触发),写⼀个类实现ServiceTaskDelegate,和⾃定义监听器实现监听器接⼝类似
ManualTask⼿⼯任务(⾃动触发)
ReceiveTask接收任务(信号触发).这4种我们都很少⽤
邮件任务(挺有⽤):例⼦
依赖
在部署前调⽤ProcessEngineConfiguration的
.tMailServerDefaultFrom("xxx@").tMailServerHost("")
.tMailServerUrname("xxx").tMailServerPassword("xxx");
在流程图中选择mailtask,在配置中⽤流程变量指定发送者,接受者等,如${to},${from},${subject}(主题)。它的正⽂有html格式
或者普通⽂本格式
最后在启动流程实例时
("to","zzz@");
("from","xxx@");
("subject","邮件任务");
即可。
-------------------------------------------
Events事件
⽤得最多的是StartEvent,可以在流程图中定义发起⼈,但我们可以不⽤这样做,我们⼀般将第⼀个任务看成是流程发起⼈
TimerStartEvent定时开始事件,它的定时时间由activiti特殊规定,但在使⽤前,要调⽤
ExecutorActivate(true)激活定时任务
MessageStartEvent消息开始事件,要先定义⼀个全局消息,在空⽩处点击,然后就可以在properties界⾯找到message,定义消息了。
然后在开始事件中引⽤这个消息,启动流程实例要⽤message,如rocessInstanceByMessage("xxx");xxx就是前
⾯全局消息的name值。
SignalStartEvent信号开始事件:要先定义⼀个全局信号,在空⽩处点击,然后就可以在properties界⾯找到signal,然后在开始事件中引
⽤这个消息,动流程实例要⽤signal,
EventReviced("xxx");xxx就是前⾯全局信号的name值。
结束事件ErrorEndEvent错误结束事件⽤于⼦流程。与ErrorBoundaryEvent错误边界事件(接收错误码)⼦流程连⽤
边界事件,只能放在任务上,⽐如任务不处理了,那么就可以由边界事件来完成
TimerBoundaryEvent定时边界事件,⽐如
MessageBoundaryEvent消息边界事件上⾯有提到过
SignalBoundaryEvent信号边界事件与上⾯是雷同的
定义全局信号,然后在边界事件引⽤它,
/**根据信号名查询执⾏对象*/
Executionexecution=ExecutionQuery().signalEventSubscriptionName("mySignal").singleResult();
/**信号事件接收完成当前信号边界事件*/
EventReceived("全局信号名",());
ErrorBoundaryEvent错误边界事件在⼦流程的时候说
中间捕获事件:
TimerCatchingEvent定时捕获事件
MessageCatchingEvent消息捕获事件
SignalCatchingEvent信号捕获事件
NoneThrowingEvent空引发事件
这个事件意义不⼤
-----------------------------
本文发布于:2022-11-27 10:40:27,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/30502.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |