Activiti7-波哥是个憨憨

一、概述

官网地址:https://www.activiti.org/

Activiti由Alfresco软件开发,目前最高版本Activiti 7。是BPMN的一个基于java的软件实现,不过Activiti 不仅仅包括BPMN,还有DMN决策表和CMMN Case管理引擎,并且有自己的用户管理、微服务API等一系列功能,是一个服务平台。

二、入门案例

官方手册:http://jeecg.com/activiti5.21/

1.创建springboot项目

现在开发中或者我们自己学习写案例都是通过SpringBoot脚手架工具来快速构建项目的。那么我们也就直接通过创建SpringBoot项目来给大家讲解相关的案例。创建一个普通的SpringBoot项目。指定版本为2.4.2即可。JDK版本得是11

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo01</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter</artifactId>
            <version>7.0.0.GA</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.获取ProcessEngine

2.1 默认的方式

在工作流引擎框架中, ProcessEngine 是一个非常核心的对象,我们需要首先解决这个对象的获取。获取方式很多。先来看最简单的一个基于 activiti.cfg.xml 的XML文件的配置方式。

/**
     * 获取ProcessEngine对象的第一种方式
     */
    @Test
    public void test1(){
        //通过 getDefaultProcessEngine()方法获取流程引擎对象  会加载resources下的activiti.cfg.xml
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        System.out.println(processEngine);
    }

通过 getDefaultProcessEngine 方法加载会默认的从classpath路径下加载 activiti.cfg.xml 配置文件。我们添加该文件。内容如下:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- id必须是 processEngineConfiguration  -->
    <bean id="processEngineConfiguration"
          class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti7" />
        <property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver" />
        <property name="jdbcUsername" value="root" />
        <property name="jdbcPassword" value="root" />
        <property name="databaseSchemaUpdate" value="true" />
        <property name="asyncExecutorActivate" value="false" />
        <property name="mailServerHost" value="mail.my-corp.com" />
        <property name="mailServerPort" value="5025" />
    </bean>
</beans>

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.2 编程方式获取

上面的配置文件的方式中的配置文件其实是一个Spring的配置文件,但是这并不意味着Activiti只能用于Spring环境。我们也可以通过编程的方式来使用配置文件,从而来构建ProcessEngineConfiguration对象,具体的实现如下:

    /**
     * 基于Java代码获取ProcessEngine对象
     */
    @Test
    public void test2(){
        ProcessEngine engine = ProcessEngineConfiguration
                .createStandaloneInMemProcessEngineConfiguration()
                .setJdbcUrl("jdbc:mysql://localhost:3306/activiti7")
                                .setJdbcDriver("com.mysql.cj.jdbc.Driver")
                                .setJdbcPassword("root")
                                .setJdbcUsername("root")
                                .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE)
                                .buildProcessEngine();
        System.out.println(engine);
    }

上面讲解中的相关属性说明:
databaseSchemaUpdate:用于设置流程引擎启动关闭时使用的数据库表结构控制策略

  • false (默认): 当引擎启动时,检查数据库表结构的版本是否匹配库文件版本。版本不匹配时抛出异常。
  • true : 构建引擎时,检查并在需要时更新表结构。表结构不存在则会创建。
  • create-drop : 引擎创建时创建表结构,并在引擎关闭时删除表结构。

2.3 表结构介绍

在Activiti7中。我们启动服务会自动维护Activiti7需要使用到的相关的表结构。在这块我们需要有个大概的了解。首先是支持的数据库有:

Activiti数据库类型示例JDBC URL备注
h2jdbc:h2:tcp://localhost/activiti默认配置的数据库
oraclejdbc:oracle:thin:@localhost:1521:xe
postgresjdbc:postgresql://localhost:5432/activiti
db2jdbc:db2://localhost:50000/activiti

Activiti的所有数据库表都以ACT_开头。第二部分是说明表用途的两字符标示符。服务API的命名也大略符合这个规则。

  • ACT_RE_*: RE 代表 repository 。带有这个前缀的表包含“静态”信息,例如流程定义与流程资源(图片、规则等)。
  • ACT_RU_*: RU 代表 runtime 。这些表存储运行时信息,例如流程实例(process instance)、用户任务(user task)、变量(variable)、作业(job)等。Activiti只在流程实例运行中保存运行时数据,并在流程实例结束时删除记录。这样保证运行时表小和快。
  • ACT_ID_*: ID 代表 identity 。这些表包含身份信息,例如用户、组等。
  • ACT_HI_*: HI 代表 history 。这些表存储历史数据,例如已完成的流程实例、变量、任务等。
  • ACT_GE_*: 通用数据。用于不同场景下

注意:MySQL数据库最好使用5.7及以上的版本

会发现act_ge_property表会有数据
在这里插入图片描述

3.在线流程设计器

接下来我们通过官方提供的流程设计器来实现一个简单流程的设计。然后完成相关的部署和流程整体操作。

官网下载地址:https://www.activiti.org/get-started 下载下来后解压缩

在这里插入图片描述

在这里插入图片描述

进入到wars中。提供的有Activiti-app.war

在这里插入图片描述

把这war包拷贝到Tomcat服务器中即可。注意Tomcat的版本不要高于8.5,然后Tomcat服务。访问 http://localhost:8080/activiti-app 即可。登录的账号密码是 admin test

将activiti-app.war放入tomcat的webapps目录下
在这里插入图片描述

然后启动tomcat
在这里插入图片描述

访问http://localhost:8080/activiti-app,输入用户名admin和密码test,即可登录成功进入
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
点击“Create Process ”,弹出窗口。录入相关的流程定义信息

在这里插入图片描述
录入流程图的名称和key和描述

在这里插入图片描述整体流程图如上图所示

在这里插入图片描述
点击“人事审批”的节点,然后下面会有相关属性出现,这里我们点击“Assignments”,然后弹出Assignment的框出现
在这里插入图片描述
在这里插入图片描述
表示该节点由zhangsan来进行审批。

配置好各自节点的审批人后,进行保存
在这里插入图片描述
在这里插入图片描述

