1. 程式人生 > 實用技巧 >Activiti7工作流的使用

Activiti7工作流的使用

Activiti服務架構

概述

activiti-cfg.xml

  • activiti-cfg.xml是activiti的引擎配置檔案,包括:ProcessEngineConfiguration的定義、資料來源的定義、事務管理器等,此檔案其實就是一個Spring配置檔案,下面是一個基本的配置只配置了ProcessEngineConfiguration和資料來源。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--  配置資料來源 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="username" value="root"/>
        <property name="url"
                  value="jdbc:mysql://192.168.134.100:3306/activiti?useUnicode=true&amp;characterEncoding=UTF-8&amp;autoReconnect=true&amp;useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true"/>
        <property name="password" value="123456"/>
        <property name="maxActive" value="3"/>
        <property name="maxIdle" value="1"/>
    </bean>

    <!-- Activiti單獨執行的ProcessEngine配置 -->
    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <!-- 資料來源 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 
            activiti資料庫表處理策略 
                false(預設值):檢查資料庫的版本和依賴庫的版本,如果不匹配就丟擲異常
                true:構建流程引擎時,執行檢查,如果需要就執行更新。如果表不存在,就建立。
                create-drop:構建流程引擎時建立資料庫報表,關閉流程引擎時就刪除這些表。
                drop-create:先刪除表再建立表。
                create:構建流程引擎時建立資料庫表,關閉流程引擎時不刪除這些表
        -->
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>
</beans>

ProcessEngineConfiguration

概述

  • 流程引擎的配置類,通過ProcessEngineConfiguration可以建立工作流引擎ProcessEngine,常用的兩種方法如下:

StandaloneProcessEngineConfiguration

  • 通過org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration,Activiti可以單獨執行,使用它建立的ProcessEngine,Activiti會自己處理事務。

  • 配置檔案方式:

    • 通常在activiti-cfg.xml配置檔案中定義一個id為processEngineConfiguration的Bean,這裡會使用Spring的依賴注入來構建引擎。
    <!-- Activiti單獨執行的ProcessEngine配置 -->
    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <!-- 資料來源 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 
                activiti資料庫表處理策略 
                    false(預設值):檢查資料庫的版本和依賴庫的版本,如果不匹配就丟擲異常
                    true:構建流程引擎時,執行檢查,如果需要就執行更新。如果表不存在,就建立。
                    create-drop:構建流程引擎時建立資料庫報表,關閉流程引擎時就刪除這些表。
                    drop-create:先刪除表再建立表。
                    create:構建流程引擎時建立資料庫表,關閉流程引擎時不刪除這些表
            -->
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>
    

SpringProcessEngineConfiguration

  • 通過org.activiti.spring.SpringProcessEngineConfiguration和Spring整合。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns="http://www.springframework.org/schema/beans" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--  配置資料來源 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="username" value="root"/>
        <property name="url"
                  value="jdbc:mysql://192.168.134.100:3306/activiti?useUnicode=true&amp;characterEncoding=UTF-8&amp;autoReconnect=true&amp;useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true"/>
        <property name="password" value="123456"/>
        <property name="maxActive" value="3"/>
        <property name="maxIdle" value="1"/>
    </bean>

    <!-- 工作流引擎配置bean -->
    <bean id="processEngineConfiguration"
          class="org.activiti.spring.SpringProcessEngineConfiguration">
        <!-- 資料來源 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 使用spring事務管理器 -->
        <property name="transactionManager" ref="transactionManager"/>
        <!-- 資料庫策略 -->
        <property name="databaseSchemaUpdate" value="drop-create"/>
    </bean>

    <!-- 流程引擎 -->
    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
        <property name="processEngineConfiguration"
                  ref="processEngineConfiguration"/>
    </bean>

    <!-- 資源服務service -->
    <bean id="repositoryService" factory-bean="processEngine"
          factory-method="getRepositoryService" />
    <!-- 流程執行service -->
    <bean id="runtimeService" factory-bean="processEngine"
          factory-method="getRuntimeService" />
    <!-- 任務管理service -->
    <bean id="taskService" factory-bean="processEngine"
          factory-method="getTaskService" />
    <!-- 歷史管理service -->
    <bean id="historyService" factory-bean="processEngine"
          factory-method="getHistoryService" />
    <!-- 引擎管理service -->
    <bean id="managementService" factory-bean="processEngine"
          factory-method="getManagementService" />


    <!-- 事務管理器 -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 傳播行為 -->
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="insert*" propagation="REQUIRED" />
            <tx:method name="delete*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
            <tx:method name="get*" propagation="SUPPORTS" read-only="true" />
        </tx:attributes>
    </tx:advice>
    <!-- 切面,根據具體專案修改切點配置 -->
    <aop:config proxy-target-class="true">
        <aop:advisor advice-ref="txAdvice"
                     pointcut="execution(* com.sunxiaping.*.service.impl.*.*(..))" />
    </aop:config>
    
