文档

Activiti 用户手册 (jeecg.com)

https://g.yuque.com/mrdeer/activiti_note/

http://doc.javaex.cn/activiti

项目中流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
我的申请-applyList
发起申请:选择流程「启用且有权限」,填写流程关联表单数据。保存表单数据+业务申请表
待提交申请
提交:
编辑: 编辑表单数据
删除: 删除表单数据、删除业务申请数据
处理中
撤回
查看进度
表单数据
结束或撤回
已撤回:重新申请、编辑
已结束:审批历史、表单数据、审批历史
我的待办-todoManage
我的已办-doneManage

运行中的流程-processInsManage
挂起、激活、事件信息、操作过程、删除
已结束流程-processFinishManage
事件信息、操作过程、删除

子流程

内嵌子流程

子流程(Sub-process)是一个包含其他节点,网关,事件等等的节点。 它自己就是一个流程,同时是更大流程的一部分。 子流程是完全定义在父流程里的 (这就是为什么叫做内嵌子流程)

子流程有两种主要场景:

  • 子流程可以使用继承式建模。 很多建模工具的子流程可以折叠, 把子流程的内部细节隐藏,显示一个高级别的端对端的业务流程总览。
  • 子流程会创建一个新的事件作用域。 子流程运行过程中抛出的事件,可以被子流程边缘定义的 边界事件捕获, 这样就可以创建一个仅限于这个子流程的事件作用范围。

使用子流程要考虑如下限制:

  • 子流程只能包含一个空开始事件, 不能使用其他类型的开始事件。子路程必须 至少有一个结束节点。注意,BPMN 2.0 规范允许忽略子流程的 开始和结束节点,但是当前 activiti 的实现并不支持。
  • 顺序流不能跨越子流程的边界。

事件子流程

启动事件

定时开始事件

描述

定时开始事件用来在指定的时间创建流程实例。 它可以同时用于只启动一次的流程 和应该在特定时间间隔启动多次的流程。

注意:子流程不能使用定时开始事件。

注意:定时开始事件在流程发布后就会开始计算时间。 不需要调用 startProcessInstanceByXXX,虽然也而已调用启动流程的方法, 但是那会导致调用 startProcessInstanceByXXX 时启动过多的流程。

注意:当包含定时开始事件的新版本流程部署时, 对应的上一个定时器就会被删除。这是因为通常不希望自动启动旧版本流程的流程实例。

图形标记

定时开始事件显示为了一个圆圈,内部是一个表。

img

XML 内容

定时开始事件的 XML 内容是普通开始事件的声明,包含一个定时定义子元素。 请参考定时定义 查看配合细节。

示例:流程会启动 4 次,每次间隔 5 分钟,从 2011 年 3 月 11 日,12:13 开始计时。

1
2
3
4
5
<startEvent id="theStart">
<timerEventDefinition>
<timeCycle>R4/2011-03-11T12:13/PT5M</timeCycle>
</timerEventDefinition>
</startEvent>

示例:流程会根据选中的时间启动一次。

1
2
3
4
5
<startEvent id="theStart">
<timerEventDefinition>
<timeDate>2011-03-11T12:13:14</timeDate>
</timerEventDefinition>
</startEvent>

消息开始事件

描述

消息开始事件可以用其使用一个命名的消息来启动流程实例。 这样可以帮助我们使用消息名称来选择正确的开始事件。

发布包含一个或多个消息开始事件的流程定义时,需要考虑下面的条件:

  • 消息开始事件的名称在给定流程定义中不能重复。流程定义不能包含多个名称相同的消息开始事件。 如果两个或以上消息开始事件应用了相同的事件,或两个或以上消息事件引用的消息名称相同,activiti 会在发布流程定义时抛出异常。
  • 消息开始事件的名称在所有已发布的流程定义中不能重复。 如果一个或多个消息开始事件引用了相同名称的消息,而这个消息开始事件已经部署到不同的流程定义中, activiti 就会在发布时抛出一个异常。
  • 流程版本:在发布新版本的流程定义时,之前订阅的消息订阅会被取消。 如果新版本中没有消息事件也会这样处理。

启动流程实例,消息开始事件可以使用 下列 RuntimeService 中的方法来触发:

1
2
3
ProcessInstance startProcessInstanceByMessage(String messageName);
ProcessInstance startProcessInstanceByMessage(String messageName, Map<String, Object> processVariables);
ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey, Map<String, Object< processVariables);

异常事件

  1. 异常事件不能独立存在,必须是其他事件的子流程

数据库表详解

意义 备注
ACT_EVT_LOG 事件处理日志
ACT_GE_BYTEARRAY 二进制数据表 存储流程定义相关的部署信息。即流程定义文档的存放地。每部署一次就会增加两条记录,一条是关于 bpmn 规则文件的,一条是图片的(如果部署时只指定了 bpmn 一个文件,activiti 会在部署时解析 bpmn 文件内容自动生成流程图)。两个文件不是很大,都是以二进制形式存储在数据库中。
ACT_GE_PROPERTY 主键生成表 主张表将生成下次流程部署的主键 ID。
ACT_HI_ACTINST 历史节点表 只记录 usertask 内容,某一次流程的执行一共经历了多少个活动
ACT_HI_ATTACHMENT 历史附件表
ACT_HI_COMMENT 历史意见表
ACT_HI_DETAIL 历史详情表,提供历史变量的查询 流程中产生的变量详细,包括控制流程流转的变量等
ACT_HI_IDENTITYLINK 历史流程人员表
ACT_HI_PROCINST 历史流程实例表
ACT_HI_TASKINST 历史任务实例表 一次流程的执行一共经历了多少个任务
ACT_HI_VARINST 历史变量表
ACT_PROCDEF_INFO
ACT_RE_DEPLOYMENT 部署信息表 存放流程定义的显示名和部署时间,每部署一次增加一条记录
ACT_RE_MODEL 流程设计模型部署表 流程设计器设计流程后,保存数据到该表
ACT_RE_PROCDEF 流程定义数据表 存放流程定义的属性信息,部署每个新的流程定义都会在这张表中增加一条记录。注意:当流程定义的 key 相同的情况下,使用的是版本升级
ACT_RU_EVENT_SUBSCR throwEvent,catchEvent 时间监听信息表
ACT_RU_EXECUTION 运行时流程执行实例表 历史流程变量
ACT_RU_IDENTITYLINK 运行时流程人员表 主要存储任务节点与参与者的相关信息
ACT_RU_INTEGRATION
ACT_RU_JOB 运行时定时任务数据表
ACT_RU_TIMER_JOB
ACT_RU_SUSPENDED_JOB
ACT_RU_TASK 运行时任务节点表
ACT_RU_TIMER_JOB
ACT_RU_VARIABLE 运行时流程变量数据表 通过 JavaBean 设置的流程变量,在 act_ru_variable 中存储的类型为 serializable,变量真正存储的地方在 act_ge_bytearray 中。
ACT_ID_GROUP 用户组信息表 已废弃
ACT_ID_INFO 用户扩展信息表 已废弃
ACT_ID_MEMBERSHIP 用户与用户组对应信息表 已废弃
ACT_ID_USER 用户信息表 已废弃

UEL 表达式

  • activiti 支持两个 UEL 表达式:UEL-value 和 UEL-method
  • 用户任务节点:受理人、候选人、候选人组;流转条件表达式

UEL-value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 一般流程变量
${acceptor}

// user 为流程变量,对象类型,acceptor 为成员变量,且提供了 getter 方法。实现了序列化
${user.acceptor}

// userBean 为 Spring Bean 对象, 调用 getName() 方法获取
${userBean.getName()}

// userBean 为 Spring Bean 对象,userId 为流程变量,getAcceptor 为 userBean 的方法
${userBean.getAcceptor(userId)}


// 网关条件表达式:一般流程变量
// 单个流程变量
${flag == true}
${flag == 1 || flag == 2}
${flag == "1" || flag == "2"}
// 多个流程变量共同决定:流程中必须设置流程变量,即使为null,否则报错
${flag1 == "1" && flag2 == "2"}

// 网关条件表达式:流程变量 user 为对象
${user.name == "zhangsan"}
${order.price > 100 && order.price < 250}

uel-value 方式设置条件表达式,支持 String、int、boolean、Object 对象(序列化的),Map,List,Array

