2023最新版本Activiti7系列-事件篇

事件篇

在这里插入图片描述

事件(event)通常用于为流程生命周期中发生的事情建模。事件总是图形化为圆圈。在BPMN 2.0中,有两种主要的事件分类:*捕获(catching)抛出(throwing)*事件。

  • 捕获: 当流程执行到达这个事件时,会等待直到触发器动作。触发器的类型由其中的图标,或者说XML中的类型声明而定义。捕获事件与抛出事件显示上的区别,是其内部的图标没有填充(即是白色的)。
  • 抛出: 当流程执行到达这个事件时,会触发一个触发器。触发器的类型,由其中的图标,或者说XML中的类型声明而定义。抛出事件与捕获事件显示上的区别,是其内部的图标填充为黑色。

1. 定时器事件

  定时器事件是一种在特定时间触发的事件。在Activiti中,可以通过定时器事件来实现定时执行某个任务或者触发某个流程实例,具体包括定时器启动事件,定时器捕获中间件事件,定时器边界事件,在很多的业务场景中。

1.1 定时器开始事件

  定时器启动事件(timer start event)在指定时间创建流程实例。在流程只需要启动一次,或者流程需要在特定的时间间隔重复启动时,都可以使用。在使用时我们需要注意如下几个点:

  1. 子流程不能有定时器启动事件。
  2. 定时器启动事件,在流程部署的同时就开始计时。不需要调用startProcessInstanceByXXX就会在时间启动。调用startProcessInstanceByXXX时会在定时启动之外额外启动一个流程。
  3. 当部署带有定时器启动事件的流程的更新版本时,上一版本的定时器作业会被移除。这是因为通常并不希望旧版本的流程仍然自动启动新的流程实例。
  4. asyncExecutorActivate:需要设置为true,否则定时器不会生效,因为这块需要开启异步任务。

定时器启动事件,用其中有一个钟表图标的圆圈来表示。我们通过具体案例来介绍

在这里插入图片描述

部署流程后会在我们设置的时间开启一个流程实例,在没有到达定时时间的时候在act_ru_timer_job可以看到我们的定时任务信息

在这里插入图片描述

时间到达后会触发定时开启事件。

在这里插入图片描述

定时器开始事件除了上面的指定固定时间启动外我们还可以通过循环和持续时间来处理

  • timeDate:指定一个具体的日期和时间,例如2022-01-01T00:00:00
  • timeCycle:指定一个重复周期,例如R/PT1H表示每隔1小时触发一次。
  • timeDuration:指定一个持续时间,例如PT2H30M表示持续2小时30分钟。

然后我们增加一个重复周期的案例。这块我们可以通过自动任务来演示案例

在这里插入图片描述

在自动任务这块绑定了一个JavaDelegate来处理

public class MyJavaDelegate implements JavaDelegate {@Overridepublic void execute(DelegateExecution execution) {System.out.println("自动任务执行了..." + LocalDateTime.now());}
}

在这里插入图片描述

然后部署流程测试,在act_ru_timer_job查看定义信息

在这里插入图片描述

在这里插入图片描述

可以看到执行了3次。都间隔了30秒

1.2 定时器中间事件

  在开始事件和结束事件之间发生的事件称为中间事件,定时器中间捕获事件指在流程中将一个定时器作为独立的节点来运行,是一个捕获事件。当流程流转到定时器中间捕获事件时,会启动一个定时器,并一直等待触发,只有到达指定时间定时器才被触发。

在这里插入图片描述

  当我们审批通过申请出库后,等待一分钟触发定时器。然后会进入到出库处理。同时在触发前在act_ru_timer_job中可以查询到对应的任务信息。

1.3 定时器边界事件

  当某个用户任务或者子流程在规定的时间后还没有执行。那么我们就可以通过定时器边界事件来触发执行特定的处理流程。

  注意在定时器边界事件配置了cancelActivity属性,用于说明该事件是否为中断事件。cancelActivity属性值默认为true,表示它是边界中断事件,当该边界事件触发时,它所依附的活动实例被终止,原有的执行流会被中断,流程将沿边界事件的外出顺序流继续流转。如果将其设置为false,表示它是边界非中断事件,当边界事件触发时,则原来的执行流仍然存在,所依附的活动实例继续执行,同时也执行边界事件的外出顺序流。

在这里插入图片描述

部署后启动流程。那么会进入到合同审批-总经理审判的这个节点。同时在act_ru_timer_job中可以看到这个边界事件的定义
在这里插入图片描述

等待了一分钟定时器边界事件触发。我们可以在控制台中看到JavaDelegate任务的执行。

在这里插入图片描述

因为这块的边界事件我们定义的是非中断。所以用户任务还在,只是在边界事件中触发了服务任务。来通知用户审批处理。

在这里插入图片描述

