Activiti 6.0 概述與 Hello World 快速入門 與 核心 API 概述

目錄

Activiti 概述 與 下載

Activiti Hello World

安裝流程設計器插件

繪製工作流程圖

IDEA 編碼實現工作流

Activiti 核心 API 預覽


Activiti 概述 與 下載

1、工作流(Workflow):是對工作流程及其各個操作步驟之間業務規則的抽象、概況和描述。

2、工作流模型:將工作流程中的工作如何前後組織在一起的邏輯和規則,在計算機中以恰當的模型表達並對其實施計算。

3、工作流要解決的問題是實現某個業務目標、利用計算機在多個參與者之間按某種預定規則自動傳遞文檔、信息或者任務。

4、主流的工作流框架:Activiti、OSWorkflow、JBoss 的 JBPM、Apache 的 ofBiz 等。生活中有很多的流程管理,比如請假流程、報銷流程、審批流程等等。

5、Activiti 歷史:JBPM 4 的時候團隊內部發生分歧,其中部分開發人員脫離了大部隊(JBoss),出來獨立寫出了 Activiti5;JBoss 則繼續 JBPM 的開發,後續又有了 JBPM 5 ...。

6、所以 Activiti 5 基本等同於 JBPM4,2016 年 11 月開源了 Activiti 5.22.0,2017 年 5 月開源了 Activiti 6.0.0,2018 年開始開源 Activiti 7.X。Activiti 7 分爲了 Activiti Core 與 Activiti Cloud 兩個方向,更傾向於雲環境、微服務。

7、Activiti 易於與 Spring、Spring boot、Spring cloud 集成,BPM 全稱 Business Process Management - 業務流程管理

8、Activiti 支持主流的數據庫(官方文檔):

Activiti database type Example JDBC URL Notes

h2

jdbc:h2:tcp://localhost/activiti

Default configured database

mysql

jdbc:mysql://localhost:3306/activiti?autoReconnect=true

Tested using mysql-connector-java database driver

oracle

jdbc:oracle:thin:@localhost:1521:xe

 

postgres

jdbc:postgresql://localhost:5432/activiti

 

db2

jdbc:db2://localhost:50000/activiti

 

mssql

jdbc:sqlserver://localhost:1433;databaseName=activiti (jdbc.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver) OR jdbc:jtds:sqlserver://localhost:1433/activiti (jdbc.driver=net.sourceforge.jtds.jdbc.Driver)

Tested using Microsoft JDBC Driver 4.0 (sqljdbc4.jar) and JTDS Driver

Activiti 官網:https://www.activiti.org

Activiti Github 開源地址:https://github.com/Activiti/Activiti

Activiti v7.X 官方開發手冊:https://activiti.gitbook.io/activiti-7-developers-guide/

Activiti v6.X 官方開發手冊:https://www.activiti.org/userguide/

Activiti v5.X 官方開始手冊:https://www.activiti.org/5.x/userguide/

9、maven 依賴:非 Spring Boot 項目,使用 activiti-engine 即可,否則推薦使用 activiti-spring-boot-starter-basic,activiti 與 spring boot 集成的啓動器,裏面包含了 activiti-engine 引擎,以及 activiti 與 spring 的集成,以及 jdbc 等。

        <!-- https://mvnrepository.com/artifact/org.activiti/activiti-engine -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-engine</artifactId>
            <version>6.0.0</version>
        </dependency>
        <!--activiti 官網地址:https://www.activiti.org/userguide/#_getting_started_2-->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter-basic</artifactId>
            <version>6.0.0</version>
        </dependency>

Activiti Hello World

1、千里之行,始於足下。學習一個新框架得先有一個 Hello World 壓壓驚,否則會很迷茫。

2、本文環境:Java JDK 1.8 + IDEA 2018 +Maven 3.1.6 + Activiti 6.0.0 + H2 Database + Spring Boot 2.1.4 進行開發。

1)使用 Maven 管理,不再去 Activiti 官網下載 jar 包,然後導入到項目中

2)暫時使用 H2 內存數據庫,讓 Activiti 的表和數據先直接在內存數據庫中使用。

3、特別提醒

1)Acticiti 工作流開發,第一步是需要繪製工作流程圖(本文開頭的那種圖),第二步就是編碼。

2)下載 Acticiti 6.0.0 開發包或者源碼可以看到,裏面提供了針對各種數據庫的 sql 文件,然後實際中並不需要手動去執行這些 sql 腳本,因爲在後臺代碼中構建流程引擎(ProcessEngine)的時候,它可以自動執行 sql 建表腳本創建好 28 張表