uel-method

1
${userBean.getAcceptor(userId)}

设置节点的执行人为 ${userBean.getAcceptor (userId)} ,其中 userBean 是我们注入到 spring 中的一个类对象,userId 是我们设置的流程变量

https://blog.csdn.net/simplemurrina/article/details/79635085

流程模型

使用RepsoitoryService接口

创建、部署、查询、删除

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package boot.deer.note.process.deployment;

import java.io.InputStream;
import java.util.List;
import java.util.zip.ZipInputStream;

import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.DeploymentQuery;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import boot.deer.SpringBootActivitiApplicationTests;
import boot.deer.component.util.DateUtil;

/**
* @ClassName: ProcessDeploymentNote.java
* @Author: Mr_Deer
* @Date: 2019年4月1日 上午10:50:15
* @Description: "流程部署"笔记 - 使用 Junit 进行测试
*/
public class ProcessDeploymentNote extends SpringBootActivitiApplicationTests {

// 注入 RepositoryService
@Autowired
private RepositoryService repositoryService;

/**
* 流程部署 — 使用流程文件资源部署
*
* 操作对应数据表:
* ACT_GE_BYTEARRAY
* ACT_RE_DEPLOYMENT
* ACT_RE_PROCDEF
*/
@Test
public void processDeploymentUseClasspathResource() {
// 创建流程部署工具
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();

// bpm 文件路径
String bpmnResourcePath = "processes/note/leave/LeaveProcess.bpmn";
// png 文件路径
String pngResourcePath = "processes/note/leave/LeaveProcess.png";
// 流程名
String processName = "请假流程";

/*
* 流程部署,其中就需要两个文件对应的路径
* 同时我们再部署的时候可以给这个流程起一个名字
* 部署后会返回一个部署对象
*/
Deployment deployment = deploymentBuilder.name(processName).addClasspathResource(bpmnResourcePath)
.addClasspathResource(pngResourcePath).deploy();

System.out.println("流程部署成功,流程部署ID:" + deployment.getId());
}

/**
* 流程部署 — 使用zip文件资源部署
*
* 操作对应数据表:
* ACT_GE_BYTEARRAY
* ACT_RE_DEPLOYMENT
* ACT_RE_PROCDEF
*/
@Test
public void processDeploymentUseZipResource() {
// zip 文件的路径
String zipPath = "/processes/note/leave/LeaveProcess.zip";

// 获取一个输入流
InputStream resourceAsStream = this.getClass().getResourceAsStream(zipPath);

// 这里使用的就是 zip 的一个封装类型
Deployment deployment = repositoryService.createDeployment().name("请假流程")
.addZipInputStream(new ZipInputStream(resourceAsStream)).deploy();

System.out.println("流程部署成功,流程部署ID:" + deployment.getId());
}

/**
* 查询流程部署
*
* 操作对应数据表:
* ACT_RE_DEPLOYMENT
*/
@Test
public void processDeploymentQuery() {
// 获取"流程部署"查询器
DeploymentQuery deploymentQuery = repositoryService.createDeploymentQuery();

List<Deployment> deployments = deploymentQuery

// 查询匹配条件

/* 流程部署ID (ID_) - 参数类型:String */
// .deploymentId(deploymentId)
/* 流程部署Name (NAME_) - 参数类型:String */
// .deploymentName(name)
/* 流程部署Name (NAME_) - 参数类型:String - 模糊匹配 %param% */
// .deploymentNameLike(nameLike)

// 排序规则

/* 流程部署ID (ID_) - 升序排序 */
// .orderByDeploymentId().asc()
/* 流程部署Name (NAME_) - 降序排序 */
// .orderByDeploymentName()deploymentQuery.desc()
/* 流程部署Time (DEPLOY_TIME_) - 升序排序 */
// .orderByDeploymenTime().asc()

// 结果类型

/* List 结果集 */
// .list()
/* List 结果集 - 分页 */
// .listPage(firstResult, maxResults)
/* 唯一的结果 */
// .singleResult()
/* 结果计数 */
// .count()

.list();

// 循环结果集
deployments.forEach(deployment -> {
System.out.println("流程部署 ID: " + deployment.getId());
System.out.println("流程部署 Name: " + deployment.getName());
System.out.println("流程部署 Time: " + DateUtil.dateTime2String(deployment.getDeploymentTime()));
System.out.println(" = = = = = = = = = = = = = = = = = = = = = = = = = ");
});
}

/**
* 删除流程部署
* 删除流程部署的同时,流程定义、正在执行的流程实例、该流程的历史记录都会一并删除
*
* 操作对应数据表:
* ACT_GE_BYTEARRAY
* ACT_RE_*
* ACT_RU_*
* ACT_HI_*
*/
@Test
public void processDeploymentDelete() {
// 需要删除的流程部署 ID
String deploymentId = "2501";
/*
* 第一个参数就是需要删除的部署 ID
* 第二个参数是代表当前如果还存在尚未执行完毕的程序,则是否强制删除
* true:即使存在为执行完毕的流程,扔强制删除
* false:存在尚未删除的流程,则不删除
* */
repositoryService.deleteDeployment(deploymentId, true);
System.out.println("删除成功");
}
}

流程定义

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package boot.deer.note.process.definition;

import java.util.List;

import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import boot.deer.SpringBootActivitiApplicationTests;

