工作流引擎:Activiti 入门
Spring Boot 整合 工作流引擎:Activiti 7 入门

基本概念

工作流

工作流(Workflow),就是通过计算机对业务流程自动化执行管理。它主要解决的是“使在多个参与者之间按照某种预定义的规则自动进行传递文档、信息或任务的过程,从而实现某个预期的业务目标,或者促使此目标的实现”。

工作流系统

一个软件系统中具有工作流的功能,我们把它称为工作流系统,一个系统中工作流的功能是什 么?就是对系统的业务流程进行自动化管理,所以工作流是建立在业务流程的基础上,所以一个软件的系统核心根本上还是系统的业务流程,工作流只是协助进行业务流程管理。即使没有工作流业务系统也可以开发运行,只不过有了工作流可以更好的管理业务流程,提高系统的可扩展性。

Activiti介绍

Alfresco 软件在 2010 年 5 月 17 日宣布 Activiti 业务流程管理(BPM)开源项目的正式启动,其首席架构师由业务流程管理 BPM 的专家 Tom Baeyens 担任,Tom Baeyens 就是原来 jbpm 的架构师,而 jbpm 是一个非常有名的工作流引擎,当然 activiti 也是一个工作流引擎。 Activiti 是一个工作流引擎, activiti 可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言(BPMN2.0)进行定义,业务系统按照预先定义的流程进行执行,实现了业务系统的业务流程由 activiti 进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的健壮性,同时也减少了系统开发维护成本。

Activiti如何使用

  • Activiti 是一个工作流引擎(其实就是一堆 jar 包 API),业务系统使用 activiti 来对系统的业务流程进行自动化管理,为了方便业务系统访问(操作)activiti 的接口或功能,通常将 activiti 环境与业务系统的环境集成在一起。
  • 使用 activiti 流程建模工具(activity-designer)定义业务流程(.bpmn 文件) 。.bpmn 文件就是业务流程定义文件,通过 xml 定义业务流程。
  • activiti 部署业务流程定义(.bpmn 文件)。使用 activiti 提供的 api 向 activiti 中部署.bpmn 文件(一般情况还需要一块儿部署业务流程的图片.png)
  • 启动一个流程实例表示开始一次业务流程的运行,比如员工请假流程部署完成,如果张三要请 假就可以启动一个流程实例,如果李四要请假也启动一个流程实例,两个流程的执行互相不影响,就好比定义一个 java 类,实例化两个对象一样,部署的流程就好比 java 类,启动一个流程实例就好比 new 一个 java 对象。
  • 因为现在系统的业务流程已经交给 activiti 管理,通过 activiti 就可以查询当前流程执行到哪了,当前用户需要办理什么任务了,这些 activiti帮我们管理了,而不像上边需要我们在 sql语句中的where条件中指定当前查询的状态值是多少。
  • 用户查询待办任务后,就可以办理某个任务,如果这个任务办理完成还需要其它用户办理,比如采购单创建后由部门经理审核,这个过程也是由 activiti 帮我们完成了,不需要我们在代码中硬编码指定下一个任务办理人了。
  • 当任务办理完成没有下一个任务/结点了,这个流程实例就完成了。

首次运行创建数据表

准备工作

  • Mysql数据库,用于存放activiti生成的数据表
  • 流程图绘制工具,这里使用IDEA中的actBPM插件(在IDEA中的plugins中搜索actBPM安装即可)

注意:本文所使用的是环境版本为: Spring Boot 2.x + Activiti 7

创建数据表

Activiti相关的数据表,由框架自动创建,而我们需要做的只是配置好Activiti

引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<?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.imxushuai</groupId>
<artifactId>activiti-demo-1</artifactId>
<version>1.0-SNAPSHOT</version>


<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.0.56</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</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>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-dependencies</artifactId>
<version>7.0.56</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>

<!-- 引入activiti的maven私服 -->
<repositories>
<repository>
<id>alfresco</id>
<name>Activiti Releases</name>
<url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>

</project>

注意事项:

  • 这里使用的是版本号不是官方提供的公开的releases版本,而是直接从Activiti私服的版本号
  • 如果使用非Bete版本,需要JDK 11
  • 如果使用h2数据库的话,不需要jdbc依赖,但是如果使用其他数据库,需要引入数据源依赖。

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
spring:
activiti:
# 自动建表
database-schema-update: true
history-level: full
db-history-used: true
copy-variables-to-local-for-tasks: false
datasource:
url: jdbc:mysql:///activiti?characterEncoding=utf-8&serverTimezone=GMT
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver

