最近在工作中使用到了activiti 工作流引擎,跟大家遇到过的情况类似,在“中国式”的工作流中,常有一些需求是工作流引擎基本使用中无法实现的。在这过程中,我和我的小伙伴们也和大家一样遇到很多困难,大海捞针似的在网上寻找着答案。特此,在这里把我们遇到的需求和解决方案分享给大家,希望能帮助到你们!
以下是我们在项目中遇到的各(奇)种(葩)需求,如果您也遇到了相同的可以借鉴:
1、工作流会签;
2、多人审批时一人通过即可;
3、在当前节点获取下一节点的信息;
4、流程部署后未发布之前获取所有节点的信息;
5、流程启动前传入后续节点办理人;
6、节点设置多个监听。
1、 activiti 工作流会签时,所有的都审批通过才可进入下一环节:
1.1 编写监听类
public class MyTaksListener implements TaskListener {
public void notify(DelegateTask delegateTask) {
System.out.println("delegateTask.getEventName() = " + delegateTask.getEventName());
//添加会签的人员,所有的都审批通过才可进入下一环节
List
assigneeList.add("wangba");
assigneeList.add("wangjiu");
delegateTask.setVariable("publicityList",assigneeList);
}
}
1.2 “员工请假申请”中添加此监听类
1.3 “项目组长审批”中
isSequential=false时,表示的并行执行,即该节点下的多条任务可以同时执行。
activiti:collection:执行该会签环节的参与人,此处是使用的一个名叫publicityList的流程变量
activiti:elementVariable:表示的是每一个分支都有一个名叫publicity的流程变量,和上方的activiti:assignee结合
1.4 项目组长审批时,通过taskAssignee来获取个人任务
// 获取总记录数
total = taskService.createTaskQuery().taskAssignee(userId).taskNameLike("%" + s_name + "%").count();
taskList = taskService.createTaskQuery()
// 根据用户id查询
.taskAssignee(userId)
// 根据任务名称查询
.taskNameLike("%" + s_name + "%")
// 返回带分页的结果集合
.listPage(pageInfo.getPageIndex(), pageInfo.getPageSize());
==================================================================================
2. activiti 工作流会签,一人通过即可进入下一环节:
2.1 编写监听类
public class MangerTaskHandlerCandidateUsers implements TaskListener{
public void notify(DelegateTask delegateTask) {
//添加审批的人员,以下任何一人通过即可进入下一环节
String[] empLoyees = {"wangba","wangjiu"};
delegateTask.addCandidateUsers(Arrays.asList(empLoyees));
}
}
2.2 “项目组长审批”中
2.3 项目组长审批时,通过taskCandidateUser来获取节点任务
// 获取总记录数
total = taskService.createTaskQuery().taskCandidateUser(userId).taskNameLike("%" + s_name + "%").count();
taskList = taskService.createTaskQuery()
// 根据用户id查询
.taskCandidateUser(userId)
// 根据任务名称查询
.taskNameLike("%" + s_name + "%")
// 返回带分页的结果集合
.listPage(pageInfo.getPageIndex(), pageInfo.getPageSize());
============================================================================
3、在当前节点获取下一节点的信息
/**
* 根据实例编号查找下一个任务节点
*
* @param String
* procInstId :实例编号
* @return
*/
@RequestMapping("/backTaskTab")
public TaskDefinition backTaskTab(String taskId) {
Task task = taskService.createTaskQuery() // 创建任务查询
.taskId(taskId) // 根据任务id查询
.singleResult();
String procInstId = task.getProcessInstanceId();
// 流程标示
String processDefinitionId = historyService.createHistoricProcessInstanceQuery().processInstanceId(procInstId)
.singleResult().getProcessDefinitionId();
ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(processDefinitionId);
// 执行实例
ExecutionEntity execution = (ExecutionEntity) runtimeService.createProcessInstanceQuery()
.processInstanceId(procInstId).singleResult();
// 当前实例的执行到哪个节点
String activitiId = execution.getActivityId();
// 获得当前任务的所有节点
List
ActivityImpl activityImpl=null;
for(int i=0;i< activitiList.size();i++){
String flag=activitiList.get(i).getId();
if(flag.equals(activitiId)){
activityImpl=activitiList.get(i);
}
}
String id = null;
int num=activitiList.indexOf(activityImpl);
ActivityImpl activityImpl_=activitiList.get(num+1);
TaskDefinition taskDefinition = ((UserTaskActivityBehavior) activityImpl_.getActivityBehavior())
.getTaskDefinition();
// 获取下一节点的代办人
System.out.println(taskDefinition.getCandidateGroupIdExpressions().toArray()[0]);
return null;
}
============================================================================
4、流程部署后未发布之前获取所有节点的信息
解决思路是这样的:部署完工作流之后,为UserTask节点动态分配任务执行者,或者在分支节点上添加条件判断的功能。为了实现这个功能,需要解析流程定义文件,取出文件中定义的所有节点。这里有两个方法可以实现此功能:
方法一(流程部署至服务器上之后可使用):
//processDefinitionId为流程定义Id,该Id可以通过多种方式获得,如通过ProcessDefinitionQuery可以查询一个 //ProcessDefinition对象,Task对象中也包含
processDefinitionIdBpmnModel model = repositoryService.getBpmnModel(processDefinitionId);
if (model != null) {
Collection
for (FlowElement e : flowElements) {
System.out.println("flowelement id:" + e.getId() + " name:" + e.getName() + " class:"
+ e.getClass().toString());
}
}
该方法适用于流程部署至服务器上之后,通过该方法可以简单快速的获取流程定义文件中各个节点信息。
方法二 读取流程定义文件方式
InputStream resouceStream = this.getClass().getClassLoader().getResourceAsStream("leave- formkey.bpmn20.xml");
XMLInputFactory xif = XMLInputFactory.newInstance();
InputStreamReader in;
XMLStreamReader xtr;
try {
in = new InputStreamReader(resouceStream, "UTF-8");
xtr = xif.createXMLStreamReader(in);
BpmnModel model = new BpmnXMLConverter().convertToBpmnModel(xtr);
Collection
for (FlowElement e : flowElements) {
System.out.println("flowelement id:" + e.getId() + " name:" + e.getName() + " class:"
+ e.getClass().toString());
}
} catch (XMLStreamException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
5.流程启动前传入后续节点办理人;
//下面name2和name3是前台传过来的第二个和第三个节点的办理人
Map
variables.put("leaveId", leaveId);
variables.put("name2", "XXX");//(前台传过来的第二个节点的办理人)
variables.put("name3", "YYY");//(前台传过来的第三个节点的办理人)
// 启动流程
pi = runtimeService.startProcessInstanceByKey("activitiemployeeProcess", variables);
在第一个节点指定第二个节点的监听
public class MyTaksListener2 implements TaskListener {
public void notify(DelegateTask delegateTask) {
Map
variables.get("name2");(前台传过来的第二个节点的办理人)
//拆分variables
List
assigneeList.add("wangba");
delegateTask.setVariable("publicityList",assigneeList);
}
}
在第三个节点指定本节点的办理人监听
public class MyTaksListener3 implements TaskListener {
public void notify(DelegateTask delegateTask) {
Map
System.out.println(variables);
variables.get("name3");
// String result=(String) variables.get("name3");(前台传过来的第三个节点的办理人)
String[] empLoyees = {"szx"};
delegateTask.addCandidateUsers(Arrays.asList(empLoyees));
}
}
============================================================================
6、节点设置多个监听
在同一节点设置两个监听,一个是设置本节点的监听,指定办理人;另一个是设置下一个节点的监听,指定会签人。
设置本节点的监听,指定办理人
public class MyTaksListener3 implements TaskListener {
public void notify(DelegateTask delegateTask) {
Map
System.out.println(variables);
String result=(String) variables.get("name3");
String[] empLoyees = {"szx"};
delegateTask.addCandidateUsers(Arrays.asList(empLoyees));
}
}
设置下一个节点的监听,指定会签人
public class MyTaksListener4 implements TaskListener {
public void notify(DelegateTask delegateTask) {
Map
String result=(String)variables.get("name2");
List
assigneeList.add("ss");
delegateTask.setVariable("publicityList",assigneeList);
}
}
至此,项目中遇到的各(奇)种(葩)问题迎刃而解。“中国式”工作流有时确实很让人头疼,但也体现了中国程序猿的强大。希望看到这里的你也能从中得到启发,尽早解决您在项目当中遇到的问题。
喜欢此文,或是能帮助您解决实际问题的话,欢迎转载,以便能帮助到更多的人,谢谢!