1. acitiviti5流程图实现驳回
rejectProcess.bpmn
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
<process id="rejectProcess" name="驳回流程测试" isExecutable="true">
<startEvent id="startevent1" name="Start"></startEvent>
<endEvent id="endevent1" name="End"></endEvent>
<userTask id="applySubmit" name="申请人提交" activiti:assignee="${applySubmit}"></userTask>
<userTask id="check" name="审批" activiti:assignee="${check}"></userTask>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="applySubmit"></sequenceFlow>
<sequenceFlow id="flow2" sourceRef="applySubmit" targetRef="check">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${applySubmitPass}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow3" sourceRef="check" targetRef="endevent1">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${checkPass}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow4" name="驳回" sourceRef="check" targetRef="applySubmit">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${checkReject}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_rejectProcess">
<bpmndi:BPMNPlane bpmnElement="rejectProcess" id="BPMNPlane_rejectProcess">
<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
<omgdc:Bounds height="35.0" width="35.0" x="70.0" y="200.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
<omgdc:Bounds height="35.0" width="35.0" x="550.0" y="200.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="applySubmit" id="BPMNShape_applySubmit">
<omgdc:Bounds height="55.0" width="105.0" x="180.0" y="190.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="check" id="BPMNShape_check">
<omgdc:Bounds height="55.0" width="105.0" x="360.0" y="190.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="105.0" y="217.0"></omgdi:waypoint>
<omgdi:waypoint x="180.0" y="217.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="285.0" y="217.0"></omgdi:waypoint>
<omgdi:waypoint x="360.0" y="217.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
<omgdi:waypoint x="465.0" y="217.0"></omgdi:waypoint>
<omgdi:waypoint x="550.0" y="217.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
<omgdi:waypoint x="412.0" y="190.0"></omgdi:waypoint>
<omgdi:waypoint x="412.0" y="144.0"></omgdi:waypoint>
<omgdi:waypoint x="232.0" y="144.0"></omgdi:waypoint>
<omgdi:waypoint x="232.0" y="190.0"></omgdi:waypoint>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="14.0" width="100.0" x="420.0" y="171.0"></omgdc:Bounds>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
2. 测试
@Slf4j
public class TestAutoSubmit {
/**
* 部署流程
*/
@Test
public void deployProcessDefinition() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取流程定义与部署相关Service
Deployment deployment = processEngine.getRepositoryService()
// 创建一个部署对象
.createDeployment()
.name("驳回流程测试")
// 加载资源文件
.addClasspathResource("processes/rejectProcess.bpmn")
.addClasspathResource("processes/rejectProcess.png")
// 完成部署
.deploy();
log.info(deployment.getId());
log.info(deployment.getName());
}
/**
* 启动流程实例
*/
@Test
public void startProcessInstance() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
Map<String, Object> varMap = new HashMap<>();
varMap.put("applySubmit", "张三");
ProcessInstance processInstance = processEngine.getRuntimeService()
.startProcessInstanceByKey("autoSubmit", "autoSubmit", varMap);
log.info(processInstance.getId());
log.info(processInstance.getProcessDefinitionId());
taskQuery();
}
/**
* 申请人提交审批节点
*/
@Test
public void doApplySubmitTask() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Map<String, Object> varMap = new HashMap<>();
varMap.put("applySubmitPass", true);
varMap.put("check", "李四");
taskService.complete("7509", varMap);
taskQuery();
}
/**
* 审批节点,驳回
*/
@Test
public void doCheckRejectTask() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Map<String, Object> varMap = new HashMap<>();
varMap.put("checkReject", true);
varMap.put("checkPass", false);
taskService.complete("7509", varMap);
taskQuery();
}
/**
* 查询待办任务
*/
@Test
public void taskQuery() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
List<Task> list = processEngine.getTaskService().createTaskQuery()
// 筛选 multiMeetingApprove 流程
.processDefinitionKey("rejectProcess")
.list();
list.forEach(task -> {
log.info("流程实例id:{}, 任务处理人:{}, 任务名:{}, 任务定义Key:{}, 任务id:{}", task.getProcessInstanceId(), task.getAssignee(), task.getName(), task.getTaskDefinitionKey(), task.getId());
});
if (list.isEmpty()) {
log.info("没有代办任务了,流程结束");
}
}
3. 去除驳回连线,代码实现驳回
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.ObjectUtils;
/**
* 往回跳转到任意节点
*
* @param taskId 任务id
* @param varMap 流程变量
* @param destTaskKey 跳转的目标任务节点key
* @apiNote 这里使用的是activiti5中 pvm包API,activiti6没有,不兼容
*/
public void rollBackToAnyTask(String taskId, Map<String, Object> varMap, String destTaskKey) {
//查询当前流程实例的待办任务
List<Task> taskList = taskService.createTaskQuery().taskId(taskId).list();
if (taskList == null || taskList.size() == 0) {
throw new ActivitiException("任务已经执行完成,无法跳转处理");
}
Task task = taskList.get(0);
// 取得当前执行对象
ExecutionEntity executionEntity = (ExecutionEntity) runtimeService.createExecutionQuery()
.executionId(task.getExecutionId())
.singleResult();
//流程定义对象
ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(executionEntity.getProcessDefinitionId());
//流程变量
Map<String, Object> variables = executionEntity.getProcessVariables();
if (varMap != null) {
variables.putAll(varMap);
}
//当前活动节点
ActivityImpl currActivityImpl = processDefinitionEntity.findActivity(executionEntity.getActivityId());
//目标活动节点
ActivityImpl nextActivityImpl = processDefinitionEntity.findActivity(destTaskKey);
//目标活动节点 不能是 当前活动节点
if (currActivityImpl != null && nextActivityImpl != currActivityImpl) {
//所有的出口连线集合
List<PvmTransition> pvmTransitions = currActivityImpl.getOutgoingTransitions();
List<PvmTransition> oriPvmTransitions = new ArrayList<>();
oriPvmTransitions.addAll(pvmTransitions);
//清除所有出口连线
pvmTransitions.clear();
//建立新的出口连线
TransitionImpl tImpl = currActivityImpl.createOutgoingTransition();
tImpl.setDestination(nextActivityImpl);
taskService.complete(task.getId(), variables);
//完成任务会新增历史任务记录,根据需要删除
// historyService.deleteHistoricTaskInstance(task.getId());
//删除新的出口
currActivityImpl.getOutgoingTransitions().remove(tImpl);
//恢复之前的所有出口
pvmTransitions.addAll(oriPvmTransitions);
}
}
4. activiti5中Command模式驳回
package com.yl.activiti.service;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.delegate.TaskListener;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.impl.ActivitiEventBuilder;
import org.activiti.engine.impl.TaskServiceImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.interceptor.CommandExecutor;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntityManager;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ScopeImpl;
import org.activiti.engine.task.IdentityLinkType;
import java.util.List;
import java.util.Map;
/**
* activiti5中 常规任务节点跳转
*
* @author liuxubo
* @date 2022/10/25 23:20
*/
public class CommonJumpCmd implements Command {
/**
* 任务id
*/
private String taskId;
/**
* 流程变量
*/
private Map<String, Object> variables;
/**
* taskKey名
*/
private String desActivityId;
/**
* 构造器
* @param taskId 任务id
* @param variables 流程变量
* @param desActivityId taskKey名
*/
public CommonJumpCmd(String taskId, Map<String, Object> variables, String desActivityId) {
this.taskId = taskId;
this.variables = variables;
this.desActivityId = desActivityId;
}
@Override
public Object execute(CommandContext commandContext) {
//获取任务实例管理类
TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();
//获取当前任务实例
TaskEntity taskEntity = taskEntityManager.findTaskById(taskId);
//获取当前节点的执行实例
ExecutionEntity executionEntity = taskEntity.getExecution();
// 设置流程变量
executionEntity.setVariables(variables);
// 触发执行监听器complete事件
taskEntity.fireEvent(TaskListener.EVENTNAME_COMPLETE);
// 触发全局事件转发器TASK_COMPLETED事件
if (Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
Context.getProcessEngineConfiguration().getEventDispatcher()
.dispatchEvent(ActivitiEventBuilder.createEntityWithVariablesEvent(ActivitiEventType.TASK_COMPLETED, this, variables, false));
}
// 添加act_ru_identitylink表记录。常规流程实例id与执行id相同
if (Authentication.getAuthenticatedUserId() != null && executionEntity.getProcessInstanceId() != null) {
executionEntity.involveUser(Authentication.getAuthenticatedUserId(), IdentityLinkType.PARTICIPANT);
}
// 删除任务
// deleteTask(String taskId, String deleteReason, boolean cascade), 判断taskId对应的TaskEntity的executionId是否为空,非空则抛出异常,导致无法删除任务
taskEntityManager.deleteTask(taskEntity, TaskEntity.DELETE_REASON_COMPLETED, false);
//触发执行监听器end事件 获取当前活动节点对应的执行监听器并触发end事件,进而会调用内置的记录监听器。如果漏了这一步骤,会影响历史表记录
ScopeImpl scope = executionEntity.getActivity();
List<ExecutionListener> exectionListeners = scope.getExecutionListeners("end");
for(ExecutionListener listener : exectionListeners) {
executionEntity.setEventName("end");
executionEntity.setEventSource(scope);
try {
listener.notify(executionEntity);
} catch (Exception e) {
throw new ActivitiException(e.getMessage());
}
}
//获取流程定义id
String processDefinitionId = executionEntity.getProcessDefinitionId();
ProcessDefinitionEntity processDefinitionEntity = Context.getProcessEngineConfiguration().getDeploymentManager()
.findDeployedProcessDefinitionById(processDefinitionId);
ActivityImpl desActivityimpl = processDefinitionEntity.findActivity(desActivityId);
//设置执行实例的当前活动节点为目标节点
executionEntity.executeActivity(desActivityimpl);
return null;
}
/**
* 常规任务节点跳转
* @param taskService
*/
public void jump(TaskService taskService) {
TaskServiceImpl taskServiceImpl = (TaskServiceImpl)taskService;
CommandExecutor commandExecutor = taskServiceImpl.getCommandExecutor();
commandExecutor.execute(this);
}
}
5.activiti6Command模式驳回
package com.yl.activiti.service;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.ManagementService;
import org.activiti.engine.impl.history.HistoryManager;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntityManager;
import org.activiti.engine.impl.util.ProcessDefinitionUtil;
/**
* activiti6中 常规任务节点跳转
*
* @author liuxubo
* @date 2022/10/26 23:39
*/
public class JumpAnyWhereCmd implements Command {
/**
* 任务ID
*/
private String taskId;
/**
* 目标任务节点key
*/
private String destTaskKey;
/**
*
* @param taskId 任务ID
* @param destTaskKey 目标任务节点key
*/
public JumpAnyWhereCmd(String taskId, String destTaskKey) {
this.taskId = taskId;
this.destTaskKey = destTaskKey;
}
/**
* 执行
* @param commandContext
* @return
*/
public Object execute(CommandContext commandContext) {
//获取任务实例管理类
TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();
//获取当前任务实例
TaskEntity currentTask = taskEntityManager.findById(taskId);
//获取当前节点的执行实例
ExecutionEntity execution = currentTask.getExecution();
//获取流程定义id
String processDefinitionId = execution.getProcessDefinitionId();
//获取目标节点
Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
FlowElement flowElement = process.getFlowElement(destTaskKey);
//获取历史管理
HistoryManager historyManager = commandContext.getHistoryManager();
//通知当前活动结束(更新act_hi_actinst)
historyManager.recordActivityEnd(execution, "jump to userTask1");
//通知任务节点结束(更新act_hi_taskinst)
historyManager.recordTaskEnd(taskId, "jump to userTask1");
//删除正在执行的当前任务
taskEntityManager.delete(taskId);
//此时设置执行实例的当前活动节点为目标节点
execution.setCurrentFlowElement(flowElement);
//向operations中压入继续流程的操作类
commandContext.getAgenda().planContinueProcessOperation(execution);
return null;
}
/**
* 跳转任意节点
* @param managementService
*/
public void jump(ManagementService managementService){
managementService.executeCommand(this);
}
}