activiti节点跳转

分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519)

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定义如下所示:

  1. <?xml version=“1.0” encoding=“UTF-8”?>  
  2. <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”>  
  3.   <process id=“daling” name=“name_daling” isExecutable=“true” activiti:candidateStarterUsers=“a,b,c,d”>  
  4.     <userTask id=“usertask2” name=“usertask2” activiti:assignee=“c”></userTask>  
  5.     <userTask id=“usertask3” name=“usertask3”></userTask>  
  6.     <sequenceFlow id=“flow4” sourceRef=“usertask2” targetRef=“usertask3”></sequenceFlow>  
  7.     <userTask id=“usertask4” name=“usertask4”></userTask>  
  8.     <sequenceFlow id=“flow5” sourceRef=“usertask3” targetRef=“usertask4”></sequenceFlow>  
  9.     <userTask id=“usertask5” name=“usertask5”></userTask>  
  10.     <sequenceFlow id=“flow6” sourceRef=“usertask4” targetRef=“usertask5”></sequenceFlow>  
  11.     <endEvent id=“endevent1” name=“End”></endEvent>  
  12.     <sequenceFlow id=“flow7” sourceRef=“usertask5” targetRef=“endevent1”></sequenceFlow>  
  13.     <startEvent id=“startevent1” name=“Start”></startEvent>  
  14.     <sequenceFlow id=“flow8” sourceRef=“startevent1” targetRef=“usertask2”></sequenceFlow>  
  15.   </process>  
  16.   <bpmndi:BPMNDiagram id=“BPMNDiagram_daling”>  
  17.     <bpmndi:BPMNPlane bpmnElement=“daling” id=“BPMNPlane_daling”>  
  18.       <bpmndi:BPMNShape bpmnElement=“usertask2” id=“BPMNShape_usertask2”>  
  19.         <omgdc:Bounds height=“55.0” width=“105.0” x=“300.0” y=“90.0”></omgdc:Bounds>  
  20.       </bpmndi:BPMNShape>  
  21.       <bpmndi:BPMNShape bpmnElement=“usertask3” id=“BPMNShape_usertask3”>  
  22.         <omgdc:Bounds height=“55.0” width=“105.0” x=“450.0” y=“90.0”></omgdc:Bounds>  
  23.       </bpmndi:BPMNShape>  
  24.       <bpmndi:BPMNShape bpmnElement=“usertask4” id=“BPMNShape_usertask4”>  
  25.         <omgdc:Bounds height=“55.0” width=“105.0” x=“600.0” y=“90.0”></omgdc:Bounds>  
  26.       </bpmndi:BPMNShape>  
  27.       <bpmndi:BPMNShape bpmnElement=“usertask5” id=“BPMNShape_usertask5”>  
  28.         <omgdc:Bounds height=“55.0” width=“105.0” x=“750.0” y=“90.0”></omgdc:Bounds>  
  29.       </bpmndi:BPMNShape>  
  30.       <bpmndi:BPMNShape bpmnElement=“endevent1” id=“BPMNShape_endevent1”>  
  31.         <omgdc:Bounds height=“35.0” width=“35.0” x=“900.0” y=“100.0”></omgdc:Bounds>  
  32.       </bpmndi:BPMNShape>  
  33.       <bpmndi:BPMNShape bpmnElement=“startevent1” id=“BPMNShape_startevent1”>  
  34.         <omgdc:Bounds height=“35.0” width=“35.0” x=“140.0” y=“90.0”></omgdc:Bounds>  
  35.       </bpmndi:BPMNShape>  
  36.       <bpmndi:BPMNEdge bpmnElement=“flow4” id=“BPMNEdge_flow4”>  
  37.         <omgdi:waypoint x=“405.0” y=“117.0”></omgdi:waypoint>  
  38.         <omgdi:waypoint x=“450.0” y=“117.0”></omgdi:waypoint>  
  39.       </bpmndi:BPMNEdge>  
  40.       <bpmndi:BPMNEdge bpmnElement=“flow5” id=“BPMNEdge_flow5”>  
  41.         <omgdi:waypoint x=“555.0” y=“117.0”></omgdi:waypoint>  
  42.         <omgdi:waypoint x=“600.0” y=“117.0”></omgdi:waypoint>  
  43.       </bpmndi:BPMNEdge>  
  44.       <bpmndi:BPMNEdge bpmnElement=“flow6” id=“BPMNEdge_flow6”>  
  45.         <omgdi:waypoint x=“705.0” y=“117.0”></omgdi:waypoint>  
  46.         <omgdi:waypoint x=“750.0” y=“117.0”></omgdi:waypoint>  
  47.       </bpmndi:BPMNEdge>  
  48.       <bpmndi:BPMNEdge bpmnElement=“flow7” id=“BPMNEdge_flow7”>  
  49.         <omgdi:waypoint x=“855.0” y=“117.0”></omgdi:waypoint>  
  50.         <omgdi:waypoint x=“900.0” y=“117.0”></omgdi:waypoint>  
  51.       </bpmndi:BPMNEdge>  
  52.       <bpmndi:BPMNEdge bpmnElement=“flow8” id=“BPMNEdge_flow8”>  
  53.         <omgdi:waypoint x=“175.0” y=“107.0”></omgdi:waypoint>  
  54.         <omgdi:waypoint x=“300.0” y=“117.0”></omgdi:waypoint>  
  55.       </bpmndi:BPMNEdge>  
  56.     </bpmndi:BPMNPlane>  
  57.   </bpmndi:BPMNDiagram>  
  58. </definitions>  
