Activiti工作流

1.簡介

Activiti項目是一項新的基于Apache許可的開源BPM平臺,從基礎開始構建,旨在提供支持新的BPMN 2.0標準。

Activiti是一種輕量級,可嵌入的BPM引擎,而且還設計適用于可擴展的云架構。 Activiti將提供寬松的Apache許可2.0,同時促進Activiti BPM引擎和BPMN 2.0的匹配。

2.Activiti的7大服務

  • RepositoryService:提供一系列管理流程部署和流程定義的API。

  • RuntimeService:在流程運行時對流程實例進行管理與控制。

  • TaskService:對流程任務進行管理,例如任務提醒、任務完成和創(chuàng)建任務等。

  • IdentityService:提供對流程角色數(shù)據(jù)進行管理的API,這些角色數(shù)據(jù)包括用戶組、用戶及它們之間的關系。

  • ManagementService:提供對流程引擎進行管理和維護的服務。

  • HistoryService:對流程的歷史數(shù)據(jù)進行操作,包括查詢、刪除這些歷史數(shù)據(jù)。

  • FormService:表單服務。

3.應用實例

3.1.開發(fā)組件

名稱 版本
HighGoDB 安全版V4.5、企業(yè)版V5及以上
HgdbJdbc 6.2.4
JDK 1.6、1.7、1.8
Java IDE IntelliJ IDEA
SpringBoot 2.1.0.RELEASE
Activiti 7.0.0.Beta2

3.2.工程示例

image

3.3.主要文件

pom.xml

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.activiti/activiti-spring-boot-starter -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.0.0.Beta2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.highgo</groupId>
<artifactId>HgdbJdbc</artifactId>
<version>6.2.4</version>
</dependency>
</dependencies>

application.yml

spring:
datasource:
url: jdbc:highgo://xxxx:5866/activiti?currentSchema=activiti
username : sysdba
password : XXXX
driver-class-name: com.highgo.jdbc.Driver
activiti:
#1.flase:默認值。activiti在啟動時,對比數(shù)據(jù)庫表中保存的版本,如果沒有表或者版本不匹配,將拋出異常
#2.true: activiti會對數(shù)據(jù)庫中所有表進行更新操作。如果表不存在,則自動創(chuàng)建
#3.create_drop: 在activiti啟動時創(chuàng)建表,在關閉時刪除表(必須手動關閉引擎,才能刪除表)
#4.drop-create: 在activiti啟動時刪除原來的舊表,然后在創(chuàng)建新表(不需要手動關閉引擎)
database-schema-update: true
#自動部署驗證設置:true-開啟(默認)、false-關閉 true時項目啟動會自動部署
check-process-definitions: false
#注意,如果activiti后面加上了/,就要求啟動的時候process文件夾中需要有流程定義文件
#是指定activiti流程描述文件的前綴(路徑),啟動時,activiti就會去尋找此路徑下的流程描述文件,并且自動部署
process-definition-location-prefix: classpath:/processes/
# suffix 是一個String數(shù)組,表示描述文件的默認后綴名,默認**.bpmn和**.bpmn20.xml
# process-definition-location-suffixes:
# - **.bpmn
# - **.bpmn20.xml
# Activiti7歷史數(shù)據(jù)無法自動插入,開啟下面兩個配置
# 檢測歷史表是否存在 activiti7默認沒有開啟數(shù)據(jù)庫歷史記錄 啟動數(shù)據(jù)庫歷史記錄
db-history-used: true
#記錄歷史等級 可配置的歷史級別有none, activity, audit, full
#none:不保存任何的歷史數(shù)據(jù),因此,在流程執(zhí)行過程中,這是最高效的。
#activity:級別高于none,保存流程實例與流程行為,其他數(shù)據(jù)不保存。
#audit:除activity級別會保存的數(shù)據(jù)外,還會保存全部的流程任務及其屬性。audit為history的默認值。
#full:保存歷史數(shù)據(jù)的最高級別,除了會保存audit級別的數(shù)據(jù)外,還會保存其他全部流程相關的細節(jié)數(shù)據(jù),包括一些流程參數(shù)等。
history-level: full
# 解決頻繁查詢SQL問題
async-executor-activate: false

