Activiti——流程回退和会签

1、流程回退

从业务上讲,流程回退存在两种情况:毫无痕迹的回退和正常的业务回退。当流程通过一个流程节点后,Activiti会记录流程的历史记录,流程的当前活动已经不再是通过的这个节点,如果想做到“毫无痕迹”的回退,那么就需要非常熟悉Activiti的数据库设计,自己编写数据
操作过程,让全部的流程数据“回退”到操作前。实现这样的功能风险非常大,牵涉较大的数据范围,而且与Activiti的数据库设计紧密地耦合在一起,如果Activiti的数据库设计发生变化,原来使用Activiti系统的逻辑也必然要改变。笔者不建议使用这种方式来实现流程回退。

另外一种回退方式,就是通过业务流程来进行控制,实际上流程回退也是业务的一种,在设计流程时考虑这种情况的出现。这种回退可以通过顺序流和单向网关来实现:

在这里插入图片描述

图中是一个正常的业务流程,当审核任务被否决(不通过)后,执行流会重新返回到款项申请的任务,这是其中一种解决流程回退的方法。除了这种方法外,还可以使用边界事件来实现流程回退。为有可能导致回退的任务加入边界事件,当边界事件被触发后,流程的走
向就会发生变化,这种业务流程如下图所示:

在这里插入图片描述

在图所示的流程中,如果审核任务不通过,就会触发信号边界事件,执行流会进入到补偿处理的任务中,补偿任务主要处理款项申请中实际产生的业务数据(非流程数据),如果没有发生任何的业务数据变化,那么可以不必存在该任务。

不管使用上述哪种流程回退方式,对于Activiti来说,这些都是实际发
生过的业务流程,因此这一过程都会被记录到流程历史中。相对于“无痕迹”的回退方式,这两种业务情景更为合理,无痕迹回退只是一种技术上的处理手段,其通过修改流程引擎数据来达到流程回退的效果。

2、会签

会签是指,一个任务需要有多个角色审批或者表决,根据这些审批结果来决定流程的走向。实际上对于这种业务,Activiti已经提供了支持,可以使用BPMN规范的多实例活动来实现。

在实际应用中,可能会出现以下几种会签业务。

  • 按数量通过:达到一定数量的通过表决后,会签通过。
  • 按比例通过:达到一定比例的通过表决后,会签通过。
  • 一票否决:只要有一个表决是否定的,会签不通过。
  • 一票通过:只要有一个表决是通过的,会签通过。

以上几种业务,均可以体现在一个流程中,如图所示:

在这里插入图片描述

<process id="Converge" name="Converge">
	<startEvent id="startevent1" name="Start"></startEvent>
	<userTask id="usertask1" name="多人会签">
		<multiInstanceLoopCharacteristics
			isSequential="false" activiti:collection="${datas}"
			activiti:elementVariable="data">
			<completionCondition>${pass == false}</completionCondition>
		</multiInstanceLoopCharacteristics>
	</userTask>
	<exclusiveGateway id="parallelgateway1" name="Parallel Gateway"></exclusiveGateway>
	<userTask id="usertask2" name="后续工作"></userTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="usertask1"
		targetRef="parallelgateway1"></sequenceFlow>
	<sequenceFlow id="flow3" name="通过" sourceRef="parallelgateway1"
		targetRef="usertask2">
		<conditionExpression xsi:type="tFormalExpression"><![CDATA[
			${pass == true}
		]]></conditionExpression>
	</sequenceFlow>
	<sequenceFlow id="flow4" name="" sourceRef="usertask2"
		targetRef="endevent1"></sequenceFlow>
	<sequenceFlow id="flow5" name="不通过" sourceRef="parallelgateway1"
		targetRef="endevent1">
		<conditionExpression xsi:type="tFormalExpression"><![CDATA[
			${pass == false}
		]]></conditionExpression>
	</sequenceFlow>
</process>

在代码中,使用multiInstanceLoopCharacteristics将用户任务配置为一个多实例的用户任务,这些实例都是并行的(isSequential=“false”),用户任务的结束条件是pass参数被
设置为false,这里设置的多实例任务结束条件,表示全部的用户任务在审批时,只要在一个任务中将pass设置为false,则结束这个任务,实际上这就实现了“一票否决”的业务:

