Activiti如何开发中国特色的合同申请会签流程程

activiti 工作流会签 / 多人审批时若一人通过即可
最近在工作中使用到了activiti 工作流引擎,跟大家遇到过的情况类似,在“中国式”的工作流中,常有一些需求是工作流引擎基本使用中无法实现的。在这过程中,我和我的小伙伴们也和大家一样遇到很多困难,大海捞针似的在网上寻找着答案。特此,在这里把我们遇到的需求和解决方案分享给大家,希望能帮助到你们!
以下是我们在项目中遇到的各(奇)种(葩)需求,如果您也遇到了相同的可以借鉴:
1、工作流会签;
2、多人审批时一人通过即可;
3、在当前节点获取下一节点的信息;
4、流程部署后未发布之前获取所有节点的信息;
5、流程启动前传入后续节点办理人;
6、节点设置多个监听。
1、 activiti 工作流会签时,所有的都审批通过才可进入下一环节:
1.1 编写监听类
public class MyTaksListener implements TaskListener {
public void notify(DelegateTask delegateTask) {
System.out.println("delegateTask.getEventName() = " + delegateTask.getEventName());
//添加会签的人员,所有的都审批通过才可进入下一环节
List&String& assigneeList = new ArrayList&String&();
assigneeList.add("wangba");
assigneeList.add("wangjiu");
delegateTask.setVariable("publicityList",assigneeList);
1.2 “员工请假申请”中添加此监听类
1.3 “项目组长审批”中
isSequential=false时,表示的并行执行,即该节点下的多条任务可以同时执行。
activiti:collection:执行该会签环节的参与人,此处是使用的一个名叫publicityList的流程变量
activiti:elementVariable:表示的是每一个分支都有一个名叫publicity的流程变量,和上方的activiti:assignee结合
1.4 项目组长审批时,通过taskAssignee来获取个人任务
// 获取总记录数
total = taskService.createTaskQuery().taskAssignee(userId).taskNameLike("%" + s_name + "%").count();
taskList = taskService.createTaskQuery()
// 根据用户id查询.taskAssignee(userId)
// 根据任务名称查询
.taskNameLike("%" + s_name + "%")
// 返回带分页的结果集合
.listPage(pageInfo.getPageIndex(), pageInfo.getPageSize());
==================================================================================
2. activiti 工作流会签,一人通过即可进入下一环节:
2.1 编写监听类
public class MangerTaskHandlerCandidateUsers implements TaskListener{
public void notify(DelegateTask delegateTask) {
//添加审批的人员,以下任何一人通过即可进入下一环节
String[] empLoyees = {"wangba","wangjiu"};
delegateTask.addCandidateUsers(Arrays.asList(empLoyees));
2.2 “项目组长审批”中
2.3 项目组长审批时,通过taskCandidateUser来获取节点任务
// 获取总记录数
total = taskService.createTaskQuery().taskCandidateUser(userId).taskNameLike("%" + s_name + "%").count();
taskList = taskService.createTaskQuery()
// 根据用户id查询.taskCandidateUser(userId)
// 根据任务名称查询
.taskNameLike("%" + s_name + "%")
// 返回带分页的结果集合
.listPage(pageInfo.getPageIndex(), pageInfo.getPageSize());
============================================================================
3、在当前节点获取下一节点的信息
* 根据实例编号查找下一个任务节点
* @param String
procInstId :实例编号
@RequestMapping("/backTaskTab")
public TaskDefinition backTaskTab(String taskId) {
Task task = taskService.createTaskQuery() // 创建任务查询
.taskId(taskId) // 根据任务id查询
.singleResult();
String procInstId = task.getProcessInstanceId();
// 流程标示
String processDefinitionId = historyService.createHistoricProcessInstanceQuery().processInstanceId(procInstId)
.singleResult().getProcessDefinitionId();
ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(processDefinitionId);
// 执行实例
ExecutionEntity execution = (ExecutionEntity) runtimeService.createProcessInstanceQuery()
.processInstanceId(procInstId).singleResult();
// 当前实例的执行到哪个节点
String activitiId = execution.getActivityId();
// 获得当前任务的所有节点
List&ActivityImpl& activitiList = def.getActivities();
ActivityImpl activityImpl=
for(int i=0;i& activitiList.size();i++){
String flag=activitiList.get(i).getId();
if(flag.equals(activitiId)){
activityImpl=activitiList.get(i);
String id =
int num=activitiList.indexOf(activityImpl);
ActivityImpl activityImpl_=activitiList.get(num+1);
TaskDefinition taskDefinition = ((UserTaskActivityBehavior) activityImpl_.getActivityBehavior())
.getTaskDefinition();
// 获取下一节点的代办人
System.out.println(taskDefinition.getCandidateGroupIdExpressions().toArray()[0]);
============================================================================
4、流程部署后未发布之前获取所有节点的信息
解决思路是这样的:部署完工作流之后,为UserTask节点动态分配任务执行者,或者在分支节点上添加条件判断的功能。为了实现这个功能,需要解析流程定义文件,取出文件中定义的所有节点。这里有两个方法可以实现此功能:
方法一(流程部署至服务器上之后可使用):
//processDefinitionId为流程定义Id,该Id可以通过多种方式获得,如通过ProcessDefinitionQuery可以查询一个 //ProcessDefinition对象,Task对象中也包含
processDefinitionIdBpmnModel model = repositoryService.getBpmnModel(processDefinitionId);
if (model != null) {
Collection&FlowElement& flowElements = model.getMainProcess().getFlowElements();
for (FlowElement e : flowElements) {
System.out.println("flowelement id:" + e.getId() + "
name:" + e.getName() + "
+ e.getClass().toString());
该方法适用于流程部署至服务器上之后,通过该方法可以简单快速的获取流程定义文件中各个节点信息。
读取流程定义文件方式
InputStream resouceStream = this.getClass().getClassLoader().getResourceAsStream("leave-
formkey.bpmn20.xml");
XMLInputFactory xif = XMLInputFactory.newInstance();
InputStreamR
XMLStreamR
in = new InputStreamReader(resouceStream, "UTF-8");
xtr = xif.createXMLStreamReader(in);
BpmnModel model = new BpmnXMLConverter().convertToBpmnModel(xtr);
Collection&FlowElement& flowElements = model.getMainProcess().getFlowElements();
for (FlowElement e : flowElements) {
System.out.println("flowelement id:" + e.getId() + "
name:" + e.getName() + "
+ e.getClass().toString());
} catch (XMLStreamException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
该方法使用到了activiti的activiti-bpmn-converter-5.20.0.jar和activiti-bpmn-model-5.20.0.jar,用到了其中比较关键的一个类BpmnXMLConverter,该类将xml定义文件解析成BpmnModel对象,使用BpmnModel的getMainProcess()获取一个Process对象,该对象实际是一个继承自BaseElement、FlowElementContainer的节点容器,通过getFlowElements()获取当前流程定义文件中所有的节点对象。该方法的好处在于可以解析本地或者未部署至Activiti引擎中的流程定义文件。两次测试打印结果如下:
flowelement id:startevent1
name:Start
class:class org.activiti.bpmn.model.StartEvent
flowelement id:deptLeaderAudit
name:部门领导审批
class:class org.activiti.bpmn.model.UserTask
flowelement id:exclusivegateway5
name:Exclusive Gateway
class:class org.activiti.bpmn.model.ExclusiveGateway
flowelement id:modifyApply
name:调整申请
class:class org.activiti.bpmn.model.UserTask
flowelement id:hrAudit
name:人事审批
class:class org.activiti.bpmn.model.UserTask
flowelement id:exclusivegateway6
name:Exclusive Gateway
class:class org.activiti.bpmn.model.ExclusiveGateway
flowelement id:reportBack
class:class org.activiti.bpmn.model.UserTask
flowelement id:endevent1
class:class org.activiti.bpmn.model.EndEvent
flowelement id:exclusivegateway7
name:Exclusive Gateway
class:class org.activiti.bpmn.model.ExclusiveGateway
flowelement id:flow2
class:class org.activiti.bpmn.model.SequenceFlow
flowelement id:flow3
class:class org.activiti.bpmn.model.SequenceFlow
flowelement id:flow4
name:不同意
class:class org.activiti.bpmn.model.SequenceFlow
flowelement id:flow5
class:class org.activiti.bpmn.model.SequenceFlow
flowelement id:flow6
class:class org.activiti.bpmn.model.SequenceFlow
flowelement id:flow7
class:class org.activiti.bpmn.model.SequenceFlow
flowelement id:flow8
class:class org.activiti.bpmn.model.SequenceFlow
flowelement id:flow9
name:不同意
class:class org.activiti.bpmn.model.SequenceFlow
flowelement id:flow10
name:重新申请
class:class org.activiti.bpmn.model.SequenceFlow
flowelement id:flow11
class:class org.activiti.bpmn.model.SequenceFlow
flowelement id:flow12
name:结束流程
class:class org.activiti.bpmn.model.SequenceFlow
流程定义文件leave-formkey.bpmn20.xml:
&?xml version="1.0" encoding="UTF-8"?&
&definitions xmlns="http://www.omg.org/spec/BPMN//MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN//DI" xmlns:omgdc="http://www.omg.org/spec/DD//DC"
xmlns:omgdi="http://www.omg.org/spec/DD//DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="OFFICE"&
&process id="leave-formkey" name="病事假申请"&
&documentation&请假流程演示&/documentation&
&startEvent id="startevent1" name="Start" activiti:initiator="applyUserId"&&/startEvent&
&userTask id="deptLeaderAudit" name="部门领导审批" activiti:assignee="${applyUserId}" activiti:formKey="leaveHandle.form"&&/userTask&
&exclusiveGateway id="exclusivegateway5" name="Exclusive Gateway"&&/exclusiveGateway&
&userTask id="modifyApply" name="调整申请" activiti:assignee="${applyUserId}" activiti:formKey="leaveApplyAgain.form"&&/userTask&
&userTask id="hrAudit" name="人事审批" activiti:assignee="${applyUserId}" activiti:formKey="leaveHandle.form"&&/userTask&
&exclusiveGateway id="exclusivegateway6" name="Exclusive Gateway"&&/exclusiveGateway&
&userTask id="reportBack" name="销假" activiti:assignee="${applyUserId}" activiti:formKey="leaveHandle.form"&&/userTask&
&endEvent id="endevent1" name="End"&&/endEvent&
&exclusiveGateway id="exclusivegateway7" name="Exclusive Gateway"&&/exclusiveGateway&
&sequenceFlow id="flow2" name="" sourceRef="startevent1" targetRef="deptLeaderAudit"&&/sequenceFlow&
&sequenceFlow id="flow3" name="" sourceRef="deptLeaderAudit" targetRef="exclusivegateway5"&&/sequenceFlow&
&sequenceFlow id="flow4" name="不同意" sourceRef="exclusivegateway5" targetRef="modifyApply"&
&conditionExpression xsi:type="tFormalExpression"&&![CDATA[${deptLeaderPass == 'false'}]]&&/conditionExpression&
&/sequenceFlow&
&sequenceFlow id="flow5" name="同意" sourceRef="exclusivegateway5" targetRef="hrAudit"&
&conditionExpression xsi:type="tFormalExpression"&&![CDATA[${deptLeaderPass == 'true'}]]&&/conditionExpression&
&/sequenceFlow&
&sequenceFlow id="flow6" name="" sourceRef="hrAudit" targetRef="exclusivegateway6"&&/sequenceFlow&
&sequenceFlow id="flow7" name="同意" sourceRef="exclusivegateway6" targetRef="reportBack"&
&conditionExpression xsi:type="tFormalExpression"&&![CDATA[${hrPass == 'true'}]]&&/conditionExpression&
&/sequenceFlow&
&sequenceFlow id="flow8" name="" sourceRef="reportBack" targetRef="endevent1"&&/sequenceFlow&
&sequenceFlow id="flow9" name="不同意" sourceRef="exclusivegateway6" targetRef="modifyApply"&
&conditionExpression xsi:type="tFormalExpression"&&![CDATA[${hrPass == 'false'}]]&&/conditionExpression&
&/sequenceFlow&
&sequenceFlow id="flow10" name="重新申请" sourceRef="exclusivegateway7" targetRef="deptLeaderAudit"&
&conditionExpression xsi:type="tFormalExpression"&&![CDATA[${reApply == 'true'}]]&&/conditionExpression&
&/sequenceFlow&
&sequenceFlow id="flow11" name="" sourceRef="modifyApply" targetRef="exclusivegateway7"&&/sequenceFlow&
&sequenceFlow id="flow12" name="结束流程" sourceRef="exclusivegateway7" targetRef="endevent1"&
&conditionExpression xsi:type="tFormalExpression"&&![CDATA[${reApply == 'false'}]]&&/conditionExpression&
&/sequenceFlow&
&/process&
&bpmndi:BPMNDiagram id="BPMNDiagram_leave-formkey"&
&bpmndi:BPMNPlane bpmnElement="leave-formkey" id="BPMNPlane_leave-formkey"&
&bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1"&
&omgdc:Bounds height="35" width="35" x="10" y="90"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNShape bpmnElement="deptLeaderAudit" id="BPMNShape_deptLeaderAudit"&
&omgdc:Bounds height="55" width="105" x="90" y="80"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNShape bpmnElement="exclusivegateway5" id="BPMNShape_exclusivegateway5"&
&omgdc:Bounds height="40" width="40" x="250" y="87"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNShape bpmnElement="modifyApply" id="BPMNShape_modifyApply"&
&omgdc:Bounds height="55" width="105" x="218" y="190"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNShape bpmnElement="hrAudit" id="BPMNShape_hrAudit"&
&omgdc:Bounds height="55" width="105" x="358" y="80"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNShape bpmnElement="exclusivegateway6" id="BPMNShape_exclusivegateway6"&
&omgdc:Bounds height="40" width="40" x="495" y="87"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNShape bpmnElement="reportBack" id="BPMNShape_reportBack"&
&omgdc:Bounds height="55" width="105" x="590" y="80"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1"&
&omgdc:Bounds height="35" width="35" x="625" y="283"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNShape bpmnElement="exclusivegateway7" id="BPMNShape_exclusivegateway7"&
&omgdc:Bounds height="40" width="40" x="250" y="280"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2"&
&omgdi:waypoint x="45" y="107"&&/omgdi:waypoint&
&omgdi:waypoint x="90" y="107"&&/omgdi:waypoint&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3"&
&omgdi:waypoint x="195" y="107"&&/omgdi:waypoint&
&omgdi:waypoint x="250" y="107"&&/omgdi:waypoint&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4"&
&omgdi:waypoint x="270" y="127"&&/omgdi:waypoint&
&omgdi:waypoint x="270" y="190"&&/omgdi:waypoint&
&bpmndi:BPMNLabel&
&omgdc:Bounds height="11" width="100" x="10" y="0"&&/omgdc:Bounds&
&/bpmndi:BPMNLabel&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5"&
&omgdi:waypoint x="290" y="107"&&/omgdi:waypoint&
&omgdi:waypoint x="358" y="107"&&/omgdi:waypoint&
&bpmndi:BPMNLabel&
&omgdc:Bounds height="11" width="100" x="-24" y="-17"&&/omgdc:Bounds&
&/bpmndi:BPMNLabel&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6"&
&omgdi:waypoint x="463" y="107"&&/omgdi:waypoint&
&omgdi:waypoint x="495" y="107"&&/omgdi:waypoint&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7"&
&omgdi:waypoint x="535" y="107"&&/omgdi:waypoint&
&omgdi:waypoint x="590" y="107"&&/omgdi:waypoint&
&bpmndi:BPMNLabel&
&omgdc:Bounds height="11" width="100" x="-22" y="-17"&&/omgdc:Bounds&
&/bpmndi:BPMNLabel&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8"&
&omgdi:waypoint x="642" y="135"&&/omgdi:waypoint&
&omgdi:waypoint x="642" y="283"&&/omgdi:waypoint&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9"&
&omgdi:waypoint x="515" y="127"&&/omgdi:waypoint&
&omgdi:waypoint x="514" y="217"&&/omgdi:waypoint&
&omgdi:waypoint x="323" y="217"&&/omgdi:waypoint&
&bpmndi:BPMNLabel&
&omgdc:Bounds height="11" width="100" x="10" y="0"&&/omgdc:Bounds&
&/bpmndi:BPMNLabel&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow10" id="BPMNEdge_flow10"&
&omgdi:waypoint x="250" y="300"&&/omgdi:waypoint&
&omgdi:waypoint x="142" y="299"&&/omgdi:waypoint&
&omgdi:waypoint x="142" y="135"&&/omgdi:waypoint&
&bpmndi:BPMNLabel&
&omgdc:Bounds height="11" width="100" x="10" y="0"&&/omgdc:Bounds&
&/bpmndi:BPMNLabel&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow11" id="BPMNEdge_flow11"&
&omgdi:waypoint x="270" y="245"&&/omgdi:waypoint&
&omgdi:waypoint x="270" y="280"&&/omgdi:waypoint&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow12" id="BPMNEdge_flow12"&
&omgdi:waypoint x="290" y="300"&&/omgdi:waypoint&
&omgdi:waypoint x="625" y="300"&&/omgdi:waypoint&
&bpmndi:BPMNLabel&
&omgdc:Bounds height="11" width="100" x="10" y="0"&&/omgdc:Bounds&
&/bpmndi:BPMNLabel&
&/bpmndi:BPMNEdge&
&/bpmndi:BPMNPlane&
&/bpmndi:BPMNDiagram&
&/definitions& ============================================================================
5.流程启动前传入后续节点办理人;
//下面name2和name3是前台传过来的第二个和第三个节点的办理人
Map&String, Object& variables = new HashMap&String, Object&();
variables.put("leaveId", leaveId);
variables.put("name2", "XXX");//(前台传过来的第二个节点的办理人)
variables.put("name3", "YYY");//(前台传过来的第三个节点的办理人)
// 启动流程
pi = runtimeService.startProcessInstanceByKey("activitiemployeeProcess", variables);
在第一个节点指定第二个节点的监听
public class MyTaksListener2 implements TaskListener {
public void notify(DelegateTask delegateTask) {
Map&String, Object& variables=delegateTask.getVariables();
variables.get("name2");(前台传过来的第二个节点的办理人)
//拆分variables
List&String& assigneeList = new ArrayList&String&();
assigneeList.add("wangba");
delegateTask.setVariable("publicityList",assigneeList);
在第三个节点指定本节点的办理人监听
public class MyTaksListener3 implements TaskListener {
public void notify(DelegateTask delegateTask) {
Map&String, Object& variables=delegateTask.getVariables();
System.out.println(variables);
variables.get("name3");
String result=(String) variables.get("name3");(前台传过来的第三个节点的办理人)
String[] empLoyees = {"szx"};
delegateTask.addCandidateUsers(Arrays.asList(empLoyees));
============================================================================
6、节点设置多个监听
在同一节点设置两个监听,一个是设置本节点的监听,指定办理人;另一个是设置下一个节点的监听,指定会签人。
设置本节点的监听,指定办理人
public class MyTaksListener3 implements TaskListener {
public void notify(DelegateTask delegateTask) {
Map&String, Object& variables=delegateTask.getVariables();
System.out.println(variables);
String result=(String) variables.get("name3");
String[] empLoyees = {"szx"};
delegateTask.addCandidateUsers(Arrays.asList(empLoyees));
设置下一个节点的监听,指定会签人
public class MyTaksListener4 implements TaskListener {
public void notify(DelegateTask delegateTask) {
Map&String, Object& variables=delegateTask.getVariables();
String result=(String)variables.get("name2");
List&String& assigneeList = new ArrayList&String&();
assigneeList.add("ss");
delegateTask.setVariable("publicityList",assigneeList);
至此,项目中遇到的各(奇)种(葩)问题迎刃而解。“中国式”工作流有时确实很让人头疼,但也体现了中国程序猿的强大。希望看到这里的你也能从中得到启发,尽早解决您在项目当中遇到的问题。
喜欢此文,或是能帮助您解决实际问题的话,欢迎转载,以便能帮助到更多的人,谢谢!
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!activiti 会签usertask multiInstance - activit-bpm - ITkeyowrd
activiti 会签usertask multiInstance
推荐:在流程业务管理中,任务是通常都是由一个人去处理的,而多个人同时处理一个任 务,这种任务我们称之为会签任务。这种业务需求也很常见,如一个请款单,领导审批
领取地址:
要把一个节点设置为多实例,节点xml元素必须设置一个multiInstanceLoopCharacteristics子元素。
&multiInstanceLoopCharacteristics isSequential=&false|true&&
&/multiInstanceLoopCharacteristics&
isSequential属性表示节点是进行 顺序执行还是并行执行。
实例的数量会在进入节点时计算一次。 有一些方法配置它。一种方法是使用loopCardinality子元素直接指定一个数字。
&multiInstanceLoopCharacteristics isSequential=&false|true&&
&loopCardinality&5&/loopCardinality&
&/multiInstanceLoopCharacteristics&
也可以使用结果为整数的表达式:
&multiInstanceLoopCharacteristics isSequential=&false|true&&
&loopCardinality&${nrOfOrders-nrOfCancellations}&/loopCardinality&
&/multiInstanceLoopCharacteristics&
另一个定义实例数目的方法是,通过loopDataInputRef子元素,设置一个类型为集合的流程变量名。 对于集合中的每个元
素,都会创建一个实例。 也可以通过inputDataItem子元素指定集合。 下面的代码演示了这些配置:
&userTask id=&miTasks& name=&My Task ${loopCounter}& activiti:assignee=&${assignee}&&
&multiInstanceLoopCharacteristics isSequential=&false&&
&loopDataInputRef&assigneeList&/loopDataInputRef&
&inputDataItem name=&assignee& /&
&/multiInstanceLoopCharacteristics&
&/userTask&
假设assigneeList变量包含这些值[kermit, gonzo, foziee]。 在上面代码中,三个用户任务会同时创建。每个分支都会拥
有一个用名为assignee的流程变量, 这个变量会包含集合中的对应元素,在例子中会用来设置用户任务的分配者。
loopDataInputRef和inputDataItem的缺点是1)名字不好记, 2)根据BPMN 2.0格式定义,它们不能包含表达式。activiti
通过在 multiInstanceCharacteristics中设置 collection和 elementVariable属性解决了这个问题:
&userTask id=&miTasks& name=&My Task& activiti:assignee=&${assignee}&&
&multiInstanceLoopCharacteristics isSequential=&true&
activiti:collection=&${myService.resolveUsersForTask()}& activiti:elementVariable=&assignee& &
&/multiInstanceLoopCharacteristics&
&/userTask&
多实例节点在所有实例都完成时才会结束。也可以指定一个表达式在每个实例结束时执行。 如果表达式返回true,所有其
他的实例都会销毁,多实例节点也会结束,流程会继续执行。 这个表达式必须定义在completionCondition子元素中。
&userTask id=&miTasks& name=&My Task& activiti:assignee=&${assignee}&&
&multiInstanceLoopCharacteristics isSequential=&false&
activiti:collection=&assigneeList& activiti:elementVariable=&assignee& &
&completionCondition&${nrOfCompletedInstances/nrOfInstances &= 0.6 }&/completionCondition&
&/multiInstanceLoopCharacteristics&
&/userTask&
在这里例子中,会为assigneeList集合的每个元素创建一个并行的实例。 当60%的任务完成时,其他任务就会删除,流程
继续执行。
要把一个节点设置为多实例,节点xml元素必须设置一个multiInstanceLoopCharacteristics子元素。 &multiInstanceLoopCharacteristics isSequential=&false|true&&...&/multiInstanceLoopCh
相关阅读排行
相关内容推荐
请激活账号
为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。
您的注册邮箱:
如果您没有收到激活邮件,请注意检查垃圾箱。

我要回帖

更多关于 流程中的会签 的文章

 

随机推荐