</beans>

建立ProcessEngineConfiguration

  • 下面的方法:要求activiti-cfg.xml中必須由一個processEngineConfiguration的Bean的id。
public static ProcessEngineConfiguration createProcessEngineConfigurationFromResource(String resource) {
    return createProcessEngineConfigurationFromResource(resource, "processEngineConfiguration");
}
  • 下面的方法,可以更改Bean的id。
public static ProcessEngineConfiguration createProcessEngineConfigurationFromResource(String resource, String beanName) {
    return BeansConfigurationHelper.parseProcessEngineConfigurationFromResource(resource, beanName);
}

ProcessEngine

  • 工作流引擎,相當於一個門面介面,通過ProcessEngineConfiguration建立ProcessEngine,通過ProcessEngine建立各個Service介面。

一般建立方式

  • 示例:
package com.sunxiaping;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;

/**
 * @author <a href="mailto:[email protected]">weiwei.xu</a>
 * @version 1.0
 * 2020-07-31 6:41
 */
public class ActivitiTest {

    public static void main(String[] args) {
        //建立ProcessEngineConfiguration物件
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        //建立ProcessEngine物件
        ProcessEngine processEngine = configuration.buildProcessEngine();
        System.out.println("processEngine = " + processEngine);
    }
}

簡單建立方式

  • 將activiti.cfg.xml檔名以及路徑固定,且activiti.cfg.xml檔案中有processEngineConfiguration的配置,那麼可以使用如下程式碼建立ProcessEngine。
package com.sunxiaping;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;

/**
 * @author <a href="mailto:[email protected]">weiwei.xu</a>
 * @version 1.0
 * 2020-07-31 6:41
 */
public class ActivitiTest {

    public static void main(String[] args) {
        //該方法有限制
        //①Activiti的配置檔名必須為activiti.cfg.xml
        //②Bean的id必須是processEngineConfiguration
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        System.out.println("processEngine = " + processEngine);
    }

}

Service

Service的建立方式

  • 通過ProcessEngine建立Service,Service是工作流引擎提供用於進行工作流部署、指定、管理的服務介面。

  • 建立方式如下:

package com.sunxiaping;

import org.activiti.engine.*;

/**
 * @author <a href="mailto:[email protected]">weiwei.xu</a>
 * @version 1.0
 * 2020-07-31 11:55
 */
public class ActivitiTest {

    public static void main(String[] args) {
        //建立ProcessEngineConfiguration物件
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        //建立ProcessEngine物件
        ProcessEngine processEngine = configuration.buildProcessEngine();

        RepositoryService repositoryService = processEngine.getRepositoryService();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        TaskService taskService = processEngine.getTaskService();
        HistoryService historyService = processEngine.getHistoryService();
        ManagementService managementService = processEngine.getManagementService();

        System.out.println("repositoryService = " + repositoryService);
        System.out.println("runtimeService = " + runtimeService);
        System.out.println("taskService = " + taskService);
        System.out.println("historyService = " + historyService);
        System.out.println("managementService = " + managementService);

    }
}

Service總覽

