1、什么是工作流
????????工作流(Workflow),就是通過計(jì)算機(jī)對(duì)業(yè)務(wù)流程自動(dòng)化執(zhí)行管理。它主要解決的是“使在多個(gè)參與者之間按照某種預(yù)定義的規(guī)則自動(dòng)進(jìn)行傳遞文檔、信息或任務(wù)的過程,從而實(shí)現(xiàn)某個(gè)預(yù)期的業(yè)務(wù)目標(biāo),或者促使此目標(biāo)的實(shí)現(xiàn)”。
1.2、工作流系統(tǒng)
????????一個(gè)軟件系統(tǒng)中具有工作流的功能,我們把它稱為工作流系統(tǒng),一個(gè)系統(tǒng)中工作流的功能是什么?就是對(duì)系統(tǒng)的業(yè)務(wù)流程進(jìn)行自動(dòng)化管理,所以工作流是建立在業(yè)務(wù)流程的基礎(chǔ)上,所以一個(gè)軟件的系統(tǒng)核心根本上還是系統(tǒng)的業(yè)務(wù)流程,工作流只是協(xié)助進(jìn)行業(yè)務(wù)流程管理。即使沒有工作流業(yè)務(wù)系統(tǒng)也可以開發(fā)運(yùn)行,只不過有了工作流可以更好的管理業(yè)務(wù)流程,提高系統(tǒng)的可擴(kuò)展性。
1.3、Activiti概述
????????Activiti是一個(gè)工作流引擎, activiti可以將業(yè)務(wù)系統(tǒng)中復(fù)雜的業(yè)務(wù)流程抽取出來,使用專門的建模語言BPMN2.0進(jìn)行定義,業(yè)務(wù)流程按照預(yù)先定義的流程進(jìn)行執(zhí)行,實(shí)現(xiàn)了系統(tǒng)的流程由activiti進(jìn)行管理,減少業(yè)務(wù)系統(tǒng)由于流程變更進(jìn)行系統(tǒng)升級(jí)改造的工作量,從而提高系統(tǒng)的健壯性,同時(shí)也減少了系統(tǒng)開發(fā)維護(hù)成本。
1.4、BPM
????????BPM即業(yè)務(wù)流程管理,是一種規(guī)范化的構(gòu)造端到端的業(yè)務(wù)流程,以持續(xù)的提高組織業(yè)務(wù)效率。 idea插件安裝:https://plugins.jetbrains.com/plugin/7429-actibpm/versions 將下載的jar包插件直接整到idea當(dāng)中,在settings當(dāng)中的插件當(dāng)中,導(dǎo)入本地插件,導(dǎo)入插件之后重啟idea即可。
2、Activiti工作流環(huán)境搭建
引入相關(guān)依賴:(主要MySQL的版本和自己本地需要一致)
<properties>
? ? <slf4j.version>1.6.6</slf4j.version>
? ? <log4j.version>1.2.12</log4j.version>
? ? <activiti.version>7.0.0.Beta1</activiti.version>
</properties>
<dependencies>
? ? <dependency>
? ? ? ? <groupId>org.activiti</groupId>
? ? ? ? <artifactId>activiti-engine</artifactId>
? ? ? ? <version>${activiti.version}</version>
? ? </dependency>
? ? <dependency>
? ? ? ? <groupId>org.activiti</groupId>
? ? ? ? <artifactId>activiti-spring</artifactId>
? ? ? ? <version>${activiti.version}</version>
? ? </dependency>
? ? <!-- bpmn 模型處理 -->
? ? <dependency>
? ? ? ? <groupId>org.activiti</groupId>
? ? ? ? <artifactId>activiti-bpmn-model</artifactId>
? ? ? ? <version>${activiti.version}</version>
? ? </dependency>
? ? <!-- bpmn 轉(zhuǎn)換 -->
? ? <dependency>
? ? ? ? <groupId>org.activiti</groupId>
? ? ? ? <artifactId>activiti-bpmn-converter</artifactId>
? ? ? ? <version>${activiti.version}</version>
? ? </dependency>
? ? <!-- bpmn json數(shù)據(jù)轉(zhuǎn)換 -->
? ? <dependency>
? ? ? ? <groupId>org.activiti</groupId>
? ? ? ? <artifactId>activiti-json-converter</artifactId>
? ? ? ? <version>${activiti.version}</version>
? ? </dependency>
? ? <!-- bpmn 布局 -->
? ? <dependency>
? ? ? ? <groupId>org.activiti</groupId>
? ? ? ? <artifactId>activiti-bpmn-layout</artifactId>
? ? ? ? <version>${activiti.version}</version>
? ? </dependency>
? ? <!-- activiti 云支持 -->
? ? <dependency>
? ? ? ? <groupId>org.activiti.cloud</groupId>
? ? ? ? <artifactId>activiti-cloud-services-api</artifactId>
? ? ? ? <version>${activiti.version}</version>
? ? </dependency>
? ? <!-- mysql驅(qū)動(dòng) -->
? ? <dependency>
? ? ? ? <groupId>mysql</groupId>
? ? ? ? <artifactId>mysql-connector-java</artifactId>
? ? ? ? <version>8.0.23</version>
? ? </dependency>
? ? <!-- mybatis -->
? ? <dependency>
? ? ? ? <groupId>org.mybatis</groupId>
? ? ? ? <artifactId>mybatis</artifactId>
? ? ? ? <version>3.4.5</version>
? ? </dependency>
? ? <!-- 鏈接池 -->
? ? <dependency>
? ? ? ? <groupId>commons-dbcp</groupId>
? ? ? ? <artifactId>commons-dbcp</artifactId>
? ? ? ? <version>1.4</version>
? ? </dependency>
? ? <dependency>
? ? ? ? <groupId>junit</groupId>
? ? ? ? <artifactId>junit</artifactId>
? ? ? ? <version>4.12</version>
? ? </dependency>
? ? <!-- log start -->
? ? <dependency>
? ? ? ? <groupId>log4j</groupId>
? ? ? ? <artifactId>log4j</artifactId>
? ? ? ? <version>${log4j.version}</version>
? ? </dependency>
? ? <dependency>
? ? ? ? <groupId>org.slf4j</groupId>
? ? ? ? <artifactId>slf4j-api</artifactId>
? ? ? ? <version>${slf4j.version}</version>
? ? </dependency>
? ? <dependency>
? ? ? ? <groupId>org.slf4j</groupId>
? ? ? ? <artifactId>slf4j-log4j12</artifactId>
? ? ? ? <version>${slf4j.version}</version>
? ? </dependency>
</dependencies>
?
?使用log4j日志,直接在resources下創(chuàng)建log4j.properties:日志文件路徑根據(jù)實(shí)際路徑修改
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=E:\\workFile\\log4jLog\\activiti.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n
添加activiti配置文件,使用activiti提供的默認(rèn)方式來創(chuàng)建mysql的表。默認(rèn)方式是在 resources 下創(chuàng)建 activiti.cfg.xml 文件,注意:默認(rèn)方式目錄和文件名不能修改,因?yàn)閍ctiviti的源碼中已經(jīng)設(shè)置,到固定的目錄讀取固定文件名的文件。默認(rèn)要在在activiti.cfg.xml中bean的名字叫processEngineConfiguration,名字不可修改,在這里直接連接到本地?cái)?shù)據(jù)庫activiti這個(gè)庫。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 默認(rèn)id對(duì)應(yīng)的值 為processEngineConfiguration -->
<!-- processEngine Activiti的流程引擎 -->
<!-- <bean id="processEngineConfiguration"-->
<!-- class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">-->
<!-- <property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"/>-->
<!-- <property name="jdbcUrl" value="jdbc:mysql:///activiti?autoReconnect=true"/>-->
<!-- <property name="jdbcUsername" value="root"/>-->
<!-- <property name="jdbcPassword" value="123456"/>-->
<!-- <property name="databaseSchemaUpdate" value="true"/>-->
<!-- </bean>-->
<!-- 這里可以使用 鏈接池 dbcp-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql:///activiti?autoReconnect=true" />
<property name="username" value="root" />
<property name="password" value="123456" />
<property name="maxActive" value="3" />
<property name="maxIdle" value="1" />
</bean>
<bean id="processEngineConfiguration"
class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<!-- 引用數(shù)據(jù)源 上面已經(jīng)設(shè)置好了-->
<property name="dataSource" ref="dataSource" />
<!-- activiti數(shù)據(jù)庫表處理策略 -->
<property name="databaseSchemaUpdate" value="true"/>
</bean>
</beans>
?創(chuàng)建一個(gè)測(cè)試類,調(diào)用activiti的工具類,生成acitivti需要的數(shù)據(jù)庫表。直接使用activiti提供的工具類ProcessEngines,會(huì)默認(rèn)讀取classpath下的activiti.cfg.xml文件,讀取其中的數(shù)據(jù)庫配置,創(chuàng)建 ProcessEngine,在創(chuàng)建ProcessEngine 時(shí)會(huì)自動(dòng)創(chuàng)建表。代碼執(zhí)行完成之后在數(shù)據(jù)庫當(dāng)中進(jìn)行查看對(duì)應(yīng)的表是否都創(chuàng)建出來了。
?
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringbootHelloApplicationTests {
@Test
void contextLoads() {
//使用classpath下的activiti.cfg.xml中的配置創(chuàng)建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
System.out.println(processEngine);
// 而除了使用默認(rèn)配置進(jìn)行創(chuàng)建工作流引擎對(duì)象,還可以通過自定義的方式進(jìn)行創(chuàng)建。
// 自定義配置文件名
ProcessEngineConfiguration processEngineConfigurationFromResource = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
System.out.println(processEngineConfigurationFromResource);
// 自定義配置文件名 bean對(duì)象id
ProcessEngineConfiguration processEngineConfigurationFromResource1 = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml", "processEngineConfiguration");
System.out.println(processEngineConfigurationFromResource1);
}
}
執(zhí)行完數(shù)據(jù)庫生成25張表。
?3、Activiti 類、配置文件之間的關(guān)系
3.1、activiti.cfg.xml
????????activiti的引擎配置文件,包括:ProcessEngineConfiguration的定義、數(shù)據(jù)源定義、事務(wù)管理器等,此文件其實(shí)就是一個(gè)spring配置文件。
3.2、流程引擎配置類
????????流程引擎的配置類(ProcessEngineConfiguration),通過ProcessEngineConfiguration可以創(chuàng)建工作流引擎ProceccEngine,常用的兩種方法如下:
????????3.2.1、StandaloneProcessEngineConfiguration
使用StandaloneProcessEngineConfigurationActiviti可以單獨(dú)運(yùn)行,來創(chuàng)建ProcessEngine,Activiti會(huì)自己處理事務(wù)。配置文件方式:通常在activiti.cfg.xml配置文件中定義一個(gè)id為 processEngineConfiguration 的bean,見環(huán)境搭建模塊,就是使用這種方式進(jìn)行配置的。
????????3.2.2、SpringProcessEngineConfiguration
通過org.activiti.spring.SpringProcessEngineConfiguration 與Spring整合。
3.3、Servcie服務(wù)接口
????????Service是工作流引擎提供用于進(jìn)行工作流部署、執(zhí)行、管理的服務(wù)接口,我們使用這些接口可以就是操作服務(wù)對(duì)應(yīng)的數(shù)據(jù)表,并且在這里通過processEngine對(duì)象get對(duì)應(yīng)的service就可以獲取到service對(duì)象了。
?4、流程的創(chuàng)建與操作
4.1 流程圖的繪制,安裝bpmn插件
?將文件后綴bpmn改為xml,打開文件如下
?4.2.1 單個(gè)文件部署方式
將上面的流程部署到activiti的數(shù)據(jù)庫中,就是流程定義部署。
/**
* 單個(gè)文件部署流程
*/
@Test
public void develop() {
// 創(chuàng)建流程對(duì)象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 獲取service對(duì)象
RepositoryService repositoryService = processEngine.getRepositoryService();
// 流程部署 設(shè)置名字 將bpmn和png部署進(jìn)去
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("bpmn/hello.bpmn")
.addClasspathResource("bpmn/hello.png")
.name("請(qǐng)假流程")
.deploy();
System.out.println("id = " + deploy.getId());
System.out.println("name = " + deploy.getName());
}
之后直接啟動(dòng)這個(gè)測(cè)試方法進(jìn)行流程部署,可以觀察日志,整個(gè)部署的過程當(dāng)中總共操作了三張表
- act_re_deployment 流程定義部署表,每部署一次增加一條記錄
- act_re_procdef 流程定義表,部署每個(gè)新的流程定義都會(huì)在這張表中增加一條記錄
- act_ge_bytearray 流程資源表
????????act_re_deployment 和 act_re_procdef一對(duì)多關(guān)系,一次部署在流程部署表生成一條記錄,但一次部署可以部署多個(gè)流程定義,每個(gè)流程定義在流程定義表生成一條記錄。每一個(gè)流程定義在act_ge_bytearray會(huì)存在兩個(gè)資源記錄,bpmn和png。
4.2.2 使用壓縮包的方式
/**
* 壓縮包的方式部署
*/
@Test
public void devoZip(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("bpmn/hello.zip");
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
Deployment deploy = repositoryService.createDeployment().addZipInputStream(zipInputStream).deploy();
System.out.println("id = " + deploy.getId());
System.out.println("name = " + deploy.getName());
}
4.3 開始流程
????????啟動(dòng)一個(gè)流程表示發(fā)起一個(gè)新的請(qǐng)假申請(qǐng),這就相當(dāng)于java類與java對(duì)象的關(guān)系,類定義好后需要new創(chuàng)建一個(gè)對(duì)象使用,當(dāng)然可以new多個(gè)對(duì)象。對(duì)于請(qǐng)出差申請(qǐng)流程,發(fā)起一個(gè)請(qǐng)假申請(qǐng)單需要啟動(dòng)一個(gè)流程實(shí)例,請(qǐng)假申請(qǐng)單發(fā)起請(qǐng)假也需要啟動(dòng)一個(gè)流程實(shí)例。
流程實(shí)例的key查看數(shù)據(jù)庫
/**
* 開始流程
*/
@Test
public void start(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
// 根據(jù)流程id啟動(dòng)流程 act_re_procdef表里的key
ProcessInstance instance = runtimeService.startProcessInstanceByKey("myProcess_1");
System.out.println("流程id = " + instance.getProcessDefinitionId());
System.out.println("實(shí)例id = " + instance.getId());
System.out.println("活動(dòng)id = " + instance.getActivityId());
}
?流程開始成功。
4.4 任務(wù)查詢
????????流程啟動(dòng)后,任務(wù)的負(fù)責(zé)人就可以查詢自己當(dāng)前需要處理的任務(wù),查詢出來的任務(wù)都是該用戶的待辦任務(wù)。
/**
* 查找任務(wù)
*/
@Test
public void findTask(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
// act_ru_task表里的assignee字段就是處理人 可以手動(dòng)設(shè)置
List<Task> list = taskService.createTaskQuery().processDefinitionKey("myProcess_1").taskAssignee("cxb").list();
for (Task task : list){
System.out.println("流程id = " + task.getProcessInstanceId());
System.out.println("任務(wù)id = " + task.getId());
System.out.println("任務(wù)負(fù)責(zé)人 = " + task.getAssignee());
System.out.println("任務(wù)名稱 = " + task.getName());
}
}
而對(duì)應(yīng)的查詢語句也是:根據(jù)流程的Key以及負(fù)責(zé)人去task當(dāng)中查詢?nèi)蝿?wù)。
SELECT DISTINCT RES.* FROM ACT_RU_TASK RES INNER JOIN ACT_RE_PROCDEF D ON RES.PROC_DEF_ID_ = D.ID_
WHERE RES.ASSIGNEE_ = 'yueyue' AND D.KEY_ = 'myLeave' ORDER BY RES.ID_ ASC LIMIT 2147483647 OFFSET 0
這里設(shè)置處理人。
?
?4.5 任務(wù)推動(dòng)
????????在前面我們可以獲取到負(fù)責(zé)人所有的任務(wù),并且可以獲取到相對(duì)應(yīng)的任務(wù)id,這里只需要獲取id進(jìn)行推動(dòng)流程即可。
/**
* 任務(wù)推動(dòng)
*/
@Test
public void next(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
taskService.complete("5005");
// 獲取單個(gè)流程數(shù)據(jù)進(jìn)行操作,替換掉上面的2505
// Task task = taskService.createTaskQuery().processDefinitionKey("myProcess_1").taskAssignee("zhangsan").singleResult();
// taskService.complete(task.getId());
System.out.println("任務(wù)完成");
}
?????????任務(wù)推動(dòng)之后還是和查詢?nèi)蝿?wù)一致的查詢語句獲取當(dāng)前負(fù)責(zé)人的數(shù)據(jù),也可以直接查看 act_ru_task這張表的流程數(shù)據(jù)推動(dòng)了沒,而之前的流程會(huì)保存在 act_hi_taskinst 這張表當(dāng)中。而這里對(duì)后續(xù)的幾個(gè)流程的推動(dòng)也是相同的道理,就不繼續(xù)進(jìn)行流程推動(dòng)了,當(dāng)最后一步的流程走完之后,整個(gè)流程已經(jīng)結(jié)束,在act_ru_task這張表就不會(huì)存在當(dāng)前這個(gè)流程的數(shù)據(jù)了。
4.6 流程定義信息查詢
????????查詢流程相關(guān)信息,包含流程定義,流程部署,流程定義版本
/**
* 流程定義信息查詢
*/
@Test
public void processInfo() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey("myProcess_1").orderByProcessDefinitionVersion().desc().list();
for (ProcessDefinition definition : list) {
System.out.println("id = " + definition.getId());
System.out.println("name = " + definition.getName());
System.out.println("key = " + definition.getKey());
System.out.println("version = " + definition.getVersion());
}
}
?4.7 流程刪除
/**
* 刪除流程
*/
@Test
public void deleteProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
// repositoryService.deleteDeployment("1");
// 如果該流程定義下存在已經(jīng)運(yùn)行的流程,使用普通刪除報(bào)錯(cuò),可用級(jí)聯(lián)刪除方法將流程及相關(guān)記錄全部刪除。
// 先刪除沒有完成流程節(jié)點(diǎn),最后就可以完全刪除流程定義信息
repositoryService.deleteDeployment("1", true);
}
?4.8 下載資源文件
????????首先可以知道資源文件存在 act_ge_bytearray 這張表當(dāng)中,而對(duì)于流程的數(shù)據(jù)bpmn和png文件的DEPLOYMENT_ID這個(gè)字段是相同的,因此只需要獲取到這個(gè)id就能得到相對(duì)應(yīng)的數(shù)據(jù),這個(gè)id如何獲取呢?在前面4.6獲取流程信息當(dāng)中就可以獲取到這個(gè)id,因此把之前獲取全部改為獲取單個(gè),就能拿到這個(gè)id了。而后續(xù)根據(jù)repositoryService來進(jìn)行獲取需要兩個(gè)參數(shù),一個(gè)就是這個(gè)id,另外一個(gè)就是文件的路徑,文件的路徑可以在 act_re_procdef 當(dāng)中進(jìn)行獲取。
?
/**
* 下載資源文件
* @throws IOException
*/
@Test
public void getBolb() throws IOException {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
ProcessDefinition definition = processDefinitionQuery.processDefinitionKey("myProcess_1").orderByProcessDefinitionVersion().desc().singleResult();
// 獲取流程id 文件名
String deploymentId = definition.getDeploymentId();
String diagramResourceName = definition.getDiagramResourceName();
String resourceName = definition.getResourceName();
// 得到input流
InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, diagramResourceName);
InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, resourceName);
File pngFile = new File("d:/leave.png");
File bpmnFile = new File("d:/leave.bpmn");
FileOutputStream pngOutputStream = new FileOutputStream(pngFile);
FileOutputStream bpmnOutputStream = new FileOutputStream(bpmnFile);
// 輸入輸出轉(zhuǎn)換
IOUtils.copy(pngInput, pngOutputStream);
IOUtils.copy(bpmnInput, bpmnOutputStream);
pngInput.close();
pngOutputStream.close();
bpmnInput.close();
bpmnOutputStream.close();
}
并且這里使用到的IOUtils工具類是apache提供的,需要引入新的依賴
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
4.9 流程歷史信息查看
????????即使流程定義已經(jīng)刪除了,流程執(zhí)行的歷史信息通過前面的分析,依然保存在activiti的act_hi_*
相關(guān)的表中。所以我們還是可以查詢流程執(zhí)行的歷史信息,可以通過HistoryService來查看相關(guān)的歷史記錄。
/**
* 查看流程歷史信息
*/
@Test
public void findHistory() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
HistoryService historyService = processEngine.getHistoryService();
// 設(shè)置查詢條件進(jìn)行查詢
List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
.orderByHistoricActivityInstanceStartTime().asc()
.processInstanceId("12501").list();
for (HistoricActivityInstance historiy : list) {
System.out.println("activiti id = " + historiy.getActivityId());
System.out.println("activiti name = " + historiy.getActivityName());
System.out.println("process definition id = " + historiy.getProcessDefinitionId());
System.out.println("process instance id = " + historiy.getProcessInstanceId());
System.out.println("start time = " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(historiy.getStartTime()));
System.out.println("===============================================");
}
}
4.10、給流程實(shí)例添加Businesskey(業(yè)務(wù)標(biāo)識(shí))
????????啟動(dòng)流程實(shí)例時(shí),指定的businesskey,就會(huì)在act_ru_execution #流程實(shí)例的執(zhí)行表中存儲(chǔ)businesskey。
Businesskey:業(yè)務(wù)標(biāo)識(shí),通常為業(yè)務(wù)表的主鍵,業(yè)務(wù)標(biāo)識(shí)和流程實(shí)例一一對(duì)應(yīng)。業(yè)務(wù)標(biāo)識(shí)來源于業(yè)務(wù)系統(tǒng)。存儲(chǔ)業(yè)務(wù)標(biāo)識(shí)就是根據(jù)業(yè)務(wù)標(biāo)識(shí)來關(guān)聯(lián)查詢業(yè)務(wù)系統(tǒng)的數(shù)據(jù)。
/**
* 增加業(yè)務(wù)標(biāo)識(shí)
*/
@Test
public void addLeaveKey() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance myLevel = runtimeService.startProcessInstanceByKey("myProcess_1", "1001");
System.out.println(myLevel.getBusinessKey());
}
4.11 流程的掛起與激活
4.11.1、全部流程實(shí)例掛起
????????操作流程定義為掛起狀態(tài),該流程定義下邊所有的流程實(shí)例全部暫停:流程定義為掛起狀態(tài)該流程定義將不允許啟動(dòng)新的流程實(shí)例,同時(shí)該流程定義下所有的流程實(shí)例將全部掛起暫停執(zhí)行。
/**
* 全部流程實(shí)例掛起
*/
@Test
public void suspendAll() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionKey("myProcess_1").singleResult();
// 是否暫停
boolean suspended = definition.isSuspended();
String id = definition.getId();
if (suspended) {
repositoryService.activateProcessDefinitionById(id, true, null);
System.out.println("id = " + id + " 激活");
} else {
repositoryService.suspendProcessDefinitionById(id, true, null);
System.out.println("id = " + id + " 掛起");
}
}
4.11.2、單個(gè)流程實(shí)例掛起
?????????操作流程實(shí)例對(duì)象,針對(duì)單個(gè)流程執(zhí)行掛起操作,某個(gè)流程實(shí)例掛起則此流程不再繼續(xù)執(zhí)行,完成該流程實(shí)例的當(dāng)前任務(wù)將報(bào)異常。
@Test
public void suspendOne() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId("12501").singleResult();
boolean suspended = processInstance.isSuspended();
String id = processInstance.getId();
if (suspended) {
runtimeService.activateProcessInstanceById(id);
System.out.println("id = " + id + " 激活");
} else {
runtimeService.suspendProcessInstanceById(id);
System.out.println("id = " + id + " 掛起");
}
}
4.11.3 流程實(shí)例推動(dòng)
????????在前面我們對(duì)一個(gè)整個(gè)的流程以及單個(gè)流程進(jìn)行了激活和掛起操作,之后可以編寫一段代碼來進(jìn)行推動(dòng)流程操作,主要是用來當(dāng)流程被掛起后流程還能否被繼續(xù)推動(dòng)。很顯然,當(dāng)掛起的流程去進(jìn)行流程推動(dòng)是不允許推動(dòng)流程的,必須是流程是激活狀態(tài)下才能夠被推動(dòng)。
具體的實(shí)例id和assignee值根據(jù)自己數(shù)據(jù)庫的值來進(jìn)行處理。
/**
* 流程實(shí)例推動(dòng)
*/
@Test
public void complete() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().processInstanceId("15001").taskAssignee("cxb").singleResult();
System.out.println("id = " + task.getId());
System.out.println("name = " + task.getName());
System.out.println("assignee = " + task.getAssignee());
taskService.complete(task.getId());
}
5、個(gè)人任務(wù)
5.1、分配任務(wù)責(zé)任人
5.1.1、固定負(fù)責(zé)人
????????在進(jìn)行業(yè)務(wù)流程建模時(shí)指定固定的任務(wù)負(fù)責(zé)人,直接在bpmn當(dāng)中指定assignee。
5.1.2、表達(dá)式分配
????????由于固定分配方式,任務(wù)只管一步一步執(zhí)行任務(wù),執(zhí)行到每一個(gè)任務(wù)將按照 bpmn 的配置去分配任務(wù)負(fù)責(zé)人。和前面一樣進(jìn)行指定,使用${變量名}的方式進(jìn)行指定。而指定之后的這些變量在流程啟動(dòng)的時(shí)候可以通過一個(gè)map對(duì)象來進(jìn)行賦值。
/**
* 表達(dá)式分配
*/
@Test
public void startDistribution () {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
// 根據(jù)流程id啟動(dòng)流程
Map<String, Object> map = new HashMap();
map.put("assignee", "huangyueyue");
map.put("director", "yueyueniao");
map.put("manager", "zhangsan");
ProcessInstance instance = runtimeService.startProcessInstanceByKey("myProcess_1", map);
}
?5.1.3、監(jiān)聽器分配
????????任務(wù)監(jiān)聽器的Event的選項(xiàng)包含:
- Create:任務(wù)創(chuàng)建后觸發(fā)
- Assignment:任務(wù)分配后觸發(fā)
- Delete:任務(wù)完成后觸發(fā)
- All:所有事件發(fā)生都觸發(fā)
定義任務(wù)監(jiān)聽類,且類必須實(shí)現(xiàn) org.activiti.engine.delegate.TaskListener 接口
package com.cxb.springboot.listener;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
public class MyTaskListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
if (delegateTask.getName().equals("請(qǐng)假申請(qǐng)") &&
delegateTask.getEventName().equals("create")) {
// 這里指定任務(wù)負(fù)責(zé)人
delegateTask.setAssignee("黃閱閱");
}
}
}
<userTask activiti:exclusive="true" id="_3" name="請(qǐng)假申請(qǐng)">
<extensionElements>
<activiti:taskListener class="com.cxb.springboot.listener.MyTaskListener" event="all"/>
</extensionElements>
</userTask>
?5.2、查詢?nèi)蝿?wù)
????????在前面就已經(jīng)可以通過流程key和負(fù)責(zé)人就可以查詢出這個(gè)人負(fù)責(zé)的流程單,而實(shí)際應(yīng)用時(shí),查詢待辦任務(wù)可能要顯示出業(yè)務(wù)系統(tǒng)的一些相關(guān)信息。這里可以通過 businessKey(業(yè)務(wù)標(biāo)識(shí) )關(guān)聯(lián)查詢業(yè)務(wù)系統(tǒng)的數(shù)據(jù)。
/**
* 查詢?nèi)蝿?wù)
*/
@Test
public void findProcessInstance() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
RuntimeService runtimeService = processEngine.getRuntimeService();
Task task = taskService.createTaskQuery()
.processDefinitionKey("myProcess_1")
.taskAssignee("cxb")
.singleResult();
String processInstanceId = task.getProcessInstanceId();
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstanceId)
.singleResult();
String businessKey = processInstance.getBusinessKey();
System.out.println("businessKey==" + businessKey);
}
?查詢業(yè)務(wù)標(biāo)識(shí)碼
?5.3、任務(wù)推動(dòng)
????????在之前可以通過TaskService這個(gè)類的complate方法推動(dòng)任務(wù)的流動(dòng),而在這里我們還需要對(duì)當(dāng)前用戶是否擁有推動(dòng)該流程的權(quán)限,只需要先通過查詢當(dāng)前負(fù)責(zé)人的所有流程進(jìn)行判斷即可。有該流程即可推動(dòng),反之無法推動(dòng)流程。
@Test
public void completeTask() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.taskId("20005")
.taskAssignee("cxb")
.singleResult();
if (task != null) {
taskService.complete("20005");
System.out.println("完成任務(wù)");
}
}
6、流程變量與組任務(wù)
6.1、流程變量概述
6.1.1、流程變量是什么
????????流程變量在 activiti 中是一個(gè)非常重要的角色,流程運(yùn)轉(zhuǎn)有時(shí)需要靠流程變量,業(yè)務(wù)系統(tǒng)和 activiti 結(jié)合時(shí)少不了流程變量,流程變量就是 activiti 在管理工作流時(shí)根據(jù)管理需要而設(shè)置的變量。
????????雖然流程變量中可以存儲(chǔ)業(yè)務(wù)數(shù)據(jù)可以通過activiti的api查詢流程變量從而實(shí)現(xiàn)查詢業(yè)務(wù)數(shù)據(jù),但是不建議這樣使用,因?yàn)闃I(yè)務(wù)數(shù)據(jù)查詢由業(yè)務(wù)系統(tǒng)負(fù)責(zé),activiti設(shè)置流程變量是為了流程執(zhí)行需要而創(chuàng)建。
6.1.2、流程變量作用域
????????流程變量的作用域可以是一個(gè)流程實(shí)例,或一個(gè)任務(wù),或一個(gè)執(zhí)行實(shí)例
1、global變量
????????流程變量的默認(rèn)作用域是流程實(shí)例。當(dāng)一個(gè)流程變量的作用域?yàn)榱鞒虒?shí)例時(shí),可以稱為 global 變量。
????????global 變量中變量名不允許重復(fù),設(shè)置相同名稱的變量,后設(shè)置的值會(huì)覆蓋前設(shè)置的變量值。
2、local變量????????任務(wù)和執(zhí)行實(shí)例僅僅是針對(duì)一個(gè)任務(wù)和一個(gè)執(zhí)行實(shí)例范圍,范圍沒有流程實(shí)例大, 稱為 local 變量。
????????Local 變量由于在不同的任務(wù)或不同的執(zhí)行實(shí)例中,作用域互不影響,變量名可以相同沒有影響。
????????Local 變量名也可以和 global 變量名相同,沒有影響。
6.2、使用global變量控制流程
?????????還是和前面的整個(gè)流程一樣,現(xiàn)在對(duì)流程的分支進(jìn)行控制,通過流程變量來進(jìn)行控制,當(dāng)天數(shù)大于或等于三天還需要通過經(jīng)理審批,反之直接通過主管審批就結(jié)束了整個(gè)流程。
?????????這里的話使用的UEL表達(dá)式使用的是uel-method來進(jìn)行賦值,所以在這里需要一個(gè)實(shí)體類來進(jìn)行值的給予,先定義一個(gè)類。該類當(dāng)中必須包含這個(gè)day變量,也就是在bpmn文件當(dāng)中指定的變量,以及該類必須實(shí)例化。并且加上getset方法。
public class Leave implements Serializable {
private Double day;
}
6.2.1、啟動(dòng)流程時(shí)設(shè)置變量
????????在啟動(dòng)流程時(shí)設(shè)置流程變量,變量的作用域是整個(gè)流程實(shí)例。通過Map<key,value>設(shè)置流程變量,map中可以設(shè)置多個(gè)變量,這個(gè)key就是流程變量的名字。后續(xù)通過TaskService的compele方法來進(jìn)行推動(dòng)流程實(shí)例的代碼就不給出了,直接獲取taskid進(jìn)行推動(dòng),查看流程的走向。
/**
* 單個(gè)文件部署流程
*/
@Test
public void developGlobal() {
// 創(chuàng)建流程對(duì)象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 獲取service對(duì)象
RepositoryService repositoryService = processEngine.getRepositoryService();
// 流程部署 設(shè)置名字 將bpmn和png部署進(jìn)去
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("bpmn/hello-global.bpmn")
.addClasspathResource("bpmn/hello-global.png")
.name("請(qǐng)假流程全局設(shè)置變量")
.deploy();
System.out.println("id = " + deploy.getId());
System.out.println("name = " + deploy.getName());
}
/**
* 啟動(dòng)流程時(shí)設(shè)置變量
*/
@Test
public void startSetGlobal() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Leave leave = new Leave();
leave.setDay(4d);
Map map = new HashMap();
map.put("leave", leave);
map.put("assignee", "yueyueniao");
map.put("director", "張三");
map.put("manager", "黃閱閱");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess_1", map);
System.out.println(processInstance);
}
6.2.2 任務(wù)辦理時(shí)設(shè)置變量
????????在完成任務(wù)時(shí)設(shè)置流程變量,該流程變量只有在該任務(wù)完成后其它結(jié)點(diǎn)才可使用該變量,它的作用域是整個(gè)流程實(shí)例,如果設(shè)置的流程變量的key在流程實(shí)例中已存在相同的名字則后設(shè)置的變量替換前邊設(shè)置的變量。這樣對(duì)前面6.2.1的代碼當(dāng)中往map對(duì)象當(dāng)中添加leave的代碼注掉。
/**
* 任務(wù)辦理時(shí)設(shè)置變量
*/
@Test
public void completeSet() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Leave leave = new Leave();
leave.setDay(4d);
Map map = new HashMap();
map.put("leave", leave);
Task task = taskService.createTaskQuery().processDefinitionKeyLike("myLeaveGlabal").taskAssignee("張三").singleResult();
if (task != null) {
taskService.complete(task.getId(), map);
}
}
?6.2.3 通過當(dāng)前流程實(shí)例設(shè)置
????????通過流程實(shí)例id設(shè)置全局變量,該流程實(shí)例必須未執(zhí)行完成。
@Test
public void setGlobalVariableByExecutionId() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Leave leave = new Leave();
leave.setDay(4d);
runtimeService.setVariable("75001", "leave", leave);
}
6.2.4 通過當(dāng)前任務(wù)設(shè)置
@Test
public void setGlobalVariableByTaskId() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Leave leave = new Leave();
leave.setDay(4d);
taskService.setVariable("75001", "leave", leave);
}
6.3 組任務(wù)辦理流程***
1)查詢組任務(wù)
指定候選人,查詢?cè)摵蜻x人當(dāng)前的待辦任務(wù)。候選人不能立即辦理任務(wù)。
2)拾取任務(wù)
該組任務(wù)的所有候選人都能拾取。將候選人的組任務(wù),變成個(gè)人任務(wù)。原來候選人就變成了該任務(wù)的負(fù)責(zé)人。如果拾取后不想辦理該任務(wù),需要將已經(jīng)拾取的個(gè)人任務(wù)歸還到組里邊,將個(gè)人任務(wù)變成了組任務(wù)。
3)查詢個(gè)人任務(wù)
查詢方式同個(gè)人任務(wù)部分,根據(jù)assignee查詢用戶負(fù)責(zé)的個(gè)人任務(wù)。
4)辦理個(gè)人任務(wù)
首先創(chuàng)建一個(gè)bpmn文件,在user當(dāng)中可以對(duì)candidateUsers進(jìn)行設(shè)置多個(gè)人員,之間用都好進(jìn)行隔開,而對(duì)應(yīng)的xml如下:
<userTask activiti:candidateUsers="zhangsan,lisi" activiti:exclusive="true" id="_3" name="申請(qǐng)-group"/>
<userTask activiti:candidateUsers="wangwu,zhaoliu" activiti:exclusive="true" id="_4" name="審核-group"/>
之后將該bpmn進(jìn)行部署,并且啟動(dòng)任務(wù)。
6.3.1 查詢組任務(wù)
????????根據(jù)候選人查詢組任務(wù),可以看到這個(gè)task在act_ru_task這張表當(dāng)中的assignee卻是一個(gè)null,也就是該用戶雖然可以查詢出該任務(wù),卻無法對(duì)該任務(wù)進(jìn)行處理。
@Test
public void findGroup() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List<Task> list = taskService.createTaskQuery().processDefinitionKey("myLeaveGroup").taskCandidateUser("zhangsan").list();
for (Task task : list) {
System.out.println("instance id = " + task.getProcessInstanceId());
System.out.println("id = " + task.getId());
System.out.println("assignee = " + task.getAssignee());
System.out.println("name = " + task.getName());
}
}
6.3.2 拾取任務(wù)
????????候選人員拾取組任務(wù)后該任務(wù)變?yōu)樽约旱膫€(gè)人任務(wù)。用戶拾取任務(wù)之后,對(duì)應(yīng)的act_ru_task表對(duì)應(yīng)的行數(shù)據(jù)的assignee就會(huì)變成相對(duì)應(yīng)的人員。
@Test
public void getTask() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().taskId("87505").taskCandidateUser("zhangsan").singleResult();
if (task != null) {
taskService.claim("87505", "zhangsan");
System.out.println("用戶拾取");
}
}
6.3.3 歸還組任務(wù)
????????直接通過assignee進(jìn)行查詢,查詢到數(shù)據(jù)再將assignee置空也就表示歸還了任務(wù)。同理任務(wù)的交接就不用設(shè)置為空了,直接設(shè)置給另一個(gè)用戶即可。
@Test
public void returnTask() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().taskId("87505").taskAssignee("zhangsan").singleResult();
if (task != null) {
taskService.setAssignee("87505", null);
System.out.println("用戶歸還");
}
}
7、網(wǎng)關(guān)
7.1 排他網(wǎng)關(guān)
????????排他網(wǎng)關(guān),用來在流程中實(shí)現(xiàn)決策。 當(dāng)流程執(zhí)行到這個(gè)網(wǎng)關(guān),所有分支都會(huì)判斷條件是否為true,如果為true則執(zhí)行該分支,注意:排他網(wǎng)關(guān)只會(huì)選擇一個(gè)為true的分支執(zhí)行。如果有兩個(gè)分支條件都為true,排他網(wǎng)關(guān)會(huì)選擇id值較小的一條分支去執(zhí)行。
?在這里對(duì)A流程后設(shè)置一個(gè)排他網(wǎng)關(guān)進(jìn)行流程分支,這兩條分支線也就對(duì)應(yīng)兩個(gè)uel表達(dá)式進(jìn)行判斷,而后就可以直接把這個(gè)流程進(jìn)行部署,部署之后在啟動(dòng)流程的時(shí)候就給這個(gè)day進(jìn)行設(shè)置值,直接進(jìn)行推動(dòng)流程,查看流程的流轉(zhuǎn)。
@Test
public void startSet() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Leave leave = new Leave();
leave.setDay(-4d);
Map map = new HashMap();
map.put("leave", leave);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("gateway-pt", map);
}
@Test
public void compete() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().processDefinitionKey("gateway-pt").taskAssignee("張三").singleResult();
if (task != null) {
taskService.complete(task.getId());
}
}
7.2 并行網(wǎng)關(guān)
????????并行網(wǎng)關(guān)允許將流程分成多條分支,也可以把多條分支匯聚到一起,并行網(wǎng)關(guān)的功能是基于進(jìn)入和外出順序流的:
????????fork分支:并行后的所有外出順序流,為每個(gè)順序流都創(chuàng)建一個(gè)并發(fā)分支。
????????join匯聚:所有到達(dá)并行網(wǎng)關(guān),在此等待的進(jìn)入分支, 直到所有進(jìn)入順序流的分支都到達(dá)以后, 流程就會(huì)通過匯聚網(wǎng)關(guān)。
????????并行網(wǎng)關(guān)的測(cè)試代碼和前面排他網(wǎng)關(guān)的代碼基本一致,在首先進(jìn)行部署之后啟動(dòng)流程,給流程設(shè)置一個(gè)天數(shù),而之后推動(dòng)任務(wù)之后,首先進(jìn)入到并行網(wǎng)關(guān),這里并不會(huì)進(jìn)行判斷,這里的意思是表示B和C都可以進(jìn)行對(duì)該任務(wù)流程進(jìn)行操作,并且只有到B和C都做了相關(guān)的操作流程才會(huì)繼續(xù)往后流轉(zhuǎn),后面接的排他網(wǎng)關(guān)直接通過最開始設(shè)置的值再進(jìn)行判斷做流程的流轉(zhuǎn)。
7.3 包含網(wǎng)關(guān)
????????包含網(wǎng)關(guān)可以看做是排他網(wǎng)關(guān)和并行網(wǎng)關(guān)的結(jié)合體。和排他網(wǎng)關(guān)一樣,可以在外出順序流上定義條件,包含網(wǎng)關(guān)會(huì)解析它們。 但是主要的區(qū)別是包含網(wǎng)關(guān)可以選擇多于一條順序流,這和并行網(wǎng)關(guān)一樣。
? ? ? ? 1、分支:所有外出順序流的條件都會(huì)被解析,結(jié)果為true的順序流會(huì)以并行方式繼續(xù)執(zhí)行, 會(huì)為每個(gè)順序流創(chuàng)建一個(gè)分支。
? ? ? ? 2、匯聚:所有并行分支到達(dá)包含網(wǎng)關(guān),會(huì)進(jìn)入等待狀態(tài), 直到每個(gè)包含流程token的進(jìn)入順序流的分支都到達(dá)。 這是與并行網(wǎng)關(guān)的最大不同。換句話說,包含網(wǎng)關(guān)只會(huì)等待被選中執(zhí)行了的進(jìn)入順序流。 在匯聚之后,流程會(huì)穿過包含網(wǎng)關(guān)繼續(xù)執(zhí)行。
????????和之前的網(wǎng)關(guān)一樣進(jìn)行部署推動(dòng)流程,可以發(fā)現(xiàn)在進(jìn)入到包含網(wǎng)關(guān)的時(shí)候,網(wǎng)關(guān)會(huì)對(duì)條件進(jìn)行判斷再進(jìn)行流轉(zhuǎn)。二里面的包含又相當(dāng)于并行網(wǎng)關(guān),當(dāng)并行的流程都執(zhí)行完成之后再由包含網(wǎng)關(guān)進(jìn)行匯聚。之后走排他網(wǎng)關(guān)進(jìn)行判斷流轉(zhuǎn)。
7.4 事件網(wǎng)關(guān)
????????事件網(wǎng)關(guān)允許根據(jù)事件判斷流向。網(wǎng)關(guān)的每個(gè)外出順序流都要連接到一個(gè)中間捕獲事件。 當(dāng)流程到達(dá)一個(gè)基于事件網(wǎng)關(guān),網(wǎng)關(guān)會(huì)進(jìn)入等待狀態(tài):會(huì)暫停執(zhí)行。與此同時(shí),會(huì)為每個(gè)外出順序流創(chuàng)建相對(duì)的事件訂閱。
????????事件網(wǎng)關(guān)的外出順序流和普通順序流不同,這些順序流不會(huì)真的"執(zhí)行", 相反它們讓流程引擎去決定執(zhí)行到事件網(wǎng)關(guān)的流程需要訂閱哪些事件。 要考慮以下條件:
? ? ? ? 1、事件網(wǎng)關(guān)必須有兩條或以上外出順序流;
? ? ? ? 2、事件網(wǎng)關(guān)后,只能使用intermediateCatchEvent類型(activiti不支持基于事件網(wǎng)關(guān)后連接ReceiveTask)
? ? ? ? 3、連接到事件網(wǎng)關(guān)的中間捕獲事件必須只有一個(gè)入口順序流。文章來源:http://www.zghlxwxcb.cn/news/detail-764180.html
參考文章來源地址http://www.zghlxwxcb.cn/news/detail-764180.html
到了這里,關(guān)于Activiti 工作流簡介的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!