Activiti工作流

2021-01-23

Activiti工作流-核心技术

1:工作流的概念

工作流管理系统的目标:管理工作的流程以确保工作在正确的时间被期望的人员所执行——在自动化进行的业务过程中插入人工的执行和干预。

2:安装插件

在eclispe中开发

  • 有在线安装和离线安装两种方式,但是两种安装都需要用到网络。有可能两种安装方式都不成功,因为需要考虑eclipse版本,与插件版本问题。(我在安装过程中,在线安装,是失败的,但是离线安装成功了,很迷)

方式一(在线安装):

有网络的情况下,安装流程设计器步骤如下:

  1.   打开 Help -> Install New Software. 在如下面板中:

img

  1.       在如下Install界面板中,**点击Add按钮**:

img

配置新装插件的地址和名称

  1.   然后填入下列字段

Name: Activiti BPMN 2.0 designer

Location: http://activiti.org/designer/update/

img

  1.   回到Install界面,在面板正中列表中把所有展示出来的项目都勾上:

img

  1.   点击复选框

在Detail部分记得选中 “Contact all updates sites..” , 因为它会检查所有当前安装所需要的插件并可以被Eclipse下载.

  1.   安装完以后,点击新建工程new->Other…打开面板,如果看到下图内容:

img

方式二(离线安装):

可以在没有网络的情况下,安装流程设计器步骤如下:

解压:

img

将解压开的jars里面三个jar放入到 eclipse/plugins 中

img

以下内容就是要连接到网络了

1)打开 Help -> Install New Software. 在如下面板中:

img

2)在如下Install界面板中,点击Add按钮:

img

配置新装插件的地址和名称

3)然后填入下列

Location 选择刚刚解压的Activiti Designer 中的 zip包

img

4)回到Install界面,在面板正中列表中把所有展示出来的项目都勾上:

img

5)点击复选框

在Detail部分记得选中 “Contact all updates sites..” , 因为它会检查所有当前安装所需要的插件并可以被Eclipse下载.

验证方式跟方式一 一样。

3:Activiti介绍

Activiti5是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架。Activiti基于Apache许可的开源BPM平台,创始人Tom Baeyens是JBoss jBPM的项目架构师,它特色是提供了eclipse插件,开发人员可以通过插件直接绘画出业务

流程图。

img

3.1:工作流引擎

ProcessEngine对象,这是Activiti工作的核心。负责生成流程运行时的各种实例及数据、监控和管理流程的运行。

3.2:BPMN

业务流程建模与标注(Business Process Model and Notation,BPMN) ,描述流程的基本符号,包括这些图元如何组合成一个业务流程图(Business Process Diagram)``

3.3:数据库(先学后看)

Activiti数据库支持:

Activiti的后台是有数据库的支持,所有的表都以ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的API对应。

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

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

  • ACT_ID_*: ‘ID’表示identity。 这些表包含身份信息,比如用户,组等等。

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

  • ACT_GE_*: 通用数据, 用于不同场景下,如存放资源文件。

表结构操作:

3.3.1:资源库流程规则表

  1. act_re_deployment 部署信息表

  2. act_re_model 流程设计模型部署表

  3. act_re_procdef 流程定义数据表

3.3.2:运行时数据库表

  1. act_ru_execution 运行时流程执行实例表

  2. act_ru_identitylink 运行时流程人员表,主要存储任务节点与参与者的相关信息

  3. act_ru_task 运行时任务节点表

  4. act_ru_variable 运行时流程变量数据表

3.3.3:历史数据库表

  1. act_hi_actinst 历史节点表

  2. act_hi_attachment 历史附件表

  3. act_hi_comment 历史意见表

  4. act_hi_identitylink 历史流程人员表

  5. act_hi_detail 历史详情表,提供历史变量的查询

  6. act_hi_procinst 历史流程实例表

  7. act_hi_taskinst 历史任务实例表

  8. act_hi_varinst 历史变量表

3.3.4:组织机构表

  1. act_id_group 用户组信息表

  2. act_id_info 用户扩展信息表

  3. act_id_membership 用户与用户组对应信息表

  4. act_id_user 用户信息表

这四张表很常见,基本的组织机构管理,关于用户认证方面建议还是自己开发一套,组件自带的功能太简单,使用中有很多需求难以满足

3.3.5:通用数据表

  1. act_ge_bytearray 二进制数据表

  2. act_ge_property 属性数据表存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录,

3.4:activiti.cfg.xml(activiti的配置文件)

Activiti核心配置文件,配置流程引擎创建工具的基本参数和数据库连接池参数。

定义数据库配置参数:

  • jdbcUrl: 数据库的JDBC URL。

  • jdbcDriver: 对应不同数据库类型的驱动。

  • jdbcUsername: 连接数据库的用户名。

  • jdbcPassword: 连接数据库的密码。