leave.bpmn20.xml

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 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" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
<process id="leave" name="leave" isExecutable="true">
<startEvent id="sid-4bb1b894-4189-4443-9d51-08408088e392"/>
<userTask id="sid-76b385e0-c375-40af-afbe-9623fe40ee7f" name="部門經(jīng)理審批" activiti:assignee="${bm}"/>
<sequenceFlow id="sid-fbfc3fc7-99c7-46fd-9825-1f5d3fa6e82a" sourceRef="sid-4bb1b894-4189-4443-9d51-08408088e392" targetRef="sid-76b385e0-c375-40af-afbe-9623fe40ee7f"/>
<userTask id="sid-4a6bd0e8-285a-4770-b49d-5fa2f8dc698b" name="總經(jīng)理審批" activiti:assignee="${gm}"/>
<sequenceFlow id="sid-d37f31eb-c958-4c5e-a834-3c48191d1091" sourceRef="sid-76b385e0-c375-40af-afbe-9623fe40ee7f" targetRef="sid-4a6bd0e8-285a-4770-b49d-5fa2f8dc698b"/>
<endEvent id="sid-9e1a9189-9194-4a79-86ba-8dcbb2280e31"/>
<sequenceFlow id="sid-b945400f-4bae-4f2e-b6e1-0d2083d4b028" sourceRef="sid-4a6bd0e8-285a-4770-b49d-5fa2f8dc698b" targetRef="sid-9e1a9189-9194-4a79-86ba-8dcbb2280e31"/>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_leave">
<bpmndi:BPMNPlane bpmnElement="leave" id="BPMNPlane_leave">
<bpmndi:BPMNShape id="shape-eaad1e5b-25df-445e-a846-7ed05e474f7e" bpmnElement="sid-4bb1b894-4189-4443-9d51-08408088e392">
<omgdc:Bounds x="-225.0" y="-60.0" width="30.0" height="30.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape-990f85eb-2522-47cf-963d-0f16efbe9011" bpmnElement="sid-76b385e0-c375-40af-afbe-9623fe40ee7f">
<omgdc:Bounds x="-130.0" y="-85.0" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-b4d997db-6421-434c-b10f-285b7f28fc26" bpmnElement="sid-fbfc3fc7-99c7-46fd-9825-1f5d3fa6e82a">
<omgdi:waypoint x="-195.0" y="-45.0"/>
<omgdi:waypoint x="-130.0" y="-45.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="shape-b3139f61-0389-4cd6-ba9a-da6f41b22e9c" bpmnElement="sid-4a6bd0e8-285a-4770-b49d-5fa2f8dc698b">
<omgdc:Bounds x="40.0" y="-85.0" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-2676f501-c646-4be0-9f69-325b55e2384e" bpmnElement="sid-d37f31eb-c958-4c5e-a834-3c48191d1091">
<omgdi:waypoint x="-30.0" y="-45.0"/>
<omgdi:waypoint x="40.0" y="-45.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="shape-55c9ee0f-8507-449d-abf2-459285170784" bpmnElement="sid-9e1a9189-9194-4a79-86ba-8dcbb2280e31">
<omgdc:Bounds x="195.0" y="-60.0" width="30.0" height="30.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-ca8ae4f1-3bfd-4011-83e0-f864a8799213" bpmnElement="sid-b945400f-4bae-4f2e-b6e1-0d2083d4b028">
<omgdi:waypoint x="140.0" y="-45.0"/>
<omgdi:waypoint x="195.0" y="-45.0"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>

3.4.流程部署

3.4.1.自動部署

當 check-process-definitions:true 配置true時則為自動部署,需要把流程文件放到/processes/文件夾下。

3.4.2.手動部署
@Test
public void deployment(){
Deployment deployment = repositoryService.createDeployment()
.name("請假流程")
.addClasspathResource("processes/leave.bpmn20.xml")
.deploy();
System.out.println("流程ID:"+deployment.getId());
System.out.println("流程名稱:"+deployment.getName());
}

日志打印輸出

image

查看數(shù)據(jù)庫表act_ge_bytearray中會增加一條數(shù)據(jù),對應的就是剛剛新增的流程。

image

查看act_re_deployment

image

查看act_re_procdef

image

3.5.開啟流程

@Test
public void startProcess(){
String processDefinitionKey = "leave";
String businessKey = "001";
Map<String,Object> map = new HashMap<>();
map.put("bm","張三");
ProcessInstance leave = runtimeService.startProcessInstanceByKey(processDefinitionKey,businessKey, map);
System.out.println("流程id:"+leave.getProcessDefinitionId());
System.out.println("流程實例id:"+leave.getId());
System.out.println("當前活動id:"+leave.getActivityId());
}

日志打印

image

因為是剛開始流程,所以沒有人需要處理,當前活動id為null。這時查看act_hi_actinst就可以看到下一個需要處理的人。

image

3.6.查詢任務

@Test
public void findTask(){
List<Task> taskList = taskService.createTaskQuery()
//流程實例key
.processDefinitionKey("leave")
//任務負責人
.taskAssignee("張三")
.list();
for (Task task : taskList) {
System.out.println("任務id:"+task.getId());
System.out.println("任務名稱:"+task.getName());
System.out.println("任務負責人:"+task.getAssignee());
System.out.println("流程定義id:"+task.getProcessDefinitionId());
System.out.println("流程實例id:"+task.getProcessInstanceId());
System.out.println("任務創(chuàng)建時間:"+task.getCreateTime());
}
}

image

查詢的數(shù)據(jù)來自表act_ru_task,需要注意的是act_ru_task 表中的數(shù)據(jù)只有需要處理的任務,一但任務完成,則會刪除已完成任務的數(shù)據(jù)。

image

3.7.處理任務

@Test
public void dealTask(){
Map<String,Object> map = new HashMap<>();
map.put("gm","李四");
Task task = taskService.createTaskQuery()
// 流程id
.processDefinitionKey("leave")
// 處理人
.taskAssignee("張三")
.singleResult();
taskService.complete(task.getId(),map);
System.out.println("處理任務id:"+task.getId());
}

act_hi_actinst表中,處理時間已填充,并且添加了一下個處理人

image

act_ru_task表,zhangsan的數(shù)據(jù)不再了,新增了李四的數(shù)據(jù)

image

3.8.完成任務

任務處理只需重復執(zhí)行上述方法即可,只是更改了任務的處理人,直至任務結束。

@Test
public void dealTask2() {
Task task = taskService.createTaskQuery()
// 流程id
.processDefinitionKey("leave")
// 處理人
.taskAssignee("李四")
.singleResult();
taskService.complete(task.getId());
System.out.println("處理任務id:"+task.getId());
}

3.9.獲取流程處理歷史

@Test
public void getHistoryList() {
List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
.processDefinitionId("leave:1:0079b147-ed6c-11ee-a186-64bc58439558")
.list();
for (HistoricTaskInstance historicTaskInstance : list) {
System.out.println("開始時間:" + historicTaskInstance.getStartTime());
System.out.println("流程名稱:" + historicTaskInstance.getName());
System.out.println("處理人名稱:" + historicTaskInstance.getAssignee());
System.out.println("結束時間:" + historicTaskInstance.getEndTime());
}
}

image