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

2023-10-31

事件篇

在这里插入图片描述

事件(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 {
    @Override
    public 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 开始事件

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

做消息的定义

在这里插入图片描述

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

在这里插入图片描述

然后就可以部署流程

    /**
     * 流程部署操作
     */
    @Test
    public 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();
    // 发送消息 发送的消息应该是具体的消息的名称而不应该是id
    runtimeService.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
     */
    @Override
    public 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>

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

2023最新版本Activiti7系列-事件篇 的相关文章

  • PageHelper 分页排序使用记录

    PageHelper 分页使用 PageHelper startPage pageNum pageSize orderBy 其中最后一个参数是数据库字段名称 按传入的字段进行排序 场景 如果有接口参数中有排序字段 则按参数中的排序字段来排序
  • sqlite的事务和锁,很透彻的讲解 【转】

    原文 sqlite的事务和锁 http 3y uu456 com bp 877d38906bec097sf46se240 1 html 事务 事务定义了一组SQL命令的边界 这组命令或者作为一个整体被全部执行 或者都不执行 事务的典型实例是
  • Flowable 之事件和网关

    文章目录 一 网关 1 1 排他网关 1 2 并行网关 1 3 包容网关 1 4 事件网关 二 事件 2 1 定时器事件 2 1 1 定时器启动事件 2 1 2 中间计时器捕获事件 2 1 3 边界计时器事件 2 2 消息事件 2 2 1
  • Vuejs实践--事件绑定

    Vue中的事件绑定一般通过v on指令来绑定事件 事件绑定 v on 事件绑定的表达式的值可以是js语句 也可以是在methods选项中定义好的方法名 有参数的时候当然需要传参 在vue事件中 如果要用到事件对象e 要将e作为形参传入函数
  • Netty (2)-ChannelInboundHandlerAdapter入站事件

    在第1篇 我们继承ChannelInboundHandlerAdapter后 即可收到消息并处理 本篇介绍其更多的用法 基本概念 Channel 可以理解为一个连接 每一个客户端连到服务器 都会有一个与之对应的Channel Channel
  • QT 鼠标事件及labe显示设置总结

    qt鼠标事件总结 转 1 QMouseEvent中的坐标 QMouseEvent中保存了两个坐标 一个是全局坐标 当然另外一个是局部坐标 全局坐标 globalPos 即是桌面屏幕坐标 screen coordinates 这个跟windo
  • activiti7-4-流程激活和挂起

    我是一个目录 1 分析 2 全部流程实例的挂起和激活 3 单个流程实例挂起 1 分析 如果公司制度发生变化 1 原本没有批完的流程怎么办 例如 30人没有处理完 怎么办 看公司制度了 有可能 按原来的走 也有可能全部打回 重新发起 全部按照
  • 工作流Activiti7整合SpringBoot使用

    前言 一个软件系统中具有工作流的功能 我们把它称为工作流系统 一个系统中工作流的功能是什么 就是对系统的业务流程进行自动化管理 所以工作流是建立在业务流程的基础上 所以一个软件的系统核心根本上还是系统的业务流程 工作流只是协助进行业务流程管
  • [数据库] Navicat for MySQL事件Event实现数据每日定期操作

    在我们操作数据库过程中 通常会遇到一些某个时间点操作数据库的问题 例如 1 每天凌晨12点对数据库进行定时备份 结算和汇总 2 每天凌晨2点删除数据库前三天的数据 3 插入某个数据超过一定时间改变某个值的状态 比如预警系统 这里就需要通过E
  • val()、html()方法改变元素值后,元素change事件无效解决方案

    原因 Change事件触发有两个必要条件 值改变 失去焦点 解决方法 改变值的同时 1 手动触发change事件 input val change input val trigger change 2 手动触发blur事件 input va
  • C# Winform 窗体传值 利用委托 子窗体传值给父窗体

    常用的Winform窗体传值有两种方式 1 更改Form designer cs文件 将控件的设为Public 供子窗体访问 在designer cs文件的最后 找到你的控件声明 private System Windows Forms T
  • Qt使用事件(event)与定时器实现字幕滚动

    目录 1 效果展示 2 实现思路 3 滚动窗口部件 3 1 成员变量 3 2 事件重写 3 3 成员方法 3 3 方法实现 1 效果展示 我们经常能够在外面看到那种滚动字幕 那么就拿qt来做一个吧 2 实现思路 实现一个窗口部件 这个窗口部
  • QT中监控全局键盘鼠标事件

    先介绍一下在单一Widget等控件中监听鼠标键盘事件的代码 void mouseMoveEvent QMouseEvent event void mouseReleaseEvent QMouseEvent event void keyPre
  • 2023最新版本Activiti7系列-源码篇-初始化过程

    源码分析 1 设计模式 1 1 命令模式 https dpb bobokaoya sm blog csdn net article details 89115420 1 2 责任链模式 https dpb bobokaoya sm blog
  • SpringBoot 事件发布监听机制使用、分析、注意点 (一篇到位)

    前言 这一篇从应用角度来跟大伙讲讲 这个 spring 事件监听机制 顺便涉及到那些我认为大家应该一块了解的 我也会展开说说 文章内容 包括不限于 1 对比观察者模式 2 应用场景的分析 3 事件的创建 编码介绍 4 事件如何 发出 5 事
  • Spring Boot 集成 Activiti7(工作流)

    Spring Boot 集成 Activiti7 工作流 本章节将介绍 Spring Boot 集成 Activiti7 工作流 Spring Boot 2 x 实践案例 代码仓库 介绍 Activiti 是一个工作流引擎 它可以将业务系统
  • activiti7-2-流程定义、实例、任务查询、任务处理、压缩部署、定义查询、定义删除、定义资源查询、历史信息查询

    我是一个目录 1 流程定义 1 1 绘制流程图 1 2 简单介绍API和原理机制 1 2 1 API 1 2 2 原理机制 1 3 流程定义部署测试类 1 4 分析影响的表 2 流程实例 2 1 启动流程实例 2 2 分析影响的表 3 任务
  • React-事件处理详解

    对于用户界面而言 展示只占整体设计因素的一半 另一半则是相应用户输入 即通过JavaScript处理用户产生的事件 React通过将事件处理器绑定到组建上处理事件 事件触发的同时更新组建的内部状态 内部状态更新会触发组件的重绘 因此 如果视
  • 2023最新版本Activiti7系列-身份服务

    身份服务 在流程定义中在任务结点的 assignee 固定设置任务负责人 在流程定义时将参与者固定设置在 bpmn 文件中 如果临时任务负责人变更则需要修改流程定义 系统可扩展性差 针对这种情况可以给任务设置多个候选人或者候选人组 可以从候
  • Java中创建事件监听器的五种方法

    在Java中处理事件的办法最原始的方法如下 一 使用内部类 一个个设置Button然后创建一个内部类 用ActionPerformed来实现按钮事件内容 import javax swing import java awt import j

随机推荐

  • 微软云计算技术Windows Azure专题(一):如何利用Service Bus向Windows商店应用推送消息...

    本文介绍了如何使用Windows Azure的Service Bus通知中心发送推送通知Windows商店应用程序 先来明确一下大体上要做哪些步骤 1 申请一个Windows应用商店的应用 每个应用都有自己的身份识别标识 不然Windows
  • idea64.exe.vmoptions 配置说明,通用于jvm配置

    一 问题场景 在使用 idea 时 经常卡顿 性能不足 且内存消耗大 在已经购买使用性能较大 酷睿12代标压 及以上 内存配置较大 32G 及以上时 为了全面释放 cpu 性能 提高 idea 性能 故对 idea 的 jvm 进行配置优化
  • 【重磅推荐】哥大开源“FinRL”: 一个用于量化金融自动交易的深度强化学习库

    深度强化学习实验室 官网 http www neurondance com 论坛 http deeprl neurondance com 编辑 DeepRL 一 关于FinRL 目前 深度强化学习 DRL 技术在游戏等领域已经取得了巨大的成
  • 架构设计师

    岗位职责 1 作为团队技术负责人 负责业务产品 重点项目的架构设计和开发管理工作 2 负责开发架构搭建和核心代码编写 3 参与需求分析 配合项目经理管理项目和制定项目战略目标 4 新技术研究和选型 5 参与产品 项目的技术评审 6 为咨询解
  • BUUCTF [ACTF2020 新生赛] Exec

    BUUCTF ACTF2020 新生赛 Exec 启动靶机 打开环境 页面可以执行Ping命令 判断应为命令执行漏洞 尝试输入正常IP127 0 0 1查看其回显 127 0 0 1 其为正常回显 测试管道连接符 是否能用 127 0 0
  • springboot静态资源存放路径解析

    1 源码分析 public void addResourceHandlers ResourceHandlerRegistry registry 1 如果静态资源已经被自定义了 则禁用默认资源处理 if this resourceProper
  • 词语提取小工具开放啦

    推荐一个词语提取小工具给大家使用 免费的 华为云的云搜索服务 可以自定义自己的词库来做分词 停词 修改词库还可以热更新 不用重启即可生效 大家都知道词库中的词从哪里来 哪些才是有用的词 这是让人头疼的事情 每天苦读海量文章 也才能从中找出几
  • Android 7.0 网络变化监听

    一般监听网络变化是在 AndroidManifest 中注册 BroadcastReceiver 来实现 targetSdkVersion 升级到 24 后 发现静态注册广播的方式要被取消了 Declaring a broadcastrec
  • 【SQL】15 SQL 约束(Constraints)、NOT NULL 约束、UNIQUE 约束、PRIMARY KEY 约束、FOREIGN KEY 约束、CHECK 约束、DEFAULT约束

    SQL 约束 Constraints SQL 约束用于规定表中的数据规则 如果存在违反约束的数据行为 行为会被约束终止 约束可以在创建表时规定 通过 CREATE TABLE 语句 或者在表创建之后规定 通过 ALTER TABLE 语句
  • 文献阅读:Chain-of-Thought Prompting Elicits Reasoning in Large Language Models

    文献阅读 Chain of Thought Prompting Elicits Reasoning in Large Language Models 1 文章简介 2 具体方法 3 实验结果 1 数学推理 1 实验设计 2 实验结果 3 消
  • 如何配置Binlog

    binlog日志有两个最重要的使用场景 1 MySQL主从复制 MySQL Replication在Master端开启binlog Master把它的二进制日志传递给slaves来达到 master slave数据一致的目的 2 自然就是数
  • VUE项目打包成apk

    在我们的开发需求中 可能会遇到需要将vue项目中的H5代码打包成一个安卓的app 那么我为大家介绍一套保姆级的解决方案 看完你就会 VUE HBuilder 1 准备工作 需要下载一个HBuilder X编辑器 不过我相信大家身为前端开发工
  • 算法设计技巧与分析(期末复习)

    查找 二分查找 include
  • 关于图像傅里叶变换得到的频谱图的通俗理解

    傅里叶变换过程 经过傅里叶变化且频谱居中化处理的频谱图 1 如果将图像某一行上的灰度变化看作是一个离散信号 那么整张图像可以看作是一个分布在二维平面上的信号 因此图像可看作是空间域信号 傅里叶变换则是将图像灰度分布 空间域信号 变换到了频域
  • vue v-for动态渲染本地图片

    记录 多张本地图片使用v for渲染时引入路径需添加 require
  • 移动端的h5可配置表头的复杂表格

    最近做移动端的h5项目 要做一个可配置表头的复杂表格 网上找了很久也没什么好方法 结合网上的一些例子 在此做一了一个完整的vue版的例子 效果图 1 引入 iscroll npm i iscroll save 2 对插件再做一层封装 封装成
  • PPTP模式跟L2TP模式有什么不同

    使用VPN的时候经常会看到商家说支持PPTP模式和L2TP模式 但是许多朋友都不知道有什么区别 该用哪一个 下面给你们讲讲 1 PPTP协议是点对点隧道协议 其将控制包与数据包分开 控制包采用TCP控制 用于严格的状态查询及信令信息 数据包
  • cryptography

    出现这个错误是因为缺少cryptography包 可以使用 pip install cryptography 安装cryptography包 如果安装cryptography失败 先检查一下自己的pip包是否为最新版本 在settings
  • CSS 实现input自定义样式--文本框

    边框 设置边框颜色
  • 2023最新版本Activiti7系列-事件篇

    事件篇 事件 event 通常用于为流程生命周期中发生的事情建模 事件总是图形化为圆圈 在BPMN 2 0中 有两种主要的事件分类 捕获 catching 与抛出 throwing 事件 捕获 当流程执行到达这个事件时 会等待直到触发器动作