基于JDBC参数配置的数据库连接 会使用默认的MyBatis连接池。 下面的参数可以用来配置连接池(来自MyBatis参数):

  • jdbcMaxActiveConnections: 连接池中处于被使用状态的连接的最大值。默认为10。

  • jdbcMaxIdleConnections: 连接池中处于空闲状态的连接的最大值。

  • jdbcMaxCheckoutTime: 连接被取出使用的最长时间,超过时间会被强制回收。 默认为20000(20秒)。

  • jdbcMaxWaitTime: 这是一个底层配置,让连接池可以在长时间无法获得连接时, 打印一条日志,并重新尝试获取一个连接。(避免因为错误配置导致沉默的操作失败)。 默认为20000(20秒)。

4.4:准备Activiti5开发环境

1:添加Activiti5的jar包

image-20200817142035341

注意:一定不要忘记添加mysql 数据库的jar包,否则万劫不复!

2:初始化数据库

1)JDBC方式

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
	import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;

public class Demo01 {

public static void main(String[] args) {
// 创建独立的流程引擎配置
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration
.createStandaloneProcessEngineConfiguration();

processEngineConfiguration.setJdbcDriver("com.mysql.jdbc.Driver");
processEngineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/activiti_demo");
processEngineConfiguration.setJdbcUsername("root");
processEngineConfiguration.setJdbcPassword("root");

// 设置建表的策略

/*
*
*
* 如果不存在表,就创建表,如果存在,就直接使用! public static final String
* DB_SCHEMA_UPDATE_FALSE = "false";
*
* // 如果不存在表,就直接抛出异常 public static final String
* DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop";
*
* //每次都要先删除表,再去创建
*
* public static final String DB_SCHEMA_UPDATE_TRUE = "true";
*
**/

//设置建表策略
processEngineConfiguration.setDatabaseSchemaUpdate("true");
// 使用流程引擎配置对象创建 流程引擎对象
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
System.out.println(processEngine);

}


}

注意建表策略

在Activiti中,在创建核心的流程引擎对象时会自动建表。如果程序正常执行,mysql会自动建库,然后创建23张表。

2)Spring方式

添加并制定配置文件

​ 在Actiiti5中定制流程必定会操作到数据库,如果都像上面那样写一大段代码会非常麻烦,所以我们可以把数据库连接配置写入配置文件。

activiti.cfg.xml(名字必须是这个)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

<bean id="processEngineConfiguration"
class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<!-- 连接数据的配置 -->
<property name="jdbcDriver" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl"
value="jdbc:mysql://localhost:3306/activiti_demo?useUnicode=true&amp;characterEncoding=utf8"></property>
<property name="jdbcUsername" value="root"></property>
<property name="jdbcPassword" value="root"></property>
<!-- 没有表创建表 -->
<property name="databaseSchemaUpdate" value="true"></property>
</bean>

</beans>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.gec.test;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;

public class SpringTest {

public static void main(String[] args) {

// 加载classpath 下名为 activiti.cfg.xml文件,创建流程引擎对象,系统会自动创建表
ProcessEngine processEngine = ProcessEngineConfiguration.
createProcessEngineConfigurationFromResource("activiti.cfg.xml").buildProcessEngine();
System.out.println(processEngine);

}
}

​ createProcessEngineConfigurationFromResource的参数值为我们添加的配置文件activiti.cfg.xml的名称,执行java代码,流程引擎对象创建成功运行后数据库会自动建表。

3)快速创建方式(开发中常用)

配置文件名为:activiti.cfg.xml(名字必须是这个)

掌握

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.gec.test;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;

public class SpringTest02 {
public static void main(String[] args) {
//自动加载加载了activiti.cfg.xml
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
System.out.println(processEngine)
}
}

运行成功:

image-20200817154018469

表也创建成功

image-20200817154039898

思考:凭什么这么一句代码就可以创建出 ProcessEngine对象呢?

img

img

自动加载了activiti.cfg.xml文件。

5:核心API

5.1:ProcessEngine

说明:

在Activiti中最核心的类,其他的类都是由他而来!!!

  1. 产生方式:

img

在前面看到了两种创建ProcessEngine(流程引擎)的方式,而这里要简化很多,调用ProcessEngines的getDefaultProceeEngine方法时会自动加载classpath下名为activiti.cfg.xml文件。

  1. 可以产生RepositoryService(部署流程)

img

  1. 可以产生RuntimeService(启动流程)

img

  1. 可以产生TaskService(对任务操作)

img

各个Service的作用:

RepositoryService 管理流程定义
RuntimeService 执行管理,包括启动、推进、删除流程实例等操作
TaskService 任务管理
HistoryService 历史管理(执行完的数据的管理)
IdentityService 组织机构管理
FormService 一个可选服务,任务表单管理
ManagerService 管理服务

