最近在做一个工作流审批的项目,类似与申请一个请假,但是在完成任务的时候需要动态指定下一级人物,在最开始了解的时候,书上都是直接根据taskId来完成,后来终于实现了这个动态指定下一级处理人的功能。
我们的项目是这么一个流程
那么例如我是一个提交申请的人,例如是一个标准的请假,那么我需要完成当前的人物,还需要动态的指定下一级的是谁来审批,可是有一个前提,那就是我是不知道是谁来完成我的审批,我只需要直接提交申请的就可以。那如果我们是对工作流信息进行审批的人呢,今天我们就看一下activiti的TaskListener。
TaskListener
TaskListener,他类似与C#中委托的功能,他能准确的再你执行完成当人物的方法时去调用该接口中你需要执行的一个方法notify。而我就是在这个方法里边去指定的他的下一级是谁。下边我以学术审批的功能来将一下我是如何实现这个的。
代码实现
添加Listener
单机new按钮
选择create,单机Select class,然后选择我们实现了TaskListener的类就可以了。
代码
既然是完成,那么我们就直接来一个完成的代码
@RequestMapping("/completeByTeacher")
public String throwApply(HttpServletRequest request,
HttpServletResponse response) {
// 1.获取页面上要处理的任务ID,按钮信息,评论信息
String userId = request.getParameter("usercode");
//String userId = "456";
String strTaskId = request.getParameter("taskId");
String isapprove = request.getParameter("msg");
String comment = request.getParameter("comment");
// String strTaskId = "11209";
// 将获取的任务id的字符串转换成数组
String[] taskIds = strTaskId.split(",");
try {
// 2.循环完成任務
for (String taskId : taskIds) {
// String taskId="3212";
// 2.1根据人物ID查询流程实力ID
Task task = processEngine.getTaskService().createTaskQuery()
.taskId(taskId).singleResult();
// 获取流程实例ID
String processInstance = task.getProcessInstanceId();
// 2.2根据流程实例ID,人物ID,评论的消息,保存教师或者学术对与该学生申请的评论信息
processEngine.getTaskService().addComment(taskId,
processInstance, comment);
EngineController engineController = new EngineController();
// 2.3查询当前任务后边的连线名称
List<String> list = findOutComeListByTaskId(taskId);
if (list.size() > 0 && list != null) {
Map<String, Object> map = new HashMap<String, Object>();
// 如果是批准操作,则根据连线名称和当前的任务名称,完成操作。
map.put("outcome", isapprove);
// 2.4如果又连线名称,则根据连线和任务ID完成人物
engineController.compalete(taskId, map);
} else {
// 2.4如果只有任务id,连线没有名称,则直接完成当前任务,并修改用户的当前状态。
intershipBean.updateUserInfoByID("itoo_intership", userId,
"1");
processEngine.getTaskService().complete(taskId);
}
}
} catch (Exception e) {
// 报错
return "redirect:/queryTaksByRole";
}
return "redirect:/queryTaksByRole";
}
上边是我的完成人物,但是我需要根据前台我选择的是通过或者驳回,来执行,那么我就需要判断我的这个任务之后的连线,很明显我的是一个通过和驳回,那么获取前台按钮的名称就可以了。然后去执行,那么我们的方法如下:
// 一直任务ID,查询processDefinitionEntity对象,从而获取
// 当前任务完成之后的连线名称,并设置到List<String>对象中
public List<String> findOutComeListByTaskId(String taskId) {
// 返回连线的名称集合
List<String> list = new ArrayList<String>();
// 1.使用任务ID查询任务对象
Task task = processEngine.getTaskService().createTaskQuery()
.taskId(taskId).singleResult();
// 2.获取流程定义ID
String processDefinitionId = task.getProcessDefinitionId();
// 3.查询流程定义(ProcessDefinitionEntity)的实体对象
ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) processEngine
.getRepositoryService().getProcessDefinition(
processDefinitionId);
// 使用任务对象Task获取流程实例ID
String processInstanceId = task.getProcessInstanceId();
// 使用历程实例ID,查询正在执行的对象表,返回流程实例对象
ProcessInstance pi = processEngine.getRuntimeService()
.createProcessInstanceQuery()
.processInstanceId(processInstanceId).singleResult();
// 4.获取当前的活动
ActivityImpl activityImpl = processDefinitionEntity.findActivity(pi
.getActivityId());
// 5.获取当前活动完成之后连线的名称
List<PvmTransition> pvmList = activityImpl.getOutgoingTransitions();
if (pvmList != null && pvmList.size() > 0) {
for (PvmTransition pvm : pvmList) {
String name = (String) pvm.getProperty("name");
if (name != null) {
list.add(name);
}
}
}
return list;
}
Listener的实现类
/**用来指定任务的办理人*/
@Override
public void notify(DelegateTask delegateTask) {
//如果任务的个数大于1的话,则ID为RoleID
String sql = "select * From tb_relation where intershipid='" + processDefId + "' and childCode='" + lastassignee + "'";
Dbhelper dbCourseCurrentadd = new Dbhelper();
dbCourseCurrentadd.setSql(sql.toString());
List<Map<String,Object>> listmap = dbCourseCurrentadd.findItemById();
if(listmap.size() > 0 && listmap!=null){
Map<String, Object> m = listmap.get(0);
nextLevel = (String) m.get("fatherCode");
}
}
需要说明的是DelegateTask这个参数中又流程实例的ID,我们可以根据这个ID,找到我们是做的哪一个审批,然后去查询相应的下一级办理人。因为我又一个tb_relation的表来存储下一级,所以直接查询就可以了。
小结
当然我们完全可以不用TaskListener的方法来实现,只是这样的话,我们是不是就可以直接达到服用,这个流程可以用这个类,其他的流程也是直接添加一下Listener,然后就不用管这里的逻辑了,能更好的实现解耦。