进行下载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="http://www.activiti.org/processdef">
  <process id="test" name="test" isExecutable="true">
    <documentation>test</documentation>
    <startEvent id="startEvent1"></startEvent>
    <userTask id="sid-69E77A57-E14F-4C79-AD4F-9AD1929406A9" name="人事审批" activiti:assignee="zhangsan">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <sequenceFlow id="sid-776DF814-E68F-49CB-90D8-6B98A1801508" sourceRef="startEvent1" targetRef="sid-69E77A57-E14F-4C79-AD4F-9AD1929406A9"></sequenceFlow>
    <userTask id="sid-732A12A2-AD4D-4406-8B23-A34BB1F60D1C" name="经理审批" activiti:assignee="lisi">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <sequenceFlow id="sid-DE9336AD-7E6D-45F8-B589-6AA3A210E8C0" sourceRef="sid-69E77A57-E14F-4C79-AD4F-9AD1929406A9" targetRef="sid-732A12A2-AD4D-4406-8B23-A34BB1F60D1C"></sequenceFlow>
    <endEvent id="sid-6CA4C975-410D-4C1B-B6A6-58894E492622"></endEvent>
    <sequenceFlow id="sid-DE19D371-8E2C-4E55-A507-68EF07CAC0B3" sourceRef="sid-732A12A2-AD4D-4406-8B23-A34BB1F60D1C" targetRef="sid-6CA4C975-410D-4C1B-B6A6-58894E492622"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_test">
    <bpmndi:BPMNPlane bpmnElement="test" id="BPMNPlane_test">
      <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
        <omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-69E77A57-E14F-4C79-AD4F-9AD1929406A9" id="BPMNShape_sid-69E77A57-E14F-4C79-AD4F-9AD1929406A9">
        <omgdc:Bounds height="80.0" width="100.0" x="175.0" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-732A12A2-AD4D-4406-8B23-A34BB1F60D1C" id="BPMNShape_sid-732A12A2-AD4D-4406-8B23-A34BB1F60D1C">
        <omgdc:Bounds height="80.0" width="100.0" x="320.0" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-6CA4C975-410D-4C1B-B6A6-58894E492622" id="BPMNShape_sid-6CA4C975-410D-4C1B-B6A6-58894E492622">
        <omgdc:Bounds height="28.0" width="28.0" x="465.0" y="164.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="sid-776DF814-E68F-49CB-90D8-6B98A1801508" id="BPMNEdge_sid-776DF814-E68F-49CB-90D8-6B98A1801508">
        <omgdi:waypoint x="130.0" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="175.0" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-DE9336AD-7E6D-45F8-B589-6AA3A210E8C0" id="BPMNEdge_sid-DE9336AD-7E6D-45F8-B589-6AA3A210E8C0">
        <omgdi:waypoint x="275.0" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="320.0" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-DE19D371-8E2C-4E55-A507-68EF07CAC0B3" id="BPMNEdge_sid-DE19D371-8E2C-4E55-A507-68EF07CAC0B3">
        <omgdi:waypoint x="420.0" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="465.0" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

然后我们就可以做流程的部署操作了

4.流程操作

4.1 流程部署

设计好了流程图我们就可以通过如下的代码完成流程的部署。

    /**
     * 流程部署操作
     */
    @Test
    public void test3(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/test.bpmn20.xml")
                .name("第一个流程")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

流程部署的行为会涉及到数据库中的这三张表

  • act_ge_bytearray 流程字节表
  • act_re_deployment 流程部署表
  • act_re_procdef 流程定义表

act_ge_bytearray:流程字节表

在这里插入图片描述
act_re_deployment:流程部署表
在这里插入图片描述
act_re_procdef 流程定义表
在这里插入图片描述

如果在执行一次部署代码,则act_ge_bytearray、act_re_deployment、act_re_procdef三个表又会添加。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

然后我们可以通过Activiti提供的相关的API来获取流程部署和流程定义的相关信息

 	/**
     * 查询当前部署的流程有哪些
     */
    @Test
    public void test4(){
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
        // 查询有哪些部署的流程-->查询相关的流程定义信息
        // repositoryService.createDeploymentQuery() 查询流程部署的相关信息
        // repositoryService.createProcessDefinitionQuery() 查询部署的流程的相关的定义

        //查询的是act_re_deployment(流程部署表)这张表的数据
        List<Deployment> list = repositoryService.createDeploymentQuery().list();
        for (Deployment deployment : list) {
            System.out.println(deployment.getId());
            System.out.println(deployment.getName());
        }

        //查询的是act_re_procdef(流程定义表)这张表的数据
        List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery().list();
        for (ProcessDefinition processDefinition : processDefinitions) {
            System.out.println(processDefinition.getId());
            System.out.println(processDefinition.getName());
            System.out.println(processDefinition.getDescription());
        }

        //查询的是act_re_model这张表的数据
        List<Model> models = repositoryService.createModelQuery().list();
        for (Model model : models) {
            System.out.println(model.getId());
        }
    }

4.2 发起流程

部署流程成功后。我们就可以发起一个流程。发起流程需要通过RuntimeService 来实现。

    /**
     * 发起一个流程
     */
    @Test
    public void test5(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("test:1:3");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());
    }

发起流程成功后。在对应的 act_ru_task 中就有一条对应的待办记录。
在这里插入图片描述
对应的流程状态如下:
在这里插入图片描述

在发起流程中,涉及到的表有:

  • act_hi_actinst
  • act_hi_identitylink
  • act_hi_procinst
  • act_hi_taskinst
  • act_ru_execution
  • act_ru_identitylink
  • act_ru_task

act_hi_actinst:任务活动节点
在这里插入图片描述
act_hi_identitylink:当前负责人
在这里插入图片描述

act_hi_procinst:结束的节点
在这里插入图片描述

act_hi_taskinst:当前代办流程节点
在这里插入图片描述

act_ru_execution:运行流程节点数据
在这里插入图片描述

act_ru_identitylink:运行某个流程定义的当前负责人
在这里插入图片描述

act_ru_task:待办节点流程
在这里插入图片描述

4.3 查询流程

用户登录后要查看待办的任务信息。我们需要通过 TaskService 来实现查询操作。具体代码如下:

    /**
     * 待办查询
     */
    @Test
    public void test6(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 待办查询 执行中的任务处理通过 TaskService来实现
        TaskService taskService = engine.getTaskService();
        // Task 对象对应的其实就是 act_ru_task 这张表的记录
        List<Task> list = taskService.createTaskQuery().taskAssignee("zhangsan").list();
        if(list != null && list.size() > 0){
            for (Task task : list) {
                System.out.println(task.getId());//对应act_ru_task表的ID_字段
                System.out.println(task.getName());//对应act_ru_task表的NAME_字段
                System.out.println(task.getAssignee());//对应act_ru_task表的ASSIGNEE_字段
            }
        }else{
            System.out.println("当前没有待办任务");
        }
    }

4.4 审批流程

当前登录用户查看到相关的待办信息后。可以做流程的审批处理。

    /**
     * 任务审批-张三
     */
    @Test
    public void test7(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 做任务申请 也需要通过 TaskService 来实现
        TaskService taskService = engine.getTaskService();
        // 完成任务
        taskService.complete("2505");//2505拿的是act_ru_task表的ID_字段值
    }

会发现act_ru_task由zhangsan变成lisi了,因为这张表展示的是待办任务的数据
在这里插入图片描述

当最后一个流程节点也审批结束后,act_ru_task表就没有数据了
在这里插入图片描述

5.涉及表结构

上面一个审批涉及到的表结构的介绍

6.流程设计器持久化

流程设计器默认是通过 H2 来完成数据的存储的。而 H2 是基于内存来存储的。所以重启服务后数据就丢失了。这时我们可以设置流程设计器的存储方式为MySQL。这样就能持久化的实现存储了。具体步骤如下:

6.1 修改配置信息

在这里插入图片描述
在webapps里的activiti-app项目里如上图的位置找到activiti-app.properties文件进行修改