3)Activiti 6.0.0  有 28 張表,使用 Activiti API 操作工作流的時候,Activiti 會自動操作自己的數據庫表。所以對於 activiti 的 28 張數據庫表,前期並不需要關心,對我們來說是透明的,入門之後可以再去深入瞭解。

安裝流程設計器插件

官網介紹地址:https://www.activiti.org/userguide/#eclipseDesignerInstallation

1、eclipse、sts、idea 都有繪製 activiti 流程圖的插件,但官方文檔介紹的是 eclipse(sts本質也是eclipse),所以這裏也採用 在 sts 上安裝流程圖插件。(注:在 sts 插件上繪製好流程圖後,本人更喜歡 IDEA 編碼,所以後續只需要將 sts 中創建好的 .bpmn 文件拷貝過去即可)

1、這裏選擇在線安裝插件 activiti 插件,打開 help -> Install New Software 安裝新的軟件(插件),在 Install 面板中,點擊 Add 按鈕添加插件名稱與地址:

Name: Activiti BPMN designer (名稱可以隨意取)
Location: http://activiti.org/designer/update/

2、點擊 "Next" 下一步,然後會聯網進行下載,之後在 "Install Detail" 面板直接 "Next",然後進入 "Review license" 查看許可證面板,點擊第一項 "I accept ..." 同意,最後點擊 "Finish" 完成安裝。

3、安裝過程中可能會彈框提示,選擇安裝所有即可,然後會提示重啓,重啓之後可以點擊菜單 "Window -> Show View -> Other..." 看到 activiti 插件:

4、設置保存 bpmn 流程圖時,同時保存一張同名的 .png 圖片:

繪製工作流程圖

1、安裝好插件之後就可以開始繪製工作流程圖了,隨便在某個目錄上右鍵,然後 "New -> Other...-> Activiti -> Activiti Diagram" 創建 Activiti 流程圖:

2、基本工作流程圖繪製並不難,從右側的選項中拖到到中間即可,開始的黑色圓圈爲開始事件,User Task 表示用戶任務,帶黑色叉的矩形爲排它網關(用於條件判斷),末尾的粗黑線圓圈爲結束事件,箭頭線表示順序流。

3、排它網關用於條件判斷,比如同意則繼續往後走、不同意則重新返回,在網關上選擇箭頭按住拖到目標按鈕上即可。

4、在空白處點擊,爲整個流程設置 id 與 name,在每個按鈕上點擊,爲他們設置 id 與 name 值,這些值將來都是 .bpmn 文件中的屬性值,代碼中會操作它們,它們也會被自動處理到數據庫中。

5、爲3個用戶任務設置 form 表單參數,即此任務執行需要的參數,因爲操作比較長,無法全部做成動圖,所以只演示添加1個屬性。type 表示參數類型,required 表示參數是否必須要填。

6、用戶任務設置的參數表示工作流中用戶提供的參數,而這些參數需要在排它網關中進行判斷,比如主管審批結果輸入爲 y 時才能繼續往後走,否則輸入 n 時,則應該重新回到 "填寫審批信息"。當排它網關未作任何限制時,則主管和人事無論輸入什麼,都會繼續往後走,顯然這不滿足我們的需求,則此時應該設置排它網關的條件,它類似 EL 表達式的寫法 ${條件判斷} ,|| 表示或,&& 表示與,條件判斷的值是上一個用戶任務中的 form 表單參數。

7、至此工作流程圖繪製完畢,第一次可能比較難理解,但是多畫幾次,然後結合後面的代碼,則容易理解。

注意:這個流程圖(.bpmn文件)本質就是一個 .xml 文件,可以用記事本、或者瀏覽器等打開就可以看出來,後面會提供完整的文件,所以即使沒畫出來,也沒關係,並不影響後面的代碼運行。

IDEA 編碼實現工作流

1、因爲本人習慣使用 IDEA,所以在 IDEA 中新建一個 Maven 項目,Java SE 應用,直接在 main 方法中進行簡單使用。

2、將 sts 中插件繪製好的流程文件 .bpmn 拷貝到 IDEA 項目的類路徑下,當然直接使用 sts 、eclipse 開發也是一樣的。

3、pom.xml 文件內容如下。

spring-boot-starter-parent 與 spring-boot-maven-plugin 是方便 maven 項目打包的,可選

slf4j-api 與 slf4j-log4j12 用於做日誌框架,可選

activiti-spring-boot-starter-basic:activiti 與 spring boot 集成的啓動器,裏面包含了 activiti-engine 引擎,以及 activiti 與 spring 的集成,以及 jdbc 。必選,