然后总经理审批通过。后会进入到财务审批的节点

在这里插入图片描述

同时会开启我们的中间边界事件。act_ru_timer_job中会生成对应的记录。

在这里插入图片描述

同时act_ru_task中的审批是财务审核

在这里插入图片描述

等待一分钟后。因为边界事件设置的是中断类型。所以触发后财务审核终止。只剩下触发后的新的出口中的财务实习审批
在这里插入图片描述

在这里插入图片描述

2.消息事件

  消息事件(message event),是指引用具名消息的事件。消息具有名字与载荷。与信号不同,消息事件只有一个接收者

2.1 开始事件

消息开始事件,也就是我们通过接收到某些消息后来启动流程实例,比如接收到了一封邮件,一条短信等,具体通过案例来讲解.
在这里插入图片描述

做消息的定义

在这里插入图片描述

在消息开始事件中我们需要绑定上面定义的消息

在这里插入图片描述

然后就可以部署流程

    /*** 流程部署操作*/@Testpublic void test1(){// 1.获取ProcessEngine对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2.完成流程的部署操作 需要通过RepositoryService来完成RepositoryService repositoryService = processEngine.getRepositoryService();// 3.完成部署操作Deployment deploy = repositoryService.createDeployment().addClasspathResource("flow/event-message-start.bpmn20.xml").name("消息启动事件").deploy(); // 是一个流程部署的行为 可以部署多个流程定义的System.out.println(deploy.getId());System.out.println(deploy.getName());}

部署完流程后。消息启动事件会在act_ru_event_subscr中记录我们的定义信息。

在这里插入图片描述

然后就可以发送相关的消息。来激活该流程实例,注意:消息的名称我们不要使用驼峰命名法来定义
在这里插入图片描述

当我们发送消息后

/*** 发送消息。触发流程*/
@Test
public void test3() throws InterruptedException {ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();RuntimeService runtimeService = engine.getRuntimeService();// 发送消息 发送的消息应该是具体的消息的名称而不应该是idruntimeService.startProcessInstanceByMessage("msg01");TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
}

可以看到消息开始事件触发了。

在这里插入图片描述

2.2 中间事件

  消息中间事件就是在流程运作中需要消息来触发的场景,案例演示,自动流程1处理完成后,需要接收特定的消息之后才能进入到自动流程2

在这里插入图片描述

然后在消息中间事件的图标中我们需要绑定刚刚定义的消息

在这里插入图片描述

部署启动和审批流程后进入到消息中间事件的节点

在这里插入图片描述

然后发送消息触发消息中间事件

/*** 触发消息中间事件*/
@Test
public void test5(){ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();RuntimeService runtimeService = engine.getRuntimeService();// 查询出当前的 执行实例的 编号Execution execution = runtimeService.createExecutionQuery().processInstanceId("110001").onlyChildExecutions().singleResult();runtimeService.messageEventReceived("msg02",execution.getId());
}

然后进入到了用户任务2的审批。说明触发了

在这里插入图片描述

2.3 边界事件

  消息边界事件同样的针对是用户节点在消息触发前如果还没有审批。就会触发消息事件的处理逻辑。同样我们通过具体的案例来介绍。

在这里插入图片描述

定义两个消息

在这里插入图片描述

部署流程、启动流程后进入到用户任务1后。在act_ru_event_subscr表中就可以看到对应的消息事件,这时我们就可以发送相关的消息。

在这里插入图片描述

public void test5(){ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();RuntimeService runtimeService = engine.getRuntimeService();runtimeService.messageEventReceived("msg03","170005");
}

然后在控制台就可以看到JavaDelegate被执行调用了

在这里插入图片描述

这里我们需要注意当前的边界事件是非中断的。所以还是需要用户任务1来审批推进,审批后会绑定msg04

在这里插入图片描述

在这里插入图片描述

当我们触发了第二个消息边界事件。那么任务会进入到用户任务3。同时用户任务2被中断了。然后msg04的任务也结束了。

3.错误事件

  错误事件可以用做一个流程的开始事件或者作为一个任务或者子流程的边界事件,错误事件没有提供作用中间事件的功能,这一点和前面介绍的定时器事件和消息事件还有区别的。在错误事件中提供了错误结束事件。我们在案例中会详细的讲解。

3.1 开始事件

  错误开始事件(error start event)可以触发一个事件子流程,且总是在另外一个流程异常结束时触发。BPMN 2.0规定了错误开始事件只能在事件子流程中被触发,不能在其他流程中被触发,包括顶级流程、嵌套子流程和调用活动。错误启动事件不能用于启动流程实例

  错误启动事件总是中断。我们通过案例来介绍

在这里插入图片描述

在对应的自动任务1中我们需要显示的抛出异常信息

/*** 自定义的委托类*/
public class MyFirstDelegate implements JavaDelegate {/*** 回调方法* @param execution*/@Overridepublic void execute(DelegateExecution execution) {System.out.println("服务任务执行了..." + LocalDateTime.now().toString());// 抛出错误 触发 子流程中的错误开始事件throw new BpmnError("error01");}
}

  那么部署完流程后。然后发起一个新的流程就会走事件子流程中的逻辑了。错误开始事件可以在如下的场景中使用:

  1. 输入验证失败:当用户提交工作流启动请求时,需要对输入的数据进行验证。如果数据不符合预期的格式或规则,可以使用错误开始事件来捕获并处理验证失败的情况。

  2. 权限验证失败:在某些情况下,只有特定的用户或用户组才能启动某个工作流。当非授权用户尝试启动工作流时,可以使用错误开始事件来捕获并处理权限验证失败的情况。

  3. 前置条件不满足:在工作流启动之前,可能需要满足一些前置条件,例如某个数据已经存在或某个服务可用。如果前置条件不满足,可以使用错误开始事件来捕获并处理这种情况。

  4. 数据源异常:在工作流启动过程中,可能需要从外部数据源获取数据。如果数据源出现异常导致无法获取数据,可以使用错误开始事件来捕获并处理数据源异常的情况。

总的来说,错误开始事件可以用于捕获工作流启动时可能出现的各种错误情况,并根据具体的业务需求进行相应的处理。

3.2 边界事件

  当某个任务发生错误时,可以通过错误边界事件来捕获并处理该错误,以保证流程的正常执行。

  错误边界事件可以在流程中的任务节点上定义,并与该任务节点关联。当任务节点执行过程中发生错误时,错误边界事件会被触发,并执行相应的处理逻辑,如发送错误通知、重新分配任务、跳转到其他节点等。

  错误边界事件可以捕获多种类型的错误,如异常、超时、网络故障等。通过使用错误边界事件,可以增加流程的容错性,并提供更好的错误处理机制,保证流程的稳定性和可靠性。

  需要注意的是,错误边界事件只能与任务节点关联,而不能与其他类型的节点(如网关、开始节点、结束节点)关联。此外,在设计流程时,需要准确定义错误边界事件的触发条件和处理逻辑,以确保错误能够被正确捕获和处理。具体我们通过案例来演示。

在这里插入图片描述

  案例中我们把错误边界事件绑定在了普通的用户任何和一个子流程上。如果对应的节点抛出的相关的错误。对应的边界事件就可以被触发。

错误边界事件可能的应用场景:

  1. 任务执行失败:当某个任务执行失败时,可以使用错误边界事件来捕获该异常,并执行一些恢复操作,例如重新分配任务给其他用户或记录错误信息。

  2. 子流程异常:当子流程执行过程中发生异常时,可以使用错误边界事件捕获该异常,并执行一些补救措施,例如回退到上一个节点或重新启动子流程。

  3. 超时处理:当某个任务或子流程在规定的时间内没有完成时,可以使用错误边界事件来捕获超时异常,并执行相应的超时处理逻辑,例如发送提醒邮件或自动终止流程。

  4. 数据校验失败:在某些场景下,需要对流程中的数据进行校验,如果校验失败,则可以使用错误边界事件来捕获校验异常,并进行相应的处理,例如返回错误信息给用户或中止流程。

总之,错误边界事件可以帮助我们在流程执行过程中及时捕获并处理异常情况,提高流程的可靠性和稳定性。

3.3 结束事件

  在Activiti中,错误结束事件(Error End Event)是一个用于标记流程实例在特定错误条件下结束的节点。当流程实例执行到错误结束事件时,流程实例将立即终止执行,并且流程实例的状态将被标记为“错误结束”。

  错误结束事件可以与错误边界事件(Error Boundary Event)结合使用,用于在流程中捕获和处理特定的错误。当错误边界事件触发时,流程会跳转到与错误边界事件关联的错误结束事件,从而使流程实例结束。

  错误结束事件可以配置一个错误代码,用于标识特定的错误类型。在流程定义中,可以定义多个错误结束事件,每个事件可以有不同的错误代码。当流程实例执行到错误结束事件时,可以根据错误代码进行相应的处理,例如记录日志、发送通知等。

  错误结束事件可以用于处理各种错误情况,例如系统异常、业务规则异常等。通过使用错误结束事件,可以使流程能够在错误发生时进行合理的处理,提高系统的可靠性和稳定性。

总之,错误结束事件是Activiti中的一个节点,用于标记流程实例在特定错误条件下结束。它可以与错误边界事件结合使用,用于捕获和处理特定的错误。通过使用错误结束事件,可以实现对流程中各种错误情况的处理和管理。
在这里插入图片描述

当子流程中的支付失败的情况下会触发错误结束事件。该事件会被错误边界事件捕获。错误边界事件捕获后会重新发起支付的流程。这就是我们介绍的案例流程。

4. 信号事件

  信号事件是Activiti中的一种事件类型,用于在流程执行过程中通知其他流程实例或任务实例。

  信号事件是一种全局事件,可以在任何流程实例或任务实例中触发和捕获。当一个流程实例或任务实例触发了一个信号事件,其他等待捕获相同信号的流程实例或任务实例将被唤醒并继续执行。

信号事件可以用于以下场景:

  1. 并行流程实例之间的协作:当一个流程实例需要与其他并行流程实例进行协作时,可以触发一个信号事件来通知其他流程实例执行相应的任务。

  2. 动态流程控制:当流程的执行需要根据外部条件进行动态调整时,可以使用信号事件来触发相应的流程变化。

  3. 异常处理:当发生异常情况时,可以触发一个信号事件来通知其他流程实例或任务实例进行异常处理。

使用信号事件需要以下几个步骤:

  1. 定义信号事件:在流程定义中定义一个信号事件,指定信号的名称和其他属性。

  2. 触发信号事件:在流程实例或任务实例中触发一个信号事件。

  3. 捕获信号事件:在其他流程实例或任务实例中捕获相同名称的信号事件。

  4. 响应信号事件:在捕获的信号事件中定义相应的处理逻辑,例如执行任务或流程变化。

  信号事件我们可以分为开始事件中间捕获事件中间抛出事件边界事件,具体的介绍如下

4.1 开始事件

  • 启动事件是一个特殊的信号事件,用于在流程启动时触发。
  • 当流程启动时,如果存在一个启动事件,并且该事件匹配到了被触发的信号,流程将会被启动。
  • 启动事件可以用于实现流程启动前的条件判断,例如当某个条件满足时,才允许启动流程。

具体的案例如下:

在这里插入图片描述

定义信号信息:

在这里插入图片描述

在定义信号的时候有一个Scope属性可以设置为Global或processInstance

  • Global:全局范围的信号定义,表示可以在任何流程实例中触发和捕获信号。当一个信号事件被触发时,所有等待捕获该信号的节点都会被唤醒。
  • processInstance:流程实例范围的信号定义,表示只能在当前流程实例中触发和捕获信号。当一个信号事件被触发时,只有等待在当前流程实例中捕获该信号的节点会被唤醒。

  而当前的启动事件是在流程实例启动时触发的事件,用于执行一些初始化操作。启动事件可以在流程定义的开始节点上定义,并在开始节点上设置事件类型为start。启动事件只有一个全局范围的信号定义,即scope属性只能设置为Global。当一个启动事件被触发时,所有等待捕获该信号的节点都会被唤醒。

然后在信号开始节点中绑定刚刚定义的信号:

在这里插入图片描述

接下就可以部署流程。然后通过信号来启动对应的流程实例了。

/*** 通过信号启动一个新的流程*/
@Test
public void test2() throws InterruptedException {ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();// 发起流程 需要通过 runtimeService来实现RuntimeService runtimeService = engine.getRuntimeService();// 通过发送信号。触发对应订阅了该信号的流程runtimeService.signalEventReceived("signal1");TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
}

执行上面的方法就可以看到act_ru_task中对应的就有了一条用户任务的待办信息

在这里插入图片描述

同时对应的信号事件存储在了act_ru_event_subscr中。
在这里插入图片描述

当然触发该事件的方式并不仅仅只有这一种方案还有:

  • 由流程中的信号中间抛出事件抛出信号,所有订阅了该信号的信号开始事件所在的流程定义都会被启动;
  • 作为普通开始事件,启动流程。

事件抛出我们在后面的案例中讲解。而作为普通的开始事件。直接执行下面的启动代码即可

// 通过流程定义ID来启动流程  返回的是流程实例对象ProcessInstance processInstance = runtimeService.startProcessInstanceById("event-signal-start1:1:232503");

4.2 中间事件

  信号中间事件分为捕获事件抛出事件.当流程流转到信号中间捕获事件时会中断并等待触发,直到接收到相应的信号后沿信号中间捕获事件的外出顺序流继续流转。信号事件默认是全局的,与其他事件(如错误事件)不同,其信号不会在捕获之后被消费。如果存在多个引用了相同信号的事件被激活,即使它们不在同一个流程实例中,当接收到该信号时,这些事件也会被一并触发。具体我们通过案例来讲解
在这里插入图片描述

消息定义我们用的scope是 processInstance。也就是只在当前流程实例生效。部署运行后可以看具体的效果

在这里插入图片描述

启动流程后在act_ru_event_subscr中记录了信号事件的相关信息。同时记录了作用域信息

在这里插入图片描述

然后我们审批用户节点进入到抛出信号事件的节点。

在这里插入图片描述

审批任务完成

/*** 任务审批*/
@Test
public void test7() throws Exception{ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();TaskService taskService = engine.getTaskService();taskService.complete("245007");Thread.sleep(100000000);
}

可以看到自动任务2执行了

在这里插入图片描述

同时因为scopeprocessInstanceact_ru_event_subscr中记录的信号事件也被消费了。如果是global则该信号事件还是继续监听。

在这里插入图片描述

4.3 边界事件

  信号边界事件会捕获与其信号事件定义引用的信号具有相同信号名称的信号。当流程流转到信号边界事件依附的流程活动(如用户任务、子流程等)时,工作流引擎会创建一个捕获事件,在其依附的流程活动的生命周期内等待一个抛出信号。该信号可以由信号中间抛出事件抛出或由API触发。信号边界事件被触发后流程会沿其外出顺序流继续流转。如果该边界事件设置为中断,则依附的流程活动将被终止。

在这里插入图片描述

部署流程后启动流程那么具有的相关的数据act_ru_event_subscr表中记录的信号事件
在这里插入图片描述

然后流程会进入到用户任务1节点。当然可以正常的审批。还有就是可以发布相关的信号事件。在当前的环境下我们可以通过runtimeService的API来触发

/*** 通过信号启动事件* 发起一个流程* 1.通过runtimeService中提供的API来发送信号* 2.通过其他流程实例中的信号中间抛出事件来触发* 3.作为普通的流程实例来启动即可*/
@Test
public void test2() throws InterruptedException {ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();// 发起流程 需要通过 runtimeService来实现RuntimeService runtimeService = engine.getRuntimeService();// 通过runtimeService的API来发布信号runtimeService.signalEventReceived("signal02");TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
}

在这里插入图片描述

同时因为是非中断的,所以用户任务1还在。接下来我们就需要做审批操作。审批通过就会进入到用户任务2

在这里插入图片描述

进入到用户任务2后。继续审批就会触发信号抛出事件,然后被信号边界事件捕获。
在这里插入图片描述

5. 其他事件

5.1 终止结束事件

  终止结束事件也称为中断结束事件,主要是对流程进行终止的事件,可以在一个复杂的流程中,如果某方想要提前中断这个流程,可以采用这个事件来处理,可以在并行处理任务中。如果你是在流程实例层处理,整个流程都会被中断,如果是在子流程中使用,那么当前作用和作用域内的所有的内部流程都会被终止。具体还是通过两个案例来给大家介绍:

第一个案例:终止结束事件是在主流程中触发的场景

在这里插入图片描述

设置终止结束事件。里面有一个terminateAll默认为false。含义是当终止结束事件在多实例或者嵌套的子流程中。那么不会终止整个流程。如果设置为true那么不管是否嵌套都会终止整个的流程实例。

在这里插入图片描述

通过案例的演示。我们发下在用户任务1用户任何2没有审批的情况下当用户任务3审批通过后同时flag设置为false的情况下触发了终止结束事件那么整个流程实例都被终止了。

另一个流程案例:在子流程中触发终止结束事件

在这里插入图片描述

在本案例中我们可以通过terminateAll属性非常方便的控制终止的范围。

5.2 取消结束事件

  取消结束事件(cancel end event)只能与BPMN事务子流程(BPMN transaction subprocess)一起使用。当到达取消结束事件时,会抛出取消事件,且必须由取消边界事件(cancel boundary event)捕获。取消边界事件将取消事务,并触发补偿(compensation)。

具体通过案例来讲解:

在这里插入图片描述

注意:结束取消事件我们只能在事务子流程中使用.

在这里插入图片描述

在流程设计器中没有直接提供事务子流程的图标,我们需要通过普通的子流程来设置事务的属性即可
在这里插入图片描述

然后就是补偿的任务我们需要勾选可补偿的选项
在这里插入图片描述

部署任务后我们再继续启动流程实例的时候。出现了如下的错误
在这里插入图片描述

检查xml文件中发现少了该属性。那么我们需要收到的加上

在这里插入图片描述

然后做正常的审批。触发取消结束事件,结合上面的流程图我们可以看到如下的效果

在这里插入图片描述

补充任务触发。可以看到控制台的日志信息

在这里插入图片描述

用户任务4在act_ru_task中可以看到对应的记录

在这里插入图片描述

5.3 补偿事件

  在Activiti中,补偿事件(Compensation Event)是一种用于处理流程中发生异常或错误的特殊事件。当流程中的某个任务或活动发生错误或无法继续执行时,补偿事件可以被触发来回滚或修复之前已经完成的任务或活动。

  补偿事件通常与错误边界事件(Error Boundary Event)结合使用。错误边界事件是在流程中的任务或活动周围设置的捕获异常的事件。当任务或活动发生异常时,错误边界事件将被触发,进而触发相应的补偿事件。

  补偿事件可以执行一系列的补偿操作,包括撤销之前已经完成的任务、还原数据、发送通知等。补偿操作的具体步骤和逻辑可以在流程定义中定义,并且可以使用Java代码或脚本来实现。

  补偿事件的触发和执行是自动完成的,无需人工干预。一旦补偿事件被触发,Activiti引擎会自动查找相应的补偿事件,并按照定义的补偿操作进行执行。

  通过使用补偿事件,可以有效地处理流程中的异常情况,提高流程的稳定性和容错性。补偿事件可以帮助流程在发生错误时自动进行修复,确保流程能够正常完成。

在这里插入图片描述

<?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"><error id="payFail" errorCode="payFail" ></error><process id="myProcess" name="My process" isExecutable="true"><startEvent id="startevent1" name="开始事件"></startEvent><parallelGateway id="parallelgateway1" name="并行网关"></parallelGateway><sequenceFlow id="flow1" sourceRef="startevent1" targetRef="parallelgateway1"></sequenceFlow><serviceTask id="servicetask1" name="预订机票" activiti:class="com.bobo.delegate.MyTwoDelegate"></serviceTask><serviceTask id="servicetask2" name="微信支付" activiti:class="com.bobo.delegate.MyOneDelegate"></serviceTask><userTask id="usertask1" name="人工出票" activiti:assignee="zhangsan"></userTask><sequenceFlow id="flow2" sourceRef="servicetask1" targetRef="usertask1"></sequenceFlow><parallelGateway id="parallelgateway2" name="Parallel Gateway"></parallelGateway><sequenceFlow id="flow3" sourceRef="usertask1" targetRef="parallelgateway2"></sequenceFlow><sequenceFlow id="flow4" sourceRef="parallelgateway1" targetRef="servicetask1"></sequenceFlow><sequenceFlow id="flow5" sourceRef="parallelgateway1" targetRef="servicetask2"></sequenceFlow><sequenceFlow id="flow6" sourceRef="servicetask2" targetRef="parallelgateway2"></sequenceFlow><serviceTask id="servicetask3" name="取消预订" isForCompensation="true" activiti:class="com.bobo.delegate.MyThreeDelegate"></serviceTask><boundaryEvent id="boundarycompensation1" name="补偿边界事件" attachedToRef="servicetask1" cancelActivity="true"><compensateEventDefinition></compensateEventDefinition></boundaryEvent><boundaryEvent id="boundaryerror1" name="错误边界事件" attachedToRef="servicetask2"><errorEventDefinition errorRef="payFail"></errorEventDefinition></boundaryEvent><intermediateThrowEvent id="compensationintermediatethrowevent1" name="补偿抛出中间事件"><compensateEventDefinition></compensateEventDefinition></intermediateThrowEvent><sequenceFlow id="flow7" sourceRef="boundaryerror1" targetRef="compensationintermediatethrowevent1"></sequenceFlow><endEvent id="endevent1" name="End"></endEvent><sequenceFlow id="flow8" sourceRef="compensationintermediatethrowevent1" targetRef="endevent1"></sequenceFlow><endEvent id="endevent2" name="End"></endEvent><sequenceFlow id="flow9" sourceRef="parallelgateway2" targetRef="endevent2"></sequenceFlow><association id="association1" sourceRef="boundarycompensation1" targetRef="servicetask3" associationDirection="None"></association></process><bpmndi:BPMNDiagram id="BPMNDiagram_myProcess"><bpmndi:BPMNPlane bpmnElement="myProcess" id="BPMNPlane_myProcess"><bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1"><omgdc:Bounds height="35.0" width="35.0" x="160.0" y="360.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="parallelgateway1" id="BPMNShape_parallelgateway1"><omgdc:Bounds height="40.0" width="40.0" x="380.0" y="357.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="servicetask1" id="BPMNShape_servicetask1"><omgdc:Bounds height="55.0" width="105.0" x="580.0" y="220.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="boundarycompensation1" id="BPMNShape_boundarycompensation1"><omgdc:Bounds height="30.0" width="30.0" x="650.0" y="270.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="servicetask2" id="BPMNShape_servicetask2"><omgdc:Bounds height="55.0" width="105.0" x="580.0" y="450.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="boundaryerror1" id="BPMNShape_boundaryerror1"><omgdc:Bounds height="30.0" width="30.0" x="650.0" y="490.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1"><omgdc:Bounds height="55.0" width="105.0" x="820.0" y="220.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="parallelgateway2" id="BPMNShape_parallelgateway2"><omgdc:Bounds height="40.0" width="40.0" x="1140.0" y="336.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="servicetask3" id="BPMNShape_servicetask3"><omgdc:Bounds height="55.0" width="105.0" x="830.0" y="336.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="compensationintermediatethrowevent1" id="BPMNShape_compensationintermediatethrowevent1"><omgdc:Bounds height="35.0" width="35.0" x="740.0" y="590.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1"><omgdc:Bounds height="35.0" width="35.0" x="820.0" y="590.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="endevent2" id="BPMNShape_endevent2"><omgdc:Bounds height="35.0" width="35.0" x="1225.0" y="339.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1"><omgdi:waypoint x="195.0" y="377.0"></omgdi:waypoint><omgdi:waypoint x="380.0" y="377.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2"><omgdi:waypoint x="685.0" y="247.0"></omgdi:waypoint><omgdi:waypoint x="820.0" y="247.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3"><omgdi:waypoint x="925.0" y="247.0"></omgdi:waypoint><omgdi:waypoint x="1160.0" y="247.0"></omgdi:waypoint><omgdi:waypoint x="1160.0" y="336.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4"><omgdi:waypoint x="400.0" y="357.0"></omgdi:waypoint><omgdi:waypoint x="400.0" y="247.0"></omgdi:waypoint><omgdi:waypoint x="580.0" y="247.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5"><omgdi:waypoint x="400.0" y="397.0"></omgdi:waypoint><omgdi:waypoint x="400.0" y="477.0"></omgdi:waypoint><omgdi:waypoint x="580.0" y="477.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6"><omgdi:waypoint x="685.0" y="477.0"></omgdi:waypoint><omgdi:waypoint x="1160.0" y="477.0"></omgdi:waypoint><omgdi:waypoint x="1160.0" y="376.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7"><omgdi:waypoint x="665.0" y="520.0"></omgdi:waypoint><omgdi:waypoint x="664.0" y="607.0"></omgdi:waypoint><omgdi:waypoint x="740.0" y="607.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8"><omgdi:waypoint x="775.0" y="607.0"></omgdi:waypoint><omgdi:waypoint x="820.0" y="607.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9"><omgdi:waypoint x="1180.0" y="356.0"></omgdi:waypoint><omgdi:waypoint x="1225.0" y="356.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="association1" id="BPMNEdge_association1"><omgdi:waypoint x="665.0" y="300.0"></omgdi:waypoint><omgdi:waypoint x="664.0" y="363.0"></omgdi:waypoint><omgdi:waypoint x="830.0" y="363.0"></omgdi:waypoint></bpmndi:BPMNEdge></bpmndi:BPMNPlane></bpmndi:BPMNDiagram>
</definitions>

然后部署流程和启动流程实例。通过控制台的输出可以看到微信支付失败后触发了补偿中间事件。然后补偿边界事件触发。触发了补偿自动任务
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/2259.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

文件共享服务器

文章目录 一、共享服务器概述二、创建共享三、访问共享四、创建隐藏的共享五、访问隐藏共享的方法六、共享相关命令七、屏蔽系统隐藏共享自动产生1. 打开注册表2. 定位共享注册表位置 八、查看本地网络连接状态&#xff08;查看开放端口&#xff09;九、关闭445服务 一、共享服…

List迭代器是如何实现的

我们知道当我们使用vector的迭代器时,它的操作可以让它指向下一个位置,解引用操作就可以找到这个位置的值,因为vector底层时用的一个顺序表,可以支持随机访问。对比list来说vector底层的迭代器是十分的简便可观的。虽然我们使用list的迭代器外观上和vector是大同小异的&#xf…

uniapp离线引入阿里巴巴图标

阿里巴巴图标地址 1.添加图标到购物车 2.点击购物车进入项目 3.下载到本地 4.解压后文件目录 5.放入项目目录中(比如说我经常放在common或者static下icon中) 6.在main.ts或者main.js中引入&#xff08;注意路径&#xff0c;用相对的也行&#xff09; import /static/iconfon…

超细,设计一个“完美“的测试用例,用户登录模块实例...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 好的测试用例一定…

java项目之足球赛会管理系统(ssm+mysql+jsp)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的足球赛会管理系统。技术交流和部署相关看文章末尾&#xff01; 项目地址&#xff1a; https://download.csdn.net/download/sinat_26552841…

C#安装.Net平台科学计算库Math.Net Numerics

工作的时候需要使用到C#的Math.Net库来进行计算。 Math.Net库涵盖的主题包括特殊函数&#xff0c;线性代数&#xff0c;概率模型&#xff0c;随机数&#xff0c;插值&#xff0c;积分&#xff0c;回归&#xff0c;优化问题等。 这里记录一下&#xff0c;安装Math.Net库的过程…

Hugging Face开源库accelerate详解

官网&#xff1a;https://huggingface.co/docs/accelerate/package_reference/accelerator Accelerate使用步骤 初始化accelerate对象accelerator Accelerator()调用prepare方法对model、dataloader、optimizer、lr_schedluer进行预处理删除掉代码中关于gpu的操作&#xff0…

【C++ 重要知识点总结】表达式

表达式 1 基础 组合运算 优先级结合律 类型转换 运算符重载 左值和右值 2 算数运算符 3 逻辑和关系运算法 短路求值 逻辑与&#xff0c;当第一个判定为否的时候&#xff0c;不再执行第二个判定&#xff0c;可以用来屏蔽第二步的计算&#xff0c;代替条件判断&#xff0…

String类

String类 String类是Java中的字符串类型,它是引用类型 三种常用的字符串构造 public class Test {public static void main(String[] args){String str1 "hello";String str2 new String("hello");char[] array {h,e,l,l,o};String str3 new String(…

云计算——虚拟化层架构

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​ 前言 本章将会讲解云计算的虚拟化层架构&#xff0c;了解云计算虚拟化层都有哪些架构模式…

WPF嵌入外部exe应用程序-实现基本的嵌入

WPF嵌入外部exe应用程序 使用场景功能实现嵌入基本功能实现1.导入windows API2.运行外部程序3. 获取窗体句柄4. 嵌入窗体5.设置子窗体位置整个代码 嵌入存在的问题&#xff1a; 使用场景 在WPF桌面应用程序开发过程中&#xff0c;有时候需要将其他程序结合到一起&#xff0c;让…

mssql 以xml类型为存储过程传递不确定数量的参数

mssql 以xml类型传递不确定数量的参数 存储过程xml 处理在存储过程中参数在存储过程中使用 xml 作为参数存储过程 相信各位小伙伴在使用数据库的过程中,或多或少的建立了一些存储过程,并且带有一些参数,用来增加存储过程的适用性。 类似老顾的截图这样的,通常,我们需要将…

Redis基本全局命令(含key过期策略)

Redis基本全局命令 KEYEXISTSDELEXPIRETTLRedis的key过期策略TYPE KEY 返回所有满⾜样式&#xff08;pattern&#xff09;的key。⽀持如下统配样式。 h?llo 匹配 hello , hallo 和 hxlloh*llo 匹配 hllo 和 heeeelloh[ae]llo 匹配 hello 和 hallo 但不匹配 hilloh[^e]llo 匹配…

Debian 系统安装中文输入法-iTOP3588开发板

Debian 系统烧写完成之后&#xff0c;并没有中文输入功能。本文档将介绍如何安装 ibus pinyin 输入法。 首先安装 fcitx 对应的工具&#xff0c;如下图所示&#xff1a; apt-get install fcitx fcitx-tools fcitx-config* fcitx-frontend* fcitx-module* fcitx-ui-* presage …

2023-7-13-第十八式观察者模式

&#x1f37f;*★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* &#x1f37f; &#x1f4a5;&#x1f4a5;&#x1f4a5;欢迎来到&#x1f91e;汤姆&#x1f91e;的csdn博文&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f49f;&#x1f49f;喜欢的朋友可以关注一下&#xf…

opencv-06 使用numpy.array 操作图片像素值

opencv-06 使用numpy.array 操作图片像素值 **1&#xff0e;二值图像及灰度图像****利用item 读取某一个像素值****利用itemset 修改像素值****彩色图像numpy.arry 像素值操作** numpy.array 提供了 item()和 itemset()函数来访问和修改像素值&#xff0c;而且这两个函数都是经…

基于MATLAB的无人机遥感数据预处理与农林植被性状估算

查看原文>>>基于MATLAB的无人机遥感数据预处理与农林植被性状估算 在新一轮互联网信息技术大发展的现今&#xff0c;无人机、大数据、人工智能、物联网等新兴技术在各行各业都处于大爆发的前夜。为了将人工智能方法引入农业生产领域。首先在种植、养护等生产作业环节…

Offset Explorer2 监视kafka的利器

kafka作为一个生产者和消费者集为一体的框架&#xff0c;消费者必须一直保持打开的状态&#xff0c;并且每隔一段时间接收一次数据&#xff0c;才能够保持生产者放入的数据及时被处理掉&#xff0c;而生产者则可以每隔一段时间发送一波数据&#xff0c;这样消费者就能够接收到了…

layui入门增删改查

layui入门增删改查 创建Lauiyi对象1.后台准备1.dao方法2.子实现类 2.R工具类的使用3.查询前端代码实现前端页面 4.增删改实现2.浮层3分离的js代码1.userManage.js2.userEdit.js3.index.js 5.运行效果 作为一名开发人员&#xff0c;我们经常需要对数据库中的数据进行增删改查&am…

前端node.js入门

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 Node.js 入门 什么是 Node.js&#xff1f; 什么是前端工程化&#xff1f; Node.js 为何能执行 JS&…