/**
* @ClassName: ProcessDefinitionNote.java
* @Author: Mr_Deer
* @Date: 2019年4月2日 上午10:02:29
* @Description: "流程定义"笔记 - 使用 Junit 进行测试
*/
public class ProcessDefinitionNote extends SpringBootActivitiApplicationTests {

// 注入 RepositoryService
@Autowired
private RepositoryService repositoryService;

/**
* 查询流程定义
*
* 操作对应数据表:
* ACT_RE_PROCDEF
*/
@Test
public void processDefinitionQuery() {
// 获取"流程定义"查询器
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();

List<ProcessDefinition> processDefinitions = processDefinitionQuery

// 查询匹配条件

/* 流程部署ID (DEPLOYMENT_ID_) - 参数类型:String */
// .deploymentId(deploymentId)
/* 流程部署ID (DEPLOYMENT_ID_) - 参数类型:Set<String> - 集合查询 IN */
// .deploymentIds(deploymentIds)
/* 流程定义ID (ID_) - 参数类型:String */
// .processDefinitionId(processDefinitionId)
/* 流程定义ID (ID_) - 参数类型:Set<String> - 集合查询 IN */
// .processDefinitionIds(processDefinitionIds)
/* 流程定义Key (KEY_) - 参数类型:String */
// .processDefinitionKey(processDefinitionKey)
/* 流程定义Key (KEY_) - 参数类型:String - 模糊匹配 %param% */
// .processDefinitionKeyLike(processDefinitionKeyLike)
/* 流程定义Name (NAME_) - 参数类型:String */
// .processDefinitionName(processDefinitionName)
/* 流程定义Name (NAME_) - 参数类型:String - 模糊匹配 %param% */
// .processDefinitionNameLike(processDefinitionNameLike)
/* 流程资源文件Name (RESOURCE_NAME_) - 参数类型:String */
// .processDefinitionResourceName(resourceName)
/* 流程资源文件Name (RESOURCE_NAME_) - 参数类型:String - 模糊匹配 %param% */
// .processDefinitionResourceNameLike(resourceNameLike)
/* 流程定义的版本 (VERSION_) - 参数类型:String */
// .processDefinitionVersion(processDefinitionVersion)
/* 流程定义的版本 (VERSION_) - 参数类型:String - VERSUIN_ > 参数版本 */
// .processDefinitionVersionGreaterThan(processDefinitionVersion) */
/* 流程定义的版本 (VERSION_) - 参数类型:String - VERSUIN_ >= 参数版本 */
// .processDefinitionVersionGreaterThanOrEquals(processDefinitionVersion)
/* 流程定义的版本 (VERSION_) - 参数类型:String - VERSUIN_ < 参数版本 */
// .processDefinitionVersionLowerThan(processDefinitionVersion)
/* 流程定义的版本 (VERSION_) - 参数类型:String - VERSUIN_ <= 参数版本 */
// .processDefinitionVersionLowerThanOrEquals(processDefinitionVersion)

// 排序规则

/* 流程部署ID (DEPLOYMENT_ID_) - 升序排序 */
// .orderByDeploymentId().asc()
/* 流程定义ID (ID_) - 升序排序 */
// .orderByProcessDefinitionId().asc()
/* 流程定义Key (KEY_)- 升序排序 */
// .orderByProcessDefinitionKey().asc()
/* 流程定义Name (NAME_) - 升序排序 */
// .orderByProcessDefinitionName().asc()
/* 流程定义的版本 (VERSION_) - 升序排序 */
// .orderByProcessDefinitionVersion().asc()

// 结果类型

/* List 结果集 */
// .list()
/* List 结果集 - 分页 */
// .listPage(firstResult, maxResults)
/* 唯一的结果 */
// .singleResult()
/* 结果计数 */
// .count()

.list();

// 循环结果集
processDefinitions.forEach(definition -> {
System.out.println("流程部署 ID: " + definition.getDeploymentId());
System.out.println("流程定义 ID: " + definition.getId());
System.out.println("流程定义 Key: " + definition.getKey());
System.out.println("流程定义 名称: " + definition.getName());
System.out.println("流程定义 版本:" + definition.getVersion());
System.out.println("流程资源 BPMN 文件名:" + definition.getResourceName());
System.out.println("流程资源 PNG 文件名:" + definition.getDiagramResourceName());
System.out.println(" = = = = = = = = = = = = = = = = = = = = = = = = = ");
});
}

/**
* 查询所有流程的最新版本
*
* 操作对应数据表:
* ACT_RE_PROCDEF
*/
@Test
public void processDefinitionQueryFinal() {
// 获取"流程定义"查询器
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();

// 这里我们没有设置查询条件,就是查询目前所有的流程,每个流程的最新版本
List<ProcessDefinition> processDefinitions = processDefinitionQuery.latestVersion().list();

// 循环结果集
processDefinitions.forEach(definition -> {
System.out.println("流程部署 ID: " + definition.getDeploymentId());
System.out.println("流程定义 ID: " + definition.getId());
System.out.println("流程定义 Key: " + definition.getKey());
System.out.println("流程定义 名称: " + definition.getName());
System.out.println("流程定义 版本:" + definition.getVersion());
System.out.println("流程资源 BPMN 文件名:" + definition.getResourceName());
System.out.println("流程资源 PNG 文件名:" + definition.getDiagramResourceName());
System.out.println(" = = = = = = = = = = = = = = = = = = = = = = = = = ");
});
}

/**
* 读取流程图文件
* 把流程图的 png 读到硬盘的某个文件里
*/
@Test
public void processDefinitionQueryView() {
// 视图存放地址路径
String viwePath = System.getProperty("user.dir") + "\\view";

// 判断文件夹是否存在
File folder = new File(viwePath);
if (!folder.exists())
// 不存在则创建一个
folder.mkdir();

// 这里可以通过查询查询到资源文件名,这里是测试,暂时写死
viwePath += "\\LeaveProcess.png";
System.out.println(viwePath);

// 创建文件,给出相对应的 path
File file = new File(viwePath);

// 流程定义 ID
String processDefinitionId = "LeaveProcess:1:4";
try (InputStream inputStream = repositoryService.getProcessDiagram(processDefinitionId);
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file))) {
// 开始写入文件
int len;
byte[] buf = new byte[1024];
while ((len = inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, len);
outputStream.flush();
}
System.out.println("视图读取完成");
} catch (Exception e) {
e.printStackTrace();
System.out.println("视图读取失败");
}
}
}

挂起、激活流程定义

1
2
3
4
5
6
7
// 挂起流程定义,不能创建新流程了
repositoryService.suspendProcessDefinitionByKey("scm");
repositoryService.suspendProcessDefinitionById(id, true, new Date());

//激活流程
repositoryService.activateProcessDefinitionById(id, true, new Date());
repositoryService.activateProcessDefinitionByKey("scm", true, new Date());

流程实例

  1. 使用 RuntimeService接口
  2. 启动流程我们可以使用”流程定义 ID 或者流程定义 Key 进行启动。更推荐使用 key 的方式进行启动,如果在一个流程有多个版本的情况下(因为有版本升级),使用 key 的方式启动,依然启动的是最新的版本流程
  3. 通过流程实例是查询不到执行实例
  4. 查询执行实例,会把「流程实例」也查询出来了

流程实例-启动、查询、指定发起人

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package boot.deer.note.process.start;

import java.util.List;

import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import boot.deer.SpringBootActivitiApplicationTests;
import boot.deer.component.util.DateUtil;

/**
* @ClassName: ProcessInstanceNote.java
* @Author: Mr_Deer
* @Date: 2019年4月2日 上午11:17:38
* @Description: "流程实例"笔记 - 使用 Junit 进行测试
*/
public class ProcessInstanceNote extends SpringBootActivitiApplicationTests {

// 注入 RuntimeService
@Autowired
private RuntimeService runtimeService;

/**
* 启动流程 - 使用"流程定义 ID"
*
* ProcessInstance startProcessInstanceByMessage(String messageName);
* ProcessInstance startProcessInstanceByMessage(String messageName, Map<String, Object> processVariables);
* ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey, Map<String, Object< processVariables);
* 操作对应数据表:
* ACT_RU_EXECUTION
* ACT_RU_TASK
* ACT_RU_VARIABLE
* ACT_RU_IDENTITYLINK
*/
@Test
public void startProcessByDefinitionId() {
// 流程定义 ID
String processDefinitionId = "LeaveProcess:1:4";

// 流程实例发起人
identityService.setAuthenticatedUserId(loginUser.getUsername());

// 启动流程
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId);
System.out.println("流程启动成功,流程实例ID:" + processInstance.getProcessInstanceId());
}

/**
* 启动流程 - 使用"流程定义 Key"
*
* 操作对应数据表:
* ACT_RU_EXECUTION
* ACT_RU_TASK
* ACT_RU_VARIABLE
* ACT_RU_IDENTITYLINK
*/
@Test
public void startProcessByKey() {
// 流程定义 Key
String processDefinitionKey = "LeaveProcess";

// 流程实例发起人
identityService.setAuthenticatedUserId(loginUser.getUsername());

// 启动流程
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey);
System.out.println("流程启动成功,流程实例ID:" + processInstance.getProcessInstanceId());
}

/**
* 查询流程实例
*
* 操作对应数据表:
* ACT_RU_EXECUTION
*/
@Test
public void processInstanceQuery() {
// 获取“流程实例”查询器
ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();

List<ProcessInstance> processInstances = processInstanceQuery

// 查询匹配条件

/* 流程实例ID (PROC_INST_ID_) - 数据类型:String */
// .processInstanceId(processInstanceId)
/* 流程实例ID (PROC_INST_ID_) - 数据类型:Set<String> - 集合查询 IN */
// .processInstanceIds(processInstanceIds)
/* 流程实例Name (NAME_) - 数据类型:String */
// .processInstanceName(name)
/* 流程实例Name (NAME_) - 数据类型:String - 模糊匹配 %param% */
// .processInstanceNameLike(nameLike)
/* 业务Key(BUSINESS_KEY_) - 数据类型:String */
// .processInstanceBusinessKey(processInstanceBusinessKey)
/*
* 业务Key(BUSINESS_KEY_) - 数据类型:String
* 流程定义Key(ACT_RE_PROCDEF.KEY_)
* */
// .processInstanceBusinessKey(processInstanceBusinessKey, processDefinitionKey)
/* 流程定义ID (PROC_DEF_ID_) - 数据类型:String */
// .processDefinitionId(processDefinitionId)
/* 流程定义ID (PROC_DEF_ID_) - 数据类型:Set<String> - 集合查询 IN */
// .processDefinitionIds(processDefinitionIds)
/* 流程定义Key(ACT_RE_PROCDEF.KEY_) - 数据类型:String */
// .processDefinitionKey(processDefinitionKey)
/* 流程定义Key(ACT_RE_PROCDEF.KEY_) - 数据类型:Set<String> - 集合查询 IN */
// .processDefinitionKeys(processDefinitionKeys)
/* 流程定义Name(ACT_RE_PROCDEF.NAME_) - 数据类型:String */
// .processDefinitionName(processDefinitionName)

// 排序

/* 流程定义ID (PROC_DEF_ID_) - 升序排序 */
// .orderByProcessDefinitionId().asc()
/*流程实例ID (PROC_INST_ID_) - 降序排序 */
// .orderByProcessInstanceId().desc()

// 结果类型

/* List 结果集 */
// .list()
/* List 结果集 - 分页 */
// .listPage(firstResult, maxResults)
/* 唯一的结果 */
// .singleResult()
/* 结果计数 */
// .count()

.list();

processInstances.forEach(processInstance -> {
System.out.println("执行实例 ID: " + processInstance.getId());
System.out.println("流程实例 ID: " + processInstance.getProcessInstanceId());
System.out.println("流程定义 ID: " + processInstance.getDeploymentId());
System.out.println("流程启动时间: " + DateUtil.dateTime2String(processInstance.getStartTime()));
System.out.println(" = = = = = = = = = = = = = = = = = = = = = = = = = ");
});
}
}

