序言
在工作中经常会有一些业务需求,需要使用到工作流,所以今天写这篇关于activiti的使用教程,帮助大家快速入门
1. 什么是工作流
工作流是一类能够完全或者部分自动执行的经营过程,它根据一系列规则、文档、信息或任务,在不同的参与者之间进行传递与执行。简单来说,工作流就是业务流程的自动化,它通过定义任务的顺序、规则和参与者,使得业务流程可以更加高效、准确地运行。
1.1 应用场景
工作流的应用场景非常多,凡是需要设计到流程的地方都会用到,比如:
企业资源规划(ERP)系统:在企业的生产、采购、销售等各个环节都有广泛应用。例如,通过工作流管理生产订单的下达、原材料的采购、产品的加工和发货等流程。
客户关系管理(CRM)系统:用于管理客户服务流程,如客户投诉处理。从客户提交投诉开始,工作流可以引导客服人员受理、调查、解决投诉,并记录整个过程。
内容管理系统(CMS):在内容发布方面发挥作用,比如管理文章的撰写、审核、发布等流程。
1.2 工作流的实现方式
大多数的工作流框架都是使用工作流引擎来实现的,通过工作流引擎来实现状态管理、流程控制等,比如Activiti中的ProcessEngine对象,就是里面的一个核心对象,提供了访问其他信息service的方法。
2.Activiti7
Activiti7 就是是一个轻量级的、开源的工作流引擎,它基于 Java 语言开发,主要用于业务流程管理(BPM)。它遵循 BPMN(业务流程建模语言)2.0 标准,能够帮助开发人员轻松地构建、部署和管理工作流。
BPMN2 是一种标准化的图形化流程建模语言,用于业务流程的可视化表示、定义和交换。它提供了一套丰富的符号和语义规则,使得业务分析师、流程设计师和开发人员能够共同协作,准确地描述从简单到复杂的业务流程。总的来说就是用来建模业务流程的标准规则,一个一个的符号。
2.1 Activiti使用
一般在使用的时候,都是使用IDEA插件的方式,支持在IDEA中编辑流程图。 在IDEA中搜索Activiti BPMN visualizer然后下载插件,下载完成之后重启IDEA
2.2 环境配置
创建数据库
CREATE DATABSE activiti DEFAULT CHARACTER SET utf8mb4
在IDEA中创建SpringBoot项目,依赖和YML配置如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>SpringBoot-Activity7</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringBoot-Activity7</name>
<description>SpringBoot-Activity7</description>
<properties>
<java.version>8</java.version>
<activiti.version>7.0.0.SR1</activiti.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.31</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
spring:
application:
name: SpringBoot-Activiti7
datasource:
url: jdbc:mysql://127.0.0.1:3306/activity?useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
activiti:
db-history-used: true #默认为false,如何不配置则activiti不会生成历史记录相关表
history-level: full
以上的工作做完以后,我们需要在resource资源路径下,创建activiti的配置文件,文件名为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"
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">
<!-- 配置数据库连接池-->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl"
value="jdbc:mysql://localhost:3306/activity?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!-- 配置activity引擎-->
<bean id="processEngineConfiguration"
class="org.activiti.spring.SpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource"/>
<!-- 设置历史级别 -->
<property name="history" value="full"/>
<!--
activity数据库表处理策略
create-drop: 每次启动activity引擎,会删除表重新创建表
true: 启动activity引擎时,会根据表的结构,自动创建表
false: 启动activity引擎时,不会自动创建表,需要手动创建表
drop-create: 每次启动activity引擎,会删除表重新创建表
-->
<property name="databaseSchemaUpdate" value="create-drop"/>
<property name="dbHistoryUsed" value="true"/>
</bean>
</beans>
注意这里的数据库必须配置,这是Activiti连接数据的必备条件,和项目中的数据库配置没有关联
2.3 创建BPMN文件
下载完以上的插件后,我们在resource文件下,创建bpmn文件,命名为evection
文件扩展名称不相同不要觉得奇怪,我们继续下一步即可。
在创建的bpmn文件中右击,选择View BPMN (Activiti) Diagram
然后会进入到如下界面:
在这个界面,我们就可以使用画图的方式来编辑bpmn文件了。
2.4 编辑BPMN文件
比如我们要设计一个请假流程,那么该如何操作呢?首先右击先建一个开始节点
空白区域,修改id为OwnerEvection
修改这个流程模版的名称,也就是修改name属性
然后右击新建任务,这里选择User Task
点击用户任务,设置Name和Assignee属性
意识就是,设置任务名称为创建出差申请,负责人为zhangsan。 接下来其他的节点依次创建,步骤和上述类似
各个节点节点之间使用竖线连接,做到这一步就算搞定了,然后将这个BPMN文件导出为PNG图片,放在项目的资源路径下
这样就算大功告成了
3.流程部署
接下来,我们使用Java代码的方式来部署流程,把BPMN对应的数据和信息保存到数据库当中。
创建ProcessEngine对象时,会自动在数据库当中帮助我们创建25张表。如果发现缺少历史信息记录表的话,查看对应的activiti-cfg.xml文件和YAML配置信息是否缺少
/**
* 部署
*/
@Test
public void createProcessEngine() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
System.out.println(processEngine);
}
部署完成以后,我们来启动流程实例
/**
* 启动流程实例
*/
@Test
public void testDeployment() {
// 1.创建 ProcessEngine 对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2.使用ProcessEngine对象创建操作数据库服务RepositoryService对象
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3.使用RepositoryService对象进行流程部署,定义一个流程名字,把bpmn文件和png文件部署到数据库中
Deployment deploy = repositoryService.createDeployment()
.name("出差申请") // 流程名字
.addClasspathResource("bpmn/evection.bpmn20.xml") // 资源文件 bpmn配置文件
.addClasspathResource("png/evection.png") // 资源文件 png流程图
.disableSchemaValidation() // 禁止校验文件
.deploy();// 部署
// 4.输出部署信息
System.out.println("部署ID:" + deploy.getId());
System.out.println("部署名称:" + deploy.getName());
}
创建实例完成后,测试完成任务。 此时任务负责人为zhangsan
以下代码,根据id模拟zhangsan已完成任务
// 根据任务id完成个人任务
@Test
public void testCompletTask() {
// 1 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2 获取service
TaskService taskService = processEngine.getTaskService();
// 3 根据任务id完成任务
taskService.complete("e865941d-9b1e-11ef-9ef7-28cdc46f3daf");
}
zhangsan任务完成后,任务自动传递给下一个负责人lisi
获取lisi的任务列表,代码如下:
/**
* 获取任务列表
*/
@Test
public void testSelectTodoTaskList() {
//任务负责人
String assignee = "lisi";
//创建ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取TaskService
TaskService taskService = processEngine.getTaskService();
//获取任务集合
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey("OwnerEvection")
.taskAssignee(assignee)
.list();
//遍历任务列表
for (Task task : taskList) {
System.out.println("流程定义id = " + task.getProcessDefinitionId());
System.out.println("流程实例id = " + task.getProcessInstanceId());
System.out.println("任务id = " + task.getId());
System.out.println("任务名称 = " + task.getName());
}
}
完成lisi的任务,任务就会自动传递给下一个任务负责人
// 根据任务id完成个人任务
@Test
public void testCompletTaskById() {
// 1 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2 获取service
TaskService taskService = processEngine.getTaskService();
// 3 获取lisi在OwnerEvection中对应的任务 我们已知只有一个任务 可使用singleResult获取一个结果集
Task task = taskService.createTaskQuery()
.processDefinitionKey("OwnerEvection") // 流程的key
.taskAssignee("lisi") // 要查询的负责人
.singleResult();// 因为可能有多个待办 所以是一个集合
System.out.println("流程实例ID:" + task.getProcessInstanceId());
System.out.println("任务ID:" + task.getId());
System.out.println("任务负责人:" + task.getAssignee());
System.out.println("任务名称:" + task.getName());
// 4 获取lisi的完成任务
taskService.complete(task.getId());
}
总的代码如下
```
@Test
public void testCompletTaskAll() {
// 1 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2 获取service
TaskService taskService = processEngine.getTaskService();
Task task = null;
// 3 获取zhangsan在myEvection中对应的任务 我们已知只有一个任务 可使用singleResult获取一个结果集
// task = taskService.createTaskQuery()
// .processDefinitionKey("OwnerEvection") // 流程的key
// .taskAssignee("zhangsan") // 要查询的负责人
// .singleResult();// 因为可能有多个待办 所以是一个集合
// taskService.complete(task.getId());
task = taskService.createTaskQuery()
.processDefinitionKey("OwnerEvection") // 流程的key
.taskAssignee("lisi") // 要查询的负责人
.singleResult();// 因为可能有多个待办 所以是一个集合
taskService.complete(task.getId());
task = taskService.createTaskQuery()
.processDefinitionKey("OwnerEvection") // 流程的key
.taskAssignee("wangwu") // 要查询的负责人
.singleResult();// 因为可能有多个待办 所以是一个集合
taskService.complete(task.getId());
task = taskService.createTaskQuery()
.processDefinitionKey("OwnerEvection") // 流程的key
.taskAssignee("zhaolou") // 要查询的负责人
.singleResult();// 因为可能有多个待办 所以是一个集合
taskService.complete(task.getId());
}
运行之后,任务审批表就不会有数据了,因为财务审批就是最后一个流程,所以的任务都已经完成
总结
至此,Activit的基本入门都已经结束了,除此之外,Activit还支持根据细粒度化的流程控制,功能非常强大。