Activiti Exploer工作流控制檯使用指南!使用Activiti Explorer定義部署執行工作流

攻城獅Chova 發表於 2021-06-10

Activiti Exploer工作流控制檯使用指南!使用Activiti Explorer定義部署執行工作流

Activiti Explorer簡介

  • Activiti Explorer: Activiti控制檯,是一個web應用程式
  • 從Activiti的官方網站下載Activiti的壓縮zip檔案時,Activiti控制檯在 ${Activiti_home}/wars資料夾下面
  • 該控制檯的目的並不是建立一個完善的web應用程式,僅僅是為客戶端使用者準備的應用程式.對於該控制檯,使用了一個記憶體資料庫,也可以換成自定義的資料庫(檢視WEB-INF資料夾下面的applicationContext.xml檔案)
  • 登入控制檯,有四個主要功能模組:
    • Tasks: 任務管理功能
      • 如果是任務執行人,可以看見執行中流程例項的待辦任務,也可以拾取組任務
      • 控制檯涉及的功能有子任務的工作,不同角色的人...
      • 控制檯允許建立一個獨立的任務,該任務不需要關聯任何流程例項
    • Processes: 顯示部署的流程定義列表,並且可以啟動一個新的流程例項
    • Reports: 生成報表和顯示之前儲存歷史的結果資料
    • Manage: 用於管理Activiti的流程引擎
      • 管理使用者和組
      • 執行和檢視停止的jobs
      • 檢視資料庫和部署新的流程定義
      • 登入的使用者具有超級管理員許可權才會顯示

流程圖

  • 控制檯包含的功能,使用RaphaëlJavascript框架自動生成一張流程圖:
    • 當流程定義XML包含的BPMN注入資訊時,該流程圖才能夠生成
    • 當流程定義XML中並沒有BPMN注入資訊,但是部署的時候包含一張流程圖,那麼該圖片也將會被顯示
      -
  • 如果不想使用Javascript生成流程圖,可以在ui.properties檔案禁用
activiti.ui.jsdiagram = false
  • 控制檯上顯示流程圖,也可以對流程圖進行檢視,根據流程定義的ID,顯示流程定義圖片:
http://localhost:8080/activiti-explorer/diagram-viewer/index.html?processDefinitionId=reviewSaledLead:1:36
  • 通過processInstanceId的請求引數,可以顯示當前流程例項的狀態:
http://localhost:8080/activiti-explorer/diagram-viewer/index.html?processDefinitionId=reviewSaledLead:1:36&processInstanceId=41

Tasks

  • 任務
    在這裡插入圖片描述
  • Inbox: 顯示登入使用者需要辦理的所有任務列表
  • My Tasks: 顯示登入使用者任務擁有者的任務列表:
    • 當建立一個獨立的任務時,可以自動化操作該任務
  • Queued: 顯示不用的組任務列表,並且登入使用者在該組中:
    • 這裡的所有任務都必須先拾取,然後才能夠完成
  • Involved: 顯示登入使用者被參與的任務,即不是執行人和任務擁有者
  • Archived: 歸檔,包含已經完成歷史任務

Processes

Deployed process definitions(部署流程定義)

  • 在流程定義選項卡中,允許檢視Activiti流程引擎部署的所有流程定義
  • 可以使用頁面頂部右邊的按鈕啟動一個新的流程例項
  • 如果該流程定義有一個啟動表單, 那麼在啟動流程例項之前就會先顯示錶單
    -

My instances(我的流程例項)

  • 顯示當前登入使用者未完成的使用者任務的所有流程例項
  • 直觀地顯示流程例項的當前活動和儲存的流程變數
    -

Manage

  • 在管理功能中,只有當登入使用者是許可權組admin中的成員時,該功能才會顯示
  • 當點選Manage圖示按鈕:

Database

  • Database: 資料庫.顯示Activiti有關內容.當開發流程或者排除故障等問題的時候是非常有用的
    在這裡插入圖片描述

Deployments

  • Deployments: 部署.顯示當前部署的流程引擎,並且可以看到部署的內容:流程定義,流程圖,業務規則,等等...
    -
  • 當點選部署按鈕時,可以上傳新的部署:
    • 從自己的計算機中選擇一個業務文件或者一個BPMN20.XML檔案
    • 簡單的拖拽到指定的區域就可以部署一個新的業務流程
      在這裡插入圖片描述

Jobs

  • Jobs: 作業
    • 在左邊顯示當前的作業(定時器等等)並且執行手動執行(例如在截止時間之前觸發定時器)
    • 如果作業執行失敗(例如郵件伺服器不能正常工作),那麼就會顯示所有的異常
      -