5.2:RepositoryService

是Activiti的仓库服务类。所谓的仓库指流程定义文档的两个文件:bpmn文件和流程图片

  1. 产生方式

img

  1. 可以产生DeploymentBuilder,用来定义流程部署的相关参数

img

  1. 删除流程定义

img

5.3:RuntimeService

是activiti的流程执行服务类。可以从这个服务类中获取很多关于流程执行相关的信息。

5.4:TaskService

是activiti的任务服务类。可以从这个类中获取任务的信息。

5.5:HistoryService

是activiti的查询历史信息的类。在一个流程执行完成后,这个对象为我们提供查询历史信息。

5.6:ProcessDefinition

流程定义类。可以从这里获得资源文件等。

5.7:ProcessInstance

代表流程定义的执行实例。如范冰冰请了一天的假,她就必须发出一个流程实例的申请。一个流程实例包括了所有的运行节点。我们可以利用这个对象来了解当前流程实例的进度等信息。流程实例就表示一个流程从开始到结束的最大的流程分支,即一个流程中流程实例只有一个。

5.8:Execution

​ Activiti用这个对象去描述流程执行的每一个节点。在没有并发的情况下,Execution就是同ProcessInstance。流程按照流程定义的规则执行一次的过程,就可以表示执行对象Execution。

​ 如图为ProcessInstance的源代码:

img

从源代码中可以看出ProcessInstance就是Execution。但在现实意义上有所区别:

img

在单线流程中,如上图的贷款流程,ProcessInstance与Execution是一致的。

img

这个例子有一个特点:wire money(汇钱)和archive(存档)是并发执行的。 这个时候,总线路代表ProcessInstance,而分线路中每个活动代表Execution。

总结:

*** **一个流程中,执行对象可以存在多个,但是流程实例只能有一个。

*** **当流程按照规则只执行一次的时候,那么流程实例就是执行对象。

6:HelloWorld程序(模拟流程的执行)

6.1绘制流程图:

注意:绘制流程图之前,请仔细先检查自己的Ecplise中有没有勾选保存img图片选项,具体操作(参考课件上面步骤),切记!切记!切记!!

image-20200817151711154

勾选上,当保存流程时,会自动生成png格式的流程图。

在项目中新建

img

创建任务节点

img

给任务节点分配待办人

img

流程Id

img

保存流程图

img

6.2:部署流程定义

发布流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 使用流程引擎配置对象(交给spring:activiti.cfg.xml中创建了)创建 流程引擎对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

@Test
public void func1() {

// 创建仓库服务的实例对象
Deployment deployment = processEngine.getRepositoryService()
.createDeployment()
.name("第一个流程图")
.addClasspathResource("myProcess.bpmn")
.addClasspathResource("myProcess.png")
.deploy();

System.out.println("部署id:"+deployment.getId());//401
System.out.println("部署名称:"+deployment.getName());//第一个流程图


}


这里使用RepositoryService部署流程定义

addClasspathResource表示从类路径下加载资源文件,一次只能加载一个文件

观察打印结果:

img

image-20200817161610785

思考:部署流程定义这一步,到底做了哪些事情?以及操作了数据库哪些表呢?

解析:

  1.            先获取流程引擎对象:在创建时会自动加载classpath下的activiti.cfg.xml

img

  1.            首先获得默认的流程引擎,通过流程引擎获取了一个RepositoryService对象(仓库对象)
  2.            由仓库的服务对象产生一个部署对象配置对象,用来封装部署操作的相关配置。
  3.            这是一个链式编程,在部署配置对象中设置显示名,上传流程定义规则文件
  4.            向数据库表中存放流程定义的规则信息。

img

  1.            这一步在数据库中将操作三张表:

1.act_re_procdef(流程定义表) :Process defintion

存放流程定义的属性信息,部署每个新的流程定义都会在这张表中增加一条记录。

注意:当流程定义的key相同的情况下,使用的是版本升级

image-20200817162153096

2.act_re_deploymen(部署对象表)

存放流程定义的显示名和部署时间,每部署一次增加一条记录

image-20200817162222977

3)act_ge_bytearray(资源文件表)

​ 存储流程定义相关的部署信息。即流程定义文档的存放地。每部署一次就会增加两条记录,一条是关于bpmn规则文件的,一条是图片的(如果部署时只指定了bpmn一个文件,activiti会在部署时解析bpmn文件内容自动生成流程图)。两个文件不是很大,都是以二进制形式存储在数据库中。

image-20200817162258809

小海豚软件中可看到BYTES_字段存储内容。

image-20200817163104336

image-20200817163123925

