監(jiān)聽器是發(fā)生對應(yīng)任務(wù)相關(guān)事件時執(zhí)行自定義的java邏輯或表達(dá)式
在使用Activiti時氯析,通常是跟業(yè)務(wù)結(jié)合缎岗,而有些業(yè)務(wù)會比較的復(fù)雜静尼,會出現(xiàn)以下的場景:
- activiti人員的動態(tài)分配
- 當(dāng)前任務(wù)節(jié)點完成時,需要指定下一個節(jié)點任務(wù)的執(zhí)行人
- 任務(wù)節(jié)點完成時需要一些復(fù)雜的業(yè)務(wù)處理
- 任務(wù)到達(dá)某一節(jié)點時,需要監(jiān)控當(dāng)前任務(wù)的以下信息或者日志
- 當(dāng)前任務(wù)執(zhí)行人處理人物的時候鼠渺,需要觸發(fā)自定義的一些業(yè)務(wù)處理
- 流程的開始和結(jié)束也有可能對應(yīng)相關(guān)的業(yè)務(wù)處理
-
不僅是節(jié)點觸發(fā)業(yè)務(wù)鸭巴,在連線上也可以自定義業(yè)務(wù)
那么是怎么實現(xiàn)這些需求的呢?為了滿足我們的業(yè)務(wù)拦盹,activiti提供了監(jiān)聽器鹃祖,下面詳細(xì)講解activiti監(jiān)聽器的使用。
任務(wù)相應(yīng)時間包括:
create:任務(wù)創(chuàng)建后觸發(fā)
assignment:任務(wù)分配后觸發(fā)
delete:任務(wù)完成后觸發(fā)
all:所有事件發(fā)生都觸發(fā)
表達(dá)式參考上篇的UEL表達(dá)式普舆,這里主要是介紹監(jiān)聽器的使用
在class中指定我們的代碼中的監(jiān)聽器類
從activiti監(jiān)聽器的使用范圍惯豆,可以分為三種:
- 全局的監(jiān)聽器
- 連線的監(jiān)聽器
- 節(jié)點的監(jiān)聽器
全局監(jiān)聽
全局監(jiān)聽可以監(jiān)聽流程啟動,任務(wù)執(zhí)行節(jié)點之間的連線和流程結(jié)束奔害,
自定義實現(xiàn)全局監(jiān)聽的類需要實現(xiàn)ExecutionListener 接口楷兽,ExecutionListener 里定義的常量start用來判斷流程的開始,end是用來判斷流程的結(jié)束华临,take時判斷節(jié)點任務(wù)之間連線使用芯杀,也就是上一個節(jié)點完成任務(wù)后可以觸發(fā)。
public interface ExecutionListener extends Serializable {
String EVENTNAME_START = "start";
String EVENTNAME_END = "end";
String EVENTNAME_TAKE = "take";
void notify(DelegateExecution var1) throws Exception;
}
演示
流程圖
流程定義的xml文件
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 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" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1596619898726" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="stuKcsqServiceExemptionApply" isClosed="false" isExecutable="true" name="申請" processType="None">
<startEvent id="startevent1" name="Start"/>
<userTask activiti:assignee="$ {name}" activiti:exclusive="true" id="apply" name="提交申請"/>//
<userTask activiti:candidateUsers="${js}" activiti:exclusive="true" id="jsCheckService" name="教師審核"/>
<userTask activiti:candidateUsers="${wm}" activiti:exclusive="true" id="wmCheckAdmin" name="秘書審核">
<extensionElements>
<activiti:taskListener event="create"/>
</extensionElements>
</userTask>
<endEvent id="endevent1" name="End">
<extensionElements>
<activiti:executionListener class="com.graduate.platform.cultivate.listener.stuExemptionApplyListener" event="end"/>
</extensionElements>
</endEvent>
<userTask activiti:candidateUsers="${yjs}" activiti:exclusive="true" id="yjsCheckAdmin" name="培養(yǎng)辦審核"/>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="apply"/>
<sequenceFlow id="flow2" sourceRef="apply" targetRef="jsCheckService">
<extensionElements>
<activiti:executionListener class="com.graduate.platform.cultivate.listener.stuExemptionApplyListener" event="take"/>
</extensionElements>
</sequenceFlow>
<sequenceFlow id="flow3" name="通過" sourceRef="jsCheckService" targetRef="wmCheckAdmin">
<extensionElements>
<activiti:executionListener class="com.graduate.platform.cultivate.listener.stuExemptionApplyListener" event="take"/>
</extensionElements>
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${state==1}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow4" name="通過" sourceRef="wmCheckAdmin" targetRef="yjsCheckAdmin">
<extensionElements>
<activiti:executionListener class="com.graduate.platform.cultivate.listener.stuExemptionApplyListener" event="take"/>
</extensionElements>
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${state==1}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow5" sourceRef="yjsCheckAdmin" targetRef="endevent1"/><sequenceFlow id="flow6" name="不通過" sourceRef="jsCheckService" targetRef="endevent1">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${state==0}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow7" name="不通過" sourceRef="wmCheckAdmin" targetRef="endevent1">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${state==0}]]></conditionExpression>
</sequenceFlow>
自定義監(jiān)聽器類
上面的流程定義中雅潭,我們在在結(jié)束跟每條連線上(除了不同意的分支揭厚,因為不同意分支流程會直接到達(dá)結(jié)束)設(shè)置了我們自定義的監(jiān)聽器類,自定義的監(jiān)聽器類負(fù)責(zé)的業(yè)務(wù)有扶供,當(dāng)前一個節(jié)點完成任務(wù)時監(jiān)聽器會根據(jù)“take”跟“end”來判斷節(jié)點的位置筛圆,當(dāng)連線處被觸發(fā)時也就是當(dāng)前任務(wù)節(jié)點完成了,可以動態(tài)的設(shè)置下一個節(jié)點任務(wù)的執(zhí)行人椿浓,在結(jié)束節(jié)點處判斷state狀態(tài)來處理業(yè)務(wù)申請是否通過太援。
public class stuExemptionApplyListener implements TaskListener, ExecutionListener {
//操作數(shù)據(jù)庫需要
ActivityService activityService = (ActivityService) ApplicationContextProvider.getBean("activityService");
@Override
public void notify(DelegateTask delegateTask) {
}
@Override
public void notify(DelegateExecution execution) throws Exception {
// TODO Auto-generated method stub
String eventName = execution.getEventName();
//申請人學(xué)號
String xh = execution.getVariable("name").toString();
String lcId = execution.getProcessInstanceId();
String names="";
String teacherId="";
if ("take".equals(eventName)) {
StudentInfo studentInfo = studentInfoService.selectInfoByXh(xh);
//獲取部門id
String deptId=studentInfo.getYxsh();
if(execution.getCurrentActivityId().equals("apply")){
String teacherGh= execution.getVariable("js").toString();
execution.setVariable(ActivityConstants.EXEMPTION_TEACHER, "admin,"+teacherGh);
}
if(execution.getCurrentActivityId().equals("jsCheckService")){
teacherId= Constants.SECRETARY;
//根據(jù)部門查詢對應(yīng)學(xué)院秘書用戶 拼接用戶名稱和所屬角色
names = activityService.selectUsersByRole(teacherId, deptId);
execution.setVariable("wm", names+",admin");
}else if(execution.getCurrentActivityId().equals("wmCheckAdmin")){
teacherId=Constants.CULTIVATEOFFICE;
//培養(yǎng)辦 拼接用戶名稱和所屬角色
names = activityService.selectUsersByRole(teacherId, "");
execution.setVariable("yjs", names+",admin");//添加候選人,admin也可以做審核
}
} else if ("end".equals(eventName)) {
String s=execution.getVariable("state")+"";
int state = Integer.parseInt( s);
StudentApplyService pyXskcsqService = (StudentApplyService ) ApplicationContextProvider.getBean("studentApplyService ");
StudentApply studentApply =new StudentApply (lcId,state);
//更新審核狀態(tài)
studentApplyService.updateByLcid(studentApply );
}
}
}
下面我們來分析一下DelegateExecution這個對象扳碍,因為上面的監(jiān)聽器類實現(xiàn)的方法中可以拿到DelegateExecution這個對象提岔,那現(xiàn)在看看這個對象為我們提供了什么。
public interface DelegateExecution extends VariableScope {
//流程id
String getId();
//流程實例id
String getProcessInstanceId();
// 用來獲取 start笋敞、end碱蒙、take
String getEventName();
// 獲取業(yè)務(wù)id 不建議使用了 廢棄
/** @deprecated */
String getBusinessKey();
//獲取業(yè)務(wù)id
String getProcessBusinessKey();
//獲取流程定義的id
String getProcessDefinitionId();
// 獲取父id,聽說是并發(fā)的時候有用
String getParentId();
//獲取 調(diào)用執(zhí)行的id夯巷。
String getSuperExecutionId();
// 獲取當(dāng)前 ActivityId
String getCurrentActivityId();
// 獲取 當(dāng)前的 ActivityName
String getCurrentActivityName();
// 獲取 TenantId 有多個 tenant 有用
String getTenantId();
//這個就不用說了赛惩,可以獲取流程的所有核心service
EngineServices getEngineServices();
}
節(jié)點監(jiān)聽器
自定義節(jié)點監(jiān)聽器類需要實現(xiàn)TaskListener接口,它跟全局監(jiān)聽器一樣趁餐,定義了不同的監(jiān)聽事件喷兼,分別為:
- create:任務(wù)被創(chuàng)建且所有的屬性被設(shè)置好后可觸發(fā)
- assignment:當(dāng)任務(wù)設(shè)置執(zhí)行人后觸發(fā)(注意 當(dāng)流程到達(dá)一個任務(wù)節(jié)點時,會先觸發(fā)assignment事件再觸發(fā)create時間)
- complete:在任務(wù)完成后澎怒,且在數(shù)據(jù)庫中的運行時數(shù)據(jù)相關(guān)表刪除數(shù)據(jù)之前
- delete:在任務(wù)將要被刪除之前發(fā)生褒搔。一般是completeTask完成任務(wù)時阶牍,它也會被執(zhí)行
- all:以上的事件都可以觸發(fā)
public interface TaskListener extends Serializable {
String EVENTNAME_CREATE = "create";
String EVENTNAME_ASSIGNMENT = "assignment";
String EVENTNAME_COMPLETE = "complete";
String EVENTNAME_DELETE = "delete";
String EVENTNAME_ALL_EVENTS = "all";
void notify(DelegateTask var1);
}
使用方式跟全局監(jiān)聽器一樣,這里就不多做代碼演示星瘾,在節(jié)點監(jiān)聽器也可以動態(tài)的分配下一個任務(wù)的執(zhí)行人走孽,可以在任務(wù)的各種狀態(tài)下處理系統(tǒng)的業(yè)務(wù)邏輯。
分析一下DelegateTask對象
public interface DelegateTask extends VariableScope {
//數(shù)據(jù)庫中的taskId主鍵
String getId();
// 任務(wù)名稱
String getName();
//修改任務(wù)名稱
void setName(String name);
//獲取任務(wù)的描述信息
String getDescription();
//修改任務(wù)的描述信息
void setDescription(String description);
// lower priority: [0..19] lowest, [20..39] low, [40..59] normal, [60..79] high
// [80..100] highest
//任務(wù)處理的優(yōu)先級范圍是0-100
int getPriority();
//修改優(yōu)先級
void setPriority(int priority);
// 獲取流程實例id
String getProcessInstanceId();
//獲取執(zhí)行id
String getExecutionId();
// 獲取流程定義id
String getProcessDefinitionId();
// Adds the given user as a candidate user to this task.添加候選人
void addCandidateUser(String userId);
// 添加多個候選人
void addCandidateUsers(Collection<String> candidateUsers);
//添加候選組
void addCandidateGroup(String groupId);
}