Flowable2-第一個應(yīng)用程序

創(chuàng)建一個流程引擎

先說一下我的環(huán)境
Windows 7
JDK 8
IDEA

第一個工作流我們就完成一個請假的流程:

1. 員工發(fā)出請假申請
2. 經(jīng)理同意或拒絕該申請
3. 發(fā)送電子郵件給員工

使用 IDEA 創(chuàng)建 Maven 項目

添加依賴項

    <dependency>
      <groupId>org.flowable</groupId>
      <artifactId>flowable-engine</artifactId>
      <version>6.2.1</version>
    </dependency>

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

由于我用的是 mysql 數(shù)據(jù)庫, 所以添加的是 mysql 的啟動.

當(dāng)你添加完了依賴后你的項目看起來是這個樣子的.(2017年12月13日 最新版本為 6.2.1)

Flowable在內(nèi)部使用SLF4J作為日志框架, 所以我們還需要加入對應(yīng)的坐標(biāo)

dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.21</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.7.21</version>
</dependency>

Log4j需要一個屬性文件進(jìn)行配置, 使用以下內(nèi)容將log4j.properties文件添加到src / main / resources文件夾中

log4j.rootLogger = DEBUG丢间,CA

log4j.appender.CA = org.apache.log4j.ConsoleAppender
log4j.appender.CA.layout = org.apache.log4j.PatternLayout
log4j.appender.CA.layout.ConversionPattern =%d {hh:mm:ss缩举,SSS} [%t]%-5p%c%x  - %m%n

創(chuàng)建一個新的Java類并添加main方法:

public class App 
{
    public static void main( String[] args )
    {
        ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
                .setJdbcUrl("jdbc:mysql://127.0.0.1:3306/basics_database?useUnicode=true&characterEncoding=UTF8&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true")
                .setJdbcUsername("root")
                .setJdbcPassword("root")
                .setJdbcDriver("com.mysql.jdbc.Driver")
                .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);

        ProcessEngine processEngine = cfg.buildProcessEngine();
    }
}

如果我們要創(chuàng)建一個 ProcessEngine 流程引擎, 那么我們就需要先創(chuàng)建一個 ProcessEngineConfiguration 實例. 它允許你配置和調(diào)整設(shè)置的流程引擎.

通常, ProcessEngineConfiguration 是使用配置XML文件創(chuàng)建的,
但是, 我們也可以通過Java代碼來創(chuàng)建它.

對于 ProcessEngineConfiguration 實例的創(chuàng)建我們要重點(diǎn)說一下 setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE) 代碼. 當(dāng)我們設(shè)置為 true 的時候, 如果我們數(shù)據(jù)庫中的表不存在會被自動創(chuàng)建.

當(dāng)我們流程引擎配置完成之后, 我們就使用 cfg.buildProcessEngine() 方法來實例化一個流程引擎.

注意: ProcessEngine 實例是一個線程安全的對象, 通常只需在應(yīng)用程序中實例化一次.

啟動應(yīng)用程序

應(yīng)用程序啟動后, 我們需要給他一定的初始化時間, 當(dāng)程序正確結(jié)束后, 我們看一下數(shù)據(jù)庫中是不是多了很多表呢.


部署流程定義

我們將建立的流程是一個非常簡單的請假流程. Flowable引擎期望過程在BPMN 2.0格式中定義, 這是業(yè)界廣泛接受的XML標(biāo)準(zhǔn).

在Flowable術(shù)語中, 我們將這作為一個流程定義來說明. 流程定義定義了請假流程所涉及的不同步驟, 而一個流程實例與特定員工的請假相匹配.

我們假設(shè)這個過程是通過提供一些信息來開始的, 例如員工姓名.

當(dāng)然, 這可以作為這個過程中的第一步. 但是, 通過將其作為輸入數(shù)據(jù), 只有在發(fā)出真正的請求時才會創(chuàng)建實例.

在另一種情況下, 用戶可以在提交之前改變主意并取消, 但是流程實例已經(jīng)被創(chuàng)建. 在某些情況下, 這可能是有價值的信息(例如, 流程已啟動多少次, 但尚未完成), 具體取決于業(yè)務(wù)目標(biāo).

  1. 左邊的圓叫做啟動事件. 這是流程實例的起點(diǎn).
  2. 第一個矩形是一個用戶任務(wù). 這是人類用戶必須執(zhí)行的過程中的一個步驟. 在這種情況下, 經(jīng)理需要批準(zhǔn)或拒絕請求.
  3. 根據(jù)經(jīng)理的決定, Exclusive Gateway(帶X字的菱形)將流程實例路由到批準(zhǔn)路徑或拒絕路徑.
  4. 如果同意, 我們必須在某個外部系統(tǒng)中注冊該請求, 然后再為用戶通知用戶任務(wù), 通知他們你的請假同意.
  5. 如果被拒絕, 則會向員工發(fā)送電子郵件, 通知他們這一點(diǎn).