@Test
public void converge() {
    ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
    RepositoryService repositoryService = engine.getRepositoryService();
    TaskService taskService = engine.getTaskService();
    RuntimeService runtimeService = engine.getRuntimeService();
    //部署文件
    Deployment deploy = repositoryService.createDeployment().addClasspathResource("demo18/Converge_1.bpmn").deploy();
    //流程定义
    ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult();
    //初始化实例任务的数据
    List<Integer> datas = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        datas.add(i);
    }
    //初始化流程参数
    Map<String, Object> vars = new HashMap<>();
    vars.put("datas", datas);
    vars.put("pass", true);
    //启动流程
    ProcessInstance pi = runtimeService.startProcessInstanceByKey("Converge", vars);
    //任务查询
    List<Task> tasks = taskService.createTaskQuery().processInstanceId(pi.getId()).list();
    System.out.println("当前任务总数:" + tasks.size());
    //完成第三个任务,否决会签
    Map<String, Object> taskResult = new HashMap<>();
    taskResult.put("pass", false);
    taskService.complete(tasks.get(2).getId(), taskResult);
    //流程实例为null,流程结束
    ProcessInstance currentPi = runtimeService.createProcessInstanceQuery().processDefinitionId(pd.getId()).singleResult();
    System.out.println(currentPi);
}

在代码中,初始化多实例的集合数据,其是一个size为10的集合。使用参数启动流程,需要注意的是,启动流程时设置了“pass”参数为true,表示默认通过。在完成其中一个任务实例(第三个任务)时,设置流程参数“pass”的值为false,跳出多实例活动的循环,根据流程图,流程结束:

当前任务总数:10
null
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Activiti中,如果在并行网关处需要进行回退操作,可以采用以下方法: 1. 使用多实例任务:在并行网关处创建多个实例任务,每个任务都是独立运行的,如果需要回退操作,可以通过撤销或跳转到之前的任务来实现回退。 2. 使用Java API:通过使用ActivitiJava API,在并行网关处根据需要的情况,将正在执行的任务撤销或跳转到之前的任务。可以使用如下代码示例: ```java // 获取当前流程实例的任务列表 List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).list(); // 获取需要回退的任务,并将其设置为活动状态,将其他正在执行的任务设置为完结状态 for (Task task : tasks) { if (task.getTaskDefinitionKey().equals("parallelGatewayId")) { taskService.complete(task.getId()); } else { // 回退到之前的任务节点,例如:可以将其跳转到上一个用户任务节点 BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId()); FlowNode targetFlowNode = (FlowNode) bpmnModel.getFlowElement(previousTaskDefinitionKey); // 通过工作流的Java API实现任务的跳转 managementService.executeCommand(new JumpTaskCmd(task.getId(), targetFlowNode.getId())); } } ``` 3. 使用流程动态调整:通过在运行时动态调整流程,将并行网关后的任务回退,然后再重新启动回退的任务。可以使用如下代码示例: ```java // 创建一个HistoricActivityInstanceQuery对象,获取并行网关后的任务节点 HistoricActivityInstanceQuery historicQuery = historyService.createHistoricActivityInstanceQuery() .processInstanceId(processInstanceId).activityType("parallelGateway"); // 获取并行网关后的任务节点的历史实例列表 List<HistoricActivityInstance> historicInstances = historicQuery.list(); // 回退并行网关后的任务节点 for (HistoricActivityInstance activityInstance : historicInstances) { // 设置任务节点为撤销状态 runtimeService.createProcessInstanceModification(processInstanceId) .cancelActivityInstances(activityInstance.getId()) .execute(); } // 重新启动回退的任务节点 runtimeService.createProcessInstanceModification(processInstanceId) .startBeforeActivity(taskDefinitionKey) .execute(); ``` 以上是在Activiti中实现并行网关回退的几种方法,具体选择哪种方法应根据具体的业务需求和实际情况进行酌情选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值