Activiti动态设置办理人扩展
作者:Jesai
扩展是要求对Activiti基础有一定的功底的
我们一直在努力,不是为了改变世界,只是不让世界去改变我们。
关键词:Assignee、Candidate users、Candidate groups;setAssignee、taskCandidateUser、taskCandidateGroup
主要解决问题:Activiti动态给任务节点设置办理人。
情景:
我们在做工作流开发,学习的时候一般都有这么一个过程:
第一阶段:最开始学习的时候,喜欢在设计流程的时候写死人名(即)办理人,这个阶段是入门级。而且你也会觉得这样做非常 so easy(方便、简单)。可是慢慢的,你就会发现,每次需要换人,你就要重新设计流程实例(workflow processInstance),一系列的design->Deployment->start processInstance,从此你再也不觉得so easy 了。
第二阶段:于是你开始使用了EL表达式变量,这个阶段代表你已经到了提升阶段。可以使用委托类来设置办理人了,是动态的设置哦。但是,你并没有整合自己的权限系统,用的还是Activiti官方的user表和group表,慢慢的,你发现一旦自己的权限系统角色和用户做了调整,那么自己还得去维护这几个表。
第三阶段:于是,你开始整合自己的权限系统,这个阶段基本是熟练了,可以说是已经完美了。但是这个阶段,每次发送的时候,我们还需要选择一个人去办理他,但是个人觉得,要达到完美状态是不可能的,但是我们还可以自己去做扩展使得它更加的好用,达到我们逾期的目的,(个人观点)。
第四阶段:其实很多人都会去扩展功能的,源码改造,或者模块扩展。在流程部署的时候就设置好办理人,这样,每次发送的时候,我们并不需要去选择办理人。
设置办理人色几种方案
我们先回顾一下,比较传统的动态设置任务办理人的几种方法:
第一种:在流程设置死,这个感觉无需多说,就是在设计流程的时候,在Assignee里面填写我们的办理人姓名或者相关的ID即可。
第二种:通过委托类(监听类)设置。在流程设计的时候设置监听类,并且在办理人里面设置EL表达式 ${UserId}(随便自己命名)。然后每次办理的时候选择一个办理人。然后传递一个变量过去,然后下一个环节的监听类会设置办理人。
1 Map<String,Object> map = delegateTask.getVariables(); 2 3 delegateTask.setAssignee(map.get("UserId").toString());
设置办理人可能有三种方案,
设置办理人的三种方案是有优先级的。
设置办理人优先级:
Assignee>Candidate users>Candidate groups。
设置办理人色几种模式
第一种:指定办理人模式,即设置办理人,就是设置Assignee。Assignee 受让人; 受托人,代理人; 被指定人;办理人只能指定一个人,不能使用逗号分隔。默认执行签收操作taskService.claim(taskId, currentUserId);在ACT_HI_TASKINST和ACT_RU_TASK会产生数据,这两个表里面的Assignee_字段就是设置的办理人姓名或者对象的ID
第二种:设置候选用户,候选用户设置办理人不是很多的情况下使用,而且需要签收,也就是说我们常说的抢件模式,Candidate users 候选用户,设置候选组的前提是没有指定Assignee,(即没有执行签收操作)。设置候选组需要主动签taskService.claim(taskId, currentUserId);
第三种:这只候选组,这个就是这只办理角色或者办理岗位,适合使用在办理人比较多的情况下,而且涉及到几个部门的情形。Candidate groups 候选组
候选组与候选用户类似,只是要获取候选用户,需要根据候选组找到对应的用户。
涉及API:
1 taskService.createTaskQuery().taskAssignee(param);
根据用户来查询任务(待办任务)
1 taskService.createTaskQuery().taskCandidateUser(param);
根据候选用户查询任务(待签收任务)
1 taskService.createTaskQuery().taskCandidateGroup(param);
候选组查询任务(待签收任务)
1 TaskService().setAssignee(taskId,userId);
设置办理人
1 taskService().addCandidateGroup(taskId, groupid);
这只候选组,可以添加多个,每次一个addCandidateGroup添加一个
1 taskService().addCandidateUser(taskId,userid);
这只候选用户,可以添加多个,每次一个addCandidateUser添加一个
1 taskService.claim(taskId, currentUserId);
签收操作。
扩展实现
扩展需要添加中间表,我们使用TDD(驱动开发模式)来实现。
需呀增加一个中间表。
流程办理人表(act_comm_taskassignee)
字段 |
名称 |
是否为空 |
备注 |
ID |
主键ID |
M |
|
SID |
节点ID |
M |
|
assignee |
办理人 |
O |
|
rolegroup |
候选组 |
O |
|
assigneeType |
办理人类型 |
M |
1办理人,2为候选人,3为候选组 |
activitiname |
节点名称 |
O |
建表SQL:
1 CREATE TABLE `act_comm_taskassignee` ( 2 3 `Id` int(11) NOT NULL AUTO_INCREMENT, 4 5 `Sid` varchar(45) NOT NULL, 6 7 `assignee` varchar(45) DEFAULT NULL, 8 9 `rolegroup` varchar(45) DEFAULT NULL, 10 11 `assigneeType` varchar(45) DEFAULT NULL, 12 13 `assigneename` varchar(200) DEFAULT NULL, 14 15 `activitiname` varchar(255) DEFAULT NULL, 16 17 PRIMARY KEY (`Id`), 18 19 UNIQUE KEY `Id_UNIQUE` (`Id`) 20 21 ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
实体Model:
1 /** 2 3 * 4 5 */ 6 7 package light.mvc.model.workflow; 8 9 10 11 import javax.persistence.Entity; 12 13 import javax.persistence.Table; 14 15 16 17 import light.mvc.model.base.IdEntity; 18 19 20 21 import org.hibernate.annotations.DynamicInsert; 22 23 import org.hibernate.annotations.DynamicUpdate; 24 25 26 27 /** 28 29 * 30 31 * 项目名称:lightmvc 32 33 * 类名称:FlowAssignee 34 35 * 类描述: 36 37 * 创建人:邓家海 38 39 * 创建时间:2017年8月15日 下午10:01:46 40 41 * 修改人:deng 42 43 * 修改时间:2017年8月15日 下午10:01:46 44 45 * 修改备注: 46 47 * @version 48 49 * 50 51 */ 52 53 @Entity 54 55 @Table(name="act_comm_taskassignee") 56 57 @DynamicInsert(true) 58 59 @DynamicUpdate(true) 60 61 public class FlowAssignee extends IdEntity implements java.io.Serializable { 62 63 private String sid; 64 65 /** 66 67 * @return the activitiname 68 69 */ 70 71 public String getActivitiname() { 72 73 return activitiname; 74 75 } 76 77 78 79 /** 80 81 * @param activitiname the activitiname to set 82 83 */ 84 85 public void setActivitiname(String activitiname) { 86 87 this.activitiname = activitiname; 88 89 } 90 91 92 93 private String assignee; 94 95 private String rolegroup; 96 97 private String activitiname; 98 99 private Integer assigneetype; 100 101 102 103 public FlowAssignee(){ 104 105 super(); 106 107 } 108 109 110 111 public FlowAssignee(String sid,String assignee,String rolegroup,Integer assigneetype,String activitiname){ 112 113 super(); 114 115 this.assignee=assignee; 116 117 this.sid=sid; 118 119 this.rolegroup=rolegroup; 120 121 this.assigneetype=assigneetype; 122 123 this.activitiname=activitiname; 124 125 } 126 127 128 129 /** 130 131 * @return the sid 132 133 */ 134 135 public String getSid() { 136 137 return sid; 138 139 } 140 141 142 143 /** 144 145 * @param sid the sid to set 146 147 */ 148 149 public void setSid(String sid) { 150 151 this.sid = sid; 152 153 } 154 155 156 157 /** 158 159 * @return the assignee 160 161 */ 162 163 public String getAssignee() { 164 165 return assignee; 166 167 } 168 169 170 171 /** 172 173 * @param assignee the assignee to set 174 175 */ 176 177 public void setAssignee(String assignee) { 178 179 this.assignee = assignee; 180 181 } 182 183 184 185 /** 186 187 * @return the rolegroup 188 189 */ 190 191 public String getRolegroup() { 192 193 return rolegroup; 194 195 } 196 197 198 199 /** 200 201 * @param rolegroup the rolegroup to set 202 203 */ 204 205 public void setRolegroup(String rolegroup) { 206 207 this.rolegroup = rolegroup; 208 209 } 210 211 212 213 /** 214 215 * @return the assigneetype 216 217 */ 218 219 public Integer getAssigneetype() { 220 221 return assigneetype; 222 223 } 224 225 226 227 /** 228 229 * @param assigneetype the assigneetype to set 230 231 */ 232 233 public void setAssigneetype(Integer assigneetype) { 234 235 this.assigneetype = assigneetype; 236 237 } 238 239 240 241 }
核心实现代码:
第一步:根据部署ID来查找所有的节点,目的(找到节点ID):
1 @Test 2 3 public void getDeploymentActivitiIdList(){ 4 5 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 6 7 8 9 String deploymantId="57577"; 10 11 12 13 ProcessDefinition processDefinition=processEngine.getRepositoryService().createProcessDefinitionQuery().deploymentId(deploymantId).singleResult(); 14 15 16 17 ProcessDefinitionEntity processDefinitionEntity=(ProcessDefinitionEntity)((RepositoryServiceImpl) processEngine 18 19 .getRepositoryService()).getDeployedProcessDefinition(processDefinition.getId()); 20 21 22 23 List<ActivityImpl> activityList=processDefinitionEntity.getActivities(); 24 25 26 27 for(ActivityImpl activiti:activityList) { 28 29 System.out.println("节点ID:"+activiti.getId()); 30 31 32 33 System.out.println("节点名称:"+activiti.getProperty("name")); 34 35 } 36 37 }
第二步,设置办理人,或者候选组,用户:
1 /** 2 3 * 1.设置办理人,一个节点一个办理人,指定办理人模式,不需要签收,办理人模式 4 5 * 2。设置岗位 1)通过角色,查找权限表,签收模式,角色岗位模式 6 7 * 2)通过节点——>办理人,签收模式,节点(一)-->办理人(多) ,角色岗位模式 8 9 */ 10 11 @Test 12 13 public void setAgneeByActivitiSid(){ 14 15 Session session = sessionFactory.openSession(); 16 17 String sid="sid-AEC4023A-DEB1-44C8-8784-C3C10F6B484A"; //节点id 18 19 String ActivitiName="总经理"; //节点名称 20 21 FlowAssignee fa=new FlowAssignee(); 22 23 fa.setActivitiname(ActivitiName); 24 25 fa.setAssignee("张三"); //办理人 26 27 fa.setAssigneetype(1); //1是指定办理人,2是指定岗位 28 29 fa.setSid(sid); 30 31 session.save(fa); 32 33 34 35 36 37 sid="sid-C8781FAE-02B8-4F8D-9A7D-A8AB4A8CB95A"; //节点id 38 39 ActivitiName="经理"; //节点名称 40 41 fa=new FlowAssignee(); 42 43 fa.setActivitiname(ActivitiName); 44 45 fa.setActivitiname(ActivitiName); 46 47 //fa.setAssignee("李四"); //办理人 设置候选组,不能设置办理人 48 49 fa.setRolegroup("产品部"); //办理岗位 50 51 fa.setAssigneetype(1); //1是指定办理人,2是指定岗位 52 53 fa.setSid(sid); 54 55 session.save(fa); 56 57 58 59 session.flush(); 60 61 }
第三步:设置启动流程,并设置第一个环节的办理人:
1 @Test 2 3 public void SetAgnee(){ 4 5 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 6 7 8 9 String deploymantId="57577"; 10 11 String pid=processEngine.getRepositoryService().createProcessDefinitionQuery().deploymentId(deploymantId) 12 13 .singleResult().getId(); 14 15 ProcessInstance pi = processEngine.getRuntimeService()//与正在执行的流程实例和执行对象相关的service 16 17 .startProcessInstanceById(pid);//使用流程定义的KEY启动流程实例,key对应helloword。bpmn中对应的ID属性值 18 19 20 21 String pdid=pi.getProcessDefinitionId(); 22 23 24 25 List<Task> taskList=processEngine.getTaskService().createTaskQuery().deploymentId(deploymantId).active().list(); 26 27 28 29 for(Task task:taskList){ 30 31 ExecutionEntity execution = (ExecutionEntity)processEngine.getRuntimeService().createExecutionQuery().executionId(task.getExecutionId()) 32 33 .singleResult(); 34 35 String activitiId = execution.getActivityId(); 36 37 38 39 Session session = sessionFactory.openSession(); 40 41 List<FlowAssignee> list=session.createQuery("from FlowAssignee where sid='"+activitiId+"'").list(); 42 43 44 45 if(list.size()>0) 46 47 for(FlowAssignee fa:list){ 48 49 if(fa.getAssigneetype()==1){ 50 51 processEngine.getTaskService().setAssignee(task.getId(), fa.getAssignee()); 52 53 }else if(fa.getAssigneetype()==2){ 54 55 processEngine.getTaskService().addCandidateUser(task.getId(), fa.getAssignee()); 56 57 }else if(fa.getAssigneetype()==3){ 58 59 processEngine.getTaskService().addCandidateGroup(task.getId(), fa.getRolegroup()); 60 61 } 62 63 64 65 66 67 } 68 69 70 71 } 72 73 }
到这里,我们的就已经完成了根据节点设置办理人的人:
查询一下:
1 @Test 2 3 public void getMyTask(){ 4 5 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 6 7 String CandGroup="产品部"; 8 9 Task task=processEngine.getTaskService().createTaskQuery().taskCandidateGroup(CandGroup).active().singleResult(); 10 11 List<IdentityLink> ilList=processEngine.getTaskService().getIdentityLinksForTask(task.getId()); 12 13 System.out.println("办理人:"+task.getAssignee()); 14 15 System.out.println("任务ID:"+task.getId()); 16 17 System.out.println("任务ID:"+task.getName()); 18 19 for(IdentityLink i:ilList){ 20 21 System.out.println("组ID:"+i.getGroupId()); 22 23 System.out.println("用户:"+i.getUserId()); 24 25 } 26 27 28 29 }
结果是正确的。
注意:
设置办理人、候选人、候选组,三个是有有优先级的,不能同时设置,同时设置等价于执行了签收操作。
扩展是要求对Activiti基础有一定的功底的,如果不是很熟悉,请先使用委托类或者直接设置办理人
本文主要实现了核心功能,整合到系统功能暂时还没实现。但是有基础的人看完本文就会知道怎么进行扩展。
Activiti交流QQ群:634320089