Activiti5入门--用户角色组

本章是Activiti的最后一章,我们开始学习Activiti提供的用户角色组。通过它,流程能够根据用户角色选择办理人完成用户任务。为了便于学习,我们新建包cn.demo.groupuser,类TaskTest,流程图文件task.bpmn

定义审批流程

和前面一样,我们定义一个审批流程,该审批用户任务节点设置Candidate-groups的值为部门经理,当流程执行到此用户任务节点时,只有角色为部门经理的人才能查询和完成该任务。

用户角色组

查看task.bpmn文件

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
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
<process id="task" name="taskProcess" isExecutable="true">
<startEvent id="startevent1" name="Start"></startEvent>
<userTask id="usertask1" name="审批" activiti:candidateGroups="部门经理"></userTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow2" sourceRef="usertask1" targetRef="endevent1"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_task">
<bpmndi:BPMNPlane bpmnElement="task" id="BPMNPlane_task">
<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
<omgdc:Bounds height="35.0" width="35.0" x="360.0" y="20.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
<omgdc:Bounds height="55.0" width="105.0" x="325.0" y="120.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
<omgdc:Bounds height="35.0" width="35.0" x="360.0" y="240.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="377.0" y="55.0"></omgdi:waypoint>
<omgdi:waypoint x="377.0" y="120.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="377.0" y="175.0"></omgdi:waypoint>
<omgdi:waypoint x="377.0" y="240.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>

注意到下面一段,我们成功设置了该用户任务所允许的办理人角色

1
2
3
4
<startEvent id="startevent1" name="Start"></startEvent>
<userTask id="usertask1" name="审批" activiti:candidateGroups="部门经理"></userTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1">

使用用户任务组

部署流程定义

现在,我们需要部署一个新的流程定义,和以往不同的是,在部署流程定义时,我们还需要创建用户、角色,并建立用户角色之间的关联关系。

假设这样一个情景,存在张三、李四、王五这三个人,张三、李四是部门经理,而王五是总经理。若我们在部署流程定义时,同时建立这三人和角色之间一一对应的关系,当我们启动流程实例后,根据上面定义的流程,可以预见张三、李四两人可以查询并完成任务,而王五由于是总经理,则无法查询并完成任务。

下面,我们就来部署一下流程定义

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
/**
* 部署流程定义
*/
@Test
public void deploymentProcessDefinition() {
InputStream inputStreamBpmn = this.getClass().getResourceAsStream("task.bpmn");
InputStream inputStreamPng = this.getClass().getResourceAsStream("task.png");
Deployment deploy = processEngine.getRepositoryService()
.createDeployment() // 创建一个部署对象
.name("任务") // 添加部署的名称
.addInputStream("task.bpmn", inputStreamBpmn)
.addInputStream("task.png",inputStreamPng)
.deploy(); // 完成部署
System.out.println("部署ID: " + deploy.getId());
System.out.println("部署名称: " + deploy.getName());
/*添加用户角色*/
IdentityService identityService = processEngine.getIdentityService();
// 创建角色
identityService.saveGroup(new GroupEntity("总经理"));
identityService.saveGroup(new GroupEntity("部门经理"));
// 创建用户
identityService.saveUser(new UserEntity("张三"));
identityService.saveUser(new UserEntity("李四"));
identityService.saveUser(new UserEntity("王五"));
// 建立角色和用户关联关系
identityService.createMembership("张三", "部门经理");
identityService.createMembership("李四", "部门经理");
identityService.createMembership("王五", "总经理");
System.out.println("添加组织机构成功");
}

可以看到,在上面的代码中,我们使用了一个新的service-identityService,通过saveGroup方法,我们创建了多个角色,通过saveUser方法创建了多个用户,通过createMembership方法我们建立了角色和用户之间的关联关系。如果没有异常,我们将成功建立用户角色之间的关系。

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

部署ID: 7401
部署名称: 任务
添加组织机构成功