调整数据库的连接信息。记得同时需要创建对应的数据库activiti6ui

jdbc:mysql://localhost:3306/activiti6ui?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&nullCatalogMeansCurrent=true

在这里插入图片描述

6.2 加入mysql依赖

在…\apache-tomcat-8.5.91\webapps\activiti-app\WEB-INF\lib目录下计入mysql依赖包
在这里插入图片描述

6.3 重新启动tomcat

启动成功后。在数据库中会维护相关的表结构
在这里插入图片描述

该操作中需要注意的点:

  1. 修改配置文件中的信息关键是连接地址的路径:jdbc:mysql://localhost:3306/activiti6ui?
    serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&nullCatalogMeansCurrent=true
  2. MySQL的驱动版本不要高于8.0.19,不然会出现LocalDataTime转换的问题

7.流程设计器汉化说明

三、任务分配

1.固定分配

在指派 用户任务 的审批人时。我们是直接指派的固定账号。但是为了保证流程设计审批的灵活性。我们需要各种不同的分配方式,所以这节我们就详细的来介绍先在Activiti7中我们可以使用的相关的分配方式。固定分配就是我们前面介绍的,在绘制流程图或者直接在流程文件中通过Assignee来指定的方式
在这里插入图片描述

2. 表达式

Activiti使用UEL进行表达式解析。UEL代表Unified Expression Language ,是 EE6规范的一部分(查看EE6规范了解更多信息)。为了在所有环境上支持UEL标准的所有最新特性,我们使用JUEL的修改版本。

表达式可以用于例如 Java服务任务 Java Service tasks , 执行监听器 Execution Listeners , 任务监听器Task Listeners 与 条件流 Conditional sequence flows。尽管有值表达式与方法表达式两种表达式,通过Activiti的抽象,使它们都可以在需要 expression (表达式)的地方使用。

${myVar}
${myBean.myProperty}

2.1 值表达式

我们在处理的位置通过UEL表达式来占位。
在这里插入图片描述
然后做流程的部署操作:

    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/test2.bpmn20.xml")
                .name("请假流程-流程变量")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

然后我们发起请假流程:

/**
     * 发起一个流程
     */
    @Test
    public void test2(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 对流程变量做赋值操作
        Map<String,Object> map = new HashMap<>();
        map.put("assign1","张三");
        map.put("assign2","李四");
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("test:2:10003",map);//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());
    }

然后我们就可以看到对应的表(act_ru_task)结构中的待办记录
在这里插入图片描述
同时需要了解 : act_ru_variable
在这里插入图片描述

2.2 方法表达式

方法表达式 Method expression: 调用一个方法,可以带或不带参数。当调用不带参数的方法时,要确保在方法名后添加空括号(以避免与值表达式混淆)。传递的参数可以是字面值(literal value),也可以是表达式,它们会被自动解析。例如:

${printer.print()}
${myBean.getAssignee()}
${myBean.addNewOrder(‘orderName’)}
${myBean.doSomething(myVar, execution)}

myBean是Spring容器中的个Bean对象,表示调用的是bean的addNewOrder方法.我们通过案例来演示下。我们先定义对应的Service

先定义Bean

package com.example.service;

public class MyBean {
    public String getAssignee(){
        System.out.println("本方法执行了....");
        return "波哥";
    }
}

然后在Spring的配置文件(activiti.cfg.xml)中注册

<bean name="myBean" class="com.example.service.MyBean"/>

在这里插入图片描述

然后在绘制流程图的时候就可以对应的指派了。
在这里插入图片描述

然后我们先部署流程

    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/test3.bpmn20.xml")
                .name("请假流程-方法表达式")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

在这里插入图片描述

然后我们发起新的流程。注意在这块我们可以不用添加流程变量信息了。因为 人事审批节点 的审批人是通过流程方法来赋值的

    /**
     * 发起一个流程
     */
    @Test
    public void test2(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("test:3:25003");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());
    }

可以看到操作成功。方法表达式被执行了
在这里插入图片描述
同时待办中的审批人就是方法表达式返回的结果

在这里插入图片描述

3.监听器分配

可以使用监听器来完成很多Activiti的流程业务。我们在此处使用监听器来完成负责人的指定,那么我们在流程设计的时候就不需要指定assignee。创建自定义监听器:

package com.example.listener;

import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;

public class MyFirstListener implements TaskListener {
    /**
     * 监听器触发的回调方法
     * @param delegateTask
     */
    @Override
    public void notify(DelegateTask delegateTask) {
        System.out.println("---->自定义的监听器执行了");
        if(EVENTNAME_CREATE.equals(delegateTask.getEventName())){
            // 表示是Task的创建事件被触发了
            // 指定当前Task节点的处理人
            delegateTask.setAssignee("boge666");
        }
    }
}

在配置流程的时候关联监听器。注意对应的事件。CREATE。先将Assignment的值取消掉
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

然后我们部署流程

    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/test4.bpmn20.xml")
                .name("请假流程-监听器分配")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

在这里插入图片描述

启动流程后。

    /**
     * 发起一个流程
     */
    @Test
    public void test2(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("test:4:30003");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());
    }

待办中的任务的处理人就是监听器中设置的信息
在这里插入图片描述

当发起该流程定义,可以看到自定义的监听器触发了
在这里插入图片描述

四、流程变量

1.运行时变量

流程实例运行时的变量,存入act_ru_variable表中。在流程实例运行结束时,此实例的变量在表中删除。在流程实例创建及启动时,可设置流程变量。所有的 startProcessInstanceXXX 方法都有一个可选参数用于设置变量。例如, RuntimeService

ProcessInstance startProcessInstanceById(String processDefinitionId, Map<String,Object> variables);

也可以在流程执行中加入变量。例如,( RuntimeService ):

void setVariable(String executionId, String variableName, Object value);
void setVariableLocal(String executionId, String variableName, Object value);
void setVariables(String executionId, Map<String, ? extends Object> variables);
void setVariablesLocal(String executionId, Map<String, ? extends Object>
variables);

读取变量方法:

Map<String, Object> getVariables(String executionId);
Map<String, Object> getVariablesLocal(String executionId);
Map<String, Object> getVariables(String executionId, Collection<String>
variableNames);
Map<String, Object> getVariablesLocal(String executionId, Collection<String>
variableNames);
Object getVariable(String executionId, String variableName);
<T> T getVariable(String executionId, String variableName, Class<T> variableClass);
........
........
........

**注意:**由于流程实例结束时,对应在运行时表的数据跟着被删除。所以查询一个已经完结流程实例的变量,只能在历史变量表中查找。

当然运行时变量我们也可以根据对应的作用域把他分为 全局变量局部变量 .

1.1 全局变量

流程变量的默认作用域是流程实例。当一个流程变量的作用域为流程实例时,可以称为 global 变量

global 变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值。

定义监听器

package com.example.listener;

import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;

import java.util.Map;
import java.util.Set;

/**
 * 自定义的监听器
 *      处理相关的变量信息
 */
