:-: 
*本小節的源碼:/activiti-01/src/test/java/-/ActivitiDemo*
下面演示上圖流程操作過程,步驟如下:
[TOC]
# 1. 流程定義
**1. 繪制流程圖**
根據【流程設計器的使用】一節我已經畫出了上面的流程圖。
一個`.bpmn`文件可以定義多個流程,不過我們建議每個文件只包含一個流程定義, 可以簡化開發過程中的維護難度。
**2. 將流程圖的`.bpmn`文件導出為`.png`圖片**
(1)將`.bpmn`后綴改成`.xml`后綴。

(2)使用流程設計器打開`.xml`文件。

(3)導出為圖片,保存到`resources`目錄下。

(4)再將`.xml`后綴改回`.bpmn`后綴。
<br/>
# 2. 流程部署
流程部署就是把流程圖的相關數據保存到數據庫中。
**部署方式1:單個文件部署**
```java
@Test
public void testDeployment() {
//1、創建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、獲取RepositoryServcie
RepositoryService repositoryService = processEngine.getRepositoryService();
//3、使用service進行流程的部署,定義一個流程的名字,把bpmn和png部署到數據中
Deployment deploy = repositoryService.createDeployment()
.name("出差申請流程")
.addClasspathResource("bpmn-02/evection.bpmn")
.addClasspathResource("bpmn-02/image/evection.png")
.deploy();
//4、輸出部署信息
System.out.println("流程部署id=" + deploy.getId()); //id為數據庫中隨機分配的id
System.out.println("流程部署名字=" + deploy.getName());//名字就是上面name("出差申請流程")設置的名字
}
```
**部署方式2:壓縮包文件部署**
```java
@Test
public void deployProcessByZip() {
//獲取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//獲取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//讀取資源包文件,構造成inputStream
InputStream inputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("bpmn-02/evection.zip");
//用inputStream 構造ZipInputStream
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
//使用壓縮包的流進行流程的部署
Deployment deploy = repositoryService.createDeployment()
.name("出差申請流程")
.addZipInputStream(zipInputStream)
.deploy();
System.out.println("流程部署id=" + deploy.getId());
System.out.println("流程部署的名稱=" + deploy.getName());
}
```
<br/>
完成上面的部署后我們到數據庫中查看主要的3張表。
```sql
-- 流程定義部署表:每部署一次增加一條記錄,即運行上面的部署程序一次,記錄就增加一條記錄
mysql> select * from act_re_deployment;
+-----+--------------+-----------+------+------------+---------------------+-----------------+
| ID_ | NAME_ | CATEGORY_ | KEY_ | TENANT_ID_ | DEPLOY_TIME_ | ENGINE_VERSION_ |
+-----+--------------+-----------+------+------------+---------------------+-----------------+
| 1 | 出差申請流程 | NULL | NULL | | 2021-10-09 14:57:27 | NULL |
+-----+--------------+-----------+------+------------+---------------------+-----------------+
-- 流程定義表:部署每個新的流程定義都會在這張表中增加一條記錄
-- 注意,KEY_ 這個字段是用來唯一識別不同流程的關鍵字
mysql> select * from act_re_procdef;
+----------------+------+------------------------------+--------------+------------+----------+----------------+-----------------------+...
| ID_ | REV_ | CATEGORY_ | NAME_ | KEY_ | VERSION_ | DEPLOYMENT_ID_ | RESOURCE_NAME_ | DGRM_...
+----------------+------+------------------------------+--------------+------------+----------+----------------+-----------------------+...
| myEvection:1:4 | 1 | http://www.activiti.org/test | 出差申請流程 | myEvection | 1 | 1 | bpmn-02/evection.bpmn | NULL ...
+----------------+------+------------------------------+--------------+------------+----------+----------------+-----------------------+...
-- 流程資源表
mysql> select id_, rev_, name_, deployment_id_, left(bytes_, 30) as bytes_, generated_ from act_ge_bytearray;
+-----+------+----------------------------+----------------+--------------------------------+------------+
| id_ | rev_ | name_ | deployment_id_ | bytes_ | generated_ |
+-----+------+----------------------------+----------------+--------------------------------+------------+
| 2 | 1 | bpmn-02/evection.bpmn | 1 | <?xml version="1.0" encoding=" | 0 |
| 3 | 1 | bpmn-02/image/evection.png | 1 | Binary/Image | 0 |
+-----+------+----------------------------+----------------+--------------------------------+------------+
act_re_deployment和act_re_procdef一對多關系,一次部署在流程部署表生成一條記錄,
但一次部署可以部署多個流程定義,每個流程定義在流程定義表生成一條記錄。
每一個流程定義在act_ge_bytearray會存在兩個資源記錄,bpmn和png。
建議:一次部署一個流程,這樣部署表和流程定義表是一對一有關系,方便讀取流程部署及流程定義信息。
```
<br/>
# 3. 啟動流程
```java
/**
* 啟動流程實例,將會依次調用下面的表,每次運行該程序就會創建一個流程實例
* `act_hi_actinst` 流程實例執行歷史信息
* `act_hi_identitylink` 流程參與用戶的歷史信息
* `act_hi_procinst` 流程實例的歷史信息
* `act_hi_taskinst` 流程任務的歷史信息
* `act_ru_execution` 流程執行信息
* `act_ru_identitylink` 流程的正在參與用戶信息
* `act_ru_task` 流程當前任務信息
*/
@Test
public void testStartProcess() {
//1、創建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、獲取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3、根據流程定義的id啟動流程
ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection");
//4、輸出內容
System.out.println("流程定義ID:" + instance.getProcessDefinitionId()); //myEvection:1:4
System.out.println("流程實例ID:" + instance.getId()); //2501
System.out.println("當前活動的ID:" + instance.getActivityId()); //null
}
```
# 4. 查詢個人待執行任務
```java
/**
* 查詢個人待執行的任務,注意查詢的是未完成的任務
*/
@Test
public void testFindPersonalTaskList() {
//1、獲取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、獲取taskService
TaskService taskService = processEngine.getTaskService();
//3、根據流程key 和 任務的負責人 查詢任務
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey("myEvection") //流程Key
.taskAssignee("張三") //要查詢的負責人
.list();
//4、輸出
for (Task task : taskList) {
System.out.println("流程實例id=" + task.getProcessInstanceId());
System.out.println("任務Id=" + task.getId());
System.out.println("任務負責人=" + task.getAssignee());
System.out.println("任務名稱=" + task.getName());
System.out.println();
}
////循環輸出如下
//流程實例id=12501
//任務Id=12505
//任務負責人=張三
//任務名稱=創建出差申請
}
```
# 5. 完成個人任務
```java
/**
* 完成個人任務
* 根據流程圖任務的執行順序為:張三->李四->王五->趙六
*/
@Test
public void completTask() {
//獲取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//獲取操作任務的服務 TaskService
TaskService taskService = processEngine.getTaskService();
//查詢張三待完成的任務
Task task = taskService.createTaskQuery()
.processDefinitionKey("myEvection")
.taskAssignee("張三") //按照該順序 張三->李四->王五->趙六 依次更換參數便可按照順序完成每個人的任務
.singleResult();
System.out.println("流程實例id=" + task.getProcessInstanceId()); //12501
System.out.println("任務Id=" + task.getId()); //12505
System.out.println("任務負責人=" + task.getAssignee()); //張三
System.out.println("任務名稱=" + task.getName()); //創建出差申請
//根據任務ID來完成對應的任務,張三->李四->王五->趙六
//完成任務后,再調用上面的查詢任務查詢就查不到了
taskService.complete(task.getId());
}
```
# 6. 其他操作
```java
/**
* 查詢流程定義
* 包含流程定義,流程部署,流程定義版本
*/
@Test
public void queryProcessDefinition() {
//獲取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//獲取Repositoryservice
RepositoryService repositoryService = processEngine.getRepositoryService();
//獲取ProcessDifinitionQuery對象
ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
//查詢當前所有的流程定義 ,返回流程定義信息的集合
List<ProcessDefinition> definitionList = definitionQuery.processDefinitionKey("myEvection")
.orderByProcessDefinitionVersion() //通過版本排序
.desc() //倒序
.list();
//輸出信息
for (ProcessDefinition processDefinition : definitionList) {
System.out.println("流程定義ID:" + processDefinition.getId());
System.out.println("流程定義名稱:" + processDefinition.getName());
System.out.println("流程定義Key:" + processDefinition.getKey());
System.out.println("流程定義版本:" + processDefinition.getVersion());
System.out.println("流程部署ID:" + processDefinition.getDeploymentId());
}
//流程定義ID:myEvection:1:4
//流程定義名稱:出差申請流程
//流程定義Key:myEvection
//流程定義版本:1
//流程部署ID:1
}
/**
* 刪除流程部署信息,會根據部署表act_re_deployment中的部署ID_來刪除下面三張表有關該記錄的數據
* `act_ge_bytearray`
* `act_re_deployment`
* `act_re_procdef`
* 1) 使用repositoryService刪除流程定義,歷史表信息不會被刪除
* 2)如果該流程定義下沒有正在運行的流程,則可以用普通刪除。如果該流程定義下存在已經運行的流程,
* 使用普通刪除報錯,可用級聯刪除方法將流程及相關記錄全部刪除。
* 先刪除沒有完成流程節點,最后就可以完全刪除流程定義信息
* 項目開發中級聯刪除操作一般只開放給超級管理員使用.
*/
@Test
public void deleteDeployMent() {
//獲取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//通過引擎來獲取 RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//通過部署id來刪除流程部署信息
String deploymentId = "1";
//repositoryService.deleteDeployment(deploymentId); 非級聯刪除
//設置true 級聯刪除流程定義,即使該流程有流程實例啟動也可以刪除,設置為false非級別刪除方式,如果流程
repositoryService.deleteDeployment(deploymentId, true);
}
/**
* 下載資源文件
* 需要引入如下依賴
* <dependency>
* <groupId>commons-io</groupId>
* <artifactId>commons-io</artifactId>
* <version>2.6</version>
* </dependency>
* <p>
* 方案1: 使用Activiti提供的api,來下載資源文件,保存到文件目錄
* 方案2: 自己寫代碼從數據庫中下載文件,使用jdbc對blob 類型,clob類型數據讀取出來,保存到文件目錄
* 這里我們使用方案1,Activiti提供的api:RespositoryService
*/
@Test
public void getDeployment() throws IOException {
//1、得到引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、獲取api,RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3、獲取查詢對象 ProcessDefinitionQuery查詢流程定義信息
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myEvection")
.singleResult();
//4、通過流程定義信息,獲取部署ID
String deploymentId = processDefinition.getDeploymentId();
//5、獲取png圖片的流
//從流程定義表中,獲取png圖片的目錄和名字
//提醒:bpmn-02/evection.bpmn,bpmn-02/image/evection.png,則在這里獲取不到圖片的名字
String pngName = processDefinition.getDiagramResourceName();
//InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName);
InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, "bpmn-02/image/evection.png");
//6、獲取bpmn的流
String bpmnName = processDefinition.getResourceName();
InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName);
//7、構造OutputStream流
File pngFile = new File("e:/evectionflow01.png");
File bpmnFile = new File("e:/evectionflow01.bpmn");
FileOutputStream pngOutStream = new FileOutputStream(pngFile);
FileOutputStream bpmnOutStream = new FileOutputStream(bpmnFile);
//8、輸入流,輸出流的轉換
IOUtils.copy(pngInput, pngOutStream);
IOUtils.copy(bpmnInput, bpmnOutStream);
//9、關閉流
pngOutStream.close();
bpmnOutStream.close();
pngInput.close();
bpmnInput.close();
}
/**
* 查看歷史信息
*/
@Test
public void findHistoryInfo() {
//獲取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//獲取HistoryService
HistoryService historyService = processEngine.getHistoryService();
//獲取 actinst表的查詢對象
HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
//查詢 actinst表,條件:根據 InstanceId 查詢
//instanceQuery.processInstanceId("2501");
//查詢 actinst表,條件:根據 DefinitionId 查詢
instanceQuery.processDefinitionId("myEvection:1:4");
//增加排序操作,orderByHistoricActivityInstanceStartTime 根據開始時間排序 asc 升序
instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
//查詢所有內容
List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();
//輸出
for (HistoricActivityInstance hi : activityInstanceList) {
System.out.println(hi.getActivityId());
System.out.println(hi.getActivityName());
System.out.println(hi.getProcessDefinitionId());
System.out.println(hi.getProcessInstanceId());
System.out.println("<==========================>");
}
//_2
//StartEvent
//myEvection:1:4
//12501
//<==========================>
//_3
//創建出差申請
//myEvection:1:4
//12501
//<==========================>
//_5
//部門經理審批
//myEvection:1:4
//12501
//<==========================>
}
```
下載的資源文件如下:

