当前位置: 首页 > news >正文

河南省台前县建设局网站磁力棒

河南省台前县建设局网站,磁力棒,文字生成二维码,购物网站后台订单处理流程概述 相比普通任务节点跳转,多实例任务的跳转要考虑更多的因素,主要是因为多实例任务包含了父execution和子execution,子execution又有其对应的task,另外还有控制多实例任务的内置变量。这几个特殊点是处理多实例任务跳转的难点。…

概述

相比普通任务节点跳转,多实例任务的跳转要考虑更多的因素,主要是因为多实例任务包含了父execution和子execution,子execution又有其对应的task,另外还有控制多实例任务的内置变量。这几个特殊点是处理多实例任务跳转的难点。关于普通节点跳转的处理,请参考前文《activiti学习(二十二)——常规任务节点跳转(退回、自由跳转功能)》

 

解决思路

与常规节点跳转相比,多实例任务有几个棘手的地方:

1、多实例任务存在父execution和子execution的情况,执行跳转时,必须删除子execution;

2、并行多实例任务存在多个task,进行跳转时,必须把多个task都删除;

3、因为并行多实例任务创建子execution的判断与流程变量有关,因此跳转时必须清除原来的流程变量;

我们的跳转命令必须解决以上三个问题。

 

具体实现

这里简单写一个命令类供各位参考。