Service介面 說明
RepositoryService Activiti的資源管理介面
RuntimeService Activiti的流程執行管理介面
TaskService Activiti的任務管理介面
HistoryService Activiti的歷史管理介面
ManagementService Activiti的引擎管理介面

RepositoryService

  • RepositoryService,是Activiti的資源管理介面,提供了管理和控制流程釋出包和流程定義的操作。使用工作流建模工具設計的業務流程圖需要使用此Service將流程定義檔案的內容部署到計算機中。
  • 除了流程部署定義以外還可以做如下的操作:
    • 1️⃣查詢引擎中的釋出包和流程定義。
    • 2️⃣暫停或啟用釋出包以及對應全部和特定流程定義。暫停意味著它們不能再在執行任務操作了,啟用是對應的反向操作。
    • 3️⃣獲取多種資源,像包含在釋出包中的檔案獲引擎自動生成的流程圖。
    • 4️⃣獲取流程定義的POJO,可以用解析流程,而不必通過XML。

RuntimeService

  • RuntimeService是Activiti的流程執行管理介面,可以從這個介面中獲取很多關於流程執行相關的資訊。

TaskService

  • TaskService是Activiti的任務管理介面,可以從這個介面中獲取任務的資訊。

HistoryService

  • HistoryService是Activiti的歷史管理類,可以查詢歷史資訊,執行流程時,引擎會包含很多資料(根據配置),比如流程例項啟動時間,任務的參與者,完成任務的時間,每個流程例項的執行路徑,等等。

ManagementService

  • ManagementService是Activiti的引擎管理介面,提供了對Activiti流程引擎的管理和維護功能,這些功能不在工作流驅動的應用程式中使用,主要用於Activiti系統的日常維護。

Activiti入門體驗

流程定義

畫板

  • 在IDEA中安裝對應的Activiti-Designer(Activiti設計器)外掛即可使用,畫板中包括以下結點:

    • Connection--連線。
    • Event--事件。
    • Task--任務。
    • Gateway--閘道器。
    • Container--容器。
    • Boundary event--邊界事件。
    • Intermediate event--中間事件。
  • 流程圖設計完畢儲存生成.bpmn檔案。

  • 本人此時使用的IDEA版本是2020.2,而IDEA中的Activiti設計器外掛actiBPM到此時位置已停止更新了。

  • 本人只能使用Eclipse畫流程圖。
    • Eclipse需要安裝Activiti外掛,略。

繪製流程

指定流程定義key

  • 流程定義key即流程定義的標識。

建議:相同的業務流程,流程定義的key名字定義一樣。如果需要建立新的業務流程,則使用新的key。

指定任務負責人

  • 為每個任務結點指定負責人,如新增請假單的負責人是張三。

部署流程定義

  • 將剛才生成的holiday.bpmn和holiday.png拷貝到專案的resources目錄下。

  • 示例:使用RepositoryService部署流程定義
package com.sunxiaping;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.junit.Test;

/**
 * @author <a href="mailto:[email protected]">weiwei.xu</a>
 * @version 1.0
 * 2020-07-31 11:55
 */
public class ActivitiDeploymentTest {

    /**
     * 部署流程定義:將下面程式碼中指定的bpmn檔案和png檔案儲存到Activiti資料庫中
     *
     * act_re_deployment 部署資訊
     * act_re_procdef 流程定義的一些資訊
     * act_ge_bytearray 流程定義bpmn檔案和png檔案
     */
    @Test
    public void test() {
        //建立ProcessEngineConfiguration物件
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //獲取RepositoryService物件
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //進行部署
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("diagram/holiday.bpmn") //新增bpmn資源
                .addClasspathResource("diagram/holiday.png")
                .name("請假申請流程")
                .deploy(); //部署
        //輸出部署的一些資訊
        String id = deployment.getId();
        System.out.println("流程部署id = " + id);
        String name = deployment.getName();
        System.out.println("流程部署名稱 = " + name);
    }

}

