使用Group对Flowable中的某一类用户进行分类,但这其实和我们平时在自己系统中使用的角色类似。也就是说,我们可以根据角色为每个UserTask设置一个handler。下面宋哥就来和小伙伴们聊聊这里的一些细节。1.用户和用户组首先我们来看一下用户组的一些基本操作。1.1添加组组的属性比较少,添加方法和user类似:@Testvoidtest09(){GroupEntityImplg=newGroupEntityImpl();g.setName("组长");g.setId("领导者");g.setRevision(0);identityService.saveGroup(g);}添加后,组信息保存在ACT_ID_GROUP表中,如下图:组创建完成后,下一步就是将用户添加到组中。添加方法如下:identityService.createMembership("zhangsan","leader");identityService.createMembership("lisi","leader");这是设置zhangsan和lisi为群主(注意用户和群的关系表中有外键,所以需要保证两个参数都是真实的)。添加关联关系后,我们查看ACT_ID_MEMBERSHIP表,如下:使用如下方法删除关联关系:identityService.deleteMembership("zhangsan","leader");1.2修改组如下,更新id为leader的组名为leader,如下:Groupg=identityService.createGroupQuery().groupId("leader").singleResult();g.setName("leader");identityService.saveGroup(g);1.3删除组删除组的方法如下:identityService.deleteGroup("leader");删除群组时,也会删除群组与用户的关系,但不用担心用户被删除。1.4查询群组可以根据id或者name或者群组成员信息查询群组:Groupg1=identityService.createGroupQuery().groupId("leader").singleResult();System.out.println("g1.getName()="+g1.getName());Groupg2=identityService.createGroupQuery().groupName("Groupleader").singleResult();System.out.println("g2.getId()="+g2.getId());Listlist=identityService.createGroupQuery().groupMember("zhangsan").list();for(Groupgroup:list){System.out.println("group.getName()="+group.getName());}2.设置候选组在画流程图的时候,我们可以给UserTask设置一个候选组,方法如下:从这个地方也可以看出,最后的选择可以给多个。好了,设置完成后,我们来下载流程图的XML文件,再看看这个地方的区别:测试流程朋友们看到了,flowable:candidateGroups="leader"表示这个任务是由一个Candidate用户管理的组用于处理。如果有多个候选用户组,不同的用户组之间用.隔开。当然,这是硬编码的。如果想像候选用户一样通过动态变量传递用户组名,具体方法如下:这样,最终生成的XML文件类似这样:flowable:candidateGroups="${g1}"。3、根据用户组查询任务接下来,我们部署启动一个流程。具体的部署和启动方法,宋大哥在上一篇文章中已经介绍过了。下面简单看一下这个方法:@Testvoidtest01(){Mapvariables=newHashMap<>();variables.put("g1","leader");ProcessInstancepi=runtimeService.startProcessInstanceByKey("demo01",变量);logger.info("id:{},activityId:{}",pi.getId(),pi.getActivityId());}这是启动进程的过程。注意在开始的时候加上参数,描述下一个UserTask的处理组。启动成功后,我们可以在ACT_RU_IDENTITYLINK表中查看用户组和UserTask的关系:接下来我们可以通过查询候选任务的方式查询zhangsan需要完成的工作,如下:@Testvoidtest19(){List<任务>list=taskService.createTaskQuery().taskCandidateUser("zhangsan").list();for(Tasktask:list){logger.info("name:{},createTime:{}",task.getName(),task.getCreateTime());}}该查询的内部实现分为两步:查找zhangsan属于哪个组,该查询执行的SQL如下:SELECTRES.*fromACT_ID_GROUPRESWHEREexists(select1fromACT_ID_MEMBERSHIPMwhereM.GROUP_ID_=RES.ID_andM.USER_ID_=?)orderbyRES.ID_asc查询中有一个参数,参数的值为zhangsan,上面的SQL可以查询出用户zhangsan属于leader分组,在接下来的查询中,参数zhangsan和leader都会用到。查询zhangsan或leader的任务,执行SQL如下:SELECTRES.*fromACT_RU_TASKRESWHERERES.ASSIGNEE_isnullandexists(selectLINK.ID_fromACT_RU_IDENTITYLINKLINKwhereLINK.TYPE_='candidate'andLINK.TASK_ID_=RES.ID_and(LINK.USER_ID_=?or(LINK.GROUP_ID_IN(?))))orderbyRES.ID_asc可以看到这个查询有两个参数,两个参数的值分别是张三和领队。也就是说这里的代码虽然是根据zhangsan去查询,但实际上查询的是zhangsan所属用户组的任务(这个逻辑也很好理解,因为哪个用户组的任务张三属于其实是张三的任务)。当然,我们也可以直接按组查询,如下:@Testvoidtest20(){Listlist=taskService.createTaskQuery().taskCandidateGroup("leader").list();for(Tasktask:list){logger.info("name:{},createTime:{}",task.getName(),task.getCreateTime());}}这个查询的原理和上面的类似,但是简单的是,这里一条SQL就搞定了(不需要根据用户名查询用户所属的组),如如下:从ACT_RU_TASKRES中选择RES.*,其中RES.ASSIGNEE_为空且存在(从ACT_RU_IDENTITYLINKLINK中选择LINK.ID_,其中LINK.TYPE_='候选人'和LINK。TASK_ID_=RES.ID_和((LINK.GROUP_ID_IN(?))))orderbyRES.ID_as好了,当查询到这些任务后,接下来如何执行,和前面介绍的内容是一样的。这里我就不细说了。