Users

  • Users: 管理使用者
    • 建立,修改和刪除使用者.關聯使用者
    • 獲取許可權檢視任務分配特定使用者資訊在這裡插入圖片描述

Groups

  • Groups: 管理組
    • 建立,修改和刪除組,關聯組
    • 獲取許可權檢視任務分配特定組等資訊

Reports

  • 報表:
    在這裡插入圖片描述
  • 注意: 如果要讓報表工作,控制檯需要配置歷史的級別不能為none.預設的配置是滿足要求的
  • 報表選項卡的子選項卡有2個:
    • 生成報表:
      • 顯示系統中已知的報表列表
      • 允許執行生成的報表
    • 儲存報表:
      • 顯示之前儲存的所有報表列表
      • 僅僅顯示的是個人儲存的報表,並且不能看見其他人儲存的報表
  • 流程的資料被用於生成報表中的列表和圖示.使用流程生成報表資料的優勢:
    • 該流程能夠直接訪問Activiti流程引擎的內部:
      • 直接可以使用流程引擎訪問資料庫
    • 作業執行器能夠用於任何其他的流程:
      • 能夠非同步生成流程
      • 僅僅非同步執行某些步驟
      • 可以使用定時器:在某些時間點上面生成報表資料
    • 可以用已知的工具和已知的概念建立一個新的報表:
      • 沒有新的概念,服務或者應用被需要
      • 部署或者上傳一個新的報表與部署一個新的流程是一樣的
    • 可以使用BPMN2.0結構:
      • 意味著所有的東西:比如並行閘道器,可以實現基於資料或使用者請求輸入生成分支
  • 生成報表資料的流程定義需要把activiti-report設定為分類,這樣就能在Explorer的報表列表中顯示出來。
  • 能夠看到報表的唯一要求是:
    • 流程建立一個名為reportData的流程變數,這個變數必須是json物件的二進位制陣列
    • 變數必須儲存到Activiti的歷史表中,所以要求引擎必須啟用歷史功能
    • 因此可以在後面報表儲存時獲取
      在這裡插入圖片描述

reportData

  • 報表流程必須生成一個變數reportData, 作為展示給使用者的JSON資料:
{
  "title": "My Report",
  "datasets": [
    {
      "type" : "lineChart",
      "description" : "My first chart",
      "xaxis" : "Year"
      "yaxis" : "Total sales"
      "data" :
      {
        "2010" : 50,
        "2011" : 33,
        "2012" : 17,
        "2013" : 87,
      }
    }
  ]
}

json資料會在Explorer中獲取,並用來生成圖表或列表

  • json的元素有:
    • title: 報表的標題
    • datasets: 資料集的陣列,對應報表中不同的圖表和列表
    • type: 資料集的型別. 這個型別會用來決定如何渲染資料,支援的值:
      • pieChart
      • lineChart
      • barChart
      • list
    • description: 每個圖表在報表中顯示一個描述,這個是可選的
    • xaxis: 只對lineChart型別起作用,這個引數是可選的,用來修改圖表座標系x軸的名稱
    • yaxis: 只對lineChart型別起作用,這個引數是可選的,用來修改圖表座標系y軸的名稱
    • data: 實際的資料,資料是一個key:value格式的json物件

流程例項

  • 流程例項總覽報表:
    • 只包含一個指令碼任務:使用javascript生成json資料集
    • 雖然所有Explorer中的例子都使用javascript, 也可以使用java服務任務
    • 執行流程最後的結果就是reportData變數,儲存資料
<?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: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="activiti-report">

    <process id="process-instance-overview-report" name="Process Instance Overview" isExecutable="true">

        <startEvent id="startevent1" name="Start" />
        <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="generateDataset" />

        <scriptTask id="generateDataset" name="Execute script" scriptFormat="JavaScript" activiti:autoStoreVariables="false">
          <script><![CDATA[

               importPackage(java.sql);
               importPackage(java.lang);
               importPackage(org.activiti.explorer.reporting);

               var result = ReportingUtil.executeSelectSqlQuery("SELECT PD.NAME_, PD.VERSION_ , count(*) FROM ACT_HI_PROCINST PI inner join ACT_RE_PROCDEF PD on PI.PROC_DEF_ID_ = PD.ID_ group by PROC_DEF_ID_");

               var reportData = {};
               reportData.datasets = [];

               var dataset = {};
               dataset.type = "pieChart";
               dataset.description = "Process instance overview (" + new java.util.Date() + ")";
               dataset.data = {};

               while (result.next()) { // process results one row at a time
                 var name = result.getString(1);
                 var version = result.getLong(2)
                 var count = result.getLong(3);
                 dataset.data[name + " (v" + version + ")"] = count;
               }
               reportData.datasets.push(dataset);

               execution.setVariable("reportData", new java.lang.String(JSON.stringify(reportData)).getBytes("UTF-8"));
          ]]></script>
        </scriptTask>
        <sequenceFlow id="flow3" sourceRef="generateDataset" targetRef="theEnd" />

        <endEvent id="theEnd" />

    </process>