啟動一個流程例項

  • 流程定義部署在Activiti中之後就可以通過工作流管理業務流程了。
  • 針對該流程,啟動一個流程表示發起一個新的請假申請單,這就相當於Java類和Java物件的關係,類定義好之後需要new建立一個物件使用,當然,也可以new多個物件。
  • 對於請假申請流程,張三發起一個請假申請單需要啟動一個流程例項,李四發起一個請求申請單也需要啟動一個流程例項。

關係:

​ 流程定義(BPMN檔案)-->流程部署(Activiti的三張表)。

​ 流程例項-->啟動流程例項。

類比:

​ 流程定義類似於Java中的類,流程例項類似於Java中的一個例項(物件),所以一個流程定義key對應多個不同的流程例項。

  • 示例:
package com.sunxiaping;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.Test;

/**
 * @author <a href="mailto:[email protected]">weiwei.xu</a>
 * @version 1.0
 * 2020-08-01 14:35
 */
public class ActivitiStartProcessInstanceTest {

    /**
     * act_hi_actinst 活動例項
     * act_hi_identitylink 參與者資訊
     * act_hi_procinst 流程例項
     * act_hi_taskinst 任務例項
     * act_ru_execution 執行表
     * act_ru_identitylink 參與者資訊
     * act_ru_task   任務表
     */
    @Test
    public void test() {
        //建立ProcessEngineConfiguration物件
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //獲取RuntimeService物件
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //根據流程定義的key啟動流程例項
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday");
        //獲取流程例項的相關資訊
        String processDefinitionId = processInstance.getProcessDefinitionId();
        System.out.println("流程定義的id = " + processDefinitionId);
        String deploymentId = processInstance.getDeploymentId();
        System.out.println("流程部署的id = " + deploymentId);
        String id = processInstance.getId();
        System.out.println("流程例項的id = " + id);
        String activityId = processInstance.getActivityId();
        System.out.println("當前活動的id = " + activityId);

    }
}

任務查詢

  • 流程啟動後,各個任務的負責人就可以查詢自己當前需要處理的任務,查詢出來的任務都是該使用者的待辦任務。

  • 示例:

package com.sunxiaping;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.junit.Test;

import java.util.List;

/**
 * @author <a href="mailto:[email protected]">weiwei.xu</a>
 * @version 1.0
 * 2020-08-01 15:00
 */
public class ActivitiTaskTest {

    /**
     * act_ru_task
     */
    @Test
    public void test() {
        //任務負責人
        String assignee = "張三";
        //建立ProcessEngineConfiguration物件
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //獲取TaskService物件
        TaskService taskService = processEngine.getTaskService();
        //查詢任務列表,根據流程定義的key和任務負責人
        List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("holiday").taskAssignee(assignee).list();
        //遍歷任務列表
        for (Task task : taskList) {
            String processDefinitionId = task.getProcessDefinitionId();
            System.out.println("流程定義id = " + processDefinitionId);
            String processInstanceId = task.getProcessInstanceId();
            System.out.println("流程例項id = " + processInstanceId);
            String assignee1 = task.getAssignee();
            System.out.println("任務負責人 = " + assignee1);
            String id = task.getId();
            System.out.println("任務id = " + id);
            String name = task.getName();
            System.out.println("任務名稱 = " + name);
        }
    }
}

任務處理

  • 任務負責人查詢待辦任務,選擇任務進行處理,完成任務。

  • 示例:

package com.sunxiaping;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.junit.Test;

import java.util.List;

/**
 * @author <a href="mailto:[email protected]">weiwei.xu</a>
 * @version 1.0
 * 2020-08-01 15:20
 */
public class ActivitiTaskCompleteTest {

    /**
     * act_hi_actinst 活動例項
     * act_hi_identitylink 參與者資訊
     * act_hi_taskinst 任務例項
     * act_ru_execution 執行表
     * act_ru_identitylink 參與者資訊
     * act_ru_task 任務表
     */
    @Test
    public void test() {
        //任務負責人
        String assignee = "張三";
        //建立ProcessEngineConfiguration物件
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //獲取TaskService物件
        TaskService taskService = processEngine.getTaskService();
        //查詢任務列表,根據流程定義的key和任務負責人
        List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("holiday").taskAssignee(assignee).list();
        //遍歷任務列表
        for (Task task : taskList) {
            String id = task.getId();
            //完成任務
            taskService.complete(id);
        }
    }

}