挂起、激活流程实例

1
2
3
4
5
// 挂起流程实例,流程不能继续执行(比如,完成任务会抛出异常), 异步操作(比如定时器)也不会执行
runtimeService.suspendProcessInstance("piid");

//激活流程实例
runtimeService.activateProcessInstanceById(id);

执行实例-查询

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
78
79
80
81
82
83
84
85
86
87
88
package boot.deer.note.process.start;

import java.util.List;

import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ExecutionQuery;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import boot.deer.SpringBootActivitiApplicationTests;

/**
* @ClassName: ExecutionNote
* @Author: Mr_Deer
* @Date: 2019年4月2日 下午8:24:19
* @Description: "执行实例"笔记 - 使用 Junit 进行测试
*/
public class ExecutionNote extends SpringBootActivitiApplicationTests {

// 注入 RuntimeService
@Autowired
private RuntimeService runtimeService;

/**
* 查询执行实例
*
* 操作对应数据表:
* ACT_RU_EXECUTION
*/
@Test
public void executionQuery() {
// 获取"执行实例"查询器
ExecutionQuery executionQuery = runtimeService.createExecutionQuery();

List<Execution> executions = executionQuery

// 查询匹配条件

/* 活动节点ID(ACT_ID_) - 数据类型:String */
// .activityId(activityId)
/* 执行实例ID(ID_) - 数据类型:String */
// .executionId(executionId)
/* 父节点ID(PARENT_ID_) - 数据类型:String */
// .parentId(parentId)
/* 流程实例ID (PROC_INST_ID_) - 数据类型:String */
// .processInstanceId(processInstanceId)
/* 业务Key(BUSINESS_KEY_) - 数据类型:String */
// .processInstanceBusinessKey(processInstanceBusinessKey)
/* 流程定义ID (PROC_DEF_ID_) - 数据类型:String */
// .processDefinitionId(processDefinitionId)
/* 流程定义Name(ACT_RE_PROCDEF.NAME_) - 数据类型:String */
// .processDefinitionName(processDefinitionName)
/* 流程定义Key(ACT_RE_PROCDEF.KEY_) - 数据类型:String */
// .processDefinitionKey(processDefinitionKey)
/* 流程定义Key(ACT_RE_PROCDEF.KEY_) - 数据类型:Set<String> - 集合查询 IN */
// .processDefinitionKeys(processDefinitionKeys)

// 排序

/* 流程定义ID (PROC_DEF_ID_) - 升序排序 */
// .orderByProcessDefinitionId().asc()
/*流程实例ID (PROC_INST_ID_) - 降序排序 */
// .orderByProcessInstanceId().desc()

// 结果类型

/* List 结果集 */
// .list()
/* List 结果集 - 分页 */
// .listPage(firstResult, maxResults)
/* 唯一的结果 */
// .singleResult()
/* 结果计数 */
// .count()

.list();

// 循环结果集
executions.forEach(execution -> {
System.out.println("执行实例ID: " + execution.getId());
System.out.println("执行实例Name: " + execution.getName());
System.out.println("父节点ID: " + execution.getParentId());
System.out.println("流程实例ID: " + execution.getProcessInstanceId());
System.out.println(" = = = = = = = = = = = = = = = = = = = = = = = = = ");
});
}
}

活动或任务

  1. 使用 TaskService 接口
  2. 整个流程结束后,在「ACT_RU_」表中的数据就被移除,存档在历史表中

个人任务

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package boot.deer.note.task.assignee;

import java.util.List;

import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import boot.deer.SpringBootActivitiApplicationTests;
import boot.deer.component.util.DateUtil;

/**
* @ClassName: AssigneeTaskNote
* @Author: Mr_Deer
* @Date: 2019年4月2日 下午9:09:53
* @Description: "个人任务"笔记 - 使用 Junit 进行测试
*/
public class AssigneeTaskNote extends SpringBootActivitiApplicationTests {

// 注入 Task
@Autowired
private TaskService taskService;

/**
* 查询个人任务
*
* 操作对应数据表:
* ACT_RU_TASK
*/
@Test
public void assigneeTaskQuery() {
// 获取“任务”查询器
List<Task> tasks = taskService.createTaskQuery()

// 查询匹配条件

/* 任务ID(ID_) - 数据类型:String */
// .taskId(taskId)
/* 办理人ID(ASSIGNEE_) - 数据类型:String */
// .taskAssignee(assignee)
/* 办理人ID(ASSIGNEE_) - 数据类型:List<String> - 集合查询 IN */
// .taskAssigneeIds(assigneeListIds)
/* 办理人ID(ASSIGNEE_) - 数据类型:String - 模糊匹配 %param% */
// .taskAssigneeLike(assigneeLike)
/* 流程变量
// .processVariableValueEquals("orderId", "0815")
/* 流程定义ID (PROC_DEF_ID_) - 数据类型:String */
// .processDefinitionId(processDefinitionId)\
/* 流程定义Key(ACT_RE_PROCDEF.KEY_) - 数据类型:String */
// .processDefinitionKey(processDefinitionKey)
/* 流程定义Key(ACT_RE_PROCDEF.KEY_) - 数据类型:List<String> - 集合查询 IN */
// .processDefinitionKeyIn(processDefinitionKeys)
/* 流程定义Key(ACT_RE_PROCDEF.KEY_) - 数据类型:String - 模糊匹配 %param% */
// .processDefinitionKeyLike(processDefinitionKeyLike)
/* 流程实例ID (PROC_INST_ID_) - 数据类型:String */
// .processInstanceId(processInstanceId)
/* 流程实例ID (PROC_INST_ID_) - 数据类型:List<String> - 集合查询 IN */
// .processInstanceIdIn(processInstanceIds)
/* 业务Key(BUSINESS_KEY_) - 数据类型:String */
// .processInstanceBusinessKey(processInstanceBusinessKey)
/* 业务Key(BUSINESS_KEY_) - 数据类型:String - 模糊匹配 %param% */
// .processInstanceBusinessKeyLike(processInstanceBusinessKeyLike)

// 排序

/* 任务创建时间 (CREATE_TIME_) - 升序排序 */
// .orderByTaskCreateTime().asc()
/* 办理人 (ASSIGNEE_) -降序排序 */
// .orderByTaskAssignee().desc()

// 结果类型

/* List 结果集 */
// .list()
/* List 结果集 - 分页 */
// .listPage(firstResult, maxResults)
/* 唯一的结果 */
// .singleResult()
/* 结果计数 */
// .count()

.list();

// 原生查询
List<Task> tasks = taskService.createNativeTaskQuery()
.sql("SELECT count(*) FROM " + managementService.getTableName(Task.class) + " T WHERE T.NAME_ = #{taskName}")
.parameter("taskName", "gonzoTask")
.list();

long count = taskService.createNativeTaskQuery()
.sql("SELECT count(*) FROM " + managementService.getTableName(Task.class) + " T1, "
+ managementService.getTableName(VariableInstanceEntity.class) + " V1 WHERE V1.TASK_ID_ = T1.ID_")
.count();

// 循环结果集
tasks.forEach(task -> {
System.out.println("任务ID: " + task.getId());
System.out.println("流程实例ID: " + task.getProcessInstanceId());
System.out.println("执行实例ID: " + task.getExecutionId());
System.out.println("任务办理人: " + task.getAssignee());
System.out.println("任务Name: " + task.getName());
System.out.println("任务创建时间: " + DateUtil.dateTime2String(task.getCreateTime()));
System.out.println(" = = = = = = = = = = = = = = = = = = = = = = = = = ");
});
}

/**
* 办理任务
*
* 操作对应数据表:
* ACT_RU_TASK
*/
@Test
public void completeTaskById() {
String taskId = "7502";

// 流程变量
Map<String, Object> variableMap = new HashMap<>(16);
// money 的值
variableMap.put("money", 360);

taskservice.complete(taskId, variableMap);

System.out.println("任务办理成功");
}


/**
* 委托给他人
*
*/
@Test
public void completeTaskById() {
String taskId = "7502";

taskService.delegateTask(taskId, "张三");
taskService.setOwner(taskId, "admin");
}
}