對應(yīng)于上圖的BPMN 2.0 XML如下所示. 請注意, 這只是過程的一部分. 如果您使用的是圖形建模工具, 則底層的XML文件還包含描述圖形信息的可視化部分, 例如流程定義的各個元素的坐標(biāo)(所有圖形信息包含在XML 中的BPMNDiagram標(biāo)記中, 這是定義標(biāo)記的子元素).

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://sourceforge.net/bpmn/definitions/_1513158409301" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:yaoqiang="http://bpmn.sourceforge.net" exporter="Yaoqiang BPMN Editor" exporterVersion="5.3" expressionLanguage="http://www.w3.org/1999/XPath" id="_1513158409301" name="" targetNamespace="http://sourceforge.net/bpmn/definitions/_1513158409301" typeLanguage="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://bpmn.sourceforge.net/schemas/BPMN20.xsd">
  <process id="PROCESS_1" isClosed="false" isExecutable="true" processType="None">
    <extensionElements>
      <yaoqiang:description/>
      <yaoqiang:pageFormat height="841.8897637795276" imageableHeight="831.8897637795276" imageableWidth="588.1102362204724" imageableX="5.0" imageableY="5.0" orientation="0" width="598.1102362204724"/>
      <yaoqiang:page background="#FFFFFF" horizontalCount="1" verticalCount="1"/>
    </extensionElements>
    <startEvent id="_2" isInterrupting="true" name="開始" parallelMultiple="false">
      <outgoing>_10</outgoing>
      <outputSet/>
    </startEvent>
    <userTask completionQuantity="1" id="_3" implementation="##unspecified" isForCompensation="false" name="同意或拒絕" startQuantity="1">
      <incoming>_10</incoming>
      <outgoing>_11</outgoing>
    </userTask>
    <exclusiveGateway gatewayDirection="Diverging" id="_4">
      <incoming>_11</incoming>
      <outgoing>_12</outgoing>
      <outgoing>_13</outgoing>
    </exclusiveGateway>
    <serviceTask completionQuantity="1" id="_5" implementation="##WebService" isForCompensation="false" name="在外部系統(tǒng)中輸入假期" startQuantity="1">
      <incoming>_12</incoming>
      <outgoing>_14</outgoing>
    </serviceTask>
    <serviceTask completionQuantity="1" id="_6" implementation="##WebService" isForCompensation="false" name="發(fā)送拒絕郵件" startQuantity="1">
      <incoming>_13</incoming>
      <outgoing>_16</outgoing>
    </serviceTask>
    <userTask completionQuantity="1" id="_7" implementation="##unspecified" isForCompensation="false" name="假期批準(zhǔn)" startQuantity="1">
      <incoming>_14</incoming>
      <outgoing>_15</outgoing>
    </userTask>
    <sequenceFlow id="_10" sourceRef="_2" targetRef="_3"/>
    <endEvent id="_9" name="結(jié)束">
      <incoming>_16</incoming>
      <inputSet/>
    </endEvent>
    <sequenceFlow id="_11" sourceRef="_3" targetRef="_4"/>

    <sequenceFlow id="_12" name="同意" sourceRef="_4" targetRef="_5">
      <conditionExpression xsi:type="tFormalExpression">
        <![CDATA[
          ${approved}
        ]]>
      </conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="_13" name="拒絕" sourceRef="_4" targetRef="_6">
      <conditionExpression xsi:type="tFormalExpression">
        <![CDATA[
          ${!approved}
        ]]>
      </conditionExpression>
    </sequenceFlow>

    <sequenceFlow id="_14" sourceRef="_5" targetRef="_7"/>
    <sequenceFlow id="_15" sourceRef="_7" targetRef="_8"/>
    <sequenceFlow id="_16" sourceRef="_6" targetRef="_9"/>
    <endEvent id="_8" name="結(jié)束">
      <incoming>_15</incoming>
      <inputSet/>
    </endEvent>
  </process>
</definitions>

Exclusive Gateway(帶X字的菱形)的流顯然是特殊的: 都具有以表達(dá)式的形式定義的條件.

當(dāng)流程實例執(zhí)行到達(dá)Exclusive Gateway時, 將評估條件獲取并解析為true, 只有第一個表達(dá)式滿足.

當(dāng)然, 如果需要不同的路由行為, 其他類型的Exclusive Gateway也是可能的.

這里以表達(dá)式形式寫出的條件是$ {approved}, 它是$ {approved == true}的簡寫形式.

approved變量稱為流程變量. 流程變量是一個持久的數(shù)據(jù)位, 與流程實例一起存儲, 可以在流程實例的生命周期中使用.

在這種情況下, 這意味著我們將不得不在流程實例中的某個點(diǎn)設(shè)置此流程變量.