public class MySecondListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        // 获取所有的流程变量
        Map<String, Object> variables = delegateTask.getVariables();
        Set<String> keys = variables.keySet();
        for (String key : keys) {
            Object obj = variables.get(key);
            System.out.println(key + " = " + obj);
            if(obj instanceof String){
                // 修改 流程变量的信息
                // variables.put(key,obj + ":boge3306"); 直接修改Map中的数据 达不到修改流程变量的效果
                delegateTask.setVariable(key,obj + "-boge3306");
            }
        }
    }
}

package com.example.listener;

import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;

import java.util.Map;
import java.util.Set;

public class MyThirdListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        // 获取所有的流程变量
        Map<String, Object> variables = delegateTask.getVariables();
        Set<String> keys = variables.keySet();
        for (String key : keys) {
            Object obj = variables.get(key);
            System.out.println(key + " = " + obj);
            if(obj instanceof String){
                // 修改 流程变量的信息
                // variables.put(key,obj + ":boge3306"); 直接修改Map中的数据 达不到修改流程变量的效果
                delegateTask.setVariable(key,obj + "[]");
            }
        }
    }
}

设计流程
在这里插入图片描述

人事审批,设置审批人和监听器
在这里插入图片描述
在这里插入图片描述

经理审批,设置审批人和监听器
在这里插入图片描述

在这里插入图片描述
然后完成流程的部署操作

/**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/test5.bpmn20.xml")
                .name("请假流程-流程变量")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

查看act_re_procdef表可以看到该部署情况
在这里插入图片描述
然后启动流程实例。注意在启动流程实例时我们需要指定相关的流程变量

    /**
     * 发起一个流程
     */
    @Test
    public void test2(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 定义流程变量信息
        Map<String,Object> map = new HashMap<>();
        map.put("assignee1","张三");
        map.put("assignee2","李四");
        map.put("ass1","变量1");
        map.put("ass2",299);
        map.put("ass3","湖南长沙");
        map.put("ass4","波哥666");
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("test:5:35003",map);//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());
    }

在这里插入图片描述

启动流程和触发对应的监听器,同时会在 act_ru_variable 中记录当前的变量信息
在这里插入图片描述

在这里插入图片描述

当然我们也可以通过 RunTimeService 来查询当前对应的流程实例的流程变量信息

    /**
     * 查询当前的流程变量信息
     */
    @Test
    public void testVal(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();
        // 获取流程变量信息 获取某个流程实例的变量信息
        Map<String, VariableInstance> variableInstances =
                runtimeService.getVariableInstances("37508");//37508值是act_ru_task表中的EXECUTION_ID_字段的值
        Set<String> keys = variableInstances.keySet();
        for (String key : keys) {
            System.out.println(key+"="+variableInstances.get(key));
        }
    }

然后进行人事审批后,查看act_ru_task表记录
在这里插入图片描述

同时执行上述的testVal单元测试方法,发现也是可以正常运行的
在这里插入图片描述

同时act_ru_variable表也发生了变化
在这里插入图片描述

这个是全局变量,可以在不同的节点都可以获取以及调整,可以看到在人事审批可以获取或修改,在经理审批也可以进行获取或者修改。

1.2 局部变量

任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大, 称为 local 变量。

Local 变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。Local 变量名也可以和 global 变量名相同,没有影响。

设计流程图
修改全局流程图的人事审批的监听器
在这里插入图片描述

package com.example.listener;

import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;

import java.util.Map;
import java.util.Set;

/**
 * 自定义的监听器
 *      处理相关的变量信息
 */
public class MyFourthListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        // 获取所有的流程变量
        Map<String, Object> variables = delegateTask.getVariables();
        Set<String> keys = variables.keySet();
        for (String key : keys) {
            Object obj = variables.get(key);
            System.out.println("---fourth---->"+key + " = " + obj);
            if(obj instanceof String){
                // 修改 流程变量的信息
                // variables.put(key,obj + ":boge3306"); 直接修改Map中的数据 达不到修改流程变量的效果
                //delegateTask.setVariable(key,obj + "-boge3306");
            }
        }
    }
}

修改全局流程图的经理审批的监听器
在这里插入图片描述

package com.example.listener;

import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;

import java.util.Map;
import java.util.Set;

public class MyFifthListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        // 获取所有的流程变量
        Map<String, Object> variables = delegateTask.getVariables();
        Set<String> keys = variables.keySet();
        for (String key : keys) {
            Object obj = variables.get(key);
            System.out.println("---fifth---->"+key + " = " + obj);
            if(obj instanceof String){
                // 修改 流程变量的信息
                // variables.put(key,obj + ":boge3306"); 直接修改Map中的数据 达不到修改流程变量的效果
                //delegateTask.setVariable(key,obj + "[]");
            }
        }
    }
}

然后进行部署

    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/test6.bpmn20.xml")
                .name("请假流程-局部流程变量")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

再然后我们进行流程的发起

    /**
     * 发起一个流程
     */
    @Test
    public void test2(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 定义流程变量信息
        Map<String,Object> map = new HashMap<>();
        map.put("assignee1","张三");
        map.put("assignee2","李四");
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("test:6:45003",map);//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());
    }

在这里插入图片描述

进行局部变量定义

    /**
     * 设置局部变量
     */
    @Test
    public void test3(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();
        runtimeService.setVariableLocal("47504","orderId","o123456");//47504是act_ru_task表的EXECUTION_ID_字段值
        runtimeService.setVariableLocal("47504","orderPrice",6666);
    }

查看act_ru_variable表,会发现有我们定义的具备变量
在这里插入图片描述

然后进行局部变量的获取

    /**
     * 读取本地流程变量
     */
    @Test
    public void test4(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();
        // 获取流程变量信息 获取某个流程实例的变量信息
        Map<String, Object> variablesLocal = runtimeService.getVariablesLocal("47504");//47504值是act_ru_task表中的EXECUTION_ID_字段的值
        System.out.println(variablesLocal);
    }

在这里插入图片描述

还可以通过TaskService来设置局部变量

    /**
     * 通过TaskService设置局部变量
     */
    @Test
    public void test5(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        taskService.setVariableLocal("47507","positionName","总经理");//47507值是act_ru_task表的ID_字段的值
    }

在这里插入图片描述

通过test4()测试方法会发现无法获取到局部变量名positionName的值,想要获取positionName的值,需要借助TaskService类

    /**
     * 通过TaskService获取局部变量
     */
    @Test
    public void test6(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        Map<String, Object> variablesLocal = taskService.getVariablesLocal("47507");
        System.out.println(variablesLocal);
    }

在这里插入图片描述

然后我们进行人事审批

    /**
     * 任务审批-张三
     */
    @Test
    public void test11(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 做任务申请 也需要通过 TaskService 来实现
        TaskService taskService = engine.getTaskService();
        // 完成任务
        taskService.complete("47507");//47507拿的是act_ru_task表的ID_字段值
    }

然后我们看act_ru_variable表,会发现positionName变量没有了

在这里插入图片描述

然后通过测试演示我们可以看到通过TaskService绑定的Local变量的作用域只是在当前的Task有效。而通过RuntimeService绑定的Local变量作用的范围是executionId