组任务

  1. 指定多个候选人,任务在多个人可见,可以由其中一个人进行任务的办理
  2. 组任务的核心就是任务的拾取,在没有领取之前,就没有具体的办理人
  3. 任务查询、拾取、回退、候选人新增、删除
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package boot.deer.note.task.group;
/**
* @ClassName: GroupTaskNote.java
* @Author: Mr_Deer
* @Date: 2019年4月3日 上午10:16:38
* @Description: "组任务"笔记 - 使用 Junit 进行测试
*/

import java.util.List;

import org.activiti.engine.TaskService;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import boot.deer.SpringBootActivitiApplicationTests;
import boot.deer.component.util.DateUtil;
import boot.deer.component.util.GlobalUtil;

public class GroupTaskNote extends SpringBootActivitiApplicationTests {

// 注入 TaskService
@Autowired
private TaskService taskService;

/**
* 查询任务 - "办理人"查询
*
* 操作对应数据表:
* ACT_RU_TASK
*/
@Test
public void taskQueryByAssignee() {
String assignee = "userA";

List<Task> tasks = taskService.createTaskQuery().taskAssignee(assignee).list();

if (GlobalUtil.isEmpty(tasks))
System.out.println("当前办理人的任务为空");
else {
// 循环结果集
tasks.forEach(task -> {
System.out.println("任务ID: " + task.getId());
System.out.println("流程实例ID: " + task.getProcessInstanceId());
System.out.println("执行实例ID: " + task.getExecutionId());
System.out.println("任务办理人: " + task.getAssignee());
System.out.println("任务Name: " + task.getName());
System.out.println("任务创建时间: " + DateUtil.dateTime2String(task.getCreateTime()));
System.out.println(" = = = = = = = = = = = = = = = = = = = = = = = = = ");
});
}
}

/**
* 查询当前组内成员 - 任务ID 查询
*
* 操作对应数据表:
* ACT_RU_IDENTITYLINK
*/
@Test
public void groupTaskQueryByTaskId() {
String taskId = "15005";
List<IdentityLink> identityLinks = taskService.getIdentityLinksForTask(taskId);

identityLinks.forEach(identity -> {
System.out.println("用户ID: " + identity.getUserId());
System.out.println("任务ID: " + identity.getTaskId());
System.out.println("任务实例ID: " + identity.getProcessInstanceId());
System.out.println("任务类型: " + identity.getType());
System.out.println("= = = = = = = = = = = = = = = = = = = = = = = =");
});
}

/**
* 任务拾取
*
* 操作对应数据表:
* ACT_RU_TASK
*/
@Test
public void taskClaim() {
String taskId = "15005";
String userId = "userA";

taskService.claim(taskId, userId);
System.out.println(userId + ":任务拾取成功");
}

/**
* 任务回退
*
* 操作对应数据表:
* ACT_RU_TASK
*/
@Test
public void taskRollback() {
String taskId = "15005";

taskService.claim(taskId, null);
System.out.println("任务回退成功");

}

/**
* 办理任务
*
* 操作对应数据表:
* ACT_RU_TASK
*/
@Test
public void completeTaskById() {
String taskId = "15005";
taskService.complete(taskId);

System.out.println("任务办理成功");
}

/**
* 给任务添加组员
*
* 操作对应数据表:
* ACT_RU_IDENTITYLINK
*/
@Test
public void addCrew() {
String taskId = "15005";
String userId = "userD";
taskService.addCandidateUser(taskId, userId);

System.out.println(userId + ":成员添加成功");
}

/**
* 删除组员
*
* 操作对应数据表:
* ACT_RU_IDENTITYLINK
*/
@Test
public void deleteCrew() {
String taskId = "15005";
String userId = "userD";
taskService.deleteCandidateUser(taskId, userId);

System.out.println("组员删除成功");
}
}

服务任务

有 4 种方法来声明 java 调用逻辑:

  • 监听类:实现 JavaDelegate 或 ActivityBehavior

    1
    activiti:class="org.activiti.MyJavaDelegate"
    1
    2
    3
    4
    5
    6
    7
    public class ToUppercase implements JavaDelegate {
    public void execute(DelegateExecution execution) throws Exception {
    String var = (String) execution.getVariable("input");
    var = var.toUpperCase();
    execution.setVariable("input", var);
    }
    }
  • 委托表达式:delegateExpressionBean 是一个实现了 JavaDelegate 接口的 bean, 它定义在实例的 spring 容器中

    1
    activiti:delegateExpression="${delegateExpressionBean}"
  • 方法表达式

    名为 printer 对象上的方法 printMessage。 第一个参数是 DelegateExecution,在表达式环境中默认名称为 execution。 第二个参数传递的是当前流程的名为 myVar 的变量

    1
    2
    3
    activiti:expression="#{printer.printMessage()}" 
    或者
    activiti:expression="#{printer.printMessage(execution, myVar)}"
  • 值表达式

    split 为 Spring 容器中 bean,ready 为成员变量,存在 getter 方法「无参」

    1
    activiti:expression="#{split.ready}"

流程变量

  • 流程变量可以帮助我们进行动态的注入”办理人”、”组员”等等,同时还可以控制流程的走向,根据变量来判断流程该流出到哪一条分支等等
  • 流程变量的属性结构就是Map,key 对应 value 的键值队
  • 流程变量可以用在办理人、连接线条件等
  • 流程变量我们之前都是存放的时 String 类型的变量,同样的,我们也可以存放不同的类型,java中基本的数据类型,应用数据类型等 。int、long、char、string、Java 对象
  • 在数据表中有一个字段就是用来存放数据类型的。如果我们想存放对象,同样也是可以的,但存放的对象必须实现序列化的接口,否则就会报错

流程变量- Process Variable

设置「启动流程/完成任务时」、变量修改、获取变量

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package boot.deer.note.variable.type;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipInputStream;

import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import boot.deer.SpringBootActivitiApplicationTests;

/**
* @ClassName: VariableTypeNote.java
* @Author: Mr_Deer
* @Date: 2019年4月9日 上午11:39:29
* @Description: "变量类型"笔记 - 使用 Junit 进行测试
*/
public class VariableTypeNote extends SpringBootActivitiApplicationTests {

// 注入 RepositoryService
@Autowired
private RepositoryService repositoryService;
// 注入 RuntimeService
@Autowired
private RuntimeService runtimeService;

/**
* 部署流程
*/
@Test
public void deploymentProcess() {
// zip 文件的路径
String zipPath = "/processes/note/leave/LeaveProcess.zip";

// 获取一个输入流
InputStream resourceAsStream = this.getClass().getResourceAsStream(zipPath);

// 这里使用的就是 zip 的一个封装类型
Deployment deployment = repositoryService.createDeployment().name("请假流程")
.addZipInputStream(new ZipInputStream(resourceAsStream)).deploy();

System.out.println("流程部署成功,流程部署ID:" + deployment.getId());
}

/**
* 启动流程同时携带一些参数
*/
@Test
public void startProcessWithVariable() {
String processDefinitionKey = "LeaveProcess";
// 参数
Map<String, Object> variableMap = new HashMap<>();
// 请假天数 5天
variableMap.put("days", 5);
// 请假理由
variableMap.put("description", "约会");

ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, variableMap);
System.out.println("流程启动成功,流程实例ID:" + processInstance.getProcessInstanceId());
}

/**
* 改变流程变量
*/
@Test
public void changeVariable() {
// 执行实例ID
String executionId = "37501";
// 变量Map
Map<String, Object> variableMap = new HashMap<>(16);
// 请假天数 3天
variableMap.put("days", 3);

// 通过 setVariables 来放置变量
runtimeService.setVariables(executionId, variableMap);
System.out.println("变量放置成功");
}