- Activiti流程引擎
- 工作流介紹
- Activiti是什么
- Activiti流程處理步驟
- Activiti環境搭建
- 搭建步驟
- 表結構介紹
- ActivitiAPI結構
- 認識流程符號
- 流程設計器的使用
- 流程處理步驟
- 亂碼問題
- 流程實例
- 流程實例是什么
- 業務標識
- 查詢流程實例
- 掛起/激活流程實例
- 個人任務
- 分配任務負責人
- 查詢待辦任務
- 辦理權限
- 流程變量
- 流程變量類型
- 流程變量作用域
- 使用流程變量控制流程
- 組任務
- 設置任務候選人
- 組任務辦理流程
- 網關
- 4種網關類型
- 排他網關
- 并行網關
- 包含網關
- 事件網關
- Spring整合Activiti
- SpringBoot整合Activiti
- Flowable流程引擎
- Flowable是什么
- Flowable與Activiti
- Flowable環境搭建
- FlowableAPI
- 流程引擎API與服務
- 流程處理步驟
- 流程部署
- 流程部署方式
- 流程定義版本
- 刪除已部署的流程
- 下載資源
- 流程實例
- 什么是流程實例
- 業務標識
- 查詢流程實例
- 掛起/激活流程實例
- 分配任務負責人
- 固定分配
- UEL表達式分配
- 監聽器分配
- 辦理權限
- 流程變量
- 流程變量類型
- 流程變量作用域
- 流程變量控制流程
- 組任務
- 設置任務候選人
- 組任務辦理流程
- 網關
- 排他網關
- 并行網關
- 包含網關
- 事件網關
- 歷史查詢
- 查詢歷史
- Spring整合Flowable
- 配置文件整合
- 配置類整合
- SpringBoot整合Flowable