h2 是內存數據庫,必須使用一個數據庫,當然可以換成其它數據庫。

guava 方便做集合、字符串等操作,可選

junit 方便做單元測試,可選

<?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 http://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.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>wmx.com</groupId>
    <artifactId>activiti-first</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>

        <!--https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.activiti/activiti-engine -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-engine</artifactId>
            <version>6.0.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.183</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>27.0-jre</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

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

4、只建了一個 MainApp.java 文件操作工作流,編碼分爲 4 步:1)創建流程引擎 -> 2)部署流程定義文件 -> 3)啓動運行流程、4)處理流程任務。內容如下:

import com.google.common.collect.Maps;
import org.activiti.engine.*;
import org.activiti.engine.form.FormProperty;
import org.activiti.engine.form.TaskFormData;
import org.activiti.engine.impl.form.DateFormType;
import org.activiti.engine.impl.form.StringFormType;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
public class MainApp {
    private static Logger LOGGER = LoggerFactory.getLogger(MainApp.class);
    public static void main(String[] args) throws ParseException {
        LOGGER.info(" App start...");

        //1、創建流程引擎
        ProcessEngine processEngine = getProcessEngine();
        //2、部署流程定義文件
        ProcessDefinition processDefinition = getProcessDefinition(processEngine);
        //3、啓動運行流程
        ProcessInstance processInstance = getProcessInstance(processEngine, processDefinition.getId());
        //4、處理流程任務
        handlingTasks(processEngine, processInstance);
        LOGGER.info(" App quit...");
    }

    /**
     * 處理流程任務
     *
     * @param processEngine
     * @param processInstance
     * @throws ParseException
     */
    private static void handlingTasks(ProcessEngine processEngine, ProcessInstance processInstance) throws ParseException {
        Scanner scanner = new Scanner(System.in);//從控制檯手動輸入數據
        while (processInstance != null && !processInstance.isEnded()) {
            TaskService taskService = processEngine.getTaskService();//獲取任務服務
            List<Task> taskList = taskService.createTaskQuery().list();
            for (Task task : taskList) {
                LOGGER.info("當前待處理任務id [{}],任務名稱 [{}]", task.getId(), task.getName());
                Map<String, Object> dataMap = getStringObjectMap(processEngine, scanner, task);
                taskService.complete(task.getId(), dataMap);//提交任務/完成任務
                //重新獲取流程實例
                processInstance = processEngine.getRuntimeService()
                        .createProcessInstanceQuery()
                        .processInstanceId(processInstance.getId())
                        .singleResult();
            }
        }
        scanner.close();
    }

    /**
     * 設置當前任務的表單參數。從控制檯輸入
     *
     * @param processEngine
     * @param scanner
     * @param task
     * @return
     * @throws ParseException
     */
    private static Map<String, Object> getStringObjectMap(ProcessEngine processEngine, Scanner scanner, Task task) throws ParseException {
        FormService formService = processEngine.getFormService();//表單服務
        TaskFormData taskFormData = formService.getTaskFormData(task.getId());//根據任務id獲取任務表單數據對象
        List<FormProperty> formPropertyList = taskFormData.getFormProperties();//獲取表單屬性
        Map<String, Object> dataMap = Maps.newHashMap();
        for (FormProperty formProperty : formPropertyList) {
            String line = null;
            if (StringFormType.class.isInstance(formProperty.getType())) {
                LOGGER.info("請輸入 {}", formProperty.getName());
                line = scanner.nextLine();
                dataMap.put(formProperty.getId(), line);
            } else if (DateFormType.class.isInstance(formProperty.getType())) {
                LOGGER.info("請輸入 {}", formProperty.getName());
                line = scanner.nextLine();
                dataMap.put(formProperty.getId(), DateUtils.parseDate(line, "yyyy-MM-dd HH:mm:ss"));
            } else {
                LOGGER.warn("暫時不支持此類型 [{}]", formProperty.getType());
            }
            LOGGER.info("您成功輸入 [{}]", line);
        }
        return dataMap;
    }