如下图所示,当任务到并行网关后的任务的执行ID(executionId)就不一样了,但实例ID是一样的。需要注意:executionId和processInstanceId的区别

在这里插入图片描述

2.历史变量

历史变量,存入 act_hi_varinst 表中。在流程启动时,流程变量会同时存入历史变量表中;在流程结束时,历史表中的变量仍然存在。可理解为“永久代”的流程变量。

    /**
     * 流程变量历史信息查询
     */
    @Test
    public void testHistoryInfo(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        List<HistoricVariableInstance> list = engine.getHistoryService().createHistoricVariableInstanceQuery().list();
        System.out.println(list);
    }

在这里插入图片描述

五、身份服务

在流程定义中在任务结点的 assignee 固定设置任务负责人,在流程定义时将参与者固定设置在.bpmn 文件中,如果临时任务负责人变更则需要修改流程定义,系统可扩展性差。针对这种情况可以给任务设置多个候选人或者候选人组,可以从候选人中选择参与者来完成任务。

1.审批人

前面案例中直接指派审批的用户的处理

2.候选人

一个审批节点可能有多个人同时具有审批的权限。这时我们就可以通过候选人来处理。

2.1 绘制流程图

我们定义一个简单的审批流程图。如下:

在这里插入图片描述

人事审批中我们设置多个候选人来处理,分别是 张三 , 李四 , 王五。表示这三人中任意一人审批了该任务即该任务完成。

在这里插入图片描述

在总经理的位置我们统一设置几个候选人来审批

在这里插入图片描述

2.2 部署和启动流程

    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/test7.bpmn20.xml")
                .name("候选人")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

在这里插入图片描述

    /**
     * 发起一个流程
     */
    @Test
    public void test2(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("admin:1:57503");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());
    }

在这里插入图片描述

可以在act_ru_identitylink表里可以看到当前任务的候选人信息

在这里插入图片描述

2.3 任务的拾取

候选要操作我们需要通过 拾取 的行为把 候选人 转换为处理人 .那么候选人登录后需要能查询出来他可以 拾取 的任务。

    /**
     * 候选人 审批任务查询
     */
    @Test
    public void test3(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery().
                taskCandidateUser("张三") //根据候选人查询审批任务
                .list();
        if (list!=null && list.size()>0){
            System.out.println(list);
        } else {
            System.out.println("没有任务");
        }
    }
    
    /**
     * 候选人 拾取操作
     *  拾取操作就是从候选人-->处理人
     */
    @Test
    public void test4(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery().
                taskCandidateUser("张三") //根据候选人查询审批任务
                .list();
        if (list!=null && list.size()>0){
            for (Task task : list) {
                //张三 拾取了 这个任务的审批权限 --> 变成了这个任务的审批人
                taskService.claim(task.getId(),"张三");
            }
        } else {
            System.out.println("没有任务");
        }
    }

在这里插入图片描述

在这里插入图片描述

发现act_ru_identitylink里的候选人数据是没有变的,只有act_ru_task的人事审批的审批人字段从开始空的变成了张三。

当其他候选人如李四进行候选任务查询,会发现没有任务,因为当拾取之后该任务就确认下来了审批人了,则其他候选人则没有候选任务了。

    /**
     * 候选人 审批任务查询
     */
    @Test
    public void test3(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery().
                taskCandidateUser("李四") //根据候选人查询审批任务
                .list();
        if (list!=null && list.size()>0){
            System.out.println(list);
        } else {
            System.out.println("没有任务");
        }
    }

在这里插入图片描述

2.4.任务的归还

    /**
     * 归还:拾取的用户 可能没有时间进行审批,就放弃审批人的操作
     * 其他的候选人可以重新拾取任务了
     */
    @Test
    public void test5(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery()
                .taskCandidateOrAssigned("张三")
                .list();
        if (list!=null && list.size()>0){
            for (Task task : list) {
                // 规范其实就是将审批人字段设置为空
                taskService.unclaim(task.getId());
            }
        } else {
            System.out.println("没有任务");
        }
    }

在这里插入图片描述

再使用test3()测试方法可以看李四或者王五的候选任务是否有,运行发现是有数据的。

在这里插入图片描述

3.候选人组

当获选人很多的情况下,我们可以分组来处理,先创建组,然后把用户分配到这个组中。

3.1 绘制流程图

在这里插入图片描述

然后在人事审批节点里,添加获选人组

在这里插入图片描述

3.2 部署流程

    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/test8.bpmn20.xml")
                .name("候选人组")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

在这里插入图片描述

3.3 发起流程

    /**
     * 发起一个流程
     */
    @Test
    public void test2(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("test8:1:3");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());
    }

在这里插入图片描述

在这里插入图片描述

3.4查询代办任务

    /**
     * 候选人组
     *  具体的用户。比如张三登录了系统
     *  查询张三对应是什么部门,然后根据部门查询代办的任务
     */
    @Test
    public void test3(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        String group = "销售部"; //根据当前登录用户查询得来的
        List<Task> list = taskService.createTaskQuery()
                .taskCandidateGroup(group)
                .list();
        if (list!=null && list.size()>0){
            System.out.println(list);
        } else {
            System.out.println("没有任务");
        }
    }

在这里插入图片描述

3.4拾取任务

    /**
     * 候选人组其中一人 拾取操作
     *  拾取操作就是从候选人-->处理人
     *  一个任务如果被拾取后,其他的候选人就查询不到该任务信息了
     */
    @Test
    public void test4(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        String group = "销售部"; //根据当前登录用户查询得来的
        List<Task> list = taskService.createTaskQuery()
                .taskCandidateGroup(group)
                .list();
        if (list!=null && list.size()>0){
            for (Task task : list) {
                //张三 拾取了 这个任务的审批权限 --> 变成了这个任务的审批人
                taskService.claim(task.getId(),"张三");
            }
        } else {
            System.out.println("没有任务");
        }
    }

在这里插入图片描述

然后调用test3()进行查询,发现该获选人组没有代办任务了。
在这里插入图片描述

3.5交接任务

    /**
     * 获取用户审批权限的用户没有时间审批了
     * 但是他也可以不用归还而是做任务的交接。把这个任务让另外一个人来审批
     */
    @Test
    public void test6(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery()
                .taskAssignee("张三")
                .list();
        if (list!=null && list.size()>0){
            for (Task task : list) {
                // 任务交接
                taskService.setAssignee(task.getId(),"李四");
            }
        } else {
            System.out.println("没有任务");
        }
    }

在这里插入图片描述

3.6 归还任务

    /**
     * 归还:拾取的用户 可能没有时间进行审批,就放弃审批人的操作
     * 其他的候选人可以重新拾取任务了
     */
    @Test
    public void test5(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery()
                .taskAssignee("李四")
                .list();
        if (list!=null && list.size()>0){
            for (Task task : list) {
                // 规范其实就是将审批人字段设置为空
                taskService.unclaim(task.getId());
            }
        } else {
            System.out.println("没有任务");
        }
    }

