flowable 駁回
歡迎大家學習交流,如有不對的地方,請大家多多指教,我接下來會把flowable的所有的中國式API*都寫出來,也希望對大家有幫助,程序員只要靜下心來,其實可以產生巨大的能量,靠任何人都沒有用,唯有靠自己。學習好一門技術,還是多看看源代碼,多在實際工作中用,如果想走捷徑,想通過一本書或者一些視頻想學好,那永遠是痴心說夢。*
網上搜索了很多關於activiti的駁回方法,flowable的駁回方法,發現一個問題,基本都是在扯淡,根本無法解決商業用途,為了把這塊吃透,我最近研究了一下他們的源代碼,已在我們公司使用,暫時沒有發現問題。其實看flowable的源代碼很簡單的,就是一個命令模式,仿照他們的命令模式寫自己的就可以了,沒有太大的難度。不得不佩服flowable的作者,用命令模式規范了自己的代碼,而且把這么好的東西開源出來,從來沒有找我們要過錢,這是何等的偉大,像大神致敬。閑話不多說,直接來代碼比較干脆。
由於我們公司的流程有規范,所以有寫地方有點特殊,如果不懂的可以隨時給我留言即可,來也網絡,去也網絡。
- 1. 判斷該節點上一個節點是不是並行網關節點
- 2. 如果上一個節點是提交者的話要處理一下
- 3. 添加審批意見和修改流程狀態
- 4. 刪除現有的所有任務
- 5. 刪除節點信息
- 6. 駁回到disk節點
- 6.1 如果當前節點是多實例節點 刪除當前多實例 如果目標節點不是多實例我們就創建一個孩子實例
- 6.2 處理並行網關的多實例
具體代碼
public ReturnVo<String> backToStep(BackVo backVo) {
ReturnVo<String> returnVo = new ReturnVo<>(ReturnCode.SUCCESS, "OK");
if (backVo != null && StringUtils.isNotBlank(backVo.getTaskId())) {
TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(backVo.getTaskId()).singleResult();
if (taskEntity != null){
Activity distActivity = processDefinitionUtils.findFlowElementById(taskEntity.getProcessDefinitionId(), backVo.getDistFlowElementId());
if (taskEntity != null && distActivity != null) {
//1. 判斷該節點上一個節點是不是並行網關節點
List<SequenceFlow> incomingFlows = distActivity.getIncomingFlows();
if (CollectionUtils.isNotEmpty(incomingFlows)) {
for (SequenceFlow sequenceFlow : incomingFlows) {
FlowElement upNode = sequenceFlow.getSourceFlowElement();
if (upNode != null && (upNode instanceof ParallelGateway || upNode instanceof InclusiveGateway)) {
returnVo = new ReturnVo<>(ReturnCode.FAIL, "並行節點無法駁回,請選擇其他節點!");
return returnVo;
}
}
}
//2. 如果上一個節點是提交者的話要處理一下
if (FlowConstant.FLOW_SUBMITTER.equals(distActivity.getName())) {
//查找發起人
ExtendHisprocinst extendHisprocinst = this.extendHisprocinstService.findExtendHisprocinstByProcessInstanceId(taskEntity.getProcessInstanceId());
if (extendHisprocinst != null) {
runtimeService.setVariable(taskEntity.getProcessInstanceId(), FlowConstant.FLOW_SUBMITTER, extendHisprocinst.getCreator());
}
}
//3. 添加審批意見和修改流程狀態
this.addCommentAndUpdateProcessStatus(backVo);
//4. 刪除現有的所有任務
managementService.executeCommand(new DeleteTaskCmd(taskEntity.getProcessInstanceId()));
//5. 刪除節點信息
this.deleteHisActivities(distActivity, taskEntity.getProcessInstanceId());
//6. 駁回到disk節點
Activity currActivity = processDefinitionUtils.findFlowElementById(taskEntity.getProcessDefinitionId(), taskEntity.getTaskDefinitionKey());
//6.1 如果當前節點是多實例節點 刪除當前多實例 如果目標節點不是多實例我們就創建一個孩子實例
boolean flag = false;
if (currActivity.getBehavior() instanceof MultiInstanceActivityBehavior){
ExecutionEntity executionEntity = (ExecutionEntity)runtimeService.createExecutionQuery().executionId(taskEntity.getExecutionId()).singleResult();
managementService.executeCommand(new DeleteMultiInstanceExecutionCmd(executionEntity.getParentId(),false));
flag = true;
}
//6.2 處理並行網關的多實例
List<Execution> executions = runtimeService.createExecutionQuery().parentId(taskEntity.getProcessInstanceId()).list();
if (CollectionUtils.isNotEmpty(executions) && executions.size() >1){
executions.forEach(execution -> {
ExecutionEntity e = (ExecutionEntity)execution;
managementService.executeCommand(new DeleteChildExecutionCmd(e));
});
flag = true;
}
if (flag) {
ExecutionEntity parentExecutionEntity = (ExecutionEntity)runtimeService.createExecutionQuery().executionId(taskEntity.getProcessInstanceId()).singleResult();
managementService.executeCommand(new AddChildExecutionCmd(parentExecutionEntity));
}
managementService.executeCommand(new JumpActivityCmd(taskEntity.getProcessInstanceId(),distActivity.getId()));
//TODO 7. 處理加簽的數據0
}
}else {
returnVo = new ReturnVo<>(ReturnCode.FAIL, "當前任務不存在!");
}
} else {
returnVo = new ReturnVo<>(ReturnCode.FAIL, "請設置相關參數!");
}
return returnVo;
}
- ProcessDefinitionUtils
@Component
public class ProcessDefinitionUtils {
@Autowired
private RepositoryService repositoryService;
/**
* 獲取end節點
*
* @param processDefId
* @return FlowElement
*/
public FlowElement findEndFlowElement(String processDefId) {
Process process = repositoryService.getBpmnModel(processDefId).getMainProcess();
Collection<FlowElement> list = process.getFlowElements();
for (FlowElement f : list) {
if (f instanceof EndEvent) {
return f;
}
}
return null;
}
/**
* 獲取指定節點的節點信息
*
* @param processDefId
* @param flowElementId
* @return FlowElement
*/
public Activity findFlowElementById(String processDefId, String flowElementId) {
Process process = repositoryService.getBpmnModel(processDefId).getMainProcess();
return (Activity) process.getFlowElement(flowElementId);
}
}
addCommentAndUpdateProcessStatus 這個方法是添加審批意見和更新流程狀態,由於流程狀態沒有,我這里擴展了一張表,狀態主要有審批中,駁回,暫存,轉辦,撤回,終止等等狀態
/**
* 添加審批意見和修改流程狀態
* @param baseProcessVo 基本流程任務參數
*/
protected void addCommentAndUpdateProcessStatus(BaseProcessVo baseProcessVo) {
//兼容處理
if (StringUtils.isBlank(baseProcessVo.getProcessInstanceId())){
Task task = taskService.createTaskQuery().taskId(baseProcessVo.getTaskId()).singleResult();
if (task != null) {
baseProcessVo.setProcessInstanceId(task.getProcessInstanceId());
}
}
//1.添加審批意見
FlowCommentVo flowCommentVo = new FlowCommentVo(baseProcessVo.getTaskId(), baseProcessVo.getUserCode(),
baseProcessVo.getProcessInstanceId(), baseProcessVo.getMessage(), baseProcessVo.getCommentTypeEnum().toString());
this.addFlowComment(flowCommentVo);
//2.修改流程實例的狀態
ExtendHisprocinst extendHisprocinst = new ExtendHisprocinst(baseProcessVo.getProcessInstanceId(), baseProcessVo.getProcessStatusEnum().toString());
extendHisprocinstService.updateStatusByProcessInstanceId(extendHisprocinst);
//3.TODO 生成索引
}
/**
* 添加審批意見
* @param flowCommentVo
*/
private void addFlowComment(FlowCommentVo flowCommentVo) {
FlowCommentCmd cmd = new FlowCommentCmd(flowCommentVo.getTaskId(), flowCommentVo.getUserId(),
flowCommentVo.getProcessInstanceId(), flowCommentVo.getType(), flowCommentVo.getMessage());
managementService.executeCommand(cmd);
}
DeleteTaskCmd 刪除任務命令
public class DeleteTaskCmd implements Command<Void> {
private String processInstanceId;
public DeleteTaskCmd(String processInstanceId) {
this.processInstanceId = processInstanceId;
}
@Override
public Void execute(CommandContext commandContext) {
TaskEntityManager taskEntityManager = CommandContextUtil.getTaskEntityManager(commandContext);
ExecutionEntityManager executionEntityManager = org.flowable.engine.impl.util.CommandContextUtil.getExecutionEntityManager(commandContext);
List<ExecutionEntity> executionEntities = executionEntityManager.findChildExecutionsByProcessInstanceId(processInstanceId);
executionEntities.forEach(executionEntity -> taskEntityManager.deleteTasksByExecutionId(executionEntity.getId()));
return null;
}
}
AddChildExecutionCmd 添加一個流程實例下面的執行實例
public class AddChildExecutionCmd implements Command<Void> {
private ExecutionEntity parentExecutionEntity;
public AddChildExecutionCmd(ExecutionEntity parentExecutionEntity) {
this.parentExecutionEntity = parentExecutionEntity;
}
@Override
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(commandContext);
executionEntityManager.createChildExecution(parentExecutionEntity);
return null;
}
}
DeleteChildExecutionCmd 刪除執行實例
public class DeleteChildExecutionCmd implements Command<Void> {
private ExecutionEntity child;
public DeleteChildExecutionCmd(ExecutionEntity child) {
this.child = child;
}
@Override
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(commandContext);
executionEntityManager.delete(child,true);
return null;
}
}
JumpActivityCmd 執行跳轉
public class JumpActivityCmd implements Command<Void> {
private String target;
private String processInstanceId;
public JumpActivityCmd(String processInstanceId, String target) {
this.processInstanceId = processInstanceId;
this.target = target;
}
@Override
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(commandContext);
List<ExecutionEntity> executionEntities = executionEntityManager.findChildExecutionsByParentExecutionId(processInstanceId);
Process process = ProcessDefinitionUtil.getProcess(executionEntities.get(0).getProcessDefinitionId());
FlowNode targetFlowElement = (FlowNode) process.getFlowElement(target);
FlowableEngineAgenda agenda = CommandContextUtil.getAgenda();
executionEntities.forEach(execution -> {
execution.setCurrentFlowElement(targetFlowElement);
agenda.planContinueProcessInCompensation(execution);
});
return null;
}