import java.util.List;
import java.util.Map;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.context.Context;
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.ExecutionEntityManager;
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.runtime.AtomicOperation;public class MultiInstanceJumpCmd implements Command {private String taskId;private Map<String, Object> variables;private String desActivityId;private String scActivityId;public MultiInstanceJumpCmd(String taskId, Map<String, Object> variables, String scActivityId, String desActivityId) {this.taskId = taskId;this.variables = variables;this.desActivityId = desActivityId;this.scActivityId = scActivityId;}public Object execute(CommandContext commandContext) {TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();TaskEntity taskEntity = taskEntityManager.findTaskById(taskId);ExecutionEntity parentExecutionEntity = taskEntity.getProcessInstance();String processDefinitionId = parentExecutionEntity.getProcessDefinitionId();ProcessDefinitionEntity processDefinitionEntity = Context.getProcessEngineConfiguration().getDeploymentManager().findDeployedProcessDefinitionById(processDefinitionId);ActivityImpl curActivityImpl = processDefinitionEntity.findActivity(scActivityId);// 设置流程变量parentExecutionEntity.setVariables(variables);parentExecutionEntity.setExecutions(null);parentExecutionEntity.setActivity(curActivityImpl);parentExecutionEntity.setEventSource(curActivityImpl);parentExecutionEntity.setActive(true);// 触发全局事件转发器TASK_COMPLETED事件if (Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createEntityWithVariablesEvent(ActivitiEventType.TASK_COMPLETED, this, variables, false));}// 删除任务List<TaskEntity> taskList = taskEntityManager.findTasksByProcessInstanceId(parentExecutionEntity.getProcessInstanceId());for(TaskEntity taskEntity1 : taskList) {taskEntity1.fireEvent(TaskListener.EVENTNAME_COMPLETE);taskEntityManager.deleteTask(taskEntity1, TaskEntity.DELETE_REASON_COMPLETED, false);	}ExecutionEntityManager executionEntityManager = Context.getCommandContext().getExecutionEntityManager();List<ExecutionEntity> childExecutionList = executionEntityManager.findChildExecutionsByParentExecutionId(parentExecutionEntity.getId());for(ExecutionEntity executionEntityChild : childExecutionList) {List<ExecutionEntity> childExecutionList1 = executionEntityManager.findChildExecutionsByParentExecutionId(executionEntityChild.getId());for(ExecutionEntity executionEntityChild1 : childExecutionList1) {executionEntityChild1.remove();Context.getCommandContext().getHistoryManager().recordActivityEnd(executionEntityChild1);}executionEntityChild.remove();Context.getCommandContext().getHistoryManager().recordActivityEnd(executionEntityChild);}commandContext.getIdentityLinkEntityManager().deleteIdentityLinksByProcInstance(parentExecutionEntity.getId());ActivityImpl desActivityimpl = processDefinitionEntity.findActivity(desActivityId);	parentExecutionEntity.removeVariable("nrOfInstances");parentExecutionEntity.removeVariable("nrOfActiveInstances");parentExecutionEntity.removeVariable("nrOfCompletedInstances");parentExecutionEntity.removeVariable("loopCounter");parentExecutionEntity.setActivity(desActivityimpl);parentExecutionEntity.performOperation(AtomicOperation.TRANSITION_CREATE_SCOPE);return null;}
}

这个类需要为其提供taskId,源节点id、目标节点id。35行获取父execution,36行获取流程定义id。54-58行通过流程定义id获取所有task,并删除之。60-70行删除子execution,之所以会有两个for循环,是因为并行多实例任务的子execution还会再创建子execution作为具体的执行实例。75-78行删除流程变量。81行不能使用普通节点跳转的executionEntity.executeActivity()。这是因为如果目标节点是多实例任务的话,不经过AtomicOperationTransitionCreateScope类,创建的execution会有问题。稍微跟踪一下AtomicOperation.TRANSITION_CREATE_SCOPE对应的AtomicOperationTransitionCreateScope类:

public class AtomicOperationTransitionCreateScope implements AtomicOperation {//......public void execute(InterpretableExecution execution) {InterpretableExecution propagatingExecution = null;ActivityImpl activity = (ActivityImpl) execution.getActivity();if (activity.isScope()) {propagatingExecution = (InterpretableExecution) execution.createExecution();propagatingExecution.setActivity(activity);propagatingExecution.setTransition(execution.getTransition());execution.setTransition(null);execution.setActivity(null);execution.setActive(false);log.debug("create scope: parent {} continues as execution {}", execution, propagatingExecution);propagatingExecution.initialize();} else {propagatingExecution = execution;}propagatingExecution.performOperation(AtomicOperation.TRANSITION_NOTIFY_LISTENER_START);}
}

对于普通节点,activity.isScope()判断为false,则执行第19行。若目标节点是普通任务节点,那不会有问题。但是目标节点是多实例任务时,会执行9-16行,除了创建一个子execution以外,还让子execution去执行接下来的原子操作。具体情况说起来比较绕口,就以数据库记录来解释方便一点,当通过跳转进入并行多实例任务时,act_ru_execution表如下:

2501是父execution,其id与流程实例id是一致的。12501是上面第9行代码创建出来的execution。12506、12507、12508则是进入并行多实例任务节点后,行为类根据节点配置的属性,创建对应数量的execution,这些execution的父亲是12501。而12506、12507、12508这三个execution,下面都有对应的task,当task完成时,对应的execution会结束。所以如果像普通节点跳转那样调用executionEntity.executeActivity()的话,就不会产生12501这个execution。

 

简单演示

新建流程图multiInstanceJump.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="multiInstanceJump" name="MultiInstance Jump" isExecutable="true"><startEvent id="startevent1" name="Start"></startEvent><userTask id="usertask1" name="usertask1"><multiInstanceLoopCharacteristics isSequential="true"><loopCardinality>3</loopCardinality></multiInstanceLoopCharacteristics></userTask><sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow><userTask id="usertask2" name="usertask2"><multiInstanceLoopCharacteristics isSequential="false"><loopCardinality>3</loopCardinality></multiInstanceLoopCharacteristics></userTask><sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow><userTask id="usertask3" name="usertask3"><multiInstanceLoopCharacteristics isSequential="true"><loopCardinality>3</loopCardinality></multiInstanceLoopCharacteristics></userTask><sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow><userTask id="usertask4" name="usertask4"><multiInstanceLoopCharacteristics isSequential="false"><loopCardinality>3</loopCardinality></multiInstanceLoopCharacteristics></userTask><sequenceFlow id="flow4" sourceRef="usertask3" targetRef="usertask4"></sequenceFlow><endEvent id="endevent2" name="End"></endEvent><sequenceFlow id="flow6" sourceRef="usertask4" targetRef="endevent2"></sequenceFlow></process><bpmndi:BPMNDiagram id="BPMNDiagram_multiInstanceJump"><bpmndi:BPMNPlane bpmnElement="multiInstanceJump" id="BPMNPlane_multiInstanceJump"><bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1"><omgdc:Bounds height="35.0" width="35.0" x="150.0" y="220.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1"><omgdc:Bounds height="55.0" width="105.0" x="230.0" y="210.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2"><omgdc:Bounds height="55.0" width="105.0" x="380.0" y="210.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3"><omgdc:Bounds height="55.0" width="105.0" x="380.0" y="300.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="usertask4" id="BPMNShape_usertask4"><omgdc:Bounds height="55.0" width="105.0" x="230.0" y="300.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="endevent2" id="BPMNShape_endevent2"><omgdc:Bounds height="35.0" width="35.0" x="150.0" y="310.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1"><omgdi:waypoint x="185.0" y="237.0"></omgdi:waypoint><omgdi:waypoint x="230.0" y="237.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2"><omgdi:waypoint x="335.0" y="237.0"></omgdi:waypoint><omgdi:waypoint x="380.0" y="237.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3"><omgdi:waypoint x="432.0" y="265.0"></omgdi:waypoint><omgdi:waypoint x="432.0" y="300.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4"><omgdi:waypoint x="380.0" y="327.0"></omgdi:waypoint><omgdi:waypoint x="335.0" y="327.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6"><omgdi:waypoint x="230.0" y="327.0"></omgdi:waypoint><omgdi:waypoint x="185.0" y="327.0"></omgdi:waypoint></bpmndi:BPMNEdge></bpmndi:BPMNPlane></bpmndi:BPMNDiagram>
</definitions>

接下来的部署和启动操作这里略过,不懂的读者请参考前面的文章,已经写过很多次了。其他配置与《activiti学习(二十二)——常规任务节点跳转(退回、自由跳转功能)》基本一致。

启动后查看act_ru_execution表:

userTask1为串行多实例节点。因此这时execution只有2个。

act_ru_task表:

该task对应2503那个execution。

现在我们准备从userTask1跳转到userTask4:

public void multiInstanceJump() {String taskId = "2509";Map<String, Object> variables = new HashMap<String, Object>();String scActivityId = "usertask1";String desActivityId = "usertask4";MultiInstanceJumpCmd multiInstanceJumpCmd = new MultiInstanceJumpCmd(taskId, variables, scActivityId, desActivityId);ServiceImpl service = (ServiceImpl)pe.getRepositoryService();CommandExecutor commandExecutor = service.getCommandExecutor();commandExecutor.execute(multiInstanceJumpCmd);
}

 执行后查看结果,act_ru_execution表:

 因为userTask4为并行数3的并行多实例节点,因此会有5个execution。

act_ru_task表:

 有3个任务,跳转正常。

 

小结

考虑到实际流程中,必然存在普通任务节点,也存在多实例任务节点,因此跳转的命令必须能兼容这两种情况。目前简单测试了一下,该命令能正常进行普通任务节点和多实例任务节点的跳转。此次文章纯属抛砖引玉,读者如果有更好的方法,或者发现命令中存在一些错误,也请给予指正。

http://www.lbrq.cn/news/2435707.html

相关文章:

  • 文昌网站建设网页设计网站
  • 个人网页设计作品代码seo外链工具有用吗
  • 鄂尔多斯 网站制作网站构建的基本流程
  • 汝阳网站建设兰州seo快速优化报价
  • 用laravel做的网站买卖网交易平台
  • 百度网站托管推手平台哪个靠谱
  • 做360全景有什么网站百度seo优化公司
  • 高端营销网站定制苏州百度快照优化排名
  • 网络建站工作室官网源码有域名有服务器怎么做网站
  • 公安部门网站建设方案网站seo优化发布高质量外链
  • 什么是网站建设与管理百度地图导航网页版
  • python怎么做抢课网站杭州百度推广代理公司哪家好
  • 自己做头像的网站精准广告投放
  • 动态网站开发难吗网络推广网络营销和网站推广的区别
  • 网站数据包如何做架构恶意点击竞价时用的什么软件
  • 南昌免费网站建站模板网站标题优化排名
  • 手机网站做淘宝客北京网站seo服务
  • 网站区域名是什么网站是怎么优化推广的
  • 做视频直播的网站有哪些seo自动刷外链工具
  • 网站制作 推荐新鸿儒百度seo搜索引擎优化
  • 宣讲家网站官德修养与作风建设洛阳网站建设
  • 自己做的网站链接到微信支付界面能打开各种网站的浏览器下载
  • oa管理系统是什么商丘网站seo
  • 怎样做赌博网站百度app下载安装官方免费下载
  • 网络推广商城网站网址生成短链接
  • 什么网站可以做外链站长工具平台
  • wordpress双域名seo模拟点击
  • 济南做网站哪家好优化关键词的作用
  • 国外做网站公司能赚钱360搜索引擎
  • 免费人才招聘网站软文代写
  • ​多线程 + io_uring 实现高效大文件写入
  • JS逆向基础( AES 解密密文WordArray和Uint8Array实战②)
  • BUUCTF(web)部分题解
  • k8s pvc是否可绑定在多个pod上
  • LeetCode 633.平方数之和
  • 现在希望用git将本地文件crawler目录下的文件更新到远程仓库指定crawler目录下,命名相同的文件本地文件将其覆盖