activiti多實例設置(會籤/或籤)
項目地址:activiti-workflow
在審批流中會遇到會籤/或籤的情況,activiti本身就已經支持,通過多實例來實現。
本文通過流程畫布和Java代碼兩中方式來作實現。
1.流程畫布設置多實例
設置如圖,會計這個節點是會籤節點。
參數說明:
-
Multi-instance-type:多人審批方式 paraller 並行,Sequential 串行,多實例需設置未並行
-
Execution-listrners:監聽器,通過監聽類設置Collection中集合的值。監聽器的設置可以看之前的博客。
-
Collection:審批人集合
-
Element varible:迭代集合(Collection)變量
-
Completion condition:完成條件(表達式)比如:${nrOfCompletedInstances/nrOfInstances >= 0.5} 。
nrOfInstances:實例總數
nrOfActiveInstances:當前活動的,還沒完成的實例數量。 對於順序執行的多實例,值一直爲1。
nrOfCompletedInstances:已經完成實例的數目。 -
Assignents:審批人(表達式),取 Element varible的值,比如Element varible設置爲assignee,Assignents就設置爲${assignee}
導出的bpmn文件如圖:
2.通過JAVA類設置
這種方式使用爲通過JAVA類生成流程定義數據
//用戶節點
UserTask userTask = new UserTask();
MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = new MultiInstanceLoopCharacteristics();
//審批人集合參數
multiInstanceLoopCharacteristics.setInputDataItem("assigneeList");
//迭代集合
multiInstanceLoopCharacteristics.setElementVariable("assignee");
//完成條件 已完成數等於實例數
multiInstanceLoopCharacteristics.setCompletionCondition("${nrOfActiveInstances == nrOfInstances}");
//並行
multiInstanceLoopCharacteristics.setSequential(false);
taskNode.setAssignee("${assignee}");
//設置多實例屬性
userTask.setLoopCharacteristics(multiInstanceLoopCharacteristics);
//設置監聽器
taskNode.setExecutionListeners(countersignTaskListener());
//設置審批人
taskNode.setCandidateUsers(candidateUser);
candidateUser爲審批人集合,用戶在設計流程是指定。CompletionCondition設置已審批數量等於實例總數(會籤)。
這裏需要注意一下,當用戶節點設置了多實例屬性後,設置監聽器時是設置executionListeners而不是taskListeners。類要實現ExecutionListener或者JavaDelegate,普通用戶節點實現TaskListener。還有多實例屬性中loopCardinality和inputDataItem兩個必須設置一個,這個在部署流程似有校驗
校驗在這裏
org.activiti.validation.validator.impl.FlowElementValidator#handleMultiInstanceLoopCharacteristics多實例檢驗(檢驗loopCardinality和inputDataItem),校驗不通過會拋出異常。
protected void handleMultiInstanceLoopCharacteristics(Process process, Activity activity, List<ValidationError> errors) {
MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics();
if (multiInstanceLoopCharacteristics != null) {
if (StringUtils.isEmpty(multiInstanceLoopCharacteristics.getLoopCardinality())
&& StringUtils.isEmpty(multiInstanceLoopCharacteristics.getInputDataItem())) {
addError(errors, Problems.MULTI_INSTANCE_MISSING_COLLECTION, process, activity,
"Either loopCardinality or loopDataInputRef/activiti:collection must been set");
}
}
}
多實例監聽器設置如下
ArrayList<ActivitiListener> listener = new ArrayList<>();
ActivitiListener activitiListener = new ActivitiListener();
//事件類型,
activitiListener.setEvent(ExecutionListener.EVENTNAME_START);
//監聽器類型
activitiListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
//設置實現了,這裏設置監聽器的類型是delegateExpression,這樣可以在實現類注入Spring bean.
activitiListener.setImplementation("${multiInstanceTaskHandler}");
listener.add(activitiListener);
監聽器類型說明:
class :java類的全路徑,類需實現 TaskListener,會執行notify()方法,這種實現類不能注入Spring bean
expression :執行特定類的特定方法 配置 :${test.test()}
delegateExpression:配置spring的bean,${test}。實現類交由spring管理。
監聽類實現
@Slf4j
@Component
public class MultiInstanceTaskHandlerimplements ExecutionListener {
@Override
public void notify(DelegateExecution delegateTask) {
log.info("任務監聽類開始執行");
FlowElement currentFlowElement = delegateTask.getCurrentFlowElement();
if(currentFlowElement instanceof UserTask){
UserTask userTask = (UserTask) currentFlowElement;
List<String> candidateUsers = userTask.getCandidateUsers();
//設爲本地變量(節點所有)
delegateTask.setVariableLocal("assigneeList",candidateUsers);
}
}
}
這樣在多實例節點創建時,assigneeList就會當作變量傳進去。