將它部署到引擎中

現(xiàn)在我們有了BPMN 2.0 XML文件的流程, 接下來我們需要將它部署到引擎中. 部署流程定義意味著:

  1. 流程引擎會將XML文件存儲在數(shù)據(jù)庫中, 因此可以在需要時進(jìn)行檢索.
  2. 流程定義被解析為一個內(nèi)部可執(zhí)行的對象模型, 以便流程實例可以從中啟動.

要將流程定義部署到Flowable引擎, 需要使用RepositoryService, 可以從ProcessEngine對象中獲取.

使用RepositoryService, 通過傳遞XML文件的位置并調(diào)用deploy()方法來實際執(zhí)行它, 創(chuàng)建一個新的部署:

        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("holiday-request.bpmn20.xml")
                .deploy();

現(xiàn)在, 我們可以通過API查詢流程定義來確認(rèn)流程定義是否已經(jīng)被引擎所了解. 這是通過RepositoryService創(chuàng)建一個新的ProcessDefinitionQuery對象來完成的雌桑。


啟動一個流程實例

我們現(xiàn)在將流程定義部署到流程引擎, 因此可以使用此流程定義作為藍(lán)圖來啟動流程實例.

要啟動流程實例, 我們需要提供一些初始流程變量. 通常情況下, 當(dāng)某個進(jìn)程被自動觸發(fā)時, 您將通過呈現(xiàn)給用戶的表單或通過REST API獲取這些表單.

在這個例子中, 我們將保持簡單并使用 java.util.Scanner 類在命令行上簡單地輸入一些數(shù)據(jù):

        Scanner scanner= new Scanner(System.in);

        System.out.println("你是誰?");
        String employee = scanner.nextLine();

        System.out.println("你要多少假期?");
        Integer nrOfHolidays = Integer.valueOf(scanner.nextLine());

        System.out.println("你為什么需要他們?");
        String description = scanner.nextLine();

接下來, 我們可以通過RuntimeService啟動一個流程實例. 收集的數(shù)據(jù)以java.util.Map實例的形式傳遞, 其中的關(guān)鍵字是稍后用于檢索變量的標(biāo)識符.

流程實例使用鍵啟動. 此鍵匹配在BPMN 2.0 XML文件中設(shè)置的id屬性, 在此情況下為PROCESS_1展父。

<process id="PROCESS_1" isClosed="false" isExecutable="true" processType="None">
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("employee", employee);
        variables.put("nrOfHolidays", nrOfHolidays);
        variables.put("description", description);
        ProcessInstance processInstance =
                runtimeService.startProcessInstanceByKey("PROCESS_1", variables);

當(dāng)流程實例啟動時, 會創(chuàng)建一個execution并放入啟動事件. 這個execution遵循用戶任務(wù)的順序流程以供管理者批準(zhǔn), 并執(zhí)行用戶任務(wù)行為. 此行為將在數(shù)據(jù)庫中創(chuàng)建一個任務(wù), 以后可以使用查詢找到該任務(wù).


查詢和完成任務(wù)

在更現(xiàn)實的應(yīng)用程序中, 將會有一個用戶界面, 員工和經(jīng)理可以登錄并查看他們的任務(wù)列表.

通過這些, 他們可以檢查存儲為流程變量的流程實例數(shù)據(jù), 并決定他們想要處理的任務(wù). 在這個例子中, 我們將通過執(zhí)行通常位于驅(qū)動UI的服務(wù)調(diào)用后面的API調(diào)用來模擬任務(wù)列表.

要注意我們還沒有為userTask進(jìn)行分配. 在這個例子中, 我們將第一個userTask分配給經(jīng)理組. 將第二個 userTask 分配給請假申請的原始請求者.

為此, 請將 candidateGroups 屬性添加到第一個任務(wù):

<userTask flowable:candidateGroups="managers" completionQuantity="1" id="_3" implementation="##unspecified" isForCompensation="false" name="同意或拒絕" startQuantity="1"></userTask>

而第二個任務(wù), 如下所示. 請注意, 我們沒有像上面的flowable:candidateGroups="managers"那樣使用靜態(tài)值, 而是基于流程實例啟動時所傳遞的流程變量的動態(tài)賦值:

<userTask flowable:assignee="${employee}" completionQuantity="1" id="_7" implementation="##unspecified" isForCompensation="false" name="假期批準(zhǔn)" startQuantity="1"></userTask>

為了得到實際的任務(wù)列表, 我們通過TaskService創(chuàng)建一個TaskQuery, 并且配置查詢只返回managers的任務(wù):

        TaskService taskService = processEngine.getTaskService();
        List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("managers").list();
        System.out.println("You have " + tasks.size() + " tasks:");
        for (int i=0; i<tasks.size(); i++) {
            System.out.println((i+1) + ") " + tasks.get(i).getName());
        }

