Activiti7 笔记
Activiti7 笔记
一、Activiti7 介绍
Activiti 是一个工作流引擎, activiti 可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言(BPMN2.0)进行定义,业务系统按照预先定义的流程进行执行,实现了业务系统的业务流程由 activiti 进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的健壮性,同时也减少了系统开发维护成本。
官方网址:https://www.activiti.org/
文章所使用的的 Activiti7 版本为 7.0.0
二、Activiti7 使用
业务流程建模
- 使用Activiti流程建模工具(Activity-designer)定义业务流程(.bpmn文件) - IDE 插件(actiBPM 插件)
- bpmn文件就是业务流程定义文件,通过xml定义业务流程
部署业务流程
- 向 Activiti 部署业务流程定义(bpmn文件)
- 使用 Activiti 提供的API向Activiti中部署 bpmn文件
启动流程实例
- 启动一个流程实例表示开始一次业务流程的运行,流程定义就好比一个模板,流程实例根据模板创建而来
- 就好比定义一个 java 类,实例化两个对象一样
查询待办任务
- 通过Activiti 提供的 API 就可以查询当前流程执行到哪里了,当前用户需要办理什么任务了,这些 Activiti 都帮我们管理了
处理待办任务
- 用户查询待办任务后,就可以办理某个任务,通过 api 完成任务,扭转到下一个节点
结束流程
- 当任务办理完成没有下一个任务/结点了,这个流程实例就完成了
三、集成 Activiti7 环境
提示
Activiti7 生成的表结构详情请查看 Activiti7 表结构
1. 普通 Maven 项目集成
在项目工程中添加 Activiti7 所需要的一些 Jar 包等,如下:
<properties>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-layout</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti.cloud</groupId>
<artifactId>activiti-cloud-services-api</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</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>
<!-- log end -->
<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>
</dependencies>
添加 log4j.properties ,我们使用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=./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
添加核心配置文件 在resource 目录下添加 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="dataSource" ref="dataSource" />
<!--
activiti数据库表处理策略
false(默认值):检查数据库的版本和依赖库的版本,如果不匹配就抛出异常
true:构建流程引擎时,执行检查,如果需要就执行更新。如果表不存在,就创建。
create-drop:构建流程引擎时创建数据库报表,关闭流程引擎时就删除这些表。
drop-create:先删除表再创建表。
create:构建流程引擎时创建数据库表,关闭流程引擎时不删除这些表
-->
<property name="databaseSchemaUpdate" value="true"/>
</bean>
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql:///act_demo?characterEncoding=utf-8&nullCatalogMeansCurrent=true&serverTimezone=UTC" />
<property name="username" value="root"/>
<property name="password" value="admin"/>
</bean>
</beans>
需要在配置文件中配置如下信息
数据库连接池
Activiti单独运行的ProcessEngine配置
测试 运行以下程序段即可完成 activiti 数据库创建
/**
* 生成Activiti的相关的表结构
*/
@Test
public void test01(){
// 使用classpath下的activiti.cfg.xml中的配置来创建 ProcessEngine对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
System.out.println(engine);
}
2. SpringBoot 集成
添加依赖 注意事项如下:
- 添加 activiti 和 SpringBoot 整合的依赖 MyBatis 版本会有冲突,所以需要排除
- Activiti7 默认和 Spring Security 集成了
<!--添加activiti和SpringBoot整合的依赖 MyBatis版本会有冲突,所以需要排除-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.0.0.SR1</version>
<exclusions>
<exclusion>
<artifactId>mybatis</artifactId>
<groupId>org.mybatis</groupId>
</exclusion>
</exclusions>
</dependency>
<!--activiti可以绘制流程的的依赖-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-image-generator</artifactId>
<version>7.0.0.SR1</version>
</dependency>
添加 activiti 配置信息
spring:
activiti:
database-schema-update: true
db-history-used: true
history-level: full
check-process-definitions: false
use-strong-uuids: false
配置文件参数说明:
- database-schema-update 属性:
- flase :默认值。activiti在启动时,对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常
- true : activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建
- create_drop : 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)
- drop-create : 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
- db-history-used :检测历史表是否存在 activiti7默认没有开启数据库历史记录,true启动数据库历史记录
- history-level :记录历史等级 可配置的历史级别有none, activity, audit, full
- none:不保存任何的历史数据,因此,在流程执行过程中,这是最高效的。
- activity:级别高于none,保存流程实例与流程行为,其他数据不保存。
- audit:除activity级别会保存的数据外,还会保存全部的流程任务及其属性。audit为history的默认值。
- full:保存历史数据的最高级别,除了会保存audit级别的数据外,还会保存其他全部流程相关的细节数据,包括一些流程参数等
- check-process-definitions :校验流程文件,默认校验resources下的processes文件夹里的流程文件
- use-strong-uuids :是否使用UUID作为主键生成策略
排除Spring Security配置
Activiti7 默认和 Spring Security 集成了, 但是有时候我们的项目中并没有使用, 所以我们需要在项目中排除掉 Spring Security 的自动装配配置, 否则我们的登录页会被覆盖
/**
* 启动程序,运行项目,如果在数据库中出现25张act_开头的表说明集成是没问题的
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,
SecurityAutoConfiguration.class,
ManagementWebSecurityAutoConfiguration.class})
public class RuoYiApplication {
public static void main(String[] args) {
SpringApplication.run(RuoYiApplication.class, args);
}
}
四、绘制流程图
在resource
目录下新建bpmn
目录用于存放所有的流程文件 , 在bpmn
目录下新建leave.bpmn
,内容如下:
为每个任务结点指定负责人,如部门经理的审核人是李四
生成png格式流程图
bpmn
文件本质上是xml格式,我们打开看到的是图片格式是因为我们在IDEA中安装了 actiBPM 的插件,如果我们把bpmn
文件部署到Web环境,那么就只能看到 xml 信息,无法看到类似上面的图形了
我们可以再部署之前,根据bpmn
文件生成png
文件,然后把bpmn
和png
文件同时部署到Web环境中.如果我们想查看流程图的话,我们就可以通过Activiti把这个png
文件读取出来. 接下来我们把bpmn
导出为png
文件
将 leave.bpmn 文件重命名为 leave.xml 文件
右键点击
leave.xml
文件 -->Diagrams
-->Show BPMN Designer...
点击导出按钮,保存在
resource/bpmn
同级目录下导出
png
之后,把leave.xml
更名为leave.bpmn
五、流程引擎 Api
在使用 Activiti7 的 Api 之前需要先了解一下 Activiti 中常用的 Service
Service 接口 | 描述 |
---|---|
RepositoryService | activiti 的资源管理类 |
RuntimeService | activiti 的流程运行管理类 |
TaskService | activiti 的任务管理类 |
HistoryService | activiti 的历史管理类 |
- RepositoryService,是Activiti的资源管理接口,提供了管理和控制流程发布包和流程定义的操作。使用工作流建模工具设计的业务流程图需要使用此Service将流程定义文件的内容部署到计算机中。
- RuntimeService,是Activiti的流程运行管理接口,可以从这个接口中获取很多关于流程执行相关的信息。
- TaskService,是Activiti的任务管理接口,可以从这个接口中获取任务的信息。
- HistoryService,是Activiti的历史管理类,可以查询历史信息,执行流程时,引擎会包含很多数据(根据配置),比如流程实例启动时间,任务的参与者,完成任务的时间,每个流程实例的执行路径,等等。
- ManagementService,是Activiti的引擎管理接口,提供了对Activiti流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用,主要用于Activiti系统的日常维护。
六、Activiti7 Api 使用
部署流程定义
/**
* 实现文件的单个部署
*/
@Test
public void test01(){
// 1.获取ProcessEngine对象
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// 2.获取RepositoryService进行部署操作
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
// 3.使用RepositoryService进行部署操作
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("bpmn/leave.bpmn")
.addClasspathResource("bpmn/leave.png")
.name("请假流程")
.deploy();
// 4.输出流程部署的信息
System.out.println("流程部署的id:" + deploy.getId());
System.out.println("流程部署的名称:" + deploy.getName());
}
部署zip文件 - 将bpmn文件和png文件两个打包为一个zip文件,统一上传
/**
* 通过一个zip文件来部署操作
*/
@Test
public void test02(){
// 定义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());
}
部署流程文件涉及的表结构:
act_ge_bytearray
二进制数据表act_re_deployment
部署信息表act_re_procdef
流程定义数据表
启动流程实例
// 启动一个流程实例
@Test
public void test03(){
// 1.创建ProcessEngine对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 2.获取RuntimeService对象
RuntimeService runtimeService = engine.getRuntimeService();
// 3.根据流程定义的id启动流程
String id= "leaveProcess";
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(id);
// 4.输出相关的流程实例信息
System.out.println("流程定义的ID:" + processInstance.getProcessDefinitionId());
System.out.println("流程实例的ID:" + processInstance.getId());
System.out.println("当前活动的ID:" + processInstance.getActivityId());
}
如果该流程定义文件中使用 UEL表达式分配 了负责人,则在启动时需要传入对应的参数,如下:
// 启动一个流程实例,带参数
@Test
public void test03(){
// 1.创建ProcessEngine对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 2.获取RuntimeService对象
RuntimeService runtimeService = engine.getRuntimeService();
// 3.根据流程定义的id启动流程
String id= "leaveProcess";
// 设置对应的参数
Map<String, Object> variables = new HashMap<String, Object>();
// 设置部门审核人
variables.put("deptLeader", "张三");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(id, variables);
// 4.输出相关的流程实例信息
System.out.println("流程定义的ID:" + processInstance.getProcessDefinitionId());
System.out.println("流程实例的ID:" + processInstance.getId());
System.out.println("当前活动的ID:" + processInstance.getActivityId());
}
启动流程实例涉及的表结构:
act_ru_execution
- 代表正在执行的流程实例表,如果当期正在执行的流程实例结束以后,该行在这张表中就被删除掉了,所以该表也是一个临时表act_ru_task
- 代表正在执行的任务表,该表是一个临时表,如果当前任务被完成以后,任务在这张表中就被删除掉了act_hi_actinst
- 流程图上出现的每一个元素都称为activity,流程图上正在执行的元素或者已经执行完成的元素称为activity instanceact_hi_procinst
- 流程历史表act_ru_identitylink
- 流程的参与用户信息- act_hi_taskinst - 历史任务表
查找用户任务
流程启动后,任务的负责人就可以查询自己当前能够处理的任务了,查询出来的任务都是当前用户的待办任务
/**
* 任务查询
*/
@Test
public void test06(){
String assignee ="张三";
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 任务查询 需要获取一个 TaskService 对象
TaskService taskService = engine.getTaskService();
// 根据流程的key和任务负责人 查询任务
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey("leaveProcess")
.taskAssignee(assignee)
.list();
// 输出当前用户具有的任务
for (Task task : list) {
System.out.println("流程实例id:" + task.getProcessInstanceId());
System.out.println("任务id:" + task.getId());
System.out.println("任务负责人:" + task.getAssignee());
System.out.println("任务名称:" + task.getName());
}
}
处理任务、以及添加批注
@Test
public void testAddComment(){
//任务负责人
String assignee = "张三";
//创建ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取TaskService
TaskService taskService = processEngine.getTaskService();
//获取任务集合
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey("leaveProcess")
.taskAssignee(assignee)
.list();
//遍历任务列表
for(Task task:taskList){
//在任务执行之前任务添加批注信息: 任务 Id、流程实例 Id、批注信息
taskService.addComment(task.getId(), task.getProcessInstanceId(), task.getName()+"审批通过");
taskService.complete(task.getId());
}
}
查询历史批注信息
@Test
public void testSelectHistoryTask(){
//流程实例ID
String processInstanceId = "2501";
//任务审核人
String taskAssignee = "张三";
//创建ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取historyService
HistoryService historyService = processEngine.getHistoryService();
//获取taskService
TaskService taskService = processEngine.getTaskService();
//获取历史审核信息
List<HistoricActivityInstance> list = historyService
.createHistoricActivityInstanceQuery()
.activityType("userTask") //只获取用户任务
.processInstanceId(processInstanceId)
.taskAssignee(taskAssignee)
.finished()
.list();
for(HistoricActivityInstance instance:list){
System.out.println("任务名称:"+instance.getActivityName());
System.out.println("任务开始时间:"+instance.getStartTime());
System.out.println("任务结束时间:"+instance.getEndTime());
System.out.println("任务耗时:"+instance.getDurationInMillis());
//获取审核批注信息
List<Comment> taskComments = taskService.getTaskComments(instance.getTaskId());
if(taskComments.size()>0){
System.out.println("审批批注:"+taskComments.get(0).getFullMessage());
}
}
}
涉及的 Api
- taskService.addComment - 添加批注 Api
- taskService.complete - 完成任务、自动转到下一个节点