flowable候选人和候选人组
之前在流程定义中的任务节点设置的负责人assignee都是固定的负责人,在流程定义设计时将参与者与文件固定设置了,如需变更任务负责人需要修改流程定义,系统可扩展性差。
针对这种情况可以给任务设置多个候选人或者候选人组,可以从候选人中选择参与者来完成任务。
这里讨论的是组任务,不同于流程变量来控制任务负责人。
1 候选人
1.1 设计流程
设计一个简单的新流程。
首先是“请假申请”,在分配用户项设置两个候选用户。
“经理审核”就设置一个${assignee0}
流程变量即可。
1.2 部署流程和启动流程实例
/**
* 部署流程
*/
@Test
public void deployment() {
//获取ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取RepositoryService对象,部署流程定义
RepositoryService repositoryService = processEngine.getRepositoryService();
//执行部署
repositoryService.createDeployment()
.addClasspathResource("flowable-4.bpmn20.xml")
.deploy();
}
/**
* 启动流程
*/
@Test
public void startProcess() {
//获取ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//通过RuntimeService启动流程
//通过流程定义ID启动流程实例
//流程定义的ID在流程部署成功后,act_re_procdef表生成的数据主键ID就是流程定义ID
RuntimeService runtimeService = processEngine.getRuntimeService();
//设置候选人流程变量
Map<String, Object> variables = new HashMap<>();
variables.put("candidate0", "员工1");
variables.put("candidate1", "员工2");
ProcessInstance processInstance = runtimeService.startProcessInstanceById("flowable-4:1:10004", variables);
// 输出相关的流程实例信息
System.out.println("流程定义的ID:" + processInstance.getProcessDefinitionId());
System.out.println("流程实例的ID:" + processInstance.getId());
}
流程启动后,act_ru_variable
表可以看到候选人流程变量
act_ru_task
表的ASSIGNEE_
字段是null
说明当前任务并没有分配给任何人,无人受理
1.3 任务查询
可以通过候选人进行查询任务
/**
* 候选人任务查询
*/
@Test
public void queryTaskCandidate() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取TaskService
TaskService taskService = processEngine.getTaskService();
List<Task> taskList = taskService.createTaskQuery().processInstanceId("12501")
//设置taskCandidateUser候选人条件来查询任务,这里的参数值就是候选人流程变量绑定的值
//员工1和员工2都是可以查询到数据的
.taskCandidateUser("员工1")
.list();
for (Task task : taskList) {
System.out.println("task.getId() = " + task.getId());
System.out.println("task.getName() = " + task.getName());
}
}
1.4 任务拾取
根据候选人查询到任务后就可以拾取该任务。注意:当一个任务被拾取后,其他用户是无法拾取该任务的。
任务拾取成功后,就会变成个人任务
/**
* 候选人拾取任务
*/
@Test
public void claimTaskCandidate() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取TaskService
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().processInstanceId("12501")
//设置taskCandidateUser候选人条件来查询任务,这里的参数值就是候选人流程变量绑定的值
//员工1和员工2都是可以查询到数据的
.taskCandidateUser("员工1")
.singleResult();
if (task != null) {
/**
* 拾取任务
* 即使该用户不是任务的候选人也可以拾取任务,建议拾取时做校验,根据候选人查询
* 任务拾取成功后,就会变成个人任务,之后的操作就和之前一样了,complete即可
*/
taskService.claim(task.getId(), "员工1");
}
}
说明:即使不是任务的候选人也可以进行拾取任务,所以需要根据任务候选人去查询任务再去进行拾取
1.5 任务归还
如果任务拾取之后不想操作或者误拾取任务也可以进行归还任务。
/**
* 任务归还
*/
@Test
public void unClaimTaskCandidate() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取TaskService
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().processInstanceId("12501")
//员工1拾取的任务,需要通过员工1查询
.taskAssignee("员工1")
.singleResult();
if (task != null) {
taskService.unclaim(task.getId());
}
}
任务成功归还后,ASSIGNEE_
就会为null,需要由任务候选人重新拾取
1.6 任务交接
如果任务拾取后,不想操作也不想归还,可以交接给他人进行处理。
/**
* 任务交接
*/
@Test
public void taskCandidate() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取TaskService
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().processInstanceId("12501")
//员工1拾取的任务,需要通过员工1查询
.taskAssignee("员工1")
.singleResult();
if (task != null) {
/**
* 任务交接,就是更新任务的分配人字段
* 由于可分配给任意的人员,所以建议实际开发中做判断处理,只将任务分配给候选人
*/
taskService.setAssignee(task.getId(), "员工3");
}
}
1.7 任务完成
就是之前正常处理流程,调用complete方法
/**
* 任务完成
*/
@Test
public void taskComplete() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取TaskService
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().processInstanceId("12501")
.taskAssignee("员工3")
.singleResult();
if (task != null) {
//流程设计的时候,经理审批有个`assignee0`流程变量,所以这里设置下
Map<String, Object> variables = new HashMap<>();
variables.put("assignee0", "经理");
taskService.complete(task.getId(), variables);
}
}
2 候选人组
当候选人很多的情况下,我们可以分组来处理。先创建组,然后把用户分配到这个组中。
2.1 管理用户和组
2.1.1 用户管理
通过act_id_user
表维护用户
/**
* 维护用户
*/
@Test
public void createUser() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 通过 IdentityService 完成相关的用户和组的管理
IdentityService identityService = processEngine.getIdentityService();
User user = null;
for (int i = 1; i <= 3; i++) {
user = identityService.newUser("员工" + i);
user.setFirstName(i+"");
user.setEmail(i+"@qq.com");
identityService.saveUser(user);
}
}
2.1.2 用户组管理
通过act_id_group
表维护
/**
* 维护用户组
*/
@Test
public void createGroup() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 通过 IdentityService 完成相关的用户和组的管理
IdentityService identityService = processEngine.getIdentityService();
Group group = identityService.newGroup("group1");
group.setName("研发部");
group.setType("1");
identityService.saveGroup(group);
}
2.1.3 用户和用户组关联
通过act_id_membership
表维护
/**
* 用户和用户组关联
*/
@Test
public void userGroup() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
IdentityService identityService = processEngine.getIdentityService();
// 根据组的编号找到对应的Group对象
Group group = identityService.createGroupQuery().groupId("group1").singleResult();
//找到用户
List<User> users = identityService.createUserQuery().list();
for (User user : users) {
//用户分配给用户组
identityService.createMembership(user.getId(), group.getId());
}
}
2.2 候选人组应用
用户和用户组的创建及关联搞清楚后,就可以使用候选人组实现流程任务分配了
2.2.1 设计流程
设计一个新的流程。
2.2.2 部署流程和启动流程实例
/**
* 部署流程
*/
@Test
public void deployment() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.createDeployment().addClasspathResource("flowable-5.bpmn20.xml").name("候选人组流程").deploy();
}
/**
* 启动流程
*/
@Test
public void startProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
//查询到用户组
IdentityService identityService = processEngine.getIdentityService();
Group group = identityService.createGroupQuery().groupId("group1").singleResult();
//然后给流程设计里面的${group1}流程变量赋值
Map<String, Object> variables = new HashMap<>();
variables.put("group1", group.getId());
runtimeService.startProcessInstanceById("flowable-5:1:32504", variables);
}
act_ru_identitylink
表中可以看到流程任务绑定的候选人组
2.2.3 任务的拾取和完成
/**
* 查询候选人组任务
*/
@Test
public void queryTaskCandidateGroup() {
//获取ProcessEngine引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//根据用户获取候选组
IdentityService identityService = processEngine.getIdentityService();
Group group = identityService.createGroupQuery().groupMember("员工1").singleResult();
//获取组任务
TaskService taskService = processEngine.getTaskService();
List<Task> taskList = taskService.createTaskQuery()
.processInstanceId("35001")
.taskCandidateGroup(group.getId())
.list();
for (Task task : taskList) {
System.out.println("task.getId() = " + task.getId());
System.out.println("task.getName() = " + task.getName());
}
}
/**
* 拾取组任务
* 就是通过候选组绑定查询出来的任务,然后拾取,和普通的流程任务操作一样
* 正常业务开发下,该组下的任务只能由该组人员拾取
* 拾取之后,不想操作的话也可以退还或者交接给他人
*/
@Test
public void claimTaskCandidate() {
//获取ProcessEngine引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//根据用户获取候选组
IdentityService identityService = processEngine.getIdentityService();
Group group = identityService.createGroupQuery().groupMember("员工1").singleResult();
//获取组任务
TaskService taskService = processEngine.getTaskService();
List<Task> taskList = taskService.createTaskQuery()
.processInstanceId("35001")
.taskCandidateGroup(group.getId())
.list();
for (Task task : taskList) {
System.out.println("task.getId() = " + task.getId());
System.out.println("task.getName() = " + task.getName());
//拾取
taskService.claim(task.getId(), "员工1");
System.out.println("任务:"+task.getName()+"拾取成功");
}
}
/**
* 完成组任务
* 就是完成正常的一个流程任务
*/
@Test
public void completeTask() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().processInstanceId("35001").taskAssignee("员工1").singleResult();
Assert.assertNotNull(task);
//流程设计的时候有个assignee0流程变量,这里需要设置下
Map<String, Object> variables = new HashMap<>();
variables.put("assignee0", "经理");
taskService.complete(task.getId(), variables);
}
启动流程实例之后,查询当前任务执行表:
select * from act_ru_task;
记录了当前执行的任务,由于该任务是组任务,assignee_
字段值是null,让拾取任务之后该字段才会有拾取用户的信息。
查询任务参与者:
select * from act_ru_identitylink
记录了参与任务用户或组,当前任务如果设置了候选人,就会向该表插入候选人记录,有几个候选人就插入几条记录,与act_ru_identitylink
对应的还有一张历史表act_hi_identitylink
,向act_ru_identitylink
插入记录的同时也会向act_hi_identitylink
插入记录。