Activiti5入门--连线

连线(SequenceFlow)是工作流中极其重要的一部分,是用于连接各个节点的有向线段。在上面的章节中,工作流流程定义都是不存在分支选择的情况的,在本章,我们将学习连线的相关知识,定义一个带有分支的工作流流程。

定义分支流程

为了定义一个新的工作流,在src/main/java下新建包cn.demo.sequencefloe,并在该包下创建sequenceFlow.bpmn文件,定义如下流程

分支流程

  1. 首先,创建一个开始节点,作为流程定义的开头
  2. 其次,创建一个用户任务节点,设置其Nam值为审批【部门经理】,其Assignee为赵六
  3. 然后,再创建一个用户任务节点,设置其Name值为审批【总经理】,其Assignee为田七
  4. 接着,再创建一个结束节点,作为流程定义的结尾
  5. 点击空白处,设置其Id为sequenceFlow,其Name为sequenceFlowProcess

通过上述的步骤,我们就完成了一个流程定义的基本雏形,下面,我们开始学习如何控制选择分支。

  1. 选中审批【部门经理】到结束节点这条连线,选择Propertis对话框中的General选项卡,设置其Name为不重要,用于显示提示信息。然后,选择Main-config选项卡,填写Condition,用于设置条件变量,当变量满足一定条件时,切换到流程分支上。在该连线上,定义流程变量message,其值为不重要,${}内的内容为一个逻辑表达式。该流程变量会在后面的代码实践中设置,这里先定义一下。
    设置部门经理审批连线
  2. 相似地,选中审批【部门经理】审批【总经理】之间的连线,设置其Name的值为重要,设置流程变量message的值为重要

当完成这两步以后,这个流程就彻底定义好了,当流程变量message的值为不重要时,部门经理直接审批通过,否则还需要总经理审批。
最终版流程定义图

连线示例

在该包下创建一个测试类SequenceFlowTest,接下来,我们就来部署该流程定义、启动流程实例,并试着设置流程变量message的值,通过设置不同的值来控制执行哪一条流程分支。

部署流程定义

不可避免地,我们先要部署一个流程定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 部署流程定义
*/
@Test
public void deploymentProcessDefinition() {
InputStream inputStreamBpmn = this.getClass().getResourceAsStream("sequenceFlow.bpmn");
InputStream inputStreamPng = this.getClass().getResourceAsStream("sequenceFlow.png");
Deployment deploy = processEngine.getRepositoryService() // 与流程定义和部署对象相关的Service
.createDeployment() // 创建一个部署对象
.name("连线") // 添加部署的名称
.addInputStream("sequenceFlow.bpmn", inputStreamBpmn)
.addInputStream("sequenceFlow.png",inputStreamPng)
.deploy(); // 完成部署
System.out.println("部署ID: " + deploy.getId());
System.out.println("部署名称: " + deploy.getName());
}

注意,此时直接执行代码,会报错,无法成功部署流程定义。

若将流程图放置在和java类相同的路径下,需要进行配置

为了使程序能够正常运行,成功部署流程定义,需要右击项目,选择Build-Path来配置Java Build Path

JavaBuildPath

选中到src/main/java下的Included那一行,选择Remove,将其改为Included:(All)

修改BuildPath

这样,我们再执行代码,就能成功部署流程定义了。执行结果如下

部署ID: 2601
部署名称: 连线

启动流程实例

部署流程定义成功以后,我们开始启动流程实例,在这里,我们使用流程定义的key来启动流程实例。

1
2
3
4
5
6
7
8
9
10
11
/**
* 启动流程实例
*/
@Test
public void startProcessInstance() {
// 流程定义的key
String processDefinitionKey = "sequenceFlow";
ProcessInstance processInstance = processEngine.getRuntimeService()
.startProcessInstanceByKey(processDefinitionKey);
System.out.println("流程实例ID: " + processInstance.getId());
System.out.println("流程定义ID: " + processInstance.getProcessDefinitionId()); }