注意事项:

  • spring.activiti.database-schema-update:此项可以不配置,默认为:true
  • spring.activiti.history-level:保存历史数据级别设置为full最高级别,建议为:full,否则生成的表格不全
  • spring.activiti.db-history-used:检查历史表是否存在,建议为:true

启动类(省略)

普通的Spring Boot启动类即可。

启动测试

查看数据库,已有25张表生成

数据表命名规则

Activiti 的表都以 ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的 API 对应。

  • ACT_RE_*: ‘RE’表示 repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。

  • ACT_RU_*:’RU’表示 runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti 只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。

  • ACT_HI_*:’HI’表示 history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。

  • ACT_GE_*:GE 表示 general。通用数据, 用于不同场景下。

防坑指南

问题一:运行报错

解决方法:

查看是否引入数据源依赖引入spring-boot-starter-jdbc依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

问题二:创建的表只有17张

解决方法:

修改配置文件:application.yml

1
2
3
4
5
6
7
spring:
activiti:
# 自动建表
database-schema-update: true
history-level: full
db-history-used: true
copy-variables-to-local-for-tasks: false

入门示例

主要API类:Service

Service 是工作流引擎提供用于进行工作流部署、执行、管理的服务接口。

常用Service介绍:

  • RepositoryService:activiti 的资源管理类
  • RuntimeService :activiti 的流程运行管理类
  • TaskService :activiti 的任务管理类
  • HistoryService:activiti 的历史管理类
  • ManagerService:activiti 的引擎管理类

绘制流程图

绘制一个简单的流程图

创建流程实例

编写Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.imxushuai;

import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.*;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.HashMap;

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class ActivitiTest {

@Autowired
private ProcessEngine processEngine;

private RuntimeService runtimeService;
private TaskService taskService;
private RepositoryService repositoryService;
private HistoryService historyService;

@Before
public void init() {
runtimeService = processEngine.getRuntimeService();
taskService = processEngine.getTaskService();
repositoryService = processEngine.getRepositoryService();
historyService = processEngine.getHistoryService();
}

/**
* 创建流程实例,会在下列表中生成数据
* 1. act_hi_actinst:会在该表中生成已经执行完毕和当前正在执行的节点的记录
* 2. act_hi_identitylink:记录流程实例的参与者
* 3. act_hi_proinst:流程实例的基本信息
* 4. act_hi_taskinst:当前待执行节点
* 5. act_ru_execution:当前正在执行的节点
* 6. act_ru_identitylink:记录流程实例的当前节点的参与者
* 7. act_ru_task:记录流程实例的当前节点的信息
*/
@Test
public void start() {
// 通过流程Key开启流程实例,key为:qingjia, 英语水平有限 emmmm.....
ProcessInstance instance = runtimeService.startProcessInstanceByKey("qingjia", new HashMap<>());
log.info("流程实例初始化成功:[{}]", instance.getId());
}

}

运行结果:

填写请假单

编写测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 填写请假单
*/
@Test
public void apply1() {
// 填写请假单,通过上一次打印的ID获取
Task task = taskService.createTaskQuery().processInstanceId("e0e3e681-c80e-11e9-bf76-005056c00001").singleResult();
// 构造请假参数
Map<String, Object> params = new HashMap<>();
params.put("dayNum", 1);
params.put("remark", "我妈叫我回家吃饭");
taskService.complete(task.getId(), params);
}

运行结果,查看运行变量表(act_ru_variable):

流程变量已经记录成功

审批流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    /**
* 审批流程
*/
@Test
public void apply2() {
// 部门经理审批
Task task = taskService.createTaskQuery().processInstanceId("e0e3e681-c80e-11e9-bf76-005056c00001").singleResult();
// 可以使用setAssignee设置下一个节点的受理人
// task.setAssignee("imxushuai");
Map<String, Object> params = taskService.getVariables(task.getId());
log.info(params.toString());
taskService.complete(task.getId());

// 总经理审批
// List<Task> list = taskService.createTaskQuery()
// .processDefinitionKey("qingjia")// 查询请假流程
// .taskAssignee("imxushuai")// 查询 imxushuai 当前代办的任务
// .list();
params = new HashMap<>();
params.put("remark", "批准,注意安全");
taskService.complete(task.getId(), params);
}

运行结果:

成功打印出请假单的参数

查看数据表是否成功审批完成

可以看到全部流程已经执行完毕

代码获取

Github:

文章作者: imxushuai
文章链接: https://www.imxushuai.com/2019/06/29/15.工作流引擎:Activiti-入门/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 imxushuai
支付宝打赏
微信打赏