1. 部署流程
部署流程的2大前提:
- 流程引擎
- 流程定義文件
流程引擎就不再多說了镀脂,無論是前面的哪種方式獲取的矩肩,在部署上是一致的铡原。
本篇的相關(guān)源碼:GitHub
流程定義文件需要通過IDEA的纱新、eclipse 中的 Activiti designer插件或者Web 編輯器Activiti modeler來的設(shè)計篮奄,且得到一個以.bpmn為后綴的流程定義文件
安裝完成插件后在Eclipse 右鍵new—Other—Activiti Diagram即可新建流程定義文件
Activiti designer插件設(shè)計界面如下
IDEA 安裝完成插件后在任意目錄下右鍵new BpmnFile 即可新建流程定義文件
actibpm 插件設(shè)計界面如下
這里如果遇到actiBPM插件中文亂碼則需要在IDEA安裝目錄下找到idea.exe.vmoptions和idea64.exe.vmoptions這兩個文件捆愁,且在最后一行添加如下配置
-Dfile.encoding=UTF-8
設(shè)計器中有很多元素可以供我們選擇割去,但是在入門階段,我認為只需要關(guān)注StartEvent UserTask EndEvent 這3個元素即可昼丑,簡單場景下呻逆,也只會用到這3個。
在我們定義好了流程定義文件后菩帝,就可以使用流程引擎部署它了咖城,前提是你已經(jīng)搭建好了Activiti的項目環(huán)境,這里可以參考快速入門(二)
@Test
public void deployMyProcess() throws FileNotFoundException {
//幾乎所有需要操作到流程文件胁附,或者讀取流程相關(guān)信息的酒繁,都是使用倉庫服務repositoryService
//部署流程 這里跟構(gòu)建流程引擎的方式差不多,都是使用了構(gòu)建者模式
//1. 首先創(chuàng)建DeploymentBuilder對象,通過這個對象控妻,我們可以指定要加載的流程定義文件州袒,以及一些其他屬性。
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
//2.1 加載流程文件弓候,從類路徑加載
// deploymentBuilder.addClasspathResource("AskForLeave.bpmn");
//2.使用InputStream加載 (替換自己的文件路徑)
FileInputStream fileInputStream = new FileInputStream("E:\\DemoProjects\\ActivitiExample\\ActivitiFirstDeploy\\src\\main\\resources\\AskForLeave.bpmn");
deploymentBuilder.addInputStream("AskForLeave.bpmn", fileInputStream);
deploymentBuilder.name("測試部署請假流程");
//還有將多個bpmn文件打包批量郎哭,以及字符串這兩種部署方式(這里暫時不介紹這兩種方式)
//執(zhí)行部署,直到調(diào)用deploy()方法才是真正的部署到引擎中了
//同時會在act_ge_bytearray ,act_re_deployment ,act_re_procdef這3個表中插入相關(guān)信息
//與以前的教程不一樣的是菇存,別的教程中會經(jīng)常將流程圖片和流程bpmn文件一起部署夸研,但我認為有點多余了,因為在部署bpmn的時候會自動生成流程圖片
Deployment deploy = deploymentBuilder.deploy();
//這個是創(chuàng)建一個部署查詢對象查詢依鸥,查詢的是act_re_deployment表這個表記錄的就是deploymentBuilder對象所附加的屬性
long count = repositoryService.createDeploymentQuery().count();
System.out.println("部署時間:"+deploy.getDeploymentTime());
Assert.assertEquals(1, count);
}
在流程部署完成后亥至,我們來看一看數(shù)據(jù)庫的變化,學習Activiti引擎就必須要對這20多張表有一個比較深刻的了解贱迟。
部署一個流程姐扮,數(shù)據(jù)庫中有act_ge_bytearray ,act_re_deployment ,act_re_procdef這3個表會發(fā)生變化
-
act_re_deployment 中插入了deploymentBuilder構(gòu)建時所附帶的信息,比如name衣吠,key茶敏,category等但是這幾個信息都是非必填項,目前即便是為空也不影響缚俏,主要是為了定義和區(qū)分不同的部署信息惊搏。
act_re_deployment -
act_re_procdef 這個表中插入的是比較重要的信息了,這里面的Name忧换,Key恬惯,Category 等等都是流程引擎從我們自己設(shè)計的AskForLeave.bpmn這個流程定義文件中解析出來的屬性,在實際業(yè)務中最常關(guān)聯(lián)的也就是這個表中的屬性亚茬。
act_re_procdef -
act_ge_bytearray在第一節(jié)中有提到過ge系列的是通用數(shù)據(jù)宿崭,可以看成是系統(tǒng)將我們的bpmn文件以及它解析這個文件生成的流程圖片以二進制的形式保存到這個表中了
act_ge_bytearray
當流程部署完成后,我們就可以調(diào)用Api啟動這個請假流程
2. 啟動流程
啟動流程的方法有很多重載最主要的就是下面展示的兩種方式
@Test
public void startAskLeaveProcess() {
//1.通過流程定義ID啟動才写,這個ID就是act_re_procdef的主鍵ID 例如Leave:1:4
//runtimeService.startProcessInstanceById();
//2.通過流程定義的Key啟動葡兑,這個Key是在我們畫流程圖的時候輸入的ID
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(LEAVEKEY);
Assert.assertEquals(LEAVEKEY, processInstance.getProcessDefinitionKey());
System.out.println("啟動時間:"+processInstance.getStartTime());
}
啟動流程成功后奖蔓,我們來看看數(shù)據(jù)庫之中的變化
- act_ru_task RU當前任務表 是Runtime的縮寫
證明這個表中存放的是當前系統(tǒng)中的任務(也就是設(shè)計流程時的Task類型的節(jié)點)其中最重要的屬性有如下:
ID:當前任務的ID(可以使用TaskService查詢)
EXECUTION_ID_: 執(zhí)行ID
PROC_INST_ID_: 流程實例ID 這個屬性非常重要,它貫穿了流程實例的整個生命周期讹堤,從啟動到結(jié)束到歷史記錄查詢都非常依賴于它吆鹤,它是流程實例的唯一標識
Name: 當前任務節(jié)點的名稱(自己定義的)
TASK_DEF_KEY_: 任務定義Key 用戶定義的任務Key
- act_ru_execution 當前執(zhí)行表
這個表可以看做是比Task記錄的節(jié)點更詳細的表,因為act_ru_task僅僅會保存Task屬性的節(jié)點洲守,而這個表會記錄所有的節(jié)點疑务,而且它主要用于子流程,或者并行流程復雜用法的時候才需要特別關(guān)心梗醇,現(xiàn)在暫時不用詳細了解
除了RU系列運行時查詢的表知允,還會有對應的歷史記錄保存表
-
act_hi_taskinst 歷史任務流程實例表 保存的內(nèi)容大體跟ru_task一致
歷史任務表 -
act_hi_procinst歷史流程實例表
這個表存儲的信息也比較重要,主要用于查詢流程的詳細信息叙谨,比如啟動時間温鸽,啟動人結(jié)束時間等等
流程實例表 -
act_hi_actinst流程活動實例表 這個表從存儲的內(nèi)容來說和act_ru_execution比較像,它會把流程所有已經(jīng)流轉(zhuǎn)過的節(jié)點都記錄下來
流程活動實例表
從上述數(shù)據(jù)庫變化中大家應該可以初步熟悉流程表的核心了手负,啟動任何一個流程上面的5張表都會產(chǎn)生新記錄涤垫,也可以說Activiti的核心功能是重度依賴這5張表的
Activiti中有不少的Query查詢對象,他們是通過各個Service獲取的竟终,目的也主要是查詢數(shù)據(jù)庫表蝠猬,我們就以上面的act_hi_procinst為例
@Test
public void listAllProcess(){
//創(chuàng)建Query查詢對象 可以在這個對象后面調(diào)用各種方法實現(xiàn)條件查詢,排序等
HistoricProcessInstanceQuery hisProcInstanceQuery = historyService.createHistoricProcessInstanceQuery();
//不加查詢條件
List<HistoricProcessInstance> processInstances = hisProcInstanceQuery.list();
for (HistoricProcessInstance processInstance : processInstances) {
System.out.println(processInstance.getId());
System.out.println(processInstance.getDeploymentId());
System.out.println(processInstance.getProcessDefinitionName());
}
//根據(jù)流程定義名稱查詢
List<HistoricProcessInstance> processInstances1 = hisProcInstanceQuery.processDefinitionName("我的流程").list();
//根據(jù)流程實例ID查詢
HistoricProcessInstance processInstance = hisProcInstanceQuery.processInstanceId("2501").singleResult();
//查詢未結(jié)束的流程
List<HistoricProcessInstance> processInstances2 = hisProcInstanceQuery.unfinished().list();
Assert.assertEquals(1, processInstances1.size());
Assert.assertNotNull(processInstance);
Assert.assertEquals(1, processInstances2.size());
}
辦理任務
流程啟動之后肯定是需要辦理任務的统捶,act_ru_task中的每一行就是我們需要處理的任務榆芦,首先熟悉一下如何查詢他們,同上依然先創(chuàng)建Query對象
@Test
public void getTask() {
//如果你的數(shù)據(jù)庫中只有一條流程那么也是可以將list()改為singleResult()的
List<HistoricProcessInstance> processInstances = historyService
.createHistoricProcessInstanceQuery().unfinished().list();
List<Task> tasks = new ArrayList<>();
for (HistoricProcessInstance processInstance : processInstances) {
String processInstanceId = processInstance.getId();
Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
tasks.add(task);
}
tasks.forEach(task -> System.out.println(task.getName()));
for (Task task : tasks) {
//TaskService可以完成某個任務的審批喘鸟,使流程流轉(zhuǎn)到下一節(jié)點歧杏,比如用戶申請審批完成后到達領(lǐng)導審批節(jié)點
taskService.complete(task.getId());
Task result = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
System.out.println(result.getName());
}
}
控制臺輸出如下
用戶申請
領(lǐng)導審批
再看數(shù)據(jù)庫之前的那一行ID為2505的用戶申請已經(jīng)沒有了,新增了5002的領(lǐng)導審批記錄迷守,這些都是流程引擎自動為我們完成的
我們在歷史活動和歷史任務中都會插入一條新記錄(新的節(jié)點或者任務),且更新之前辦理的任務的END_TIME用來表示他們的處理時間
在我們最終調(diào)用TaskService.complete()完成最后一個任務的審批后旺入,會更新歷史流程實例的完成時間兑凿,這就代表這個流程已經(jīng)結(jié)束了所有的ru跟他相關(guān)的都會被清空