使用任務(wù)標(biāo)識符, 我們現(xiàn)在可以獲得特定的流程實例變量,
并在屏幕上顯示實際的請求:

        System.out.println("你想完成哪個任務(wù)?");
        int taskIndex = Integer.valueOf(scanner.nextLine());
        Task task = tasks.get(taskIndex - 1);
        Map<String, Object> processVariables = taskService.getVariables(task.getId());
        System.out.println(processVariables.get("employee") + " wants " +
                processVariables.get("nrOfHolidays") + " of holidays.  你贊成這個嗎?");

如果上面都做完了, 我們可以執(zhí)行以下程序, 就可以看到我們的任務(wù)列表.

boolean approved = scanner.nextLine().toLowerCase().equals("y");
variables = new HashMap<String, Object>();
variables.put("approved", approved);
taskService.complete(task.getId(), variables);

該任務(wù)現(xiàn)在已經(jīng)完成, 并且基于同意的流程變量來選擇離開專用網(wǎng)關(guān)的兩個路徑之一.


編寫JavaDelegate

還有最后一塊難題還沒有完成: 我們還沒有實現(xiàn)自動邏輯,
當(dāng)請求被同意時, 這些自動邏輯就會被執(zhí)行. 在BPMN 2.0 XML中, 這是一個 serviceTask, 它看起來像:

<serviceTask flowable:class="Flowable.cc.CallExternalSystemDelegate" ></serviceTask>

實際上, 這個邏輯可以是任何東西, 從用HTTP REST調(diào)用一個服務(wù)到執(zhí)行一些傳統(tǒng)的代碼調(diào)用到一個組織幾十年來一直使用的系統(tǒng). 我們不會在這里實現(xiàn)實際的邏輯, 只是記錄處理.

使該類實現(xiàn) org.flowable.engine.delegate.JavaDelegate 接口并實現(xiàn) execute 方法:

public class CallExternalSystemDelegate implements JavaDelegate {
    public void execute(DelegateExecution delegateExecution) {

    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末姜贡,一起剝皮案震驚了整個濱河市错忱,隨后出現(xiàn)的幾起案子倘待,更是在濱河造成了極大的恐慌,老刑警劉巖姐叁,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓦盛,死亡現(xiàn)場離奇詭異洗显,居然都是意外死亡外潜,警方通過查閱死者的電腦和手機(jī)原环,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來处窥,“玉大人嘱吗,你說我怎么就攤上這事√霞荩” “怎么了谒麦?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵哆致,是天一觀的道長绕德。 經(jīng)常有香客問我摊阀,道長,這世上最難降的妖魔是什么胞此? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任臣咖,我火速辦了婚禮漱牵,結(jié)果婚禮上夺蛇,老公的妹妹穿的比我還像新娘酣胀。我一直安慰自己刁赦,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布闻镶。 她就那樣靜靜地躺著,像睡著了一般儒溉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上顿涣,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天涛碑,我揣著相機(jī)與錄音,去河邊找鬼蒲障。 笑死瘫证,一個胖子當(dāng)著我的面吹牛庄撮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洞斯,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼么抗!你這毒婦竟也來了亚铁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤吞琐,失蹤者是張志新(化名)和其女友劉穎甸昏,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體施蜜,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年缸沃,在試婚紗的時候發(fā)現(xiàn)自己被綠了修械。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡翘单,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蹦渣,到底是詐尸還是另有隱情,我是刑警寧澤柬唯,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布锄奢,位于F島的核電站剧腻,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏书在。R本人自食惡果不足惜胯陋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一袱箱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧发笔,春花似錦盟萨、人聲如沸了讨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽男杈。三九已至,卻和暖如春伶棒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背先蒋。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工宛渐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人业岁。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓鳍烁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親幔荒。 傳聞我的和親對象是個殘疾皇子梳玫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理提澎,服務(wù)發(fā)現(xiàn)念链,斷路器,智...
    卡卡羅2017閱讀 134,601評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法掂墓,類相關(guān)的語法,內(nèi)部類的語法跨嘉,繼承相關(guān)的語法吃嘿,異常的語法,線程的語...
    子非魚_t_閱讀 31,587評論 18 399
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,522評論 25 707
  • 學(xué)習(xí): 每天中午一小時 讀完《聰明人都是清單控》亮瓷,運(yùn)用清單思維做整理如 吵架清單降瞳、作息清單、目標(biāo)清單力崇、朋友清單、優(yōu)...
    Sunnyshuang閱讀 148評論 0 1
  • 1.出版社 每個出版社各有所長,盡量選要讀領(lǐng)域的知名出版社搓侄。比如商務(wù)印書館的漢譯名著系列。 2.作者 作者是書的靈...
    栗子醬paramita閱讀 311評論 0 0