1. 基本使用
(1)创建Maven应用
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sw</groupId>
<artifactId>ActivitiDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<activiti.version>7.0.0.Beta1</activiti.version>
<mysql.version>8.0.26</mysql.version>
<mybatis.version>3.5.13</mybatis.version>
<dbcp.version>1.4</dbcp.version>
<junit.version>4.12</junit.version>
<commons-io.version>2.6</commons-io.version>
</properties>
<dependencies>
<!-- activiti core -->
<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 转换 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn json转换 -->
<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>
<exclusions>
<exclusion>
<groupId>com.github.jgraph</groupId>
<artifactId>jgraphx</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- bpmn cloud -->
<dependency>
<groupId>org.activiti.cloud</groupId>
<artifactId>activiti-cloud-services-api</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- dbcp -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>${dbcp.version}</version>
</dependency>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<!-- sl4j -->
<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>
<!-- commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
</dependencies>
</project>
(2)log4j
# 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=D:\logs\act\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
(3)添加Activiti配置文件
在resources下创建 activiti.cfg.xml
(默认命名方式不能修改)文件
此处使用单独配置数据源的方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration" id="processEngineConfiguration">
<!--<property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"/>-->
<!--<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/activiti?characterEncoding=utf-8&nullCatalogMeansCurrent=true&serverTimezone=UTC"/>-->
<!--<property name="jdbcUsername" value="root"/>-->
<!--<property name="jdbcPassword" value="123456"/>-->
<property name="databaseSchemaUpdate" value="true"/>
<property name="dataSource" ref="dataSource" />
</bean>
<bean class="org.apache.commons.dbcp.BasicDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/activiti?characterEncoding=utf-8&nullCatalogMeansCurrent=true&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="maxActive" value="3"/>
<property name="maxIdle" value="2"/>
</bean>
</beans>
(4)单元测试自动生成表结构
通过单元测试调用 Activiti API
来生成需要的表
@Test
public void test01() {
//使用classpath下的activiti.cfg.xml中的配置来创建ProcessEngine
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
System.out.println(engine);
}
2. 表结构介绍
(1)表的命名规则和作用
- ACT_RE :
RE
表示repository
,这个前缀的表包含了流程定义和流程静态资源 (图片,规则等等) - ACT_RU:
RU
表示runtime
, 包含流程实例,任务,变量,异步任务,等运行中的 数据。Activiti
只在流程实例执行过程中保存这些数据,在流程结束时就会删除这些记录 - ACT_HI:
HI
表示history
, 包含历史数据,比如历史流程实例, 变量,任务等等 - ACT_GE :
GE
表示general
,通用数据,用于不同场景下
(2)数据表介绍
表分类 | 表名 | 解释 |
---|---|---|
一般数据 | ACT_GE_BYTEARRAY | 通用的流程定义和流程资源 |
ACT_GE_PROPERTY | 系统相关属性 | |
流程历史记录 | ACT_HI_ACTINST | 历史的流程实例 |
ACT_HI_ATTACHMENT | 历史的流程附件 | |
ACT_HI_COMMENT | 历史的说明性信息 | |
ACT_HI_DETAIL | 历史的流程运行中的细节信息 | |
ACT_HI_IDENTITYLINK | 历史的流程运行过程中用户关系 | |
ACT_HI_PROCINST | 历史的流程实例 | |
ACT_HI_TASKINST | 历史的任务实例 | |
ACT_HI_VARINST | 历史的流程运行中的变量信息 | |
流程定义表 | ACT_RE_DEPLOYMENT | 部署单元信息 |
ACT_RE_MODEL | 模型信息 | |
ACT_RE_PROCDEF | 已部署的流程定义 | |
运行实例表 | ACT_RU_EVENT_SUBSCR | 运行时事件 |
ACT_RU_EXECUTION | 运行时流程执行实例 | |
ACT_RU_IDENTITYLINK | 运行时用户关系信息,存储任务节点与参与者的相关信息 | |
ACT_RU_JOB | 运行时作业 | |
ACT_RU_TASK | 运行时任务 | |
ACT_RU_VARIABLE | 运行时变量表 |
3. ProcessEngine创建方式
前面使用的是 getDefaultProcessEngine()
方法来加载 classpath
下的 activiti.cfg.xml
文件,还可以通过自定义的方式加载配置文件
@Test
public void test02() {
//创建ProcessEngineConfiguration对象
ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
//创建ProcessEngine对象
ProcessEngine engine = configuration.buildProcessEngine();
System.out.println(engine);
}
4. Service服务接口
Service是工作流引擎提供用于进行工作流部署、执行、管理的服务接口,使用这些接口就是操作服务对应的数据表
(1)创建方式
通过 ProcessEngine
创建 Service
//RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//TaskService
TaskService taskService = processEngine.getTaskService();
(2)Service总览
名称 | 作用 |
---|---|
RepositoryService | 资源管理 |
RuntimeService | 流程运行管理 |
TaskService | 任务管理 |
HistoryService | 历史管理 |
ManagementService | 引擎管理 |
RepositoryService:是
activiti
的资源管理类,提供了管理和控制流程发布包和流程定义的操作。使用工作流建模工具设计的业务流程图需要使用此service
将流程定义文件的内容进行部署。除了部署流程定义以外还可以:- 查询引擎中的发布包和流程定义
- 暂停或激活发布包,对应全部和特定流程定义,暂停意味着它们不能再执行任何操作了,激活是对应的反向操作
- 获得多种资源,像是包含在发布包里的文件,或引擎自动生成的流程图。获得流程定义的pojo版本,可以用来通过java解析流程,而不必通过xml
- RuntimeService:获取很多关于流程执行相关的信息
- TaskService:获取任务的信息
- HistoryService:查询历史信息,执行流程时,引擎会根据配置保存很多数据,如:流程实例启动时间,任务的参与者,完成任务的时间,每个流程实例的执行路径等等
- ManagementService:提供了对
Activiti
流程引擎的管理和维护功能,这些功能主要用于Activiti
系统的日常维护,而不在工作流驱动的应用程序中使用
5. 流程绘制
(1)绘制插件
IDEA在2019版本之后没有再维护 Activiti
的流程设计工具,此处使用 Eclipse 来进行流程设计
(2)绘制流程
指定流程主键
指定任务负责人
(3)图标介绍
流程符号 BPMN 2.0是业务流程建模符号2.0的缩写,它由Business Process Management Initiative这个非营利协会创建并不断发展。作为一种标识,BPMN 2.0是使用一些符号来明确业务流程设计流程图的一整套符号规范,它能增进业务建模时的沟通效率。 目前BPMN2.0是最新的版本,它用于在BPM上下文中进行布局和可视化的沟通。
BPMN 2.0的基本符号主要包含:
事件 Event
活动 Activity
网关 GateWay
网关用来处理决策,常用网关有:
- 排他网关:只有一条路径会被选择,流程执行到该网关时,按照输出流的顺序逐个计算,当条件的计算结果为
true
时,继续执行当前网关的输出流; 如果多条线路计算结果都是true
,则会执行第一个值为true
的线路,如果所有网关计算结果没有true
,则引擎会抛出异常。 排他网关需要和条件顺序流结合使用,default
属性指定默认顺序流,当所有的条件不满足时会执行默认顺序流 并行网关:所有路径会被同时选择:
- 拆分:并行执行所有输出顺序流,为每一条顺序流创建一个并行执行线路
- 合并:所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行
包容网关:可以同时执行多条线路,也可以在网关上设置条件
- 拆分:计算每条线路上的表达式,当表达式计算结果为
true
时,创建一个并行线路并继续执行 - 合并:所有从包容网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下 执行
- 拆分:计算每条线路上的表达式,当表达式计算结果为
- 事件网关:专门为中间捕获事件设置的,允许设置多个输出流指向多个不同的中间捕获事件。当流程执行到事 件网关后,流程处于等待状态,需要等待抛出事件才能将等待状态转换为活动状态
流向 Flow
流是连接两个流程节点的连线,常见的流向有以下几种:
Palette(画板)
- Connection 连接 Event事件
- Task 任务
- Gateway 网关
- Container 容器
- Boundary event 边界事件
- Intermediate event 中间事件
6. 流程操作
(1)流程部署
流程部署即将流程设计器中定义的流程部署到 activiti
数据库中
单文件部署
@Test
public void deploy() {
//1.获取ProcessEngine对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
//2.获取RepositoryService
RepositoryService service = engine.getRepositoryService();
//3.部署
Deployment deploy = service.createDeployment()
.addClasspathResource("bpmn/evection.bpmn")
.addClasspathResource("bpmn/evection.png")
.name("出差申请流程")
.deploy();
System.out.println("id: " + deploy.getId());
System.out.println("name: " + deploy.getName());
}
压缩包文件部署
将bpmn和png文件打包为 .zip
文件,进行部署
@Test
public void test04(){
//定义zip文件的输入流
InputStream inputStream =this.getClass().getClassLoader().getResourceAsStream("bpmn/evection.zip");
//对inputStream做装饰
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.addZipInputStream(zipInputStream)
.name("出差申请流程")
.deploy();
// 4.输出流程部署的信息
System.out.println("流程部署的id:" + deploy.getId());
System.out.println("流程部署的名称:" + deploy.getName());
}
流程定义部署后操作activiti中的三张表:
- act_re_deployment:流程定义部署表,每部署一次就增加一条记录
- act_re_procdef :流程定义表,部署每个新的流程定义都会在这张表中增加一条记录
- act_ge_bytearray :流程资源表,流程部署的bpmn文件和png图片会保存在该表中
(2)启动流程实例
启动一个流程表示发起一个新的出差申请单
@Test
public void start() {
//1.获取ProcessEngine对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
//2.RuntimeService
RuntimeService service = engine.getRuntimeService();
//3.启动
ProcessInstance instance = service.startProcessInstanceByKey("evection");
System.out.println("流程定义id: " + instance.getProcessDefinitionId());
System.out.println("流程实例id: " + instance.getProcessInstanceId());
System.out.println("当前活动id: " + instance.getActivityId());
}
启动流程实例涉及到的表:
- act_hi_actinst 流程实例执行历史
- act_hi_identitylink 流程的参与用户的历史信息
- act_hi_procinst 流程实例历史信息
- act_hi_taskinst 流程任务历史信息
- act_ru_execution 流程执行信息
- act_ru_identitylink 流程的参与用户信息
- act_ru_task 任务信息
(3)任务查找
流程启动后,对应的任务负责人就可以查询自己当前能够处理的任务,查询出来的任务都是当前用户的待办任务
@Test
public void queryTask() {
//1.获取ProcessEngine对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
//2.TaskService
TaskService service = engine.getTaskService();
//3.根据流程key、任务负责人查询
List<Task> list = service.createTaskQuery().processDefinitionKey("evection").taskAssignee("zhansan").list();
for (Task task : list) {
System.out.println("流程定义id: " + task.getProcessDefinitionId());
System.out.println("任务id: " + task.getId());
System.out.println("任务负责人: " + task.getAssignee());
System.out.println("任务名称: " + task.getName());
}
}
(4)流程任务处理
任务负责人查询出来了待办的任务,选择任务进行处理,即完成任务
@Test
public void dealTask() {
//1.获取ProcessEngine对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
//2.TaskService
TaskService service = engine.getTaskService();
//3.根据流程key、任务负责人查询
Task task = service.createTaskQuery().processDefinitionKey("evection").taskAssignee("孙笑川").singleResult();
//4.处理任务
service.complete(task.getId());
}
孙笑川 处理完成之后,任务流转到药水哥处,接着由药水哥登录系统进行处理
(5)查询流程定义
查询流程相关的信息:流程的定义,流程的部署,流程定义的版本
@Test
public void queryProcessDefinition() {
//1.获取ProcessEngine对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
//2.RepositoryService
RepositoryService service = engine.getRepositoryService();
List<ProcessDefinition> list = service.createProcessDefinitionQuery().processDefinitionKey("evection").orderByProcessDefinitionVersion().desc().list();
for (ProcessDefinition processDefinition : list) {
System.out.println("流程定义id: " + processDefinition.getId());
System.out.println("流程定义name: " + processDefinition.getName());
System.out.println("流程定义key: " + processDefinition.getKey());
System.out.println("流程定义version: " + processDefinition.getVersion());
System.out.println("流程部署id: " + processDefinition.getDeploymentId());
}
}
(6)删除流程
@Test
public void deleteProcess() {
//1.获取ProcessEngine对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
//2.RepositoryService
RepositoryService service = engine.getRepositoryService();
//如果该流程定义已经有启动了的流程实例,则无法删除
service.deleteDeployment("1");
//级联删除,设置为true时同时删除流程定义、运行中的流程实例
//service.deleteDeployment("1", true);
}
级联删除权限一般只开放给系统管理员
(7)流程资源下载
用户想要查看流程定义相关的信息时,可以从数据库中下载对应资源到本地(数据库直接查询blob类型数据或通过api下载资源文件,二选一即可)
@Test
public void readFileFromDatabase() throws IOException {
//1.获取ProcessEngine对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
//2.RepositoryService
RepositoryService service = engine.getRepositoryService();
//3.查询器
ProcessDefinition definition = service.createProcessDefinitionQuery().processDefinitionKey("evection").singleResult();
//4.流程部署id
String deploymentId = definition.getDeploymentId();
//png
InputStream pngIs = service.getResourceAsStream(deploymentId, definition.getDiagramResourceName());
//bpmn
InputStream bpmnIs = service.getResourceAsStream(deploymentId, definition.getResourceName());
//5.保存
File pngFile = new File("d:/evection.png");
File bpmnFile = new File("d:/evection.bpmn");
FileOutputStream pngOs = new FileOutputStream(pngFile);
FileOutputStream bpmnOs = new FileOutputStream(bpmnFile);
IOUtils.copy(pngIs, pngOs);
IOUtils.copy(bpmnIs, bpmnOs);
//6.关闭流
pngIs.close();
pngOs.close();
bpmnIs.close();
bpmnOs.close();
}
(8)查看历史流程信息
即使流程定义已经被删除了,流程执行的实例信息依然保存在Activiti的 act_hi_*
相关的表中
@Test
public void processHistoryInfo() {
//1.获取ProcessEngine对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
//2.HistoryService
HistoryService service = engine.getHistoryService();
HistoricActivityInstanceQuery instanceQuery = service.createHistoricActivityInstanceQuery().processDefinitionId("evection:1:4").orderByHistoricActivityInstanceStartTime().desc();
List<HistoricActivityInstance> list = instanceQuery.list();
for (HistoricActivityInstance hi : list) {
System.out.println(hi.getActivityId());
System.out.println(hi.getActivityName());
System.out.println(hi.getActivityType());
System.out.println(hi.getAssignee());
System.out.println(hi.getProcessDefinitionId());
System.out.println(hi.getProcessInstanceId());
System.out.println("--------------------------------");
}
}
评论 (0)