流程定義

流程定義概述

什麼是流程定義?

  • 流程定義是按照BPMN2.0標準去描述業務流程,通常使用Activiti-explorer(Activiti控制檯)或Activiti-eclipse-designer(Activiti的eclipse設計器)外掛對業務流程進行建模,這兩種方式都遵循BPMN2.0標準。
  • 如果使用Activiti-eclipse-designer外掛完成業務流程建模。可以生成兩個檔案:.bpmn和.png檔案。

.bpmn檔案

  • .bpmn檔案其實就是XML檔案。
<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">
  <process id="holiday" name="請假申請流程" isExecutable="true">
    <startEvent id="startevent2" name="開始"/>
    <userTask id="usertask1" name="填寫請假申請單" activiti:assignee="張三"/>
    <sequenceFlow id="flow1" sourceRef="startevent2" targetRef="usertask1"/>
    <userTask id="usertask2" name="部門經理審批" activiti:assignee="李四"/>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"/>
    <userTask id="usertask3" name="總經理審批" activiti:assignee="王五"/>
    <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"/>
    <endEvent id="endevent1" name="結束"/>
    <sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1"/>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_holiday">
    <bpmndi:BPMNPlane bpmnElement="holiday" id="BPMNPlane_holiday">
      <bpmndi:BPMNShape bpmnElement="startevent2" id="BPMNShape_startevent2">
        <omgdc:Bounds height="35.0" width="35.0" x="100.0" y="160.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
        <omgdc:Bounds height="55.0" width="105.0" x="180.0" y="150.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
        <omgdc:Bounds height="55.0" width="105.0" x="330.0" y="150.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
        <omgdc:Bounds height="55.0" width="105.0" x="480.0" y="150.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="630.0" y="160.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="135.0" y="177.0"/>
        <omgdi:waypoint x="180.0" y="177.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="285.0" y="177.0"/>
        <omgdi:waypoint x="330.0" y="177.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
        <omgdi:waypoint x="435.0" y="177.0"/>
        <omgdi:waypoint x="480.0" y="177.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
        <omgdi:waypoint x="585.0" y="177.0"/>
        <omgdi:waypoint x="630.0" y="177.0"/>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>
  • .bpmn檔案的根節點是definitions節點。這個元素中,可以定義多個流程定義(建議每個檔案只包含一個流程定義,可以簡化開發過程中的維護難度)。注意,definitions元素最少也要包含xmlns和targetNamespace的宣告。targetNamespace可以是任何值,它用來對流程例項進行分類。
  • 流程定義部分:定義了流程每個結點的描述和結點之間的流程流轉。
  • 流程佈局定義:定義流程每個結點在流程圖上的位置座標等資訊。

.png圖片檔案

  • 如果是在Eclipse中,需要進行如下的配置:

流程定義部署

什麼是流程定義部署

  • 將生成的流程定義部署到Activiti的資料庫中,這就是流程定義部署,通過呼叫Activiti的API將流程定義的bpmn和png兩個檔案一個一個新增部署到Activiti中,也可以將兩個檔案打成zip包進行部署。

單個檔案部署方式

  • 分別將bpmn檔案和png圖片檔案部署。

  • 示例:

package com.sunxiaping;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.junit.Test;

/**
 * @author <a href="mailto:[email protected]">weiwei.xu</a>
 * @version 1.0
 * 2020-07-31 11:55
 */
public class ActivitiDeploymentTest {