执行代码,得到如下结果

流程实例ID: 2701
流程定义ID: sequenceFlow:1:2604

此时,流程执行到审批【部门经理】任务,联系上下文可知,当前任务的执行人是赵六,可以通过执行人得到当前任务的详细信息。

查询个人任务

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
/**
* 查询当前人的个人任务
*/
@Test
public void findMyPersonalTask() {
String assignee = "赵六";
List<Task> list = processEngine.getTaskService() // 与正在执行的任务管理相关的Service
.createTaskQuery() // 创建任务对象
/*查询条件(部分)*/
.taskAssignee(assignee) // 指定个人任务,指定办理人
// .taskCandidateUser(arg0) 组任务的办理人
// .processDefinitionId(arg0) 流程定义id
// .processInstanceId(arg0) // 流程实例id
// .executionId(arg0) // 执行对象id
/*排序*/
.orderByTaskCreateTime().asc()
/*返回结果集*/
// .singleResult() // 返回唯一结果集
// .count() // 返回结果集数量
// .listPage(arg0, arg1) // 分页查询结果集
.list();
// 存储在act_ru_task表
if (list != null && list.size() > 0) {
for (Task task : list) {
System.out.println("任务ID: " + task.getId());
System.out.println("任务名称: " + task.getName());
System.out.println("任务的创建时间: " + task.getCreateTime());
System.out.println("任务的办理人: " + task.getAssignee());
System.out.println("流程实例ID: " + task.getProcessInstanceId());
System.out.println("执行对象ID: " + task.getExecutionId());
System.out.println("流程定义ID: " + task.getProcessDefinitionId());
System.out.println("");
}
}
}

执行代码,我们得到如下结果

任务ID: 2704
任务名称: 审批【部门经理】
任务的创建时间: Wed Oct 10 21:07:20 CST 2018
任务的办理人: 赵六
流程实例ID: 2701
执行对象ID: 2701
流程定义ID: sequenceFlow:1:2604

完成任务(重点)

现在,我们可以完成任务了,这里涉及到一个问题,执行完审批【部门经理】任务后,是直接结束还是需要执行审批【总经理】任务呢?由流程图可知,若是事情不重要,则直接结束,若事情重要,则还需要经过总经理审批。

在前面定义流程的时候,我们设置了一个流程变量message,当该变量的值为不重要时,部门经理审批后可以直接结束流程,当该变量的值为重要时,需要总经理审批之后才能结束流程。因此,我们可以通过在完成任务时设置流程变量message的值来控制是直接结束还是需要继续审批。

在前面的流程变量文章中,提到过activiti提供了该方法。

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 完成我的任务
*/
@Test
public void completeMyPersonalTask() {
String taskId = "2704";
// 完成任务的同时,设置流程变量message的值,来控制下一连线
Map<String,Object> map = new HashMap<String,Object>();
map.put("message", "不重要");
processEngine.getTaskService().complete(taskId, map);
System.out.println("完成任务:任务Id:" + taskId);
}

当我们执行完上述代码后,输出下面的结果,并且由流程图可知,该流程已经结束了。

完成任务:任务Id:2704

查询act_hi_procinst(流程实例的历史表),可以看到该流程实例记录的结束时间不为空,该流程实例确实结束了。

总结

  1. 一个活动中可以指定一个或多个SequenceFlow(Start中有一个,End中没有)。

    开始活动中有一个SequenceFlow

    结束活动中没有SequenceFlow

    其他活动中有1条或多条SequenceFlow

  2. 如果只有一个SequenceFlow ,即只有唯一一条分支。则可以不使用流程变量设置codition的名称,如果有多个,则需要使用流程变量设置codition的名称。前面使用的message为流程变量的名称,${}中间的内容要使用boolean类型的表达式,用来判断应该执行的连线,即走哪一条分支。