    /**
     * 啓動運行流程
     *
     * @param processEngine
     * @param processDefinitionId
     */
    private static ProcessInstance getProcessInstance(ProcessEngine processEngine, String processDefinitionId) {
        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId);
        String processDefinitionKey_ = processInstance.getProcessDefinitionKey();
        LOGGER.info("啓動流程,流程key [{}] ", processDefinitionKey_);//輸出:啓動流程,流程key [approvalFor2Level]
        return processInstance;
    }

    /**
     * 部署流程定義文件
     *
     * @param processEngine
     * @return
     */
    private static ProcessDefinition getProcessDefinition(ProcessEngine processEngine) {
        RepositoryService repositoryService = processEngine.getRepositoryService();//獲取存儲服務
        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();//創建部署構建器
        //通過類路徑下的 .bpmn 文件進行構建。.bpmn 文件的本質其實就是一個定義好的 .xml 文件
        deploymentBuilder.addClasspathResource("approvalFor2Level.bpmn");
        //部署流程定義文件。此時 Activiti 會自動將 .bpmn 中的數據添加到數據庫中,以備後續數據庫操作
        Deployment deployment = deploymentBuilder.deploy();
        String deploymentId = deployment.getId();
        String deploymentKey = deployment.getKey();
        String deploymentName = deployment.getName();
        Date deploymentTime = deployment.getDeploymentTime();

        //輸出:部署id [1],部署key [null],部署名稱 [null],部署時間 [Wed Jul 24 09:40:00 CST 2019]
        LOGGER.info("部署id [{}],部署key [{}],部署名稱 [{}],部署時間 [{}]", deploymentId, deploymentKey, deploymentName, deploymentTime);

        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploymentId)
                .singleResult();
        String processDefinitionName = processDefinition.getName();
        String processDefinitionId = processDefinition.getId();
        String processDefinitionKey = processDefinition.getKey();
        //輸出:流程定義文件名 [二級審批流程],流程id [approvalFor2Level:1:4],流程key [approvalFor2Level]
        LOGGER.info("流程定義文件名 [{}],流程id [{}],流程key [{}]", processDefinitionName, processDefinitionId, processDefinitionKey);
        return processDefinition;
    }

    /**
     * 創建流程引擎
     *
     * @return
     */
    private static ProcessEngine getProcessEngine() {
        //StandaloneInMemProcessEngineConfiguration:標準的基於內存數據庫的流程引擎配置.
        ProcessEngineConfiguration pecfg = ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration();
        //buildProcessEngine:通過流程引擎配置構建流程引擎,此時會自動創建 activiti 的 28 張表
        ProcessEngine processEngine = pecfg.buildProcessEngine();
        String name = processEngine.getName();
        String version = ProcessEngine.VERSION;
        LOGGER.info("流程引擎名稱 [{}],版本 [{}]", name, version);//輸出:流程引擎名稱 [default],版本 [6.0.0.4]
        return processEngine;
    }
}

5、整個項目源碼:https://github.com/wangmaoxiong/activitiFirst,核心就是 pom.xml 文件、MainApp.java、approvalFor2Level.bpmn 流程文件、log4j.properties 日誌文件。

1)上面的 hello World 要想成功運行,之前繪製好的 .bpmn 文件是必不可少的,因爲內容較長,所以不再這裏粘貼,從這裏獲取:https://github.com/wangmaoxiong/activitiFirst/tree/master/src/main/resources

2)其中可以修改 log4j.properties 的日誌輸出級別爲 DEBUG log4j.rootLogger=DEBUG ,console,logFile,就會發現應用啓動到結束,它在不停的操作數據庫,做 sql 操作。

6、因爲使用的是 StandaloneInMemProcessEngineConfiguration 流程引擎配置,它的源碼如下,顯然它默認使用的是 h2 內存數據庫,create-drop 表示應用啓動時自動建表,應用關閉時自動刪除,數據不會持久化到磁盤。

public class StandaloneInMemProcessEngineConfiguration extends StandaloneProcessEngineConfiguration {
    public StandaloneInMemProcessEngineConfiguration() {
        this.databaseSchemaUpdate = "create-drop";
        this.jdbcUrl = "jdbc:h2:mem:activiti";
    }
}

7、啓動應用,測試如下:

上面只是測試了正常情況下,全部通過的情景,也可以放棄提交,主管或者人事輸入 n 拒絕通過等否則情況都是沒問題的

Activiti 核心 API 預覽

 

1、ProcessEngine:流程引擎,這是最重要的 API,通過它可以獲取其它的 API。

2、RepositoryService:流程存儲服務,管理流程定義文件 xm 及靜態資源的服務,對特定流程的暫停和激活,流程定義啓動權限管理。

3、RuntimeService:流程運行服務,用於對流程運行過程的控制,如啓動流程實例、暫停、掛起、繼續等

4、TaskService:流程任務服務,用於對人工任務的管理(如增刪改查),設置操作權限。

5、HistoryService:歷史記錄相關服務接口。

6、FormService:表單服務。

7、IdentityService:身份服務,提供對流程角色數據進行管理的 API,這些角色數據包括用戶組、用戶及它們之間的關係。

8、ManagementService:提供對流程引擎進行管理和維護的服務。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章