    /**
     * 部署流程定義:將下面程式碼中指定的bpmn檔案和png檔案儲存到Activiti資料庫中
     *
     * act_re_deployment 部署資訊
     * act_re_procdef 流程定義的一些資訊
     * act_ge_bytearray 流程定義bpmn檔案和png檔案
     */
    @Test
    public void test() {
        //建立ProcessEngineConfiguration物件
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //獲取RepositoryService物件
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //進行部署
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("diagram/holiday.bpmn") //新增bpmn資源
                .addClasspathResource("diagram/holiday.png")
                .name("請假申請流程")
                .deploy(); //部署
        //輸出部署的一些資訊
        String id = deployment.getId();
        System.out.println("流程部署id = " + id);
        String name = deployment.getName();
        System.out.println("流程部署名稱 = " + name);
    }
}

壓縮包部署方式

  • 將.bpmn檔案和.png圖片壓縮成一個zip包。

  • 示例:
package com.sunxiaping;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.junit.Test;

import java.io.InputStream;
import java.util.zip.ZipInputStream;

/**
 * @author <a href="mailto:[email protected]">weiwei.xu</a>
 * @version 1.0
 * 2020-07-31 11:55
 */
public class ActivitiZipDeploymentTest {

    /**
     * 部署流程定義:將下面程式碼中指定的bpmn檔案和png檔案儲存到Activiti資料庫中
     *
     * act_re_deployment 部署資訊
     * act_re_procdef 流程定義的一些資訊
     * act_ge_bytearray 流程定義bpmn檔案和png檔案
     */
    @Test
    public void test() {
        //建立ProcessEngineConfiguration物件
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //獲取RepositoryService物件
        RepositoryService repositoryService = processEngine.getRepositoryService();

        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("diagram/holiday.zip");

        ZipInputStream zipInputStream = new ZipInputStream(inputStream);

        //進行部署
        Deployment deployment = repositoryService.createDeployment()
                .addZipInputStream(zipInputStream)
                .name("請假申請流程")
                .deploy(); //部署
        //輸出部署的一些資訊
        String id = deployment.getId();
        System.out.println("流程部署id = " + id);
        String name = deployment.getName();
        System.out.println("流程部署名稱 = " + name);
    }
}

操作資料表

  • 流程定義部署後,會操作三張表:act_re_deploymentact_re_procdefact_ge_bytearray
  • act_re_deployment是流程定義部署表,記錄流程部署資訊。
  • act_re_procdef是流程定義表,記錄流程定義資訊。
  • act_ge_bytearray是資源表,將.bpmn檔案和.png圖片存入到這個表。

說明:

  • act_re_deploymentact_re_procdef是一對多的關係,一次部署在流程部署表生成一條記錄,但一次流程部署可以部署多個流程定義,每個流程定義在流程定義表生成一條記錄。每一個流程定義在act_ge_bytearray會存在兩個資源記錄.bpmn檔案和.png圖片。

建議:

  • 一次部署一個流程,這樣部署表和流程定義表示一對一的關係,方便讀取流程部署和流程定義資訊。

流程定義查詢

  • 示例:
package com.sunxiaping;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.junit.Test;

import java.util.List;

/**
 * @author <a href="mailto:[email protected]">weiwei.xu</a>
 * @version 1.0
 * 2020-08-01 21:24
 */
public class ActivitiProcessDefinitionQueryTest {

    /**
     * 查詢流程定義資訊
     */
    @Test
    public void test() {
        //建立ProcessEngineConfiguration物件
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //獲取RepositoryService物件
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //得到ProcessDefinitionQuery物件
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        //設定條件,並查詢出當前的所有流程定義
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.processDefinitionKey("holiday")
                .orderByProcessDefinitionVersion()
                .desc()
                .list();
        //輸出流程定義資訊
        for (ProcessDefinition processDefinition : processDefinitionList) {
            System.out.println("流程定義的id = " + processDefinition.getId());
            System.out.println("流程定義的name = " + processDefinition.getName());
            System.out.println("流程定義的key = " + processDefinition.getKey());
            System.out.println("流程定義的version = " + processDefinition.getVersion());
        }
    }
}

流程定義刪除

  • 示例:
package com.sunxiaping;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.junit.Test;

/**
 * @author <a href="mailto:[email protected]">weiwei.xu</a>
 * @version 1.0
 * 2020-08-01 21:13
 */
