关于Activiti工作流委托代理人方案实现
作者:Jesai
生活就要像写代码,一行行的去写。认认真真,整整齐齐,漂漂亮亮,干干净净,简洁明了!
梦想还是要有的,万一就实现了呢
前言:
现实生活里面,我们上司可能工作繁忙,经常不在公司或者出差,这个时候,上司就会委托一个得力助手在他不在公司的这段时间处理一些事务。包括文件审批,战略决策,财务审批等工作。这个时候,被委托人拥有委托人部分或者全部的权力。权力的大小取决于委托人授予你多少。那么,这个委托人是拥有绝对主动权的,也就是说委托人可以随时回收被委托人的全力。当委托人不授予(回收)权力的时候,被委托人就没有决策的能力了。还有一种情况就是,委托人在某一段时间内进行委托操作。一旦超过了或者不在这个委托时间段里面,被委托也是没有委托权限来决策的。委托的方式也可能有几种,第一种:委托具体的某一个或者具体某一项决策。第二种:委托某一部分或者某一个领域决策。第三种:全权委托。通俗的讲,第一种就是一次性行为,整个周期就是这件事情的开始到结束。第二种就是某一个方面,这个方面你来管理决策。第三种就是管理委托人所拥有的一切决策和能力。
要素:
(1)委托的范围(某一项、某一类、全部)
(2)委托的时间(无限期、某一时间段)
(3)委托的绝对主动权(委托人拥有绝对主动权,随时回收或者委托)
(4)存据(委托有效的依据、不能越权办事,也不能先办事后授权)
当前已有方案:
当前已有工作流可以实现的方案是基于某一个task(任务)的委托。比如编号为10001的任务,我没有时间去看具体的事项,那么。我需要委托一个人来帮我办理这个任务。这个方案目前只能很不灵活。也就是说很不适用。因为假如有10000个这类任务,那么我需要委托10000次。显然这个方案是笨拙的。然后回到我们问题的本身。我们是要实现某一个时间段里面可以实行委托操作的。比如,上司出差。委托甲来全权负责公司的请假审批。请乙负责公司的人力资源审批。请丙丁两个人共同来审核公司的财务管理。
旧方案实现
1 //直接委托任务 2 @RequestMapping("/taskEntrust") 3 @ResponseBody 4 public Json taskEntrust(@RequestParam String taskId,@RequestParam String taskAssignee){ 5 Json j=new Json(); 6 try{ 7 Task task=taskService.createTaskQuery().taskId(taskId).active().singleResult(); 8 taskService.delegateTask(task.getId(), taskAssignee); 9 j.setMsg("任务委托成功!"); 10 j.setSuccess(true); 11 }catch(Exception ex){ 12 ex.printStackTrace(); 13 j.setMsg("任务委托失败"); 14 } 15 return j; 16 }
你可以看到,其实这个实现是很笨拙的,他就是流程转发的一种,流程转发是这么来实现的
1 //指派任务 2 @RequestMapping("/assignProcessInstance") 3 @ResponseBody 4 public Json assignProcessInstance(@RequestParam String taskId,@RequestParam String taskAssignee){ 5 Json j=new Json(); 6 try{ 7 taskService.createTaskQuery().taskId(taskId).singleResult().setAssignee(taskAssignee); 8 j.setMsg("任务指派成功!"); 9 j.setSuccess(true); 10 }catch(Exception ex){ 11 ex.printStackTrace(); 12 j.setMsg("任务指派失败"); 13 } 14 return j; 15 }
那么我们要实现灵活控制工作流,在我们的OA系统就需要考虑那几个方面的因素:
考虑因素:
(1)不同任务委托给不同人
(2)全盘委托
(3)委托给多个人共同决策(一票否决,一票通过)
(4)委托时间
案例:
原来正常的流程:
现在部门主管需要出差,那么我们原先的计划是,部门主管超时未处理的任务会直接提交给总经理。当然这个时候是部门主管不作为,就是部门主管不干事。那么部门主管需要委托人来办理他的任务,那么他需要怎么做呢。这就是我们需要做的任务了。
(1)委托到某一个人
(2)委托到多个人共同决策
一般是第一种情况出现的最多,那么我们先考虑第一种情况,第二种情况后续再考虑。
设计表:
表act_ru_delegate
字段 |
类型 |
长度 |
是否必填 |
属性 |
描述 |
ID |
BIGINT |
20 |
M |
Pk |
|
ASSIGNEE |
VARCHAR |
200 |
O |
|
办理人 |
ATTORNEY |
VARCHAR |
200 |
O |
|
代理人 |
START_TIME |
TIMESTAMP |
|
O |
|
CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
END_TIME |
TIMESTAMP |
|
O |
|
'0000-00-00 00:00:00' |
PROCESS_DEFINITION_ID |
VARCHAR |
100 |
O |
Fk |
|
STATUS |
INT |
11 |
O |
|
表act_hi_delegate
字段 |
类型 |
长度 |
是否必填 |
属性 |
描述 |
ID |
BIGINT |
20 |
M |
Pk |
|
ASSIGNEE |
VARCHAR |
200 |
O |
|
办理人 |
ATTORNEY |
VARCHAR |
200 |
O |
|
代理人 |
DELEGATE_TIME |
TIMESTAMP |
|
O |
|
CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
TASK_ID |
VARCHAR |
100 |
O |
Fk |
任务ID |
STATUS |
INT |
11 |
O |
|
Model实现:
(1)DelegateHistory类
1 /** 2 * 3 */ 4 package light.mvc.workflow.model; 5 6 import java.sql.Date; 7 8 import javax.persistence.Column; 9 import javax.persistence.Entity; 10 import javax.persistence.Table; 11 import javax.persistence.Temporal; 12 import javax.persistence.TemporalType; 13 14 import org.hibernate.annotations.DynamicInsert; 15 import org.hibernate.annotations.DynamicUpdate; 16 import org.hibernate.validator.constraints.NotBlank; 17 18 /** 19 * 20 * 项目名称:lightmvc 21 * 类名称:DelegateHistory 22 * 类描述: 23 * 创建人:邓家海 24 * 创建时间:2017年6月3日 下午2:37:13 25 * 修改人:deng 26 * 修改时间:2017年6月3日 下午2:37:13 27 * 修改备注: 28 * @version 29 * 30 */ 31 @Entity 32 @Table(name = "act_hi_delegate") 33 @DynamicInsert(true) 34 @DynamicUpdate(true) 35 public class DelegateHistory { 36 private String Assignee; 37 private String Attorney; 38 private Date Delegate_Time; 39 private String TaskId; 40 private Integer Status; 41 public DelegateHistory(){ 42 super(); 43 } 44 public DelegateHistory(String assignee,String attorney, Date delegate_time, String taskId,Integer status){ 45 super(); 46 this.Assignee=assignee; 47 this.Attorney=attorney; 48 this.Delegate_Time=delegate_time; 49 this.TaskId=taskId; 50 this.Status=status; 51 } 52 /** 53 * @return the assignee 54 */ 55 @NotBlank 56 public String getAssignee() { 57 return Assignee; 58 } 59 /** 60 * @param assignee the assignee to set 61 */ 62 public void setAssignee(String assignee) { 63 Assignee = assignee; 64 } 65 /** 66 * @return the attorney 67 */ 68 @NotBlank 69 public String getAttorney() { 70 return Attorney; 71 } 72 /** 73 * @param attorney the attorney to set 74 */ 75 public void setAttorney(String attorney) { 76 Attorney = attorney; 77 } 78 /** 79 * @return the delegate_Time 80 */ 81 public Date getDelegate_Time() { 82 return Delegate_Time; 83 } 84 /** 85 * @param delegate_Time the delegate_Time to set 86 */ 87 @Temporal(TemporalType.TIMESTAMP) 88 @Column(name = "delegate_Time", length = 19) 89 public void setDelegate_Time(Date delegate_Time) { 90 Delegate_Time = delegate_Time; 91 } 92 /** 93 * @return the taskId 94 */ 95 @NotBlank 96 public String getTaskId() { 97 return TaskId; 98 } 99 /** 100 * @param taskId the taskId to set 101 */ 102 public void setTaskId(String taskId) { 103 TaskId = taskId; 104 } 105 /** 106 * @return the status 107 */ 108 public Integer getStatus() { 109 return Status; 110 } 111 /** 112 * @param status the status to set 113 */ 114 public void setStatus(Integer status) { 115 Status = status; 116 } 117 }
(2)DelegateInfo类
1 /** 2 * 3 */ 4 package light.mvc.workflow.model; 5 6 import java.sql.Date; 7 8 import javax.persistence.Column; 9 import javax.persistence.Entity; 10 import javax.persistence.Table; 11 import javax.persistence.Temporal; 12 import javax.persistence.TemporalType; 13 14 import light.mvc.model.base.IdEntity; 15 16 import org.hibernate.annotations.DynamicInsert; 17 import org.hibernate.annotations.DynamicUpdate; 18 import org.hibernate.validator.constraints.NotBlank; 19 20 /** 21 * 22 * 项目名称:lightmvc 23 * 类名称:DelegateInfo 24 * 类描述: 25 * 创建人:邓家海 26 * 创建时间:2017年6月3日 下午2:36:55 27 * 修改人:deng 28 * 修改时间:2017年6月3日 下午2:36:55 29 * 修改备注: 30 * @version 31 * 32 */ 33 34 @Entity 35 @Table(name = "act_ru_delegate") 36 @DynamicInsert(true) 37 @DynamicUpdate(true) 38 public class DelegateInfo extends IdEntity implements java.io.Serializable{ 39 private String Assignee; 40 private String Attorney; 41 private Date Start_Time; 42 private Date End_Time; 43 private String Process_Definition_Id; 44 private Integer Status; 45 public DelegateInfo(){ 46 super(); 47 } 48 public DelegateInfo(String assignee,String attorney, Date start_time, Date end_time,String process_definition_id,Integer status){ 49 super(); 50 this.Assignee=assignee; 51 this.Attorney=attorney; 52 this.Start_Time=start_time; 53 this.End_Time=end_time; 54 this.Process_Definition_Id=process_definition_id; 55 this.Status=status; 56 } 57 /** 58 * @return the assignee 59 */ 60 public String getAssignee() { 61 return Assignee; 62 } 63 /** 64 * @param assignee the assignee to set 65 */ 66 public void setAssignee(String assignee) { 67 Assignee = assignee; 68 } 69 /** 70 * @return the attorney 71 */ 72 public String getAttorney() { 73 return Attorney; 74 } 75 /** 76 * @param attorney the attorney to set 77 */ 78 public void setAttorney(String attorney) { 79 Attorney = attorney; 80 } 81 /** 82 * @return the start_Time 83 */ 84 public Date getStart_Time() { 85 return Start_Time; 86 } 87 /** 88 * @param start_Time the start_Time to set 89 */ 90 public void setStart_Time(Date start_Time) { 91 Start_Time = start_Time; 92 } 93 /** 94 * @return the end_Time 95 */ 96 public Date getEnd_Time() { 97 return End_Time; 98 } 99 /** 100 * @param end_Time the end_Time to set 101 */ 102 public void setEnd_Time(Date end_Time) { 103 End_Time = end_Time; 104 } 105 /** 106 * @return the process_Definition_Id 107 */ 108 public String getProcess_Definition_Id() { 109 return Process_Definition_Id; 110 } 111 /** 112 * @param process_Definition_Id the process_Definition_Id to set 113 */ 114 public void setProcess_Definition_Id(String process_Definition_Id) { 115 Process_Definition_Id = process_Definition_Id; 116 } 117 /** 118 * @return the status 119 */ 120 public Integer getStatus() { 121 return Status; 122 } 123 /** 124 * @param status the status to set 125 */ 126 public void setStatus(Integer status) { 127 Status = status; 128 } 129 }
(3)DelegateServiceI接口
1 /** 2 * 3 */ 4 package light.mvc.service.workflow; 5 6 import java.sql.Date; 7 8 import light.mvc.workflow.model.DelegateInfo; 9 10 /** 11 * 12 * 项目名称:lightmvc 13 * 类名称:DelegateServiceI 14 * 类描述: 15 * 创建人:邓家海 16 * 创建时间:2017年6月3日 下午5:18:53 17 * 修改人:deng 18 * 修改时间:2017年6月3日 下午5:18:53 19 * 修改备注: 20 * @version 21 * 22 */ 23 //接口 24 public interface DelegateServiceI { 25 26 DelegateInfo getDelegateInfo(String targetAssignee,String targetProcessDefinitionId); 27 28 void saveRecord(String assignee, String attorney, String taskId); 29 30 void removeRecord(Long id); 31 32 void addDelegateInfo(String assignee, String attorney,Date startTime, Date endTime, String processDefinitionId); 33 34 }
(4)DelegateServiceImpl类
1 /** 2 * 3 */ 4 package light.mvc.service.workflow.impl; 5 6 import java.sql.Date; 7 import java.util.HashMap; 8 import java.util.List; 9 import java.util.Map; 10 11 import org.springframework.beans.factory.annotation.Autowired; 12 13 import light.mvc.dao.BaseDaoI; 14 import light.mvc.model.sys.Tuser; 15 import light.mvc.service.workflow.DelegateServiceI; 16 import light.mvc.workflow.model.DelegateHistory; 17 import light.mvc.workflow.model.DelegateInfo; 18 19 /** 20 * 21 * 项目名称:lightmvc 22 * 类名称:DelegateServiceImpl 23 * 类描述: 24 * 创建人:邓家海 25 * 创建时间:2017年6月3日 下午5:20:30 26 * 修改人:deng 27 * 修改时间:2017年6月3日 下午5:20:30 28 * 修改备注: 29 * @version 30 * 31 */ 32 33 public class DelegateServiceImpl implements DelegateServiceI { 34 @Autowired 35 private BaseDaoI<DelegateInfo> delegateInfoDao; 36 @Autowired 37 private BaseDaoI<DelegateHistory> delegateHistoryDao; 38 39 40 public DelegateInfo getDelegateInfo(String targetAssignee,String targetProcessDefinitionId) { 41 42 Map<String,Object> map=new HashMap<String, Object>(); 43 map.put("assignee", targetAssignee); 44 List<DelegateInfo> list=delegateInfoDao.find("from DelegateInfo d where d.status=1 and d.assignee=:assignee order by id desc",map); 45 for (DelegateInfo delegateInfo : list) { 46 47 String processDefinitionId = (String) delegateInfo.getProcess_Definition_Id(); 48 Date startTime = (Date) delegateInfo.getStart_Time(); 49 Date endTime = (Date) delegateInfo.getEnd_Time(); 50 51 52 if (timeNotBetweenNow(startTime, endTime)) { 53 54 continue; 55 } 56 57 if ((processDefinitionId == null)|| processDefinitionId.equals(targetProcessDefinitionId)) { 58 return delegateInfo; 59 } 60 } 61 62 return null; 63 } 64 65 public void saveRecord(String assignee, String attorney, String taskId) { 66 DelegateHistory delegateHistory=new DelegateHistory(); 67 delegateHistory.setAttorney(assignee); 68 delegateHistory.setAttorney(attorney); 69 delegateHistory.setTaskId(taskId); 70 delegateHistory.setDelegate_Time(new java.sql.Date(System.currentTimeMillis())); 71 delegateHistory.setStatus(1); 72 delegateHistoryDao.update(delegateHistory); 73 } 74 75 public void removeRecord(Long id) { 76 77 DelegateInfo delegateInfo=delegateInfoDao.get(DelegateInfo.class, id); 78 delegateInfoDao.delete(delegateInfo); 79 } 80 81 public void addDelegateInfo(String assignee, String attorney,Date startTime, Date endTime, String processDefinitionId) { 82 DelegateInfo delegateInfo=new DelegateInfo(); 83 delegateInfo.setAssignee(assignee); 84 delegateInfo.setAttorney(attorney); 85 delegateInfo.setEnd_Time(endTime); 86 delegateInfo.setStart_Time(startTime); 87 delegateInfo.setProcess_Definition_Id(processDefinitionId); 88 delegateInfo.setStatus(1); 89 delegateInfoDao.save(delegateInfo); 90 } 91 92 private boolean timeNotBetweenNow(Date startTime, Date endTime) { 93 Date now = new Date(System.currentTimeMillis()); 94 95 if (startTime != null) { 96 return now.before(startTime); 97 } 98 99 if (endTime != null) { 100 return now.after(endTime); 101 } 102 103 return false; 104 } 105 }
(5)TaskAsigneeListenerImpl监听类
1 /** 2 * 3 */ 4 package light.mvc.workflow.taskListener; 5 6 import java.util.Map; 7 8 import light.mvc.service.workflow.impl.DelegateServiceImpl; 9 import light.mvc.workflow.model.DelegateInfo; 10 11 import org.activiti.engine.delegate.DelegateTask; 12 import org.activiti.engine.delegate.TaskListener; 13 import org.springframework.beans.factory.annotation.Autowired; 14 15 /** 16 * 17 * 项目名称:lightmvc 18 * 类名称:TaskAsigneeListenerImpl 19 * 类描述: 20 * 创建人:邓家海 21 * 创建时间:2017年6月1日 下午11:48:55 22 * 修改人:deng 23 * 修改时间:2017年6月1日 下午11:48:55 24 * 修改备注: 25 * @version 26 * 27 */ 28 29 public class TaskAsigneeListenerImpl implements TaskListener { 30 @Autowired 31 private DelegateServiceImpl delegateServiceImpl; 32 @Override 33 public void notify(DelegateTask delegateTask) { 34 Map<String,Object> map = delegateTask.getVariables(); 35 delegateTask.setAssignee(map.get("userId").toString()); 36 37 //如果有委托,设置委托人 38 String assignee = delegateTask.getAssignee(); 39 String processDefinitionId = delegateTask.getProcessDefinitionId(); 40 DelegateInfo delegateInfo = delegateServiceImpl.getDelegateInfo(assignee, 41 processDefinitionId); 42 43 if (delegateInfo == null) { 44 return; 45 } 46 47 String attorney = delegateInfo.getAttorney(); 48 delegateTask.setAssignee(attorney); 49 delegateServiceImpl.saveRecord(assignee, attorney, delegateTask.getId()); 50 51 } 52 }
(6)act_hi_delegate表
1 SELECT * FROM lightmvc.act_hi_delegate;CREATE TABLE `act_hi_delegate` ( 2 `ID` bigint(20) NOT NULL AUTO_INCREMENT, 3 `ASSIGNEE` varchar(200) DEFAULT NULL, 4 `ATTORNEY` varchar(200) DEFAULT NULL, 5 `DELEGATE_TIME` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 6 `TASK_ID` varchar(100) DEFAULT NULL, 7 `STATUS` int(11) DEFAULT NULL, 8 PRIMARY KEY (`ID`) 9 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
(7)act_ru_delegate表
1 CREATE TABLE `act_ru_delegate` ( 2 `ID` bigint(20) NOT NULL AUTO_INCREMENT, 3 `ASSIGNEE` varchar(200) DEFAULT NULL, 4 `ATTORNEY` varchar(200) DEFAULT NULL, 5 `START_TIME` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 6 `END_TIME` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 7 `PROCESS_DEFINITION_ID` varchar(100) DEFAULT NULL, 8 `STATUS` int(11) DEFAULT NULL, 9 PRIMARY KEY (`ID`) 10 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;