六、网关篇

6.1 排他网关

6.1.1 绘制流程图

在这里插入图片描述

在这里插入图片描述

创建请假单流程节点进行审批人设置

在这里插入图片描述

部门经理审批流程节点进行审批人设置
在这里插入图片描述

总经理审批流程节点进行审批人设置

在这里插入图片描述

人事审批流程节点进行审批人设置

在这里插入图片描述

进行线条的排他网关的条件设置
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

表示请假天数如果<3则走部门经理审批,>=3则走总经理审批。

6.1.2 部署流程


    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/gateway1.bpmn20.xml")
                .name("排他网关")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

在这里插入图片描述

6.1.2 发起流程

    /**
     * 发起一个流程
     */
    @Test
    public void test2(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("gateway:1:2503");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());
    }

在这里插入图片描述

6.1.3 创建请假单审批

    /**
     * 创建请假单 流程审批  张三
     */
    @Test
    public void test3(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery().taskAssignee("zhangsan").list();
        Map<String,Object> map = new HashMap<>();
        //绑定对应的请假天数
        map.put("days",6);
        for (Task task : list) {
            taskService.complete(task.getId(),map);
        }
    }

在这里插入图片描述

在这里插入图片描述

6.2 并行网关

6.2.1 绘制流程图

在这里插入图片描述

分别给创建请假单技术经理审批项目经理审批人事经理审批总经理审批设置审批人分别为zhangsan,lisi,wangwu,zhaoliu,boos

6.2.2 流程部署

    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/gateway2.bpmn20.xml")
                .name("并行网关")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

在这里插入图片描述

6.2.3 发起流程

    /**
     * 发起一个流程
     */
    @Test
    public void test2(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("gateway2:1:3");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());
    }

在这里插入图片描述

在这里插入图片描述

6.2.4 流程审批

    /**
     * 创建请假单 流程审批  张三
     */
    @Test
    public void test3(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery().taskAssignee("zhangsan").list();
        for (Task task : list) {
            taskService.complete(task.getId());
        }
    }

在这里插入图片描述

在这里插入图片描述
act_ru_execution执行流程表中,存在一条PARENT_ID_为null的主执行流程实例,其余为PARENT_ID_为主执行流程实例ID为2501的子执行流程实例,分别表示是技术经理审批项目经理审批人事经理审批

然后技术经理李四进行审批,会发现act_ru_task表中没有了lisi的代办审批任务
在这里插入图片描述

会发现主执行流程随着审批任务运行一次,REV_字段主执行流程会累加,第一条子执行流程也是会累加。
在这里插入图片描述

然后项目经理王五进行审批,会发现act_ru_task表中没有了wangwu的代办审批任务

在这里插入图片描述
会发现主执行流程随着审批任务运行一次,REV_字段主执行流程会累加,第二条子执行流程也是会累加为2了。
在这里插入图片描述

然后人事经理赵六进行审批,会发现act_ru_task表中没有了zhaoliu的代办审批任务
在这里插入图片描述

在这里插入图片描述

然后总经理boos进行审批,会发现act_ru_task表中没有了boos的代办审批任务
在这里插入图片描述

在这里插入图片描述

6.3 包容网关

6.3.1 绘制流程图

在这里插入图片描述

说明:人事审批是不过请假天数如何是一定会走的。

分别给创建请假单项目经理人事审批技术总监总经理审批设置审批人分别为zhangsan,lisi,wangwu,zhaoliu,boos

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

6.3.2 部署流程

    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/gateway3.bpmn20.xml")
                .name("并行网关")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

在这里插入图片描述

6.3.3 发起流程

    /**
     * 发起一个流程
     */
    @Test
    public void test2(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("gateway3:1:3");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());
    }

在这里插入图片描述

在这里插入图片描述

6.3.4 流程审批

    /**
     * 创建请假单 流程审批  张三
     */
    @Test
    public void test3(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        Map<String,Object> map = new HashMap<>();
        map.put("days",3);
        List<Task> list = taskService.createTaskQuery().taskAssignee("zhangsan").list();
        for (Task task : list) {
            taskService.complete(task.getId(),map);
        }
    }

在这里插入图片描述

在这里插入图片描述

然后技术总监zhaoliu进行审批
在这里插入图片描述

在这里插入图片描述

然后人事wangwu审批

在这里插入图片描述

在这里插入图片描述

然后总经理boss审批,两个表都空空如也。

七、事件篇

7.1 定时器事件

7.1.1 定时器开始事件

7.1.1.1 绘制流程图

在这里插入图片描述

注意的点:需要在activiti.cfg.xml表中加入

<property name="asyncExecutorActivate" value="true" />
7.1.1.2 流程部署
    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/event01.bpmn20.xml")
                .name("定时器开始事件")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

会发现没到2023年8月19日的19时35分钟后几秒,act_ru_timer_job表会有一条记录
在这里插入图片描述

当时间到了2023年8月19日的19时35分钟后几秒,act_ru_timer_job表没有任何数据了
在这里插入图片描述
同时也会发现act_ru_task有了一条用户任务的任务记录
在这里插入图片描述

使用场景:如每个月1号进行一些审核任务,如月度绩效考核任务填写。

在这里插入图片描述

在这里插入图片描述

其中R3/PT30S表示每隔30秒,执行三次。

package com.example.delegate;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

import java.time.LocalDateTime;

/**
 * 自定义委托类
 */
public class MyFirstDelegate implements JavaDelegate {

    /**
     * 回调方法
     * @param execution
     */
    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("服务任务执行了......" + LocalDateTime.now().toString());
    }
}

    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/event02.bpmn20.xml")
                .name("定时器开始事件")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

从控制台搜索服务任务执行了,会发现有三条打印日志,且事件相差30秒

在这里插入图片描述

7.1.2 定时器中间事件

7.1.2.1 绘制流程图

在这里插入图片描述

PT1M表示申请出库审批通过后等待1分钟后定时器触发然后进入出库处理流程

7.1.2.2 部署流程
    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/event03.bpmn20.xml")
                .name("定时器中间事件")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

在这里插入图片描述

7.1.2.3 发起流程
    /**
     * 发起一个流程
     */
    @Test
    public void test2(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("event03:1:3");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());
    }

在这里插入图片描述

