根据网上的资料整合,如有不对谢谢指出。
1. 先贴出流程图,代码是根据流程图写的,大概就是这么一个思路,可自行根据思路更改。
2. 并行任务撤回
出差申请撤回任务,由于任务已经到了技术经理和项目经理那里,所以必须将技术经理和项目经理的任务同时回撤到出差申请的节点上;首先将网关1的流向指向到出差申请的节点,然后将技术经理和项目经理节点流向指向网关1,最后执行技术经理和项目经理的任务,来实现任务回撤到出差申请节点。
3. 汇集任务回撤
如任务执行到了人事审批环节,技术经理节点需要撤回任务;这里的思路跟并行任务回撤差不多,将网关的流向反转,但是这里必须保证项目经理不能收到任务;人事审批节点的流向指向网关2,网关2将任务分发到技术经理和项目经理的节点上,最后将网关2的流向恢复,根据节点id判断,将不需要回撤的节点默认执行,将任务卡在网关2的节点上。
4. 串行任务回撤
人事审批节点回撤总经理审批的任务,只需要将反转流向即可。
5. 详细代码(代码里很详细的注释)
public class ActivitiUtil {
private static ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
private static HistoryService historyService = processEngine.getHistoryService();
private static TaskService taskService = processEngine.getTaskService();
private static RuntimeService runtimeService = processEngine.getRuntimeService();
private static RepositoryService repositoryService = processEngine.getRepositoryService();
/**
* 任务撤回
* @param taskId
* @return
*/
public static boolean withdraw(String taskId) throws Exception {
// 当前任务
HistoricTaskInstance currTask = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
//获取当前的流程定义id
String processDefinitionId = currTask.getProcessDefinitionId();
//获取当前的流程实例id
String processInstanceId = currTask.getProcessInstanceId();
//获取流程定义信息模型
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
//根据任务key得到当前活动节点
FlowElement currElement = bpmnModel.getFlowElement(currTask.getTaskDefinitionKey());
//根据流程id查询代办任务中流程信息
List<Task> list = taskService.createTaskQuery().processInstanceId(currTask.getProcessInstanceId()).list();
if (list.size() == 1){
//单向流入,当前任务是串行任务
Task task = list.get(0);
// 根据任务key得到目标活动节点
FlowElement targetElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
//将FlowElement强转为UserTask,方便得到流向
UserTask targetTask = (UserTask)targetElement;
//判断流入的UserTask还是并行网关
UserTask currUserTask = (UserTask)currElement;
List<SequenceFlow> outgoingFlows = currUserTask.getOutgoingFlows();
Class<? extends FlowElement> aClass = outgoingFlows.get(0).getTargetFlowElement().getClass();
String typeName = aClass.getTypeName();
if (typeName.equals("org.activiti.bpmn.model.ParallelGateway")) {
//类型是ParallelGateway需要操作网关
FlowElement flowElement = outgoingFlows.get(0).getTargetFlowElement();
//强转为parallel
ParallelGateway parallel = (ParallelGateway)flowElement;
//获取网关的流入
List<SequenceFlow> incomingFlowsPar = parallel.getIncomingFlows();
//获取网关的流出
List<SequenceFlow> outgoingFlowsPar = parallel.getOutgoingFlows();
List<SequenceFlow> newOutcomingFlows = new ArrayList<>();
//将网关流入的流向全部改为流出,每个流向都需要转向,然后添加到list
for (SequenceFlow sequenceFlow:incomingFlowsPar) {
SequenceFlow newSequenceFlow = CreateSequenceFlow(sequenceFlow.getSourceFlowElement(), sequenceFlow.getTargetFlowElement());
newOutcomingFlows.add(newSequenceFlow);
}
//这里只考虑网关的汇集状态,即只有一个流出
SequenceFlow sequenceFlow = outgoingFlowsPar.get(0);
SequenceFlow newSequenceFlow = CreateSequenceFlow(sequenceFlow.getSourceFlowElement(), sequenceFlow.getTargetFlowElement());
//给网关设置新的流出
parallel.setOutgoingFlows(newOutcomingFlows);
//给网关设置新的流入
parallel.setIncomingFlows(Arrays.asList(newSequenceFlow));
//给目标活动节点设置新的流出
targetTask.setOutgoingFlows(Arrays.asList(newSequenceFlow));
//执行目标活动的任务,使之通过网关回到原来的多条任务
taskService.complete(task.getId());
//恢复流向
parallel.setIncomingFlows(incomingFlowsPar);
parallel.setOutgoingFlows(outgoingFlowsPar);
//手动完成不需要回退的任务
for (SequenceFlow sequenceFlow1:incomingFlowsPar) {
UserTask userTask = (UserTask)sequenceFlow1.getSourceFlowElement();
//根据taskDefinitionKey获取任务
Task task1 = taskService.createTaskQuery().processInstanceId(processInstanceId).taskDefinitionKey(userTask.getId()).singleResult();
String id = task1.getId();
String userTaskKey = userTask.getId();
String taskDefinitionKey = currTask.getTaskDefinitionKey();
//不同的key说明不需要回退,直接执行
if (!userTaskKey.equals(taskDefinitionKey)){
taskService.complete(id);
}
}
} else {
//如果是其他类型,就是最简单的操作,直接转向执行就可以了
//创建新流向 参数1:目标活动节点 参数2:起始活动节点
SequenceFlow sequenceFlow = CreateSequenceFlow(currElement, targetTask);
List<SequenceFlow> sequenceFlows = new ArrayList<>();
sequenceFlows.add(sequenceFlow);
// 流程转向操作
turnTransition(targetElement,task.getId(),sequenceFlows);
}
}else if(list.size()>1){
//当前任务是并行任务
//当前活动节点可以强转为用户任务节点
UserTask currUserTask = (UserTask)currElement;
//得到流向
List<SequenceFlow> outgoingFlows = currUserTask.getOutgoingFlows();
SequenceFlow outgoingFlow = outgoingFlows.get(0);
// 得到活动节点
FlowElement flowElement = outgoingFlow.getTargetFlowElement();
//强转为parallel
ParallelGateway parallel = (ParallelGateway)flowElement;
//获取网关的流向
List<SequenceFlow> outgoingFlowsPar = parallel.getOutgoingFlows();
//获取网关的流入
List<SequenceFlow> incomingFlowsPar = parallel.getIncomingFlows();
//创建网关的新流入
List<SequenceFlow> incomingFlows = new ArrayList<>();
for (Task task:list) {
// 根据任务key得到目标活动节点
FlowElement targetElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
UserTask targetTask = (UserTask)targetElement;
//创建新流向
SequenceFlow sequenceFlow = CreateSequenceFlow(flowElement, targetTask);
incomingFlows.add(sequenceFlow);
}
// 创建新流向
SequenceFlow sequenceFlow = CreateSequenceFlow(currElement, parallel);
List<SequenceFlow> sequenceFlows = new ArrayList<>();
sequenceFlows.add(sequenceFlow);
//加入到目标的输出流向
parallel.setOutgoingFlows(sequenceFlows);
parallel.setIncomingFlows(incomingFlows);
List<FlowElement> targetElementList = new ArrayList<>();
for (Task task:list) {
// 根据任务key得到目标活动节点
FlowElement targetElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
UserTask targetTask = (UserTask)targetElement;
List<SequenceFlow> newIncomingFlows = new ArrayList<>();
//拿到创建的流向
for (SequenceFlow sequenceFlow1 :incomingFlows) {
if (sequenceFlow1.getSourceRef() == targetTask.getId()){
newIncomingFlows.add(sequenceFlow1);
}
}
//转向操作
turnTransition(targetElement ,task.getId(),newIncomingFlows);
}
// 还原以前流向
parallel.setOutgoingFlows(outgoingFlowsPar);
parallel.setIncomingFlows(incomingFlowsPar);
}else {
throw new Exception("当前已经是最后一个任务了");
}
//删除历史流程走向记录
historyService.deleteHistoricTaskInstance(currTask.getId());
for (Task task:list) {
historyService.deleteHistoricTaskInstance(task.getId());
}
return true;
}
/**
* * 流程转向操作
* * @param targetElement 目标节点
* * @param taskId 目标节点任务Id
* * @throws Exception
*
*/
private static void turnTransition(FlowElement targetElement,String taskId,List<SequenceFlow> sequenceFlows) throws Exception {
// 目标节点 强转为UserTask方便得到流向
UserTask targetTask = (UserTask)targetElement;
// // 保存原来的流向
List<SequenceFlow> outgoingFlows = targetTask.getOutgoingFlows();
// //加入到目标的输出流向
targetTask.setOutgoingFlows(sequenceFlows);
// 执行转向任务
taskService.complete(taskId);
// 还原以前流向
targetTask.setOutgoingFlows(outgoingFlows);
}
/**
* 创建新流向
* @param targetFlowElement 目标活动节点
* @param sourceFlowElement 起始活动节点
* @return
*/
private static SequenceFlow CreateSequenceFlow(FlowElement targetFlowElement,FlowElement sourceFlowElement){
// 创建新流向
SequenceFlow sequenceFlow = new SequenceFlow();
// 设置新流向的起始节点
sequenceFlow.setSourceFlowElement(sourceFlowElement);
// 设置新流向的起始key
sequenceFlow.setSourceRef(sourceFlowElement.getId());
// 设置新流向的为当前节点
sequenceFlow.setTargetFlowElement(targetFlowElement);
sequenceFlow.setTargetRef(targetFlowElement.getId());
//设置流向id
sequenceFlow.setId("_"+ UUID.randomUUID().toString());
return sequenceFlow;
}
}
6. 结语
任务驳回也差不多一样,主要也是流向改变指向来操作;本人也是刚接触,如有错误的地方欢迎指出。