public class ActivitiDeleteProcessDefinitionTest {

    /**
     * 刪除已經部署的流程定義
     *
     * 注意事項:
     *  ①當我們正在執行的這一套流程沒有結束,此時如果要刪除流程定義資訊就會失敗(呼叫void deleteDeployment(String deploymentId)方法)。
     *  ②當我們正在執行的這一套流程沒有結束,此時如果要強制刪除流程定義資訊,需要呼叫void deleteDeployment(String deploymentId, boolean cascade)這個方式,將cascade設定為true。
     */
    @Test
    public void test() {
        //建立ProcessEngineConfiguration物件
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //獲取RepositoryService物件
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //刪除已經部署的流程定義
        String deploymentId = "1";
        repositoryService.deleteDeployment(deploymentId);
    }
}

流程定義資源查詢

  • 示例:通過查詢流程定義物件獲取流程定義資源,即bpmn和png
package com.sunxiaping;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.junit.Test;
import org.springframework.util.FileCopyUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @author <a href="mailto:[email protected]">weiwei.xu</a>
 * @version 1.0
 * 2020-08-02 10:22
 */
public class ActivitiResourceTest {

    @Test
    public void test() throws IOException {
        //建立ProcessEngineConfiguration物件
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //獲取RepositoryService物件
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //獲取ProcessDefinitionQuery物件
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        //設定查詢條件,執行查詢操作
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.processDefinitionKey("holiday").orderByProcessDefinitionVersion().desc().list();
        //遍歷查詢結果
        for (ProcessDefinition processDefinition : processDefinitionList) {
            //獲取資源名稱,即png圖片的名稱
            String resourceName = processDefinition.getResourceName();
            //獲取圖表資源,即bpmn圖片的名稱
            String diagramResourceName = processDefinition.getDiagramResourceName();
            //獲取資源的輸入流,即png圖片的輸入流
            InputStream resourceNameInputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
            InputStream diagramResourceNameInputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), diagramResourceName);

            String resourcePath = "d:" + File.separator + resourceName;
            File file = new File(resourcePath);
            if (!file.exists()) {
                file.getParentFile().mkdirs();
            }

            String diagramResourcePath = "d:" + File.separator + diagramResourceName;
            file = new File(diagramResourcePath);
            if (!file.exists()) {
                file.getParentFile().mkdirs();
            }

            //複製檔案
            FileCopyUtils.copy(resourceNameInputStream, new FileOutputStream(resourcePath));
            FileCopyUtils.copy(diagramResourceNameInputStream, new FileOutputStream(diagramResourcePath));
        }
    }
}

流程歷史資訊查詢

  • 示例:
package com.sunxiaping;

import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.junit.Test;

import java.util.List;

/**
 * @author <a href="mailto:[email protected]">weiwei.xu</a>
 * @version 1.0
 * 2020-08-01 21:13
 */
public class ActivitiHistoryTest {

    @Test
    public void test() {
        //建立ProcessEngineConfiguration物件
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti-cfg.xml");
        //獲取ProcessEngine物件
        ProcessEngine processEngine = configuration.buildProcessEngine();
        //獲取HistoryService物件
        HistoryService historyService = processEngine.getHistoryService();
        //獲取HistoricActivityInstanceQuery查詢物件
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
        List<HistoricActivityInstance> historicActivityInstanceList = historicActivityInstanceQuery.list();
        for (HistoricActivityInstance historicActivityInstance : historicActivityInstanceList) {
            String activityId = historicActivityInstance.getActivityId();
            System.out.println("activityId = " + activityId);
            String activityName = historicActivityInstance.getActivityName();
            System.out.println("activityName = " + activityName);
            String processDefinitionId = historicActivityInstance.getProcessDefinitionId();
            System.out.println("processDefinitionId = " + processDefinitionId);
            String processInstanceId = historicActivityInstance.getProcessInstanceId();
            System.out.println("processInstanceId = " + processInstanceId);
        }

    }
}