7.1.2.4 审批流程
    /**
     * 流程审批  张三
     */
    @Test
    public void test3(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery().taskAssignee("zhangsan").list();
        for (Task task : list) {
            taskService.complete(task.getId());
        }

        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

执行test3()测试方法,可以看到act_ru_timer_job表有一条数据
在这里插入图片描述
当执行1分钟之后,会发现,原本空空如也的act_ru_task出现了出库处理的任务,同时act_ru_timer_job表里的数据被清空了。

在这里插入图片描述

在这里插入图片描述

7.1.3 定时器边界事件

7.1.3.1 绘制流程图

在这里插入图片描述

PT1M表示“合同审批-总经理审批”如果一分钟之后没有处理,则定时器边界事件会被触发,从而会执行下图的服务任务。

Time date in ISO-8601为这个节点的特定时间
Time End Date in ISO-8601结束时间
Time cycle:循环。也就是总经理审批这个节点两天没有审批,那么我每隔半小时给他发送个消息
Time duration:持续。表示这个节点多久没去审批,我可以给他做个处理。
Cancel activity为勾选(true)表示这个整个流程发生表示中断的,也就是财务审批不再进行了。为非勾选,则表示这个流程还是继续做流转的和审批的,即财务审批还是继续执行的。

需要 注意将Boundary timer event要放在用户任务的边上

在这里插入图片描述
在这里插入图片描述

7.1.3.2 流程部署
    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/event04.bpmn20.xml")
                .name("定时器边界事件")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

在这里插入图片描述

7.1.3.3 流程发起

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

在这里插入图片描述

在这里插入图片描述

等待了一分钟定时器边界事件触发。我们可以在控制台中看到MySecondDelegate任务的执行
在这里插入图片描述

因为这块的边界事件我们定义的是非中断,所以用户任务还在。即使定时器边界事件也结束。只是在边界事件中触发了服务任务来通过用户审批处理
在这里插入图片描述

7.1.3.4 流程审批
    /**
     * 流程审批  张三
     */
    @Test
    public void test3(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery().taskAssignee("zhangsan").list();
        for (Task task : list) {
            taskService.complete(task.getId());
        }

        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

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

在这里插入图片描述

同时会开启我们的中间边界事件。act_ru_timer_job中会生成对应的记录
在这里插入图片描述

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

7.2.消息事件

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

7.2.1 开始事件

消息开始事件,也就是我们通过接收到某些消息后来启动流程实例,比如我们接收到了一封邮件,一条短信等,具体通过案例来讲解。

7.2.1.1 绘制流程图

在这里插入图片描述

在这里插入图片描述

做消息的定义
在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

部署完流程后,消息启动事件会在act_ru_event_subscr表中记录我们的定义事件
在这里插入图片描述

7.2.1.3 流程发起
    /**
     * 发送消息,触发流程
     */
    @Test
    public void test2() throws InterruptedException {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();
        //发送消息
        runtimeService.startProcessInstanceByMessage("msg01");//值为act_ru_event_subscr表中的EVENT_NAME_字段值

        TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
    }

注意:消息的名称我们不要使用驼峰命名法来定义
这时候可以看到消息启动事件之后的任务

在这里插入图片描述

7.2.2 中间事件

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

7.2.2.1 绘制流程图

在这里插入图片描述

做消息定义
在这里插入图片描述

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

7.2.2.3 流程发起
    /**
     * 发起一个流程
     */
    @Test
    public void test2() throws InterruptedException {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("event06:1:3");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());

    }

在这里插入图片描述

7.2.2.4 流程审核
    /**
     * 流程审批  张三
     */
    @Test
    public void test3(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery().taskAssignee("zhangsan").list();
        for (Task task : list) {
            taskService.complete(task.getId());
        }
    }

然后发现act_ru_task表中没有了任务
在这里插入图片描述

同时在act_ru_event_subscr表中有一条msg02的数据
在这里插入图片描述

部署启动和审批流程后进入到消息中间事件的节点,然后发送消息触发事件,则执行7.2.2.5

7.2.2.5 触发消息中间事件
    /**
     * 触发消息中间事件-第一种方式
     */
    @Test
    public void test41(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();
        // 查询当前的 执行实例的编号
        Execution execution = runtimeService.createExecutionQuery()
                .processInstanceId("2501")
                .onlyChildExecutions()
                .singleResult();//值为act_ru_suspended_job表中的PROC_INST_ID_字段的值
        runtimeService.messageEventReceived("msg02", execution.getId());
    }

    /**
     * 触发消息中间事件-第二种方式
     */
    @Test
    public void test42(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();
        // 查询当前的 执行实例的编号
        Execution execution = runtimeService.createExecutionQuery()
                .processInstanceId("2501")
                .messageEventSubscriptionName("msg02")
                .singleResult();//值为act_ru_event_subscr表中的PROC_INST_ID_字段的值
        runtimeService.messageEventReceived("msg02", execution.getId());
    }

建议使用第二种方式

然后进入到了用户任务2的审批任务节点,说明消息中间事件被触发了。

在这里插入图片描述

7.2.3 边界事件

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

7.2.3.1 绘制流程图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

package com.example.delegate;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

import java.time.LocalDateTime;

/**
 * 自定义委托类
 */
public class MyThirdDelegate implements JavaDelegate {

    /**
     * 回调方法
     * @param execution
     */
    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("消息边界的服务任务执行了......" + LocalDateTime.now().toString());
    }
}

在这里插入图片描述

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

在这里插入图片描述

7.2.3.3 流程发起
    /**
     * 发起一个流程
     */
    @Test
    public void test2() throws InterruptedException {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("event07:1:3");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());

    }

在这里插入图片描述

在这里插入图片描述

7.2.3.4 触发消息边界事件
    /**
     * 触发消息边界事件
     */
    @Test
    public void test3(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();
        runtimeService.messageEventReceived("msg03","2505");//第二个值为:act_ru_event_subscr表中的EXECUTION_ID_字段值
    }

然后在控制台就可以看到JavaDelegate被执行调用了
在这里插入图片描述

这里我们需要注意当前的边界事件是非中断的。所以还是需要用户任务1来审批

7.2.3.5 任务审核
    /**
     * 流程审批  张三
     */
    @Test
    public void test4(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery().taskAssignee("zhangsan").list();
        for (Task task : list) {
            taskService.complete(task.getId());
        }
    }

在这里插入图片描述

在这里插入图片描述

7.2.3.6 触发消息边界事件
    /**
     * 触发消息边界事件
     */
    @Test
    public void test5(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();
        runtimeService.messageEventReceived("msg04","7502");//第二个值为:act_ru_event_subscr表中的EXECUTION_ID_字段值
    }

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

在这里插入图片描述

7.3 错误事件

7.3.1 开始事件

7.3.1.1 绘制流程图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

package com.example.delegate;

import org.activiti.engine.delegate.BpmnError;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

import java.time.LocalDateTime;

/**
 * 自定义委托类
 */
public class MyErrorDelegate1 implements JavaDelegate {

    /**
     * 回调方法
     * @param execution
     */
    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("错误开始事件的任务服务执行了1111......" + LocalDateTime.now().toString());

        // 显示的抛出error1 的异常信息  触发 错误开始事件
        throw new BpmnError("error1");
    }
}

package com.example.delegate;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

import java.time.LocalDateTime;

/**
 * 自定义委托类
 */
public class MyErrorDelegate2 implements JavaDelegate {

    /**
     * 回调方法
     * @param execution
     */
    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("错误开始事件的任务服务执行了2222......" + LocalDateTime.now().toString());
    }
}

7.3.1.2 部署流程
    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/event08.bpmn20.xml")
                .name("错误开始事件")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

在这里插入图片描述

7.3.1.3 发起流程
    /**
     * 发起一个流程
     */
    @Test
    public void test2() throws InterruptedException {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("event08:1:3");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());

    }