<?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. 代码实现

 

  1. package com.daling.ch1.jd;  
  2. import java.util.Iterator;  
  3. import java.util.Map;  
  4. import org.activiti.engine.impl.context.Context;  
  5. import org.activiti.engine.impl.interceptor.Command;  
  6. import org.activiti.engine.impl.interceptor.CommandContext;  
  7. import org.activiti.engine.impl.persistence.entity.ExecutionEntity;  
  8. import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;  
  9. import org.activiti.engine.impl.persistence.entity.TaskEntity;  
  10. import org.activiti.engine.impl.pvm.process.ActivityImpl;  
  11.    
  12. /** 
  13.  * 
  14.  * JD节点的跳转 
  15.  * 分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519) 
  16.  */  
  17. public class JDJumpTaskCmd implements Command<Void> {  
  18. protected String executionId;  
  19. protected ActivityImpl desActivity;  
  20. protected Map<String, Object> paramvar;  
  21. protected ActivityImpl currentActivity;  
  22. /** 
  23.  * 分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519) 
  24.  */  
  25. public Void execute(CommandContext commandContext) {  
  26. ExecutionEntityManager executionEntityManager = Context  
  27. .getCommandContext().getExecutionEntityManager();  
  28. // 获取当前流程的executionId,因为在并发的情况下executionId是唯一的。  
  29. ExecutionEntity executionEntity = executionEntityManager  
  30. .findExecutionById(executionId);  
  31. executionEntity.setVariables(paramvar);  
  32. executionEntity.setEventSource(this.currentActivity);  
  33. executionEntity.setActivity(this.currentActivity);  
  34. // 根据executionId 获取Task  
  35. Iterator<TaskEntity> localIterator = Context.getCommandContext()  
  36. .getTaskEntityManager()  
  37. .findTasksByExecutionId(this.executionId).iterator();  
  38.    
  39. while (localIterator.hasNext()) {  
  40. TaskEntity taskEntity = (TaskEntity) localIterator.next();  
  41. // 触发任务监听  
  42. taskEntity.fireEvent(”complete”);  
  43. // 删除任务的原因  
  44. Context.getCommandContext().getTaskEntityManager()  
  45. .deleteTask(taskEntity, ”completed”false);  
  46. }  
  47. executionEntity.executeActivity(this.desActivity);  
  48. return null;  
  49. }  
  50.    
  51. /** 
  52.  * 构造参数 可以根据自己的业务需要添加更多的字段 
  53.  * 分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519) 
  54.  * @param executionId 
  55.  * @param desActivity 
  56.  * @param paramvar 
  57.  * @param currentActivity 
  58.  */  
  59. public JDJumpTaskCmd(String executionId, ActivityImpl desActivity,  
  60. Map<String, Object> paramvar, ActivityImpl currentActivity) {  
  61. this.executionId = executionId;  
  62. this.desActivity = desActivity;  
  63. this.paramvar = paramvar;  
  64. this.currentActivity = currentActivity;  
  65. }  
  66. }  
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没有连线,如果成功了,就说明我们这个方法正确。

执行下面的代码,根据自己的数据库信息修改相对应的值即可。

  1. Map<String, Object> vars = new HashMap<String, Object>();  
  2. String[] v = { ”shareniu1”“shareniu2”“shareniu3”“shareniu4” };  
  3. vars.put(”assigneeList”, Arrays.asList(v));  
  4. //分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519)  
  5. RepositoryService repositoryService = demo.getRepositoryService();  
  6. ReadOnlyProcessDefinition processDefinitionEntity = (ReadOnlyProcessDefinition) repositoryService  
  7. .getProcessDefinition(”daling:29:137504”);  
  8. // 目标节点  
  9. ActivityImpl destinationActivity = (ActivityImpl) processDefinitionEntity  
  10. .findActivity(”usertask5”);  
  11. String executionId = ”137509”;  
  12. // 当前节点  
  13.    ActivityImpl currentActivity = (ActivityImpl)processDefinitionEntity  
  14.       .findActivity(”usertask3”);  
  15. demo.getManagementService().executeCommand(  
  16. new JDJumpTaskCmd(executionId, destinationActivity, vars,  
  17. currentActivity));  
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. 第二种方式

  1. Map<String, Object> vars = new HashMap<String, Object>();  
  2. String[] v = { ”shareniu1”“shareniu2”“shareniu3”“shareniu4” };  
  3. vars.put(”assigneeList”, Arrays.asList(v));  
  4. //分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519)  
  5.     CommandExecutor commandExecutor = taskServiceImpl  
  6.       .getCommandExecutor();  
  7.     commandExecutor.execute(new JDJumpTaskCmd(executionId,  
  8.       destinationActivity, vars, currentActivity));  
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.任意节点的跳转可以实现回退、转办、转阅、越级上报、一步到底等等功能,关于这些更多的实战,我们将在最后的工作流实战项目中一步步封装。使用。

分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519)

分享牛,分享、我们是快乐的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值