/**
* 对象变量
*/
@Test
public void objectVariable() {
// 执行实例ID
String executionId = "37501";
// 变量Map
Map<String, Object> variableMap = new HashMap<>(16);

// 这里我们放置 user 对象,与常规的变量放置方式一样
UserModel user = new UserModel();
user.setName("Mr_Deer");
user.setAge(24);

variableMap.put("user", user);

// 通过 setVariables 来放置变量
runtimeService.setVariables(executionId, variableMap);
System.out.println("变量放置成功");
}

/**
* 获取变量
*/
@Test
public void getVariable() {
// 执行实例ID
String executionId = "37501";

// 需要获取的变量 key
String daysKey = "days";
String descriptionKey = "description";
String userKey = "user";

// 通过 runtimeService 获取
Integer daysValue = (Integer) runtimeService.getVariable(executionId, daysKey);
String descriptionValue = (String) runtimeService.getVariable(executionId, descriptionKey);
UserModel userValue = (UserModel) runtimeService.getVariable(executionId, userKey);

System.out.println("请假天数:" + daysValue);
System.out.println("请假理由:" + descriptionValue);
System.out.println("用户对象:" + userValue.toString());
}
}

连线-Sequence Flow

连线就是我们节点与节点直接的连接线,他明确了我们流程的流向。可以通过流程变量控制分支情况中不同流向

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package boot.deer.note.variable.sequence;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipInputStream;

import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import boot.deer.SpringBootActivitiApplicationTests;

/**
* @ClassName: SequenceFlowNote.java
* @Author: Mr_Deer
* @Date: 2019年4月3日 下午3:52:21
* @Description: "连线"笔记 - 使用 Junit 进行测试
*/
public class SequenceFlowNote extends SpringBootActivitiApplicationTests {
// 注入 RepositoryService
@Autowired
private RepositoryService repositoryService;
// 注入 RuntimeService
@Autowired
private RuntimeService runtimeService;
// 注入 TaskService
@Autowired
private TaskService taskService;

/**
* 流程部署
*/
@Test
public void processDeployment() {
String path = "/processes/note/file/version_2/FileProcess.zip";
InputStream inputStream = this.getClass().getResourceAsStream(path);

String processName = "文件审批流程";
Deployment deployment = repositoryService.createDeployment().name(processName)
.addZipInputStream(new ZipInputStream(inputStream)).deploy();

System.out.println("流程部署成功,流程部署ID:" + deployment.getId());
}

/**
* 启动流程
*/
@Test
public void processStartByKey() {
String processDefinitionKey = "FileProcess";
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey);

System.out.println("流程启动成功,流程实例ID:" + processInstance.getProcessInstanceId());
}

/**
* 办理任务
*/
@Test
public void completeTaskById() {
String taskId = "30003";
taskService.complete(taskId);

System.out.println("任务办理成功");
}

/**
* 办理任务 - 携带参数
*/
@Test
public void completeTaskByIdWithVariable() {
String taskId = "27502";
Map<String, Object> variableMap = getVariableMap("isImportant", "重要");
taskService.complete(taskId, variableMap);

System.out.println("任务办理成功");
}

/**
* 获取流程变量
*
* @param key key
* @param value value
* @return Map 集合
*/
private Map<String, Object> getVariableMap(String key, Object value) {
HashMap<String, Object> variableMap = new HashMap<>(16);
variableMap.put(key, value);

return variableMap;
}
}

历史记录

  • 使用 HistoryService 接口
  • 历史流程表存放的全部都是已经完成的”流程实例”、”任务实例”、”流程变量”等等
  • 当一条流程执行完毕后,ACT_RU_* 表中数据都会被抹除,这是因为全部都存放在历史流程表中了 ACT_HI_PROCINST

历史流程 - History Process

  • 查询接口:historyService.createHistoricProcessInstanceQuery()

  • 主要字段:任务开始时间、任务结束时间、任务持续时间、开始节点、结束节点

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package boot.deer.note.history.process;

import java.util.List;

import org.activiti.engine.HistoryService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import boot.deer.SpringBootActivitiApplicationTests;
import boot.deer.component.util.DateUtil;

/**
* @ClassName: HistoryProcessNote.java
* @Author: Mr_Deer
* @Date: 2019年4月3日 下午1:02:34
* @Description: "历史流程"笔记 - 使用 Junit 进行测试
*/
public class HistoryProcessNote extends SpringBootActivitiApplicationTests {

// 注入 HistoryService
@Autowired
private HistoryService historyService;

/**
* 查询历史流程
*
* 操作对应数据表:
* ACT_HI_PROCINST
*/
@Test
public void historyProcessQuery() {
// 获取“历史流程”查询器
HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();

List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery

// 查询匹配条件

/* 流程定义ID (PROC_DEF_ID_) - 数据类型:String */
// .processDefinitionId(processDefinitionId)
/* 流程定义Key(ACT_RE_PROCDEF.KEY_) - 数据类型:String */
// .processDefinitionKey(processDefinitionKey)
/* 流程定义Key(ACT_RE_PROCDEF.KEY_) - 数据类型:List<String> - 集合查询 IN */
// .processDefinitionKeyIn(processDefinitionKeys)
/* 流程定义Name(ACT_RE_PROCDEF.NAME_) - 数据类型:String */
// .processDefinitionName(processDefinitionName)
/* 流程实例ID (PROC_INST_ID_) - 数据类型:String */
// .processInstanceId(processInstanceId)
/* 流程实例ID (PROC_INST_ID_) - 数据类型:Set<String> - 集合查询 IN */
// .processInstanceIds(processInstanceIds)
/* 流程实例Name (NAME_) - 数据类型:String */
// .processInstanceName(name)
/* 流程实例Name (NAME_) - 数据类型:String - 模糊匹配 %param% */
// .processInstanceNameLike(nameLike)
/* 业务Key(BUSINESS_KEY_) - 数据类型:String */
// .processInstanceBusinessKey(processInstanceBusinessKey)

// 排序

/* 流程定义ID (PROC_DEF_ID_) - 升序排序 */
// .orderByProcessDefinitionId().asc()
/*流程实例ID (PROC_INST_ID_) - 降序排序 */
// .orderByProcessInstanceId().desc()

// 结果类型

/* List 结果集 */
// .list()
/* List 结果集 - 分页 */
// .listPage(firstResult, maxResults)
/* 唯一的结果 */
// .singleResult()
/* 结果计数 */
// .count()

.list();

// 循环结果集
historicProcessInstances.forEach(processInstance -> {
System.out.println("历史流程 ID: " + processInstance.getId());
System.out.println("流程定义 ID: " + processInstance.getDeploymentId());
System.out.println("历史流程开始时间: " + DateUtil.dateTime2String(processInstance.getStartTime()));
System.out.println("历史流程结束时间: " + DateUtil.dateTime2String(processInstance.getEndTime()));
System.out.println(
"流程持续周期时间(:秒): " + DateUtil.milliseconds2Second(processInstance.getDurationInMillis()) + "s");
System.out.println(" = = = = = = = = = = = = = = = = = = = = = = = = = ");
});
}
}

历史任务-History Task

  • 查询接口:historyService.createHistoricTaskInstanceQuery()

  • 我们在执行流程任务的时候,每一个任务都会在执行的时候就同步到历史表中了,这也就保证了每条任务的记录都会存在在历史表中,为我们后面查询带来很多的便捷

  • 历史任务的查询表是 ACT_HI_TASKINST ,里面主要的数据是:任务名称、任务办理人、开始时间、结束时间、持续时间

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package boot.deer.note.history.task;

import java.util.List;

import org.activiti.engine.HistoryService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import boot.deer.SpringBootActivitiApplicationTests;
import boot.deer.component.util.DateUtil;