在这里插入图片描述
在这里插入图片描述

7.3.2 边界事件

7.3.2.1 绘制流程图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

自动任务1自动任务2自动任务3自动任务4自动任务5的class属性分别对应MyBoundaryErrorDelegate1MyBoundaryErrorDelegate2MyBoundaryErrorDelegate3MyBoundaryErrorDelegate4MyBoundaryErrorDelegate5的全限定名

package com.example.delegate;

import org.activiti.engine.delegate.BpmnError;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

import java.time.LocalDateTime;

/**
 * 自定义委托类
 */
public class MyBoundaryErrorDelegate1 implements JavaDelegate {

    /**
     * 回调方法
     * @param execution
     */
    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("错误边界事件的任务服务执行了1111......" + LocalDateTime.now().toString());

        // 显示的抛出error2 的异常信息  触发 错误开始事件
        throw new BpmnError("error2");
    }
}

package com.example.delegate;

import org.activiti.engine.delegate.BpmnError;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

import java.time.LocalDateTime;

/**
 * 自定义委托类
 */
public class MyBoundaryErrorDelegate2 implements JavaDelegate {

    /**
     * 回调方法
     * @param execution
     */
    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("错误边界事件的任务服务执行了2222......" + LocalDateTime.now().toString());

        // 显示的抛出error3 的异常信息  触发 错误开始事件
        throw new BpmnError("error3");
    }
}

package com.example.delegate;

import org.activiti.engine.delegate.BpmnError;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

import java.time.LocalDateTime;

/**
 * 自定义委托类
 */
public class MyBoundaryErrorDelegate3 implements JavaDelegate {

    /**
     * 回调方法
     * @param execution
     */
    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("错误边界事件的任务服务执行了3333......" + LocalDateTime.now().toString());
    }
}

package com.example.delegate;

import org.activiti.engine.delegate.BpmnError;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

import java.time.LocalDateTime;

/**
 * 自定义委托类
 */
public class MyBoundaryErrorDelegate4 implements JavaDelegate {

    /**
     * 回调方法
     * @param execution
     */
    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("错误边界事件的任务服务执行了4444......" + LocalDateTime.now().toString());

    }
}

package com.example.delegate;

import org.activiti.engine.delegate.BpmnError;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

import java.time.LocalDateTime;

/**
 * 自定义委托类
 */
public class MyBoundaryErrorDelegate5 implements JavaDelegate {

    /**
     * 回调方法
     * @param execution
     */
    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("错误边界事件的任务服务执行了5555......" + LocalDateTime.now().toString());

    }
}

7.3.2.2 部署流程
    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/event09.bpmn20.xml")
                .name("错误边界事件")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

在这里插入图片描述

7.3.2.3 发起流程
    /**
     * 发起一个流程
     */
    @Test
    public void test2() throws InterruptedException {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("event09:1:2503");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());

    }

在这里插入图片描述

在这里插入图片描述

当将MyBoundaryErrorDelegate1类注释掉throw new BpmnError("error2");在发起一次流程,搜索日志会发现走了1,2,5

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

当将MyBoundaryErrorDelegate2类注释掉throw new BpmnError("error3");在发起一次流程,搜索日志会发现走了1,2,3

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

7.3.3 结束事件

7.3.3.1 绘制流程图

在这里插入图片描述

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

7.3.3.2 流程部署
    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/event10.bpmn20.xml")
                .name("错误结束事件")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

在这里插入图片描述

7.3.3.3 发起流程
    /**
     * 发起一个流程
     */
    @Test
    public void test2() throws InterruptedException {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("event10:1:3");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());

    }

在这里插入图片描述

7.3.3.4 审批流程
    /**
     * 任务审批-张三
     */
    @Test
    public void test3(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 做任务申请 也需要通过 TaskService 来实现
        TaskService taskService = engine.getTaskService();
        // 完成任务
        taskService.complete("2505");//2505拿的是act_ru_task表的ID_字段值
    }

在这里插入图片描述

    /**
     * 任务审批-李四
     */
    @Test
    public void test4(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 做任务申请 也需要通过 TaskService 来实现
        TaskService taskService = engine.getTaskService();
        Map<String,Object> map = new HashMap<>();
        map.put("payFlag",false);
        // 完成任务
        taskService.complete("5007",map);//5007拿的是act_ru_task表的ID_字段值
    }

在这里插入图片描述
会发现ID是发生了变化的,流程的名称还是支付

    /**
     * 任务审批-李四
     */
    @Test
    public void test4(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 做任务申请 也需要通过 TaskService 来实现
        TaskService taskService = engine.getTaskService();
        Map<String,Object> map = new HashMap<>();
        map.put("payFlag",true);
        // 完成任务
        taskService.complete("7511",map);//5007拿的是act_ru_task表的ID_字段值
    }

在进行重新支付后,支付成功后,就会流转到“发货”的流程

在这里插入图片描述

7.4 信息事件

7.4.1 开始事件

7.4.1.1 绘制流程图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

在这里插入图片描述

在这里插入图片描述

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

        // 通过runtimeService中提供的API来发布信号
        runtimeService.signalEventReceived("signal01");
        TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
    }

在这里插入图片描述

    /**
     * 发起一个流程
     */
    @Test
    public void test22() throws InterruptedException {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("event11:1:3");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());

    }

在这里插入图片描述

7.4.2 中间事件

7.4.2.1 绘制流程图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

7.4.2.2 部署流程
    /**
     * 流程部署操作
     */
    @Test
    public void test1(){
        // 1.获取ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.完成流程的部署操作 需要通过RepositoryService来完成
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3.完成部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/event12.bpmn20.xml")
                .name("信息中间事件")
                .deploy();//是一个流程部署的行为  可以部署多个流程定义(act_re_procdef表)
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

在这里插入图片描述

7.4.2.3 发起流程
    /**
     * 发起一个流程
     */
    @Test
    public void test2() throws InterruptedException {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 发起流程 需要通过 runtimeService 来实现
        RuntimeService runtimeService = engine.getRuntimeService();
        // 通过流程定义来启动流程  返回的是流程实例对象
        //这里流程实例和流程定义 有点像实例和类的关系
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("event12:1:5003");//值是流程定义表act_re_procdef的ID_字段值
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getDeploymentId());
        System.out.println(processInstance.getDescription());

    }

在这里插入图片描述

7.4.2.4 审核流程
    /**
     * 任务审批-张三
     */
    @Test
    public void test3(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 做任务申请 也需要通过 TaskService 来实现
        TaskService taskService = engine.getTaskService();
        // 完成任务
        taskService.complete("7509");//2505拿的是act_ru_task表的ID_字段值

        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

发现他触发了同样信号为signal01的开始事件,有了如上红框里的任务。

在这里插入图片描述

7.4.3 边界事件

7.4.3.1 绘制流程图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

7.4.3.2 部署流程
7.4.3.3 发起流程
7.4.3.4 审核流程

7.5 其他事件

7.5.1 终止结束事件

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值