activiti使用的时候,通常需要跟业务紧密的结合在一起,有些业务非常的复杂,比如一个简单的采购流程:流程如下:
供应商上新商品的时候,提交商务审核,商务审核通过提交运营审核,审核失败退回供应商。
运营审核成功提交合同签订。交运营审核审核失败退回商务审核或者直接退回供应商。
合同签订审核通过结束,合同签订审核不通过返回运营审核或者退回商务审核,或者退回供应商。
上面的流程就出现了一个问题,什么问题呢?
我们来观察一下退回线的问题。
1.商务审核退回供应商上新。
2.运营审核可能退回商务审核,运营审核可能退回供应商上新。
3.合同签订可能退回运营审核,合同签订可能退回商务审核,合同签订可能退回供应商上新。
4....
假如以后我们的流程在添加新的部门审核,是不是我们的退回线更加的多了。其实就是n!的问题,难道我们没添加一个节点,就要画很多的退回线吗?这显然是一个糟糕的设计。oh my god.
存在的问题就是,我们要是想让我们的流程更加的通用,我们可能在设计的时候,需要添加很多的退回线控制,防止业务变化,流程跟起来变化,这就是应对了变化,同时在增加了冗余设计。
那有没有一种更好的方式,能解决上面的问题呢?很显然这就是我们本章要解决的问题。
1.1.1. activiti节点跳转实现
实现之前,我们考虑几个问题。
1.当前流程在哪一个节点。
2.流程需要跳转的目标节点。
3.跳转到目标节点之后,需要添加变量吗?有可能需要把,总不能无缘无故的跳转到了目标节点。痕迹肯定要记录。
4.跳转到目标节点,那当前节点配置的任务监听需要触发吗?(可参考 activiti监听器使用).当前节点跳转到目标节点的时候,如果当前节点配置了任务监听业务,调转到目标节点之前,这些当前的任务节点的是否触发任务监听业务必须能支持灵活配置。
上面的思考点,也是我们接下来需要重点讲解的内容。那下面就开始我们的设计吧。
1.1.1.1. 流程图
下面我们先定义一个流程如下图所示:
1.1.1.2. xml
下面我们先定义一个xml定义如下所示:
<?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=\"daling\">
<process id=\"daling\" name=\"name_daling\" isExecutable=\"true\" activiti:candidateStarterUsers=\"a,b,c,d\">
<userTask id=\"usertask2\" name=\"usertask2\" activiti:assignee=\"c\"></userTask>
<userTask id=\"usertask3\" name=\"usertask3\"></userTask>
<sequenceFlow id=\"flow4\" sourceRef=\"usertask2\" targetRef=\"usertask3\"></sequenceFlow>
<userTask id=\"usertask4\" name=\"usertask4\"></userTask>
<sequenceFlow id=\"flow5\" sourceRef=\"usertask3\" targetRef=\"usertask4\"></sequenceFlow>
<userTask id=\"usertask5\" name=\"usertask5\"></userTask>
<sequenceFlow id=\"flow6\" sourceRef=\"usertask4\" targetRef=\"usertask5\"></sequenceFlow>
<endEvent id=\"endevent1\" name=\"End\"></endEvent>
<sequenceFlow id=\"flow7\" sourceRef=\"usertask5\" targetRef=\"endevent1\"></sequenceFlow>
<startEvent id=\"startevent1\" name=\"Start\"></startEvent>
<sequenceFlow id=\"flow8\" sourceRef=\"startevent1\" targetRef=\"usertask2\"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id=\"BPMNDiagram_daling\">
<bpmndi:BPMNPlane bpmnElement=\"daling\" id=\"BPMNPlane_daling\">
<bpmndi:BPMNShape bpmnElement=\"usertask2\" id=\"BPMNShape_usertask2\">
<omgdc:Bounds height=\"55.0\" width=\"105.0\" x=\"300.0\" y=\"90.0\"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement=\"usertask3\" id=\"BPMNShape_usertask3\">
<omgdc:Bounds height=\"55.0\" width=\"105.0\" x=\"450.0\" y=\"90.0\"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement=\"usertask4\" id=\"BPMNShape_usertask4\">
<omgdc:Bounds height=\"55.0\" width=\"105.0\" x=\"600.0\" y=\"90.0\"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement=\"usertask5\" id=\"BPMNShape_usertask5\">
<omgdc:Bounds height=\"55.0\" width=\"105.0\" x=\"750.0\" y=\"90.0\"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement=\"endevent1\" id=\"BPMNShape_endevent1\">
<omgdc:Bounds height=\"35.0\" width=\"35.0\" x=\"900.0\" y=\"100.0\"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement=\"startevent1\" id=\"BPMNShape_startevent1\">
<omgdc:Bounds height=\"35.0\" width=\"35.0\" x=\"140.0\" y=\"90.0\"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement=\"flow4\" id=\"BPMNEdge_flow4\">
<omgdi:waypoint x=\"405.0\" y=\"117.0\"></omgdi:waypoint>
<omgdi:waypoint x=\"450.0\" y=\"117.0\"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement=\"flow5\" id=\"BPMNEdge_flow5\">
<omgdi:waypoint x=\"555.0\" y=\"117.0\"></omgdi:waypoint>
<omgdi:waypoint x=\"600.0\" y=\"117.0\"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement=\"flow6\" id=\"BPMNEdge_flow6\">
<omgdi:waypoint x=\"705.0\" y=\"117.0\"></omgdi:waypoint>
<omgdi:waypoint x=\"750.0\" y=\"117.0\"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement=\"flow7\" id=\"BPMNEdge_flow7\">
<omgdi:waypoint x=\"855.0\" y=\"117.0\"></omgdi:waypoint>
<omgdi:waypoint x=\"900.0\" y=\"117.0\"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement=\"flow8\" id=\"BPMNEdge_flow8\">
<omgdi:waypoint x=\"175.0\" y=\"107.0\"></omgdi:waypoint>
<omgdi:waypoint x=\"300.0\" y=\"117.0\"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
1.1.1.3. 代码实现
package com.daling.ch1.jd;
import java.util.Iterator;
import java.util.Map;
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.TaskEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
/**
*
* JD节点的跳转
* 分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519)
*/
public class JDJumpTaskCmd implements Command<Void> {
protected String executionId;
protected ActivityImpl desActivity;
protected Map<String, Object> paramvar;
protected ActivityImpl currentActivity;
/**
* 分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519)
*/
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = Context
.getCommandContext().getExecutionEntityManager();
// 获取当前流程的executionId,因为在并发的情况下executionId是唯一的。
ExecutionEntity executionEntity = executionEntityManager
.findExecutionById(executionId);
executionEntity.setVariables(paramvar);
executionEntity.setEventSource(this.currentActivity);
executionEntity.setActivity(this.currentActivity);
// 根据executionId 获取Task
Iterator<TaskEntity> localIterator = Context.getCommandContext()
.getTaskEntityManager()
.findTasksByExecutionId(this.executionId).iterator();
while (localIterator.hasNext()) {
TaskEntity taskEntity = (TaskEntity) localIterator.next();
// 触发任务监听
taskEntity.fireEvent(\"complete\");
// 删除任务的原因
Context.getCommandContext().getTaskEntityManager()
.deleteTask(taskEntity, \"completed\", false);
}
executionEntity.executeActivity(this.desActivity);
return null;
}
/**
* 构造参数 可以根据自己的业务需要添加更多的字段
* 分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519)
* @param executionId
* @param desActivity
* @param paramvar
* @param currentActivity
*/
public JDJumpTaskCmd(String executionId, ActivityImpl desActivity,
Map<String, Object> paramvar, ActivityImpl currentActivity) {
this.executionId = executionId;
this.desActivity = desActivity;
this.paramvar = paramvar;
this.currentActivity = currentActivity;
}
}
1.1.1.4. 使用
我们先让流程运转到usertask3节点的时候开始测试跳转。
怎么使用上面的JDJumpTaskCmd类呢,直接new JDJumpTaskCmd()调用,肯定不行了,因为activiti引擎程序没有获取,肯定报错,正确的的使用方式如下:
1.1.1.4.1. 第一种方式
我们先来观察一下数据库ACT_RU_TASK表任务的记录信息,方便我们的操作,数据库记录如下图所示:
可以看到当前的节点在usertask3,我们现在把usertask3跳转到usertask5节点,看是否能成功,因为usertask3到usertask5没有连线,如果成功了,就说明我们这个方法正确。
执行下面的代码,根据自己的数据库信息修改相对应的值即可。
Map<String, Object> vars = new HashMap<String, Object>();
String[] v = { \"shareniu1\", \"shareniu2\", \"shareniu3\", \"shareniu4\" };
vars.put(\"assigneeList\", Arrays.asList(v));
//分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519)
RepositoryService repositoryService = demo.getRepositoryService();
ReadOnlyProcessDefinition processDefinitionEntity = (ReadOnlyProcessDefinition) repositoryService
.getProcessDefinition(\"daling:29:137504\");
// 目标节点
ActivityImpl destinationActivity = (ActivityImpl) processDefinitionEntity
.findActivity(\"usertask5\");
String executionId = \"137509\";
// 当前节点
ActivityImpl currentActivity = (ActivityImpl)processDefinitionEntity
.findActivity(\"usertask3\");
demo.getManagementService().executeCommand(
new JDJumpTaskCmd(executionId, destinationActivity, vars,
currentActivity));
执行上面的代码之后,我们看一下数据库中的记录。
节点确实跳转到了usertask5。ok了这个方法确实可以没问题,下面说一下第二种方式执行executeCommand命令。
1.1.1.4.2. 第二种方式
Map<String, Object> vars = new HashMap<String, Object>();
String[] v = { \"shareniu1\", \"shareniu2\", \"shareniu3\", \"shareniu4\" };
vars.put(\"assigneeList\", Arrays.asList(v));
//分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519)
CommandExecutor commandExecutor = taskServiceImpl
.getCommandExecutor();
commandExecutor.execute(new JDJumpTaskCmd(executionId,
destinationActivity, vars, currentActivity));
上面的两种方式都可以执行自定义的Command子类。读者选择自己喜欢使用的方式即可。
1.1.2. 小结
1.任意节点的跳转,前提是节点必须在模板定义中。
2.任意节点的跳转暂时不能跨流程跳转。
3.任意节点的跳转不需要连线即可、
4.任意节点的跳转可以实现回退、转办、转阅、越级上报、一步到底等等功能,关于这些更多的实战,我们将在最后的工作流实战项目中一步步封装。使用。
以上所述是小编给大家介绍的activiti节点跳转的相关知识,希望对大家有所帮助!
本文地址:https://www.stayed.cn/item/20799
转载请注明出处。
本站部分内容来源于网络,如侵犯到您的权益,请 联系我