</definitions>
  • 除了流程xml頂部的標準xml,主要區別是targetNamespace設定為activiti-report,分類設定為與部署的流程定義一樣的名稱
    • 指令碼的第一行是進行一些匯入,避免每次使用時,都要寫包名
    • 第一個有意義的程式碼是使用ReportingUtil讀取activiti資料庫.返回結果是一個JDBC 結果集
    • 查詢語句下面 ,javascript建立了使用的json.json是符合上面描述的需求的
    • 最後一行指令碼,首先需要把json物件轉換成字串,使用javascript函式JSON.stringify(). 字串需要儲存為二進位制陣列型別的變數
      • 這是一個技術問題:
        • 二進位制陣列的大小是無限的,但是字串的長度有限制
        • 這就是為什麼javascript字串必須轉換成一個java字串以獲得轉換成二進位制的功能
  • 原生json功能無法使用,這裡提供了一些幫助類ReportDataDataset:
<?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: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="activiti-report">

    <process id="process-instance-overview-report" name="Process Instance Overview" isExecutable="true">

        <startEvent id="startevent1" name="Start" />
        <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="generateDataset" />

        <scriptTask id="generateDataset" name="Execute script" scriptFormat="js" activiti:autoStoreVariables="false">
          <script><![CDATA[

               importPackage(java.sql);
               importPackage(java.lang);
               importPackage(org.activiti.explorer.reporting);

               var result = ReportingUtil.executeSelectSqlQuery("SELECT PD.NAME_, PD.VERSION_ , count(*) FROM ACT_HI_PROCINST PI inner join ACT_RE_PROCDEF PD on PI.PROC_DEF_ID_ = PD.ID_ group by PROC_DEF_ID_");





               var reportData = new ReportData;
               var dataset = reportData.newDataset();
               dataset.type = "pieChart";
               dataset.description = "Process instance overview (" + new java.util.Date() + ")"


               while (result.next()) { // process results one row at a time
                 var name = result.getString(1);
                 var version = result.getLong(2);
                 var count = result.getLong(3);
                 dataset.add(name + " (v" + version + ")", count);
               }

               execution.setVariable("reportData", reportData.toBytes());

          ]]></script>
        </scriptTask>
        <sequenceFlow id="flow3" sourceRef="generateDataset" targetRef="theEnd" />

        <endEvent id="theEnd" />

    </process>

</definitions>

報告開始表單

  • 報表是使用普通流程來生成的,所以表單功能也可以使用
  • 直接在開始事件里加一個開始表單 ,Explorer就會在生成報表之前展示給使用者
<startEvent id="startevent1" name="Start">
  <extensionElements>
    <activiti:formProperty id="processDefinition" name="Select process definition" type="processDefinition" required="true" />
      <activiti:formProperty id="chartType" name="Chart type" type="enum" required="true">
        <activiti:value id="pieChart" name="Pie chart" />
        <activiti:value id="barChart" name="Bar chart" />
      </activiti:formProperty>
  </extensionElements>
</startEvent>
  • 為使用者渲染一個普通的表單:
    -
  • 表單屬性會在啟動流程時提交,然後就可以像普通的流程變數一樣使用.指令碼中可以使用這些流程變數來生成資料:
var processDefinition = execution.getVariable("processDefinition");

流程示例

  • 控制檯中包含4個報表示例:
    • Employee productivity(員工的工作效率):
      • 報表演示使用折線圖和開始表單
      • 報表的指令碼比其他例子要複雜,因為資料會在指令碼中先進行解釋,再儲存到報表資料中
    • Helpdesk(一線與升級):
      • 使用餅圖進行展示
      • 結合兩個不同的資料庫查詢結果
    • Process instance overview(流程例項總覽):
      • 使用多個資料集的報表例項
      • 報表包含使用相同資料的餅圖和列表檢視
      • 展示多種資料集可以用來在一個頁面中生成不同圖表
    • Task duration(任務持續時間):
      • 另一個使用開始表單的例子
      • 會使用對應的變數來動態生成SQL查詢語句

修改資料庫

  • 要修改控制檯例子所用的資料庫:
    • 改變屬性檔案:apps/apache-tomcat-6.x/webapps/activiti-explorer/WEB-INF/classes/db.properties
    • 在類路徑下放上合適的資料庫驅動:
      • Tomcat共享類庫
      • apps/apache-tomcat-6.x/webapps/activiti-explorer/WEB-INF/lib/