接口
import org.activiti.bpmn.model.FlowElement;
import java.util.Collection;
import java.util.Map;
/**
* @author : ZhiPengyu
* @ClassName : [ExecutionService]
* @Description : [节点跳转操作]
* @CreateDate : [2021/8/11 10:24]
*/
public interface ExecutionService {
/**
* 获取流程实例的全部节点<br>
* jumpSpecifiedNode方法的targetTaskId为FlowElement.getId()
* @param processDefinitionId 流程定义ID ProcessInstance.getProcessDefinitionId()
* @return
*/
Collection<FlowElement> getProcessElements(String processDefinitionId);
/**
* 跳转到指定节点<br>
* 可以跳转到本实例的任意节点-向前向后
* @param processInstanceId 实例ID
* @param targetTaskId 任务ID,与运行时任务ID不同,为xml文件上的ID
* @param variables 本节点处理参数
* @return
*/
Boolean jumpSpecifiedNode(String processInstanceId, String targetTaskId, Map<String, Object> variables);
/**
* 回退到指定历史节点
* @param processInstanceId 流程实例ID
* @param targetTaskId 回跳任务ID,为null是默认选择最近的上一任务
* @param variables 撤回者处理当前任务参数
* @return
*/
Boolean rollBackTargetHisNode(String processInstanceId, String targetTaskId, Map<String, Object> variables);
}
实现
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* @author : ZhiPengyu
* @ClassName : [ExecutionServiceImpl]
* @Description : []
* @CreateDate : [2021/8/11 10:24]
*/
@Service
public class ExecutionServiceImpl implements ExecutionService {
/**
* 仓储服务,用于管理流程仓库,例如:部署,删除,读取流程资源
* 可以用来部署我们的流程图,还可以创建我们的流程部署查询对象,用于查询刚刚部署的流程列表,便于我们管理流程
*/
@Autowired
private RepositoryService repositoryService;
/**
* 运行时服务,可以处理所有正在运行状态的流程实例,任务等
* 主要用来开启流程实例,一个流程实例对应多个任务,也就是多个流程节点
*/
@Autowired
private RuntimeService runtimeService;
/**
* 任务服务,用于管理,查询任务,例如:签收,办理,指派等
* 是用来可以用来领取,完成,查询任务列表功能的
*/
@Autowired
private TaskService taskService;
/**
* 历史服务,可以查询所有历史数据,例如:流程实例,任务,活动,变量,附件等
* 可以查看审批人曾经审批完成了哪些项目,审批项目总共花了多少时间,以及在哪个环节比较耗费时间等等
*/
@Autowired
private HistoryService historyService;
/**
* 唯一服务,可以管理,查询用户,组之间的关系
* 操作用户信息,用户分组信息等,组信息包括如部门表和职位表,可以自己建表来存储用户信息和组信息
*/
@Autowired
private IdentityService identityService;
@Override
public Collection<FlowElement> getProcessElements(String processDefinitionId) {
Process process = repositoryService.getBpmnModel(processDefinitionId).getMainProcess();
Collection<FlowElement> flowElements = process.getFlowElements();
return flowElements;
}
@Override
public Boolean jumpSpecifiedNode(String processInstanceId, String targetTaskId, Map<String, Object> variables) {
//获取流程实例
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if (pi == null){//流程已结束
return false;
}
//当前任务
Task curTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
BpmnModel bpmnModel = repositoryService.getBpmnModel(curTask.getProcessDefinitionId());
//目标任务
Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements();
Optional<FlowElement> optional = flowElements.stream().filter(target -> targetTaskId.equals(target.getId())).findFirst();
if (!optional.isPresent()){//无指定任务
return false;
}
UserTask targetUserTask = (UserTask) optional.get();
// 获取目标节点的信息
FlowNode targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(targetUserTask.getId());
// 取得当前节点的信息
Execution execution = runtimeService.createExecutionQuery().executionId(curTask.getExecutionId()).singleResult();
FlowNode curFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(execution.getActivityId());
// 记录当前节点的原活动方向
List<SequenceFlow> oriSequenceFlows = new ArrayList<>();
oriSequenceFlows.addAll(curFlowNode.getOutgoingFlows());
// 清理活动方向
curFlowNode.getOutgoingFlows().clear();
// 建立新方向
List<SequenceFlow> newSequenceFlow = newSequenceFlowList(curFlowNode,targetFlowNode);
curFlowNode.setOutgoingFlows(newSequenceFlow);
// 添加批注并完成任务
commentAndComplete(processInstanceId,curTask.getId(),curTask.getAssignee(),variables,"跳转");
// 恢复原方向
curFlowNode.setOutgoingFlows(oriSequenceFlows);
// 设置执行人
Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
if (nextTask != null) {
taskService.setAssignee(nextTask.getId(), targetUserTask.getAssignee());
}
return true;
}
@Override
public Boolean rollBackTargetHisNode(String processInstanceId, String targetTaskId, Map<String, Object> variables) {
//获取流程实例
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if (pi == null){//流程已结束
return false;
}
//对应实例的任务历史节点
List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).orderByTaskCreateTime().desc().list();
// 跳转的之前某一节点
HistoricTaskInstance targetTask = getTargetTask(htiList,targetTaskId);
// list里第一条代表当前任务
HistoricTaskInstance curTask = htiList.get(0);
if (targetTask == null){
return false;
}
targetTaskId = targetTask.getId();
BpmnModel bpmnModel = repositoryService.getBpmnModel(targetTask.getProcessDefinitionId());
// 得到ActivityId,只有HistoricActivityInstance对象里才有此方法
String lastActivityId = getLastActivityId(targetTaskId,targetTask.getExecutionId());
// 得到上个节点的信息
FlowNode lastFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(lastActivityId);
// 取得当前节点的信息
Execution execution = runtimeService.createExecutionQuery().executionId(curTask.getExecutionId()).singleResult();
FlowNode curFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(execution.getActivityId());
// 记录当前节点的原活动方向
List<SequenceFlow> oriSequenceFlows = new ArrayList<>();
oriSequenceFlows.addAll(curFlowNode.getOutgoingFlows());
// 清理活动方向
curFlowNode.getOutgoingFlows().clear();
// 建立新方向
List<SequenceFlow> newSequenceFlow = newSequenceFlowList(curFlowNode,lastFlowNode);
curFlowNode.setOutgoingFlows(newSequenceFlow);
// 添加批注并完成任务
Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
commentAndComplete(processInstanceId,task.getId(),task.getAssignee(),variables,"撤回");
// 恢复原方向
curFlowNode.setOutgoingFlows(oriSequenceFlows);
Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
// 设置执行人
if (nextTask != null) {
taskService.setAssignee(nextTask.getId(), targetTask.getAssignee());
}
return true;
}
/**
* 添加批注并完成任务
* @param processInstanceId
* @param curTaskId 当前任务ID
* @param targetTaskAssignee
* @param variables
* @param message
*/
private void commentAndComplete(String processInstanceId,String curTaskId,String targetTaskAssignee,Map<String, Object> variables,String message){
identityService.setAuthenticatedUserId(targetTaskAssignee);
taskService.addComment(curTaskId,processInstanceId,message);
taskService.complete(curTaskId,variables);
}
/**
* 获取指定的目标历史任务
* @param htiList 历史任务列表
* @param targetTaskId 目标任务ID,为null是默认选择最近的上一任务
* @return
*/
private HistoricTaskInstance getTargetTask(List<HistoricTaskInstance> htiList,String targetTaskId){
HistoricTaskInstance targetTask = null;
if (targetTaskId == null){
targetTask = htiList.get(1);
} else {
Optional<HistoricTaskInstance> optional = htiList.stream().filter(hisTask -> targetTaskId.equals(hisTask.getId())).findFirst();
targetTask = optional.isPresent() ? optional.get() : null;
}
return targetTask;
}
/**
* 新建连线
* @param curFlowNode 当前节点
* @param targetFlowNode 目标节点
* @return
*/
private List<SequenceFlow> newSequenceFlowList(FlowNode curFlowNode,FlowNode targetFlowNode) {
List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
SequenceFlow newSequenceFlow = new SequenceFlow();
newSequenceFlow.setId("newJumpFlow");
newSequenceFlow.setSourceFlowElement(curFlowNode);
newSequenceFlow.setTargetFlowElement(targetFlowNode);
newSequenceFlowList.add(newSequenceFlow);
return newSequenceFlowList;
}
/**
* 获取目标历史节点的活动ID
* @param targetTaskId 目标历史节点
* @param targetExecutionId 目标历史执行流ID
* @return
*/
private String getLastActivityId(String targetTaskId,String targetExecutionId){
List<HistoricActivityInstance> haiFinishedList = historyService.createHistoricActivityInstanceQuery().executionId(targetExecutionId).finished().list();
Optional<HistoricActivityInstance> optional = haiFinishedList.stream().filter(his -> targetTaskId.equals(his.getTaskId())).findFirst();
String lastActivityId = optional.isPresent() ? optional.get().getActivityId() : null;
return lastActivityId;
}
}