/**
* @ClassName: HistoryTaskNote.java
* @Author: Mr_Deer
* @Date: 2019年4月8日 上午10:31:09
* @Description: "历史任务"笔记 - 使用 Junit 进行测试
*/
public class HistoryTaskNote extends SpringBootActivitiApplicationTests {

// 注入 HistoryService
@Autowired
private HistoryService historyService;

/**
* 查询历史任务流程
*
* 操作对应数据表:
* ACT_HI_TASKINST
*/
@Test
public void historyTaskQuery() {
// 获取“历史任务”查询器
HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();

List<HistoricTaskInstance> historicTaskInstances = historicTaskInstanceQuery

// 查询匹配条件

/* 流程定义ID (PROC_DEF_ID_) - 数据类型:String */
// .processDefinitionId(processDefinitionId)
/* 流程定义Key(ACT_RE_PROCDEF.KEY_) - 数据类型:String */
// .processDefinitionKey(processDefinitionKey)
/* 流程定义Key(ACT_RE_PROCDEF.KEY_) - 数据类型:String - 模糊匹配 %param% */
// .processDefinitionKeyLike(processDefinitionKeyLike)
/* 流程定义Key(ACT_RE_PROCDEF.KEY_) - 数据类型:List<String> - 集合查询 IN */
// .processDefinitionKeyIn(processDefinitionKeys)
/* 流程定义Name(ACT_RE_PROCDEF.NAME_) - 数据类型:String */
// .processDefinitionName(processDefinitionName)
/* 流程定义Name(ACT_RE_PROCDEF.NAME_) - 数据类型:String - 模糊匹配 %param% */
// .processDefinitionNameLike(processDefinitionNameLike)
/* 流程实例ID (PROC_INST_ID_) - 数据类型:String */
// .processInstanceId(processInstanceId)
/* 流程实例ID (PROC_INST_ID_) - 数据类型:Set<String> - 集合查询 IN */
// .processInstanceIdIn(processInstanceIds)

// 排序

/* 任务开始时间 (START_TIME_) - 升序排序 */
// .orderByHistoricTaskInstanceEndTime().asc()
/* 任务结束时间 (END_TIME_) - 升序排序 */
// .orderByHistoricTaskInstanceEndTime().desc()

// 结果类型

/* List 结果集 */
// .list()
/* List 结果集 - 分页 */
// .listPage(firstResult, maxResults)
/* 唯一的结果 */
// .singleResult()
/* 结果计数 */
// .count()

.list();

// 循环结果集
historicTaskInstances.forEach(historyTask -> {
System.out.println("历史任务ID:" + historyTask.getId());
System.out.println("历史任务执行实例ID:" + historyTask.getExecutionId());
System.out.println("历史任务实例ID:" + historyTask.getProcessInstanceId());
System.out.println("历史任务定义ID:" + historyTask.getProcessDefinitionId());
System.out.println("历史任务开始时间:" + DateUtil.dateTime2String(historyTask.getStartTime()));
System.out.println("历史任务结束时间:" + DateUtil.dateTime2String(historyTask.getEndTime()));
System.out.println("历史任务名称:" + historyTask.getName());
System.out.println("历史任务办理人:" + historyTask.getAssignee());
System.out.println(
"历史任务办理持续周期时间(:秒):" + DateUtil.milliseconds2Second(historyTask.getDurationInMillis()) + "s");
System.out.println(" = = = = = = = = = = = = = = = = = = = = = = = = = ");
});
}
}

历史活动节点 - History Activity

  • 查询的表 ACT_HI_ACTINST ,其中基本比较重要的属性:节点ID、任务ID、节点Name、节点类型
  • 保存的节点只是我们走过的节点
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
78
79
80
81
82
83
84
85
86
87
88
package boot.deer.note.history.activity;

import java.util.List;

import org.activiti.engine.HistoryService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import boot.deer.SpringBootActivitiApplicationTests;
import boot.deer.component.util.DateUtil;

/**
* @ClassName: HistoryActivityNote.java
* @Author: Mr_Deer
* @Date: 2019年4月8日 上午11:18:41
* @Description: "历史活动节点"笔记 - 使用 Junit 进行测试
*/
public class HistoryActivityNote extends SpringBootActivitiApplicationTests {

// 注入 HistoryService
@Autowired
private HistoryService historyService;

/**
* 查询历史活动节点
*
* 操作对应数据表:
* ACT_HI_ACTINST
*/
@Test
public void historyActivityQuery() {
// 获取“历史活动节点”查询器
HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService
.createHistoricActivityInstanceQuery();

List<HistoricActivityInstance> activityInstances = historicActivityInstanceQuery

// 查询匹配条件

/* 流程定义ID (PROC_DEF_ID_) - 数据类型:String */
// .processDefinitionId(processDefinitionId)
/* 流程实例ID (PROC_INST_ID_) - 数据类型:String */
// .processInstanceId(processInstanceId)
/* 活动节点ID(ACT_ID_) - 数据类型:String */
// .activityId(activityId)
/* 任务节点Name(ACT_NAME_) - 数据类型:String */
// .activityName(activityName)
/* 任务节点类型(ACT_TYPE) - 数据类型:String */
// .activityType(activityType)
/* 任务办理人(ASSIGNEE_) */
// .taskAssignee(userId)

// 排序

/* 活动节点ID(ACT_ID) - 升序排序 */
// .orderByActivityId().asc()
/* 活动节点类型(ACT_ID) - 降序排序 */
// .orderByActivityType().desc()

// 结果类型

/* List 结果集 */
// .list()
/* List 结果集 - 分页 */
// .listPage(firstResult, maxResults)
/* 唯一的结果 */
// .singleResult()
/* 结果计数 */
// .count()
.list();

// 循环结果集
activityInstances.forEach(activity -> {
System.out.println("历史活动节点ID:" + activity.getActivityId());
System.out.println("历史活动节点任务ID:" + activity.getTaskId());
System.out.println("历史活动节点Name:" + activity.getActivityName());
System.out.println("历史活动节点类型:" + activity.getActivityType());
System.out.println("历史活动节点办理人:" + activity.getAssignee());
System.out.println("历史活动节点开始时间:" + DateUtil.dateTime2String(activity.getStartTime()));
System.out.println("历史活动节点结束时间:" + DateUtil.dateTime2String(activity.getEndTime()));
System.out.println(
"历史活动节点办理持续周期时间(:秒):" + DateUtil.milliseconds2Second(activity.getDurationInMillis()) + "s");
System.out.println(" = = = = = = = = = = = = = = = = = = = = = = = = = ");
});
}
}

历史流程变量-History Variable

  • 主要字段:变量类型、变量名称、变量值、创建时间、最后一次修改时间
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package boot.deer.note.history.variable;

import java.util.List;

import org.activiti.engine.HistoryService;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.history.HistoricVariableInstanceQuery;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import boot.deer.SpringBootActivitiApplicationTests;
import boot.deer.component.util.DateUtil;

/**
* @ClassName: HistoryVariableNote.java
* @Author: Mr_Deer
* @Date: 2019年4月9日 上午10:16:01
* @Description: "历史流程变量"笔记 - 使用 Junit 进行测试
*/
public class HistoryVariableNote extends SpringBootActivitiApplicationTests {

// 注入 HistoryService
@Autowired
private HistoryService historyService;

/**
* 查询历史流程变量
*
* 操作对应数据表:
* ACT_HI_VARINST
*/
@Test
public void historyVariableQuery() {
// 获取“历史流程变量”查询器
HistoricVariableInstanceQuery historicVariableInstanceQuery = historyService
.createHistoricVariableInstanceQuery();

List<HistoricVariableInstance> variableInstances = historicVariableInstanceQuery

// 查询匹配条件

/* 流程实例ID (PROC_INST_ID_) - 数据类型:String */
// .processInstanceId(processInstanceId)
/* 变量名称(NAME_) - 数据类型:String */
// .variableName(variableName)
/* 变量名称(NAME_) - 数据类型:String - 模糊匹配 %param% */
// .variableNameLike(variableNameLike)
/*
* 变量名称(NAME_) - 数据类型:String
* 变量值 - 数据类型:String
* 相等匹配
*/
// .variableValueEquals(variableName, variableValue)
/*
* 变量名称(NAME_) - 数据类型:String
* 变量值 - 数据类型:String
* 模糊匹配
*/
// .variableValueLike(variableName, variableValue)

// 排序

/*流程实例ID (PROC_INST_ID_) - 升序排序 */
// .orderByProcessInstanceId().asc()
/*变量名称 (NAME) - 降序排序 */
// .orderByVariableName().desc()

// 结果类型

/* List 结果集 */
// .list()
/* List 结果集 - 分页 */
// .listPage(firstResult, maxResults)
/* 唯一的结果 */
// .singleResult()
/* 结果计数 */
// .count()

.list();

// 循环结果集
variableInstances.forEach(variable -> {
System.out.println("历史变量ID:" + variable.getId());
System.out.println("历史流程实例ID:" + variable.getProcessInstanceId());
System.out.println("历史变量Name:" + variable.getVariableName());
System.out.println("历史变量值类型:" + variable.getVariableTypeName());
System.out.println("历史变量值:" + variable.getValue());
System.out.println("历史变量创建时间:" + DateUtil.dateTime2String(variable.getCreateTime()));
System.out.println("历史变量最后修改时间:" + DateUtil.dateTime2String(variable.getLastUpdatedTime()));
System.out.println(" = = = = = = = = = = = = = = = = = = = = = = = = = ");
});
}
}