6.3:启动流程实例

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void func2() {
String processDefinitionKey="myProcess";
ProcessInstance processInstance = processEngine.getRuntimeService()
.startProcessInstanceByKey(processDefinitionKey);
//流程定义id;
System.out.println("流程定义id:"+processInstance.getProcessDefinitionId()); //

System.out.println("流程实例id:"+processInstance.getProcessInstanceId()); //

}

这里使用RuntimeService启动流程实例

img

img

img

1
2
3
4
5
6
7
8
SELECT * FROM act_hi_procinst;    -- 流程实例历史表


SELECT * from act_ru_execution; -- 流程实例的执行对象表


SELECT *from act_ru_task; -- 当前活动(节点)任务表 ,默认 act_ru_task 和 act_ru_execution 是一对一

思考:流程定义和流程是流程实例的关系是?

  • 流程定义相当于 类(模板)

  • 流程实例相当于 对象(具体的)

6.4:查看我的个人任务

获取当前代办人的任务列表

这里使用TaskService完成任务的查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

// 获取当前代办人的任务列表
@Test
// 查看任務列表
public void fun3() {
String assignee = "跑腿1";
List<org.activiti.engine.task.Task> list = processEngine.getTaskService()
.createTaskQuery()
.taskAssignee(assignee)
.list();

for (org.activiti.engine.task.Task task : list) {
System.out.println("流程的定义id:" + task.getProcessDefinitionId());
System.out.println("流程的实例id:" + task.getProcessInstanceId());
System.out.println("任务的id:" + task.getId());
System.out.println("任务的创建时间:" + task.getCreateTime());
System.out.println("任务的名称:" + task.getName());
System.out.println("任务的待办人:" + task.getAssignee());
}
}

这里使用TaskService完成任务的查询

6.5:完成我的个人任务

这里使用TaskService完成任务的办理

1
2
3
4
5
6
7
8
		
@Test
public void fun4(){
String taskId="1108";
processEngine.getTaskService().complete(taskId);
System.out.println("该任务已完成");
}

注意:当所有的流程走完了后,那么在

  • act_ru_execution; – 流程实例的执行对象表

  • act_ru_task; – 正在运行任务(节点)

以上两种表中看不到任何信息了,都将成为历史数据,所以需要查看另外一张表!

  • act-hi-taskinst 历史任务记录表!

img

7.流程定义详解

7.1.设计流程定义文档-画流程图

img

7.2.bpmn文件

​ BPMN 2.0根节点是definitions节点。 这个元素中,可以定义多个流程定义(不过我们建议每个文件只包含一个流程定义, 可以简化开发过程中的维护难度)。 一个空的流程定义看起来像下面这样。注意:definitions元素 最少也要包含xmlns 和 targetNamespace的声明。 targetNamespace可以是任意值,它用来对流程实例进行分类。

img

说明:流程定义文档有两部分组成:

  1. bpmn文件

​ 流程规则文件。在部署后,每次系统启动时都会被解析,把内容封装成流程定义放入项目缓存中。Activiti框架结合这个xml文件自动管理流程,流程的执行就是按照bpmn文件定义的规则执行的,bpmn文件是给计算机执行用的

  1. 展示流程图的图片

在系统里需要展示流程的进展图片,图片是给用户看的

img

7.3.部署流程定义

在activiti中一共支持两种方式进行流程部署

  • (classpath路径加载文件)

  • (zip格式文件)

7.3.1.classpath方式加载

上面演示的就是用calsspath路径加载文件,就不过多赘述。

7.3.2.zip格式加载

将helloworld.bpmn + helloworld.png => helloworld.zip

压缩成zip格式的文件,使用zip的输入流用作部署流程定义

img

img

1
2
3
4
5
6
7
8
9
10
11
12
13
// 部署流程定义 zip方式加载
@Test
public void test2() {
InputStream in = this.getClass().getClassLoader().getResourceAsStream("diagrams/helloworld.zip");
ZipInputStream zipInputStream = new ZipInputStream(in);
Deployment deployment = processEngine.getRepositoryService().createDeployment().name("部署流程定义测试")
.addZipInputStream(zipInputStream).deploy();

System.out.println("部署id:" + deployment.getId());
System.out.println("部署名称:" + deployment.getName());

}

img

7.4.查询流程定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 获取所有的流程定义列表信息

@Test
public void fun3()
{
List<ProcessDefinition> list = processEngine.getRepositoryService()
.createProcessDefinitionQuery()
.orderByProcessDefinitionName()
.desc()
.list();

for (ProcessDefinition processDefinition : list) {

System.out.println("流程定义的id:"+processDefinition.getId());
System.out.println("流程的定义的版本:"+processDefinition.getVersion());
System.out.println("流程定义的key:"+processDefinition.getKey());
System.out.println("流程定义的部署id:"+processDefinition.getDeploymentId());
}
}

查看流程定义列表,实际上操作的查看如下表

act_re_procdef

img

image-20200818152314090