1. 说明
Activiti中内置了一套用户、用户组关系,以及对它们的操作API。关于用户和用户组表工业四张,如下图:
表名 | 含义 |
---|---|
act_id_user | 身份信息-用户信息 |
act_id_group | 身份信息-组信息 |
act_id_info | 身份信息-用户扩展信息表 |
act_id_membership | 身份信息-用户和组关系的中间表 |
2. 用户与用户组表的介绍
1、ACT_ID_USER(用户信息表)
2、ACT_ID_INFO(用户扩展信息表)
3、ACT_ID_GROUP(用户组信息表)
4、ACT_ID_MEMBERSHIP(用户与用户组关系信息表)
3. 项目中用户和角色与Activiti中的用户、用户组整合
通常来说在项目中都已经是有了用户和角色权限功能。比如我创建了一个springboot项目,已经创建了用户表和角色表,那么如何将项目本身的用户和角色与activiti的用户、用户组整合在一起啦。
我的思路:在项目中创建了用户时,同时也需要将用户与Activiti的用户关联起来,直接通过id关联即可。
3.1 整合
/**
* 把自定义用户同步到activiti用户
*/
@Test
public void addUser(){
List<com.yb.domain.User> all = userDao.findAll();
for (com.yb.domain.User user : all) {
User user1 = identityService.newUser(user.getUid()+"");
user1.setFirstName(user.getUsername());
user1.setPassword(user.getPassword());
identityService.saveUser(user1);
}
}
/**
* 查询用户信息
*/
@Test
public void queryUser(){
User user = identityService.createUserQuery()
.userId("1")
.singleResult();
System.out.println(user.getFirstName());
}
/**
* 创建activiti用户组
*/
@Test
public void addGroup(){
Group group1 = identityService.newGroup("group1");
group1.setName("主管组");
group1.setType("主管组");
identityService.saveGroup(group1);
Group group2 = identityService.newGroup("group2");
group2.setName("总监组");
group2.setType("总监组");
identityService.saveGroup(group2);
Group group3 = identityService.newGroup("group3");
group3.setName("项目经理组");
group3.setType("项目经理组");
identityService.saveGroup(group3);
Group group4 = identityService.newGroup("group4");
group4.setName("员工组");
group4.setType("员工组");
identityService.saveGroup(group4);
Group group5 = identityService.newGroup("group5");
group5.setName("人力资源组");
group5.setType("人力资源组");
identityService.saveGroup(group5);
}
/**
* 查询用户组
*/
@Test
public void queryGroup( ){
Group group = identityService.createGroupQuery()
.groupId("group1")
.singleResult();
System.out.println(group.getId());
System.out.println(group.getName());
System.out.println(group.getType());
}
/**
* 创建用户-用户组之间的关系
*/
@Test
public void addMembership( ){
identityService.createMembership("1", "group4");
identityService.createMembership("3", "group3");
identityService.createMembership("4", "group3");
identityService.createMembership("5", "group3");
identityService.createMembership("6", "group5");
}
/**
* 查询属于用户组group3的用户
*/
@Test
public void queryUserListByGroup( ){
//查询属于组group1的用户
List<User> usersInGroup = identityService.createUserQuery()
.memberOfGroup("group3")
.list();
for (User user : usersInGroup) {
System.out.println(user.getFirstName());
}
}
数据库:
用户表
中间表
用户组表
3.2 测试
流程图
Bpmn文件
可以看到设置项目经理审批节点的组为’group3’,也就是项目经理组,属于这个组的人员都可以进行审批
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 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" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1597729482723" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="parallel" isClosed="false" isExecutable="true" processType="None">
<startEvent id="_2" name="开始"/>
<userTask activiti:candidateGroups="group3" activiti:exclusive="true" id="_3" name="项目经理审批"/>
<parallelGateway gatewayDirection="Unspecified" id="_4" name="ParallelGateway"/>
<userTask activiti:assignee="user2" activiti:exclusive="true" id="_5" name="上级领导审批"/>
<userTask activiti:assignee="user3" activiti:exclusive="true" id="_6" name="董事长审批"/>
<userTask activiti:assignee="user4" activiti:exclusive="true" id="_7" name="主管审批"/>
<userTask activiti:assignee="user5" activiti:exclusive="true" id="_8" name="总监审批"/>
<parallelGateway gatewayDirection="Unspecified" id="_9" name="ParallelGateway"/>
<endEvent id="_10" name="结束"/>
<sequenceFlow id="_11" sourceRef="_2" targetRef="_3"/>
<sequenceFlow id="_12" sourceRef="_3" targetRef="_4"/>
<sequenceFlow id="_13" sourceRef="_4" targetRef="_5"/>
<sequenceFlow id="_14" sourceRef="_4" targetRef="_7"/>
<sequenceFlow id="_15" sourceRef="_5" targetRef="_6"/>
<sequenceFlow id="_16" sourceRef="_7" targetRef="_8"/>
<sequenceFlow id="_17" sourceRef="_6" targetRef="_9"/>
<sequenceFlow id="_18" sourceRef="_8" targetRef="_9"/>
<sequenceFlow id="_19" sourceRef="_9" targetRef="_10"/>
</process>
<bpmndi:BPMNDiagram documentation="background=#000000;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
<bpmndi:BPMNPlane bpmnElement="parallel">
<bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
<omgdc:Bounds height="32.0" width="32.0" x="285.0" y="-10.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
<omgdc:Bounds height="55.0" width="85.0" x="260.0" y="60.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
<omgdc:Bounds height="32.0" width="32.0" x="285.0" y="145.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
<omgdc:Bounds height="55.0" width="85.0" x="190.0" y="265.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6" id="Shape-_6">
<omgdc:Bounds height="55.0" width="85.0" x="190.0" y="405.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_7" id="Shape-_7">
<omgdc:Bounds height="55.0" width="85.0" x="335.0" y="265.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_8" id="Shape-_8">
<omgdc:Bounds height="55.0" width="85.0" x="335.0" y="405.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_9" id="Shape-_9">
<omgdc:Bounds height="32.0" width="32.0" x="290.0" y="530.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_10" id="Shape-_10">
<omgdc:Bounds height="32.0" width="32.0" x="290.0" y="645.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_13" id="BPMNEdge__13" sourceElement="_4" targetElement="_5">
<omgdi:waypoint x="285.0" y="161.0"/>
<omgdi:waypoint x="235.0" y="230.0"/>
<omgdi:waypoint x="235.0" y="265.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_12" id="BPMNEdge__12" sourceElement="_3" targetElement="_4">
<omgdi:waypoint x="301.0" y="115.0"/>
<omgdi:waypoint x="301.0" y="145.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_15" id="BPMNEdge__15" sourceElement="_5" targetElement="_6">
<omgdi:waypoint x="232.5" y="320.0"/>
<omgdi:waypoint x="232.5" y="405.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_14" id="BPMNEdge__14" sourceElement="_4" targetElement="_7">
<omgdi:waypoint x="317.0" y="161.0"/>
<omgdi:waypoint x="375.0" y="225.0"/>
<omgdi:waypoint x="375.0" y="265.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_17" id="BPMNEdge__17" sourceElement="_6" targetElement="_9">
<omgdi:waypoint x="235.0" y="460.0"/>
<omgdi:waypoint x="235.0" y="490.0"/>
<omgdi:waypoint x="290.0" y="546.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_16" id="BPMNEdge__16" sourceElement="_7" targetElement="_8">
<omgdi:waypoint x="377.5" y="320.0"/>
<omgdi:waypoint x="377.5" y="405.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_19" id="BPMNEdge__19" sourceElement="_9" targetElement="_10">
<omgdi:waypoint x="306.0" y="562.0"/>
<omgdi:waypoint x="306.0" y="645.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_18" id="BPMNEdge__18" sourceElement="_8" targetElement="_9">
<omgdi:waypoint x="380.0" y="460.0"/>
<omgdi:waypoint x="380.0" y="490.0"/>
<omgdi:waypoint x="322.0" y="546.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_11" id="BPMNEdge__11" sourceElement="_2" targetElement="_3">
<omgdi:waypoint x="301.0" y="22.0"/>
<omgdi:waypoint x="301.0" y="60.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
测试类
/**
* 部署流程,测试用户组审批
*/
@Test
public void repositoryDeploy(){
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("processes/activiti_ParallelFallback.bpmn")
.addClasspathResource("processes/activiti_ParallelFallback.png")
.name("测试用户组审批-1")
.deploy();
System.out.println("部署ID:"+deploy.getId());
System.out.println("部署名称"+deploy.getName());
}
/**
* 发布流程
*/
@Test
public void runtimeRelease(){
ProcessInstance pi = runtimeService.startProcessInstanceByKey("parallel");
System.out.println("流程实例ID:"+pi.getId());
System.out.println("流程定义ID:"+pi.getProcessDefinitionId());
}
/**
* 查询及完成任务
*/
@Test
public void taskQueryComplete(){
List<Task> list = taskService.createTaskQuery()
.taskName("项目经理审批")
.list();
for (Task task : list) {
System.out.println("--------------------------------------------");
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("--------------------------------------------");
// taskService.complete(task.getId());
List<IdentityLink> identityLinksForTask = taskService.getIdentityLinksForTask(task.getId());
for (IdentityLink identityLink : identityLinksForTask) {
System.out.println(identityLink.getGroupId());
//查询属于组group3(项目经理子)的用户
List<User> usersInGroup = identityService.createUserQuery()
.memberOfGroup(identityLink.getGroupId())
.list();
for (User user : usersInGroup) {
System.out.println(user.getFirstName());
// 这一步可根据当前登录的用户判断是否属于项目经理组,属于,就可以为此分配任务
if(user.getFirstName().equals("王二")){
taskService.claim(task.getId(),user.getFirstName());
}
}
}
}
}
/**
* 拾取任务还可以回退给用户组
*/
@Test
public void test01(){
//此方式如果有审批人拾取到任务不想审批,可以回退给用户组,让其他人审批
Task task = taskService.createTaskQuery()
.taskName("项目经理审批")
.singleResult();
taskService.setAssignee(task.getId(),null);
}
/**
* 完成任务
*/
@Test
public void test02(){
Task task = taskService.createTaskQuery()
.taskAssignee("王二")
.singleResult();
taskService.complete(task.getId());
}
效果:
所有属于项目经理组的人员都可以看到项目经理审批任务,只需一个人审批通过即可完成该任务,下图是任务完成后走向了并行流程。