网关

排他网关 - Exclusive Gateway

  • 什么是排他网管?

    排他网关是工作流中网关的一种。其主要的功能就是判断分流,通过不同的流程变量来判断接下改流向哪一条分支(流程肯定是多分支的)

  • 为什么要使用?之前不是已经使用流程变量来控制了吗?

    之前的那种控制很不严谨,并且流程图可读性不高,并且存在一些BUG,并不推荐那种使用方式,我们下面的例子就会体现出”排他网管”的优势

  • 排他网关就是一个菱形里面有一个X的就是排他网管
  • 一个”排他网关”对应一个以上的顺序流
  • 由”排他网关”流出的顺序流都有个”conditionExpression:匹配规则”,该匹配规则都是返回boolean
  • “排他网关”只会选择一条结果,执行到”排他网关”时,流程引擎会自动检索网关出口,从上到下检索出一个匹配规则返回 true的分支流进行流出
    • 如果设置设立”默认连线”时,那么该流出的连线会最后进行匹配,同时也是默认为 true
    • 如果没有设置”默认连线”时,同时也没有匹配的规则,则会抛出异常

并行网关 - Parallel Gateway

  • 可以同时的、并行执行的多个流程
  • 并行网关就是一个菱形的图标中间一个”+”
  • 并行网关包括开始和结束两个节点
  • 必须两分支的任务都执行完毕才会判定整个流程结束,有一个没有办理完成都不会判定流程结束

流程启动

  • 流程启动和常规的流程启动方式没有什么区别,重点在于数据库中的数据。

  • 我们看到数据库中出现了三条数据,其中后面的两条的 PARENT_ID_ 都是第一条的数据。这也就是我们之前说的,在单分支流程的时候,执行实例就等同于流程实例,而在多分支的时候就不能相提并论的。

    • PARENT_ID 为空的就是流程实例
    • PARENT_ID 非空的则是执行实例
    • 他们都是需要依附一个流程实例来存在的
  • 在任务的数据表中,也看到了存在了两条记录,也就意味着流程一旦启动,所有的任务都会同时的执行

总结

  • 一个流程中”流程实例”只有一个,”执行实例”会存在多个
  • “并行网关”的功能是基于进入和外出的顺序流
    1. 分支(fork):

    2. 并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。

    3. 也就是我们流程已启动,就会执行第一个”并发网关”后面的所有顺序流且并发执行

    1. 汇聚(join):
    2. 所有到达”并行网关”,在此等候,直到所有进入顺序流的分支都到达后,流程才会通过”汇聚网关”
  • “并行网关”的进入和流出使用的都是一样的图标

  • 如果一个”并行网关”有多个进入和多个流出的顺序流,那么他就同时具备分支和汇聚的功能,这时,网关会先汇聚所有的进入顺序流,然后再切分多个并行分支(流出)

  • “并行网关”不会解析条件,即使再 sequenceFlow 中定义了条件,也会别忽略

  • “并行网关”不需要具备”平衡性”,则随意使用

监听器 - Listener

  • 我们在流程”办理人”的设置中之前有使用过”变量”来注入每个任务的和更改下次任务的办理人,但不过我们之前是在办理任务的时候才去设置变量的,但这样并不方便,因为我们想更关注于业务逻辑,想单独的有个类来去设置办理人,而 Listener 就是帮助我们来解决这个问题的

  • 我们需要先创建一个 Listener,这个类必须实现 TaskListener 这个类,重写 notify 方法即可。 notify 方法块中就是我们需要关于的这个流程变量(这里是办理人)的业务逻辑了

  • 全局的监听器、连线的监听器、节点的监听器

参考

https://g.yuque.com/torey-4fmbn/hhfum8/wxcr8b

全局监听器「执行监听器」

  • 可以捕获的事件有:
    • 流程实例的启动和结束
    • 选中一条连线
    • 节点的开始和结束
    • 网关的开始和结束
    • 中间事件的开始和结束
    • 开始时间结束或结束事件开始
  • 实现的接口是org.activiti.engine.delegate.ExecutionListener
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
package io.renren.modules.activiti.Score;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;

public class ScoreExecutionListener implements ExecutionListener {
/**
* 全局监听器
* @param execution
* @throws Exception
*/
@Override
public void notify(DelegateExecution execution) throws Exception {
String eventName = execution.getEventName();
System.out.println(eventName);
if ("start".equals(eventName)) {
//流程实例开始
System.out.println("start=========");
}else if ("end".equals(eventName)) {
//流程实例结束
System.out.println("end=========");
}
else if ("take".equals(eventName)) {
// take是监控连线
System.out.println("take=========");
}
}
}

//DelegateExecution 常用方法如下:
/** execution Id */
String getId();

/** 流程实例id*/
String getProcessInstanceId();

/** 这个比较有用 主要就是start、end、take */
String getEventName();

/**
* 业务id已经废弃
*/
String getBusinessKey();

/**
* 业务id */
String getProcessBusinessKey();

/**
* 流程定义id
*/
String getProcessDefinitionId();

/**
* 获取父id,并发的时候有用
*/
String getParentId();

/**
* 获取当前的.Activityid
*/
String getCurrentActivityId();

/**
* 获取当前的.Activity name
*/
String getCurrentActivityName();

/**
* 获取TenantId 当有多个TenantId 有用
*/
String getTenantId();

/**
* 这个非常有用吧。当拿到EngineServices 对象所有的xxxService都可以拿到。
*/
EngineServices getEngineServices();

节点监听器「任务监听器」

  • 可以捕获的事件有:
    • create:任务创建并设置所有属性后触发。
    • assignment:任务分配给一些人时触发。 当流程到达 userTask, assignment 事件 会在 create 事件 之前发生。 这样的顺序似乎不自然,但是原因很简单:当获得 create 时间时, 我们想获得任务的所有属性,包括执行人。
    • complete:当任务完成,并尚未从运行数据中删除时触发。
    • delete:只在任务删除之前发生。 注意在通过 completeTask 正常完成时,也会执行。
  • 实现的接口是org.activiti.engine.delegate.TaskListener
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
package io.renren.modules.activiti.Score;

import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;

public class ScoreExecutionListener implements TaskListener {
/**
* 具体某个节点的监听
* @param delegateTask
*/
@Override
public void notify(DelegateTask delegateTask) {
String eventName = delegateTask.getEventName();
System.out.println(eventName);
if ("create".endsWith(eventName)) {
//
System.out.println("create=========");
}else if ("assignment".endsWith(eventName)) {
System.out.println("assignment========");
}else if ("complete".endsWith(eventName)) {
System.out.println("complete===========");
}else if ("delete".endsWith(eventName)) {
System.out.println("delete=============");
}
}
}

//DelegateTask 常用方法如下:
/** 数据库中的taskId主键*/
String getId();

/** 任务名称 */
String getName();

/** 修改任务名称 */
void setName(String name);

/** 获取任务的描述信息 */
String getDescription();

/** 修改任务的描述信息 */
void setDescription(String description);

/**
* lower priority: [0..19] lowest, [20..39] low, [40..59] normal, [60..79] high
* [80..100] highest
任务处理的优先级范围是0-100
*/
int getPriority();

/** 修改优先级*/
void setPriority(int priority);

/** 获取流程实例id */
String getProcessInstanceId();

/**获取执行id*/
String getExecutionId();

/** 获取流程定义id*/
String getProcessDefinitionId();
/** Adds the given user as a candidate user to this task. */
void addCandidateUser(String userId);

/** 添加候选人 */
void addCandidateUsers(Collection<String> candidateUsers);

/** 添加候选组 */
void addCandidateGroup(String groupId);