为了证明我们确实建立了用户角色之间的关联关系,我们查询下面三张表

查询act_id_group(角色表),可以看到,该表存储了两个角色:部门经理和总经理

角色表

查询act_id_user,可以看到存在三条记录,正是我们添加的三个人:张三、李四和王五

用户表

查询act_id_membership(用户角色关系表)

用户角色关系表

由此,我们知道,用户角色之间的关联关系成功创建了。

启动流程实例

成功部署流程定义和建立用户角色关系后,我们开始启动流程实例

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

运行代码,得到如下结果

流程实例ID: 7501
流程定义ID: task:7:7404

我们查询一下act_ru_task(正在执行的任务表),发现ASSIGNEE_的值为空。于是,我们查询act_ru_identitylink(任务办理人表)act_hi_identitylink(历史任务办理人表)

查询act_ru_identitylink(任务办理人表)GROUP_ID字段不为空,为部门经理

任务办理人表

查询act_hi_identitylink(历史任务办理人表),我们看到了和上面一样的结果

历史任务办理人表

由前面可知,部门经理包括两个人:张三和李四。由于ASSIGNEE_字段的值为空结合这两张表,我们知道该用户任务属于组任务的一种。因此,我们来查询两人的组任务。

查询组任务

我们先查询张三的组任务

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
/**
* 查询当前人的组任务
*/
@Test
public void findMyGroupTask() {
String assignee = "张三";
List<Task> list = processEngine.getTaskService()
.createTaskQuery() // 创建任务对象
/*查询条件(部分)*/
.taskCandidateUser(assignee)
/*排序*/
.orderByTaskCreateTime().asc()
.list();
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: 7504
任务名称: 审批
任务的创建时间: Wed Oct 31 21:26:17 CST 2018
任务的办理人: null
流程实例ID: 7501
执行对象ID: 7501
流程定义ID: task:7:7404

接下来,我们查询李四的组任务

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
/**
* 查询当前人的组任务
*/
@Test
public void findMyGroupTask() {
String assignee = "李四";
List<Task> list = processEngine.getTaskService()
.createTaskQuery() // 创建任务对象
/*查询条件(部分)*/
.taskCandidateUser(assignee)
/*排序*/
.orderByTaskCreateTime().asc()
.list();
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: 7504
任务名称: 审批
任务的创建时间: Wed Oct 31 21:26:17 CST 2018
任务的办理人: null
流程实例ID: 7501
执行对象ID: 7501
流程定义ID: task:7:7404

我们再查询王五的组任务,显然,我们查询不出数据,因为他是总经理,不是部门经理。

拾取任务

既然是组任务,我们将其分配给张三,由张三去完成该任务。

1
2
3
4
5
6
7
8
9
10
11
/**
* 拾取任务,将组任务分配给个人任务,指定任务办理人Assignee字段
*/
@Test
public void claim() {
String taskId = "7504";
// 分配个人任务(可以是组任务的成员,也可以是非组任务的成员)
String userId = "张三";
processEngine.getTaskService()
.claim(taskId, userId);
}

执行代码,查询act_ru_task(正在执行的任务表)ASSIGNEE_字段的值为张三,我们成功将组任务分配给张三了。

完成任务

最后,我们让张三完成任务

1
2
3
4
5
6
7
8
9
/**
* 完成我的任务
*/
@Test
public void completeMyPersonalTask() {
String taskId = "7504";
processEngine.getTaskService().complete(taskId);
System.out.println("完成任务:任务Id:" + taskId);
}

这样,该流程就结束了。

总结

通过上面的例子,我们对用户角色组有所了解了。现在,我们来总结一下,本章用户角色组涉及到了一个新的service-identityService,我们可以通过其相关方法完成添加用户,角色,以及用户角色等相关操作。另外在我们还了解了与此有关的三张表及其作用。

act_id_group(角色表):用于存储工作流定义的角色

act_id_user(用户表):用于存储用户

act_id_membership(用户角色表):用于存储用户角色对应关系