Activiti工做流

1:工做流的概念

說明:html

1) 假設:這兩張圖就是華誼兄弟的請假流程圖java

2) 圖的組成部分:mysql

A. 人物:范冰冰 馮小剛王中軍spring

B. 事件(動做):請假、批准、不批准sql

          

 

 

工做流(Workflow),就是「業務過程的部分或總體在計算機應用環境下的自動化」,它主要解決的是「使在多個參與者之間按照某種預約義的規則傳遞文檔、信息或任務的過程自動進行,從而實現某個預期的業務目標,或者促使此目標的實現」。數據庫

工做流管理系統(Workflow Management System, WfMS)是一個軟件系統,它完成工做量的定義和管理,並按照在系統中預先定義好的工做流規則進行工做流實例的執行。工做流管理系統不是企業的業務系統,而是爲企業的業務系統的運行提供了一個軟件的支撐環境。編程

工做流管理聯盟(WfMC,Workflow Management Coalition)給出的關於工做流管理系統的定義是:工做流管理系統是一個軟件系統,它經過執行通過計算的流程定義去支持一批專門設定的業務流程。工做流管理系統被用來定義、管理、和執行工做流程。緩存

工做流管理系統的目標:管理工做的流程以確保工做在正確的時間被指望的人員所執行——在自動化進行的業務過程當中插入人工的執行和干預。 網絡

2:工做流的執行過程

演示程序:Activiti控制檯架構

3:Activiti介紹

Activiti5是由Alfresco軟件在2010年5月17日發佈的業務流程管理(BPM)框架,它是覆蓋了業務流程管理、工做流、服務協做等領域的一個開源的、靈活的、易擴展的可執行流程語言框架。Activiti基於Apache許可的開源BPM平臺,創始人Tom Baeyens是JBoss jBPM的項目架構師,它特點是提供了eclipse插件,開發人員能夠經過插件直接繪畫出業務

流程圖。

3.1:工做流引擎

ProcessEngine對象,這是Activiti工做的核心。負責生成流程運行時的各類實例及數據、監控和管理流程的運行。

3.2:BPMN

業務流程建模與標註(Business Process Model and Notation,BPMN),描述流程的基本符號,包括這些圖元如何組合成一個業務流程圖(Business Process Diagram)

3.3:數據庫(先學後看)

Activiti數據庫支持:

Activiti的後臺是有數據庫的支持,全部的表都以ACT_開頭。 第二部分是表示表的用途的兩個字母標識。 用途也和服務的API對應。

ACT_RE_*: 'RE'表示repository。 這個前綴的表包含了流程定義和流程靜態資源 (圖片,規則,等等)。

ACT_RU_*: 'RU'表示runtime。 這些運行時的表,包含流程實例,任務,變量,異步任務,等運行中的數據。 Activiti只在流程實例執行過程當中保存這些數據, 在流程結束時就會刪除這些記錄。 這樣運行時表能夠一直很小速度很快。

ACT_ID_*: 'ID'表示identity。 這些表包含身份信息,好比用戶,組等等。

ACT_HI_*: 'HI'表示history。 這些表包含歷史數據,好比歷史流程實例, 變量,任務等等。

ACT_GE_*: 通用數據, 用於不一樣場景下,如存放資源文件。

 

表結構操做:

3.3.1:資源庫流程規則表

1) act_re_deployment 部署信息表

2) act_re_model   流程設計模型部署表

3) act_re_procdef   流程定義數據表

3.3.2:運行時數據庫表

1) act_ru_execution 運行時流程執行實例表

2) act_ru_identitylink 運行時流程人員表,主要存儲任務節點與參與者的相關信息

3) act_ru_task 運行時任務節點表

4) act_ru_variable 運行時流程變量數據表

3.3.3:歷史數據庫表

1) act_hi_actinst 歷史節點表

2) act_hi_attachment 歷史附件表

3) act_hi_comment 歷史意見表

4) act_hi_identitylink 歷史流程人員表

5) act_hi_detail 歷史詳情表,提供歷史變量的查詢

6) act_hi_procinst 歷史流程實例表

7) act_hi_taskinst 歷史任務實例表

8) act_hi_varinst 歷史變量表

3.3.4:組織機構表

1) act_id_group 用戶組信息表

2) act_id_info 用戶擴展信息表

3) act_id_membership 用戶與用戶組對應信息表

4) act_id_user 用戶信息表

這四張表很常見,基本的組織機構管理,關於用戶認證方面建議仍是本身開發一套,組件自帶的功能太簡單,使用中有不少需求難以知足

3.3.5:通用數據表

1) act_ge_bytearray 二進制數據表

2) act_ge_property 屬性數據表存儲整個流程引擎級別的數據,初始化表結構時,會默認插入三條記錄,

3.4:activiti.cfg.xml(activiti的配置文件)

Activiti核心配置文件,配置流程引擎建立工具的基本參數和數據庫鏈接池參數。

定義數據庫配置參數:

jdbcUrl: 數據庫的JDBC URL。
jdbcDriver: 對應不一樣數據庫類型的驅動。
jdbcUsername: 鏈接數據庫的用戶名。
jdbcPassword: 鏈接數據庫的密碼。
基於JDBC參數配置的數據庫鏈接 會使用默認的MyBatis鏈接池。 下面的參數能夠用來配置鏈接池(來自MyBatis參數):
jdbcMaxActiveConnections: 鏈接池中處於被使用狀態的鏈接的最大值。默認爲10。

jdbcMaxIdleConnections: 鏈接池中處於空閒狀態的鏈接的最大值。

jdbcMaxCheckoutTime: 鏈接被取出使用的最長時間,超過期間會被強制回收。 默認爲20000(20秒)。

jdbcMaxWaitTime: 這是一個底層配置,讓鏈接池能夠在長時間沒法得到鏈接時, 打印一條日誌,並從新嘗試獲取一個鏈接。(避免由於錯誤配置致使沉默的操做失敗)。 默認爲20000(20秒)。
示例數據庫配置:

 

也可使用javax.sql.DataSource。 (好比,Apache Commons的DBCP):

3.5:logging.properties(日誌處理)

日誌的配置文件,Activiti操做數據庫的時候,整合的日誌文件

4:準備環境

4.1:activiti5軟件環境

1) JDK1.6或者更高版本

2) 支持的數據庫有:h2, mysql, oracle, postgres, mssql, db2等。

3) 支持activiti5運行的jar包

4) 開發環境爲Eclipse3.7或者以上版本,myeclipse爲8.6版本

4.2:相關資源下載

1) JDK能夠到sun的官網下載

http://www.oracle.com/technetwork/java/javase/downloads/index.html

2) 數據庫,例如:mysql能夠在官網上下載。

http://www.mysql.com

3) activiti也能夠到Activiti官方網站下載獲得。

http://activiti.org/download.html

4)  Eclipse3.7或者MyEclipse8.6也能夠到相應的網站上得到下載。

4.3:安裝流程設計器(eclipse插件)

4.3.1:安裝方式

有網絡的狀況下,安裝流程設計器步驟以下:

1) 打開 Help -> Install New Software. 在以下面板中:

 

2) 在以下Install界面板中,點擊Add按鈕:

配置新裝插件的地址和名稱

 

3) 而後填入下列字段

Name: Activiti BPMN 2.0 designer

Location: http://activiti.org/designer/update/

4) 回到Install界面,在面板正中列表中把全部展現出來的項目都勾上:

5) 點擊複選框

在Detail部分記得選中 "Contact all updates sites.." , 由於它會檢查全部當前安裝所須要的插件並能夠被Eclipse下載.

 

6) 安裝完之後,點擊新建工程new->Other…打開面板,若是看到下圖內容:

說明安裝成功了。

4.4:對流程設計器的使用說明

打開菜單Windows->Preferences->Activiti->Save下流程流程圖片的生成方式:

雖然流程引擎在單獨部署bpmn文件時會自動生成圖片,但在實際開發過程當中,自動生成的圖片會致使和BPMN中的座標有出入,在實際項目中展現流程當前位置圖會有問題。

所在完成以上配置後,會由咱們本身來管理流程圖片。在發佈流程時把流程規則文件和流程圖片一塊兒上傳就好了。

4.5:準備Activiti5開發環境

4.5.1:添加Activiti5的jar包

在activiti-5.13->wars目錄下是一些示例項目,解壓activiti-rest項目,導入activiti-rest目錄中WEB-INF\lib下全部包。添加到classpath中。

因爲咱們使用的是Mysql數據庫,Mysql數據庫的連接驅動Activiti官方包中並無提供,須要咱們本身導入。手動導入mysql-connector-java.jar,添加到classpath下。

4.5.2:初始化數據庫


  在Activiti中,在建立核心的流程引擎對象時會自動建表。若是程序正常執行,mysql會自動建庫,而後建立23張表。

4.5.3:添加並制定配置文件

在Actiiti5中定製流程一定會操做到數據庫,若是都像上面那樣寫一大段代碼會很是麻煩,因此咱們能夠把數據庫鏈接配置寫入配置文件。

在Activiti5的官方示例中並無現成的配置文件,因此先得找到activiti-rest\WEB-INF\classes下有:

 

4.5.3.1:activiti-context.xml:

一個相似spring結構的配置文件,清空內容後更名爲activiti.cfg.xml,用來作流程引擎的相關配置。

按照上面代碼配置ProcessEngineConfiguration對象,主要定義數據庫的鏈接配置和建表策略,配置文件代碼以下:

Java代碼以下:

createProcessEngineConfigurationFromResource的參數值爲咱們添加的配置文件activiti.cfg.xml的名稱,執行java代碼,流程引擎對象建立成功運行後數據庫會自動建表。

 
4.5.3.2:log4j.properties日誌配置文件

把兩個文件放入resource目錄下便可。

5:核心API

5.1:ProcessEngine

說明:

1) 在Activiti中最核心的類,其餘的類都是由他而來。

2) 產生方式:


在前面看到了兩種建立ProcessEngine(流程引擎)的方式,而這裏要簡化不少,調用ProcessEngines的getDefaultProceeEngine方法時會自動加載classpath下名爲activiti.cfg.xml文件。

3) 能夠產生RepositoryService

4) 能夠產生RuntimeService

5) 能夠產生TaskService

各個Service的做用:

RepositoryService

管理流程定義

RuntimeService

執行管理,包括啓動、推動、刪除流程實例等操做

TaskService

任務管理

HistoryService

歷史管理(執行完的數據的管理)

IdentityService

組織機構管理

FormService

一個可選服務,任務表單管理

ManagerService

 

5.2:RepositoryService

是Activiti的倉庫服務類。所謂的倉庫指流程定義文檔的兩個文件:bpmn文件和流程圖片。

1) 產生方式



2) 能夠產生DeploymentBuilder,用來定義流程部署的相關參數

 

3) 刪除流程定義

5.3:RuntimeService

是activiti的流程執行服務類。能夠從這個服務類中獲取不少關於流程執行相關的信息。

 

5.4:TaskService

是activiti的任務服務類。能夠從這個類中獲取任務的信息。

5.5:HistoryService

是activiti的查詢歷史信息的類。在一個流程執行完成後,這個對象爲咱們提供查詢歷史信息。

5.6:ProcessDefinition

流程定義類。能夠從這裏得到資源文件等。

5.7:ProcessInstance

表明流程定義的執行實例。如范冰冰請了一天的假,她就必須發出一個流程實例的申請。一個流程實例包括了全部的運行節點。咱們能夠利用這個對象來了解當前流程實例的進度等信息。流程實例就表示一個流程從開始到結束的最大的流程分支,即一個流程中流程實例只有一個。

5.8:Execution

Activiti用這個對象去描述流程執行的每個節點。在沒有併發的狀況下,Execution就是同ProcessInstance。流程按照流程定義的規則執行一次的過程,就能夠表示執行對象Execution。

如圖爲ProcessInstance的源代碼:


 

從源代碼中能夠看出ProcessInstance就是Execution。但在現實意義上有所區別:


 

在單線流程中,如上圖的貸款流程,ProcessInstance與Execution是一致的。


 

這個例子有一個特色:wire money(匯錢)和archive(存檔)是併發執行的。這個時候,總線路表明ProcessInstance,而分線路中每一個活動表明Execution。

總結:

* 一個流程中,執行對象能夠存在多個,可是流程實例只能有一個。

* 當流程按照規則只執行一次的時候,那麼流程實例就是執行對象。

6:HelloWorld程序(模擬流程的執行)

6.1:流程圖:


 

6.2:部署流程定義


 

這裏使用RepositoryService部署流程定義

addClasspathResource表示從類路徑下加載資源文件,一次只能加載一個文件

 

6.3:啓動流程實例

6.4:查看個人我的任務

 

這裏使用TaskService完成任務的查詢

6.5:完成個人我的任務

 

 

7:管理流程定義

7.1:設計流程定義文檔

7.1.1:流程圖


7.1.2:bpmn文件

    BPMN 2.0根節點是definitions節點。 這個元素中,能夠定義多個流程定義(不過咱們建議每一個文件只包含一個流程定義, 能夠簡化開發過程當中的維護難度)。 一個空的流程定義看起來像下面這樣。注意,definitions元素 最少也要包含xmlns 和 targetNamespace的聲明。 targetNamespace能夠是任意值,它用來對流程實例進行分類。

說明:流程定義文檔有兩部分組成:

1) bpmn文件

流程規則文件。在部署後,每次系統啓動時都會被解析,把內容封裝成流程定義放入項目緩存中。Activiti框架結合這個xml文件自動管理流程,流程的執行就是按照bpmn文件定義的規則執行的,bpmn文件是給計算機執行用的。

2) 展現流程圖的圖片

在系統裏須要展現流程的進展圖片,圖片是給用戶看的。

7.2:部署流程定義(classpath路徑加載文件)

說明:

1) 先獲取流程引擎對象:在建立時會自動加載classpath下的activiti.cfg.xml

2) 首先得到默認的流程引擎,經過流程引擎獲取了一個RepositoryService對象(倉庫對象)

3) 由倉庫的服務對象產生一個部署對象配置對象,用來封裝部署操做的相關配置。

4) 這是一個鏈式編程,在部署配置對象中設置顯示名,上傳流程定義規則文件

5) 向數據庫表中存放流程定義的規則信息。

6) 這一步在數據庫中將操做三張表:

a) act_re_deployment(部署對象表)

存放流程定義的顯示名和部署時間,每部署一次增長一條記錄

b) act_re_procdef(流程定義表)

存放流程定義的屬性信息,部署每一個新的流程定義都會在這張表中增長一條記錄。

注意:當流程定義的key相同的狀況下,使用的是版本升級

c) act_ge_bytearray(資源文件表)

存儲流程定義相關的部署信息。即流程定義文檔的存放地。每部署一次就會增長兩條記錄,一條是關於bpmn規則文件的,一條是圖片的(若是部署時只指定了bpmn一個文件,activiti會在部署時解析bpmn文件內容自動生成流程圖)。兩個文件不是很大,都是以二進制形式存儲在數據庫中。

 

7.3:部署流程定義(zip格式文件)


 

壓縮成zip格式的文件,使用zip的輸入流用做部署流程定義

 

7.4:查看流程定義

查詢流程定義的信息

 

結果:

 

再部署一次運行結果爲:

 

能夠看到流程定義的key值相同的狀況下,版本是從1開始逐次升級的

流程定義的Id是【key:版本:生成ID】

說明:

1) 流程定義和部署對象相關的Service都是RepositoryService。

2) 建立流程定義查詢對象,能夠在ProcessDefinitionQuery上設置查詢的相關參數

3) 調用ProcessDefinitionQuery對象的list方法,執行查詢,得到符合條件的流程定義列表

4) 由運行結果能夠看出:

Key和Name的值爲:bpmn文件process節點的id和name的屬性值

 

5) key屬性被用來區別不一樣的流程定義。

6) 帶有特定key的流程定義第一次部署時,version爲1。以後每次部署都會在當前最高版本號上加1

7) Id的值的生成規則爲:{processDefinitionKey}:{processDefinitionVersion}:{generated-id},這裏的generated-id是一個自動生成的惟一的數字

8) 重複部署一次,deploymentId的值以必定的形式變化

   規則act_ge_property表生成

7.5:刪除流程定義

刪除部署到activiti中的流程定義。

 

說明:

1) 由於刪除的是流程定義,而流程定義的部署是屬於倉庫服務的,因此應該先獲得RepositoryService

2) 若是該流程定義下沒有正在運行的流程,則能夠用普通刪除。若是是有關聯的信息,用級聯刪除。項目開發中使用級聯刪除的狀況比較多,刪除操做通常只開放給超級管理員使用。

7.6:獲取流程定義文檔的資源(查看流程圖附件)

查詢出流程定義文檔。主要查的是圖片,用於顯示流程用。

 

說明:

1) deploymentId爲流程部署ID

2) resourceName爲act_ge_bytearray表中NAME_列的值

3) 使用repositoryService的getDeploymentResourceNames方法能夠獲取指定部署下得全部文件的名稱

4) 使用repositoryService的getResourceAsStream方法傳入部署ID和資源圖片名稱能夠獲取部署下指定名稱文件的輸入流

5) 最後的有關IO流的操做,使用FileUtils工具的copyInputStreamToFile方法完成流程流程到文件的拷貝,將資源文件以流的形式輸出到指定文件夾下

7.7:附加功能:查詢最新版本的流程定義

 

7.8:附加功能:刪除流程定義(刪除key相同的全部不一樣版本的流程定義)

 

7.9:總結

Deployment   部署對象

一、一次部署的多個文件的信息。對於不須要的流程能夠刪除和修改。

二、對應的表:

  act_re_deployment:部署對象表

  act_re_procdef:流程定義表

  act_ge_bytearray:資源文件表

  act_ge_property:主鍵生成策略表

 

ProcessDefinition流程定義

一、解析.bpmn後獲得的流程定義規則的信息,工做流系統就是按照流程定義的規則執行的。

8:流程實例、任務的執行

8.1:流程圖

 

8.2:部署流程定義

 

8.3:啓動流程實例

 

說明:

1) 操做數據庫的act_ru_execution表,若是是用戶任務節點,同時也會在act_ru_task添加一條記錄

8.4:查詢個人我的任務

 

說明:

1) 由於是任務查詢,因此從processEngine中應該獲得TaskService

2) 使用TaskService獲取到任務查詢對象TaskQuery

3) 爲查詢對象添加查詢過濾條件,使用taskAssignee指定任務的辦理者(即查詢指定用戶的代辦任務),同時能夠添加分頁排序等過濾條件

4) 調用list方法執行查詢,返回辦理者爲指定用戶的任務列表

5) 任務ID、名稱、辦理人、建立時間能夠從act_ru_task表中查到。

6) Execution與ProcessInstance見5.6和5.7章節的介紹。在這種狀況下,ProcessInstance至關於Execution

7) 若是assignee屬性爲部門經理,結果爲空。由於如今流程只到了」填寫請假申請」階段,後面的任務尚未執行,即在數據庫中沒有部門經理能夠辦理的任務,因此查詢不到。

8) 一個Task節點和Execution節點是1對1的狀況,在task對象中使用Execution_來表示他們之間的關係

9) 任務ID在數據庫表act_ru_task中對應「ID_」列

 

附加:

在activiti任務中,主要分爲兩大類查詢任務(我的任務和組任務):

1.確切指定了辦理者的任務,這個任務將成爲指定者的私有任務,即我的任務。

2.沒法指定具體的某一我的來辦理的任務,能夠把任務分配給幾我的或者一到 多個小組,讓這個範圍內的用戶能夠選擇性(若有空餘時間時)來辦理這類任務,即組任務。

先知道我的任務的查詢和辦理,組任務的操做後面講

8.5:辦理任務

 

說明:

1) 是辦理任務,因此從ProcessEngine獲得的是TaskService。

2) 當執行完這段代碼,再以員工的身份去執行查詢的時候,會發現這個時候已經沒有數據了,由於正在執行的任務中沒有數據。

3) 對於執行完的任務,activiti將從act_ru_task表中刪除該任務,下一個任務會被插入進來。

4) 以」部門經理」的身份進行查詢,能夠查到結果。由於流程執行到部門經理審批這個節點了。

5) 再執行辦理任務代碼,執行完之後以」部門經理」身份進行查詢,沒有結果。

6) 重複第3和4步直到流程執行完。

8.6:查詢流程狀態(判斷流程正在執行,仍是結束)

 

在流程執行的過程當中,建立的流程實例ID在整個過程當中都不會變,當流程結束後,流程實例將會在正在執行的執行對象表中(act_ru_execution)被刪除

說明:

1) 由於是查詢流程實例,因此先獲取runtimeService

2) 建立流程實例查詢對象,設置實例ID過濾參數

3) 因爲一個流程實例ID只對應一個實例,使用singleResult執行查詢返回一個惟一的結果,若是結果數量大於1,則拋出異常

4) 判斷指定ID的實例是否存在,若是結果爲空,則表明流程結束,實例在正在執行的執行對象表中已被刪除,轉換成歷史數據。

8.7:附加功能:查詢歷史任務(後面講)

 

8.8:附加功能:查詢歷史流程實例(後面講)

 

8.9:總結

Execution   執行對象

 按流程定義的規則執行一次的過程.

 對應的表:

  act_ru_execution: 正在執行的信息

  act_hi_procinst:已經執行完的歷史流程實例信息

  act_hi_actinst:存放歷史全部完成的活動

ProcessInstance  流程實例

 特指流程從開始到結束的那個最大的執行分支,一個執行的流程中,流程實例只有1個。

 

注意

    (1)若是是單例流程,執行對象ID就是流程實例ID

    (2)若是一個流程有分支和聚合,那麼執行對象ID和流程實例ID就不相同

    (3)一個流程中,流程實例只有1個,執行對象能夠存在多個。

 

Task任務

 執行到某任務環節時生成的任務信息。

 對應的表:

  act_ru_task:正在執行的任務信息

  act_hi_taskinst:已經執行完的歷史任務信息

 

9:流程變量

9.1:流程圖

流程變量在整個工做流中扮演很重要的做用。例如:請假流程中有請假天數、請假緣由等一些參數都爲流程變量的範圍。流程變量的做用域範圍是只對應一個流程實例。也就是說各個流程實例的流程變量是不相互影響的。流程實例結束完成之後流程變量還保存在數據庫中。

例如:

即:

9.2:部署流程定義

 

說明:

• 輸入流加載資源文件的3種方式

9.3:啓動流程實例

9.4:設置流程變量

說明:

1) 流程變量的做用域就是流程實例,因此只要設置就好了,不用管在哪一個階段設置

2) 基本類型設置流程變量,在taskService中使用任務ID,定義流程變量的名稱,設置流程變量的值。

3) Javabean類型設置流程變量,須要這個javabean實現了Serializable接口

4) 設置流程變量的時候,向act_ru_variable這個表添加數據

9.5:獲取流程變量

說明:

1) 流程變量的獲取針對流程實例(即1個流程),每一個流程實例獲取的流程變量時不一樣的

2) 使用基本類型獲取流程變量,在taskService中使用任務ID,流程變量的名稱,獲取流程變量的值。

3) Javabean類型設置獲取流程變量,除了須要這個javabean實現了Serializable接口外,還要求流程變量對象的屬性不能發生編號,不然拋出異常。

9.6:模擬流程變量的設置和獲取的場景

說明:

1) RuntimeService對象能夠設置流程變量和獲取流程變量

2) TaskService對象能夠設置流程變量和獲取流程變量

3) 流程實例啓動的時候能夠設置流程變量

4) 任務辦理完成的時候能夠設置流程變量

5) 流程變量能夠經過名稱/值的形式設置單個流程變量

6) 流程變量能夠經過Map集合,同時設置多個流程變量

Map集合的key表示流程變量的名稱

Map集合的value表示流程變量的值

 

9.7:查詢歷史的流程變量

 

說明:

1)歷史的流程變量查詢,指定流程變量的名稱,查詢act_hi_varinst表(也能夠針對,流程實例ID,執行對象ID,任務ID查詢)

 

 

9.8:流程變量的支持的類型

如圖是從官網列出來的流程變量

 

從圖中能夠看出包括了大部分封裝類型和Date、String和實現了Serializable接口的類的類型。

9.9:總結

• 1:流程變量

在流程執行或者任務執行的過程當中,用於設置和獲取變量,使用流程變量在流程傳遞的過程當中傳遞業務參數。

對應的表:

act_ru_variable:正在執行的流程變量表

act_hi_varinst:流程變量歷史表

 

• 2:擴展知識:setVariable和setVariableLocal的區別

setVariable:設置流程變量的時候,流程變量名稱相同的時候,後一次的值替換前一次的值,並且能夠看到TASK_ID的字段不會存聽任務ID的值

setVariableLocal:

1:設置流程變量的時候,針對當前活動的節點設置流程變量,若是一個流程中存在2個活動節點,對每一個活動節點都設置流程變量,即便流程變量的名稱相同,後一次的版本的值也不會替換前一次版本的值,它會使用不一樣的任務ID做爲標識,存放2個流程變量值,並且能夠看到TASK_ID的字段會存聽任務ID的值

例如act_hi_varinst 表的數據:不一樣的任務節點,即便流程變量名稱相同,存放的值也是不一樣的。

如圖:

2:還有,使用setVariableLocal說明流程變量綁定了當前的任務,當流程繼續執行時,下個任務獲取不到這個流程變量(由於正在執行的流程變量中沒有這個數據),全部查詢正在執行的任務時不能查詢到咱們須要的數據,此時須要查詢歷史的流程變量。

10:流程執行歷史記錄

10.1:查詢歷史流程實例

查找按照某個流程定義的規則一共執行了多少次流程

 

10.2:查詢歷史活動

某一次流程的執行一共經歷了多少個活動

 

 

10.3:查詢歷史任務

某一次流程的執行一共經歷了多少個任務

 

 

10.4:查詢歷史流程變量

某一次流程的執行一共設置的流程變量

 

10.5:總結

因爲數據庫中保存着歷史信息以及正在運行的流程實例信息,在實際項目中對已完成任務的查看頻率遠不及對代辦和可接任務的查看,因此在activiti採用分開管理,把正在運行的交給RuntimeService、TaskService管理,而歷史數據交給HistoryService來管理。

這樣作的好處在於,加快流程執行的速度,由於正在執行的流程的表中數據不會很大。

 

11:連線

11.1:流程圖

 

 

注意:若是將流程圖放置在和java類相同的路徑,須要配置

 

11.2:部署流程定義+啓動流程實例

 

11.3:查詢個人我的任務

 

11.4:完成任務

 

說明:

1)使用流程變量,設置連線須要的流程變量的名稱message,並設置流程變量的值

對應:

 

11.5:總結

一、一個活動中能夠指定一個或多個SequenceFlow(Start中有一個,End中沒有)。

  * 開始活動中有一個SequenceFlow 。

  * 結束活動中沒有SequenceFlow 。

  * 其餘活動中有1條或多條SequenceFlow

二、若是隻有一個,則能夠不使用流程變量設置codition的名稱;

 

若是有多個,則須要使用流程變量設置codition的名稱。message表示流程變量的名稱,‘不重要’表示流程變量的值,${}(或者#{})中間的內容要使用boolean類型的表達式,用來判斷應該執行的連線。

 

12:排他網關(ExclusiveGateWay)

12.1:流程圖

 

12.2:部署流程定義+啓動流程實例

 

12.3:查詢個人我的任務

 

12.4:完成個人我的任務

 

說明:

1) 一個排他網關對應一個以上的順序流

2) 由排他網關流出的順序流都有個conditionExpression元素,在內部維護返回boolean類型的決策結果。

3) 決策網關只會返回一條結果。當流程執行到排他網關時,流程引擎會自動檢索網關出口,從上到下檢索若是發現第一條決策結果爲true或者沒有設置條件的(默認爲成立),則流出。

4) 若是沒有任何一個出口符合條件,則拋出異常

5) 使用流程變量,設置連線的條件,並按照連線的條件執行工做流,若是沒有條件符合的條件,則以默認的連線離開。例如:

 

則執行連線:

 

若是使用流程變量設置

 

則執行連線:

 

13:並行網關(parallelGateWay)

13.1:流程圖

 

 

 

 

13.2:部署流程定義+啓動流程實例

 

13.3:查詢個人我的任務

 

13.4:完成個人我的任務

 

說明:

1) 一個流程中流程實例只有1個,執行對象有多個

2) 並行網關的功能是基於進入和外出的順序流的:

分支(fork):並行後的全部外出順序流,爲每一個順序流都建立一個併發分支。

匯聚(join):全部到達並行網關,在此等待的進入分支,直到全部進入順序流的分支都到達之後,流程就會經過匯聚網關。

3) 並行網關的進入和外出都是使用相同節點標識

4) 若是同一個並行網關有多個進入和多個外出順序流, 它就同時具備分支和匯聚功能。 這時,網關會先匯聚全部進入的順序流,而後再切分紅多個並行分支。

5) 並行網關不會解析條件。即便順序流中定義了條件,也會被忽略。

6)並行網關不須要是「平衡的」(好比, 對應並行網關的進入和外出節點數目不必定相等)。如圖中標示是合法的:

14:開始活動節點

14.1:流程圖

14.2:部署流程定義+啓動流程實例+查詢流程實例+查詢歷史流程實例

14.3:總結

1):結束節點沒有出口

2):其餘節點有一個或多個出口。

若是有一個出口,則表明是一個單線流程

若是有多個出口,則表明是開啓併發流程

15:接收活動(receiveTask,即等待活動)

接收任務是一個簡單任務,它會等待對應消息的到達。 當前,官方只實現了這個任務的java語義。 當流程達到接收任務,流程狀態會保存到數據庫中。

在任務建立後,意味着流程會進入等待狀態,直到引擎接收了一個特定的消息,這會觸發流程穿過接收任務繼續執行。

15.1:流程圖

15.2:部署流程定義+啓動流程實例

/**

 * ReceiceTask任務,機器自動完成的任務

 * 只會在act_ru_execution表中產生一條數據

 * @throws Exception

 */

@Test

public void testExecution()throws Exception {

// 1發佈流程

InputStream inputStreamBpmn = this.getClass().getResourceAsStream("receiveTask.bpmn");

InputStream inputStreamPng = this.getClass().getResourceAsStream("receiveTask.png");

processEngine.getRepositoryService()//

.createDeployment()//

.addInputStream("receiveTask.bpmn", inputStreamBpmn)//

.addInputStream("receiveTask.png", inputStreamPng)//

.deploy();

// 2啓動流程

ProcessInstance pi = processEngine.getRuntimeService()//

.startProcessInstanceByKey("receiveTaskDemo");

System.out.println("pid:" + pi.getId());

String pid = pi.getId();

// 3查詢是否有一個執行對象在描述」彙總當日銷售額「

Execution e1 = processEngine.getRuntimeService()//

.createExecutionQuery()//

.processInstanceId(pid)//

.activityId("彙總當日銷售額")//

.singleResult();

 

// 4執行一堆邏輯,並設置流程變量

Map<String,Object> vars = new HashMap<String, Object>();

vars.put("當日銷售額", 10000);

// 5流程向後執行一步:日後推移e1,使用signal給流程引擎信號,告訴他當前任務已經完成了,能夠日後執行

processEngine.getRuntimeService()

.signal(e1.getId(),vars);

// 6判斷當前流程是否在」給老闆發短信「節點

Execution e2 = processEngine.getRuntimeService()//

.createExecutionQuery()//

.processInstanceId(pid)//

.activityId("給總經理髮短信")//

.singleResult();

// 7獲取流程變量

Integer money = (Integer) processEngine.getRuntimeService()//

.getVariable(e2.getId(), "當日銷售額");

System.out.println("老闆,今天賺了" +money);

// 8向後執行一步:任務完成,日後推移」給老闆發短信「任務

processEngine.getRuntimeService()//

.signal(e2.getId());

// 9查詢流程狀態

    pi = processEngine.getRuntimeService()//

     .createProcessInstanceQuery()//

     .processInstanceId(pid)//

     .singleResult();

    if(pi==null){

         System.out.println("流程正常執行!!!,已經結束了");

    }

}

說明:

1) 當前任務(通常指機器自動完成,但須要耗費必定時間的工做)完成後,向後推移流程,能夠調用runtimeService.signal(executionId),傳遞接收執行對象的id。

16:用戶任務(userTask,即用戶操做的任務)

16.1:我的任務

16.1.1:流程圖

16.1.2::分配我的任務方式一(直接指定辦理人)

1:流程圖中任務節點的配置

2:測試代碼:

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//部署流程定義,啓動流程實例

@Test

public void testTask()throws Exception {

// 1 發佈流程

InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn");

InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png");

processEngine.getRepositoryService()//

.createDeployment()//

.addInputStream("userTask.bpmn", inputStreamBpmn)//

.addInputStream("userTask.png", inputStreamPng)//

.deploy();

// 2 啓動流程

//啓動流程實例的同時,設置流程變量

ProcessInstance pi = processEngine.getRuntimeService()//

.startProcessInstanceByKey("taskProcess");

System.out.println("pid:" + pi.getId());

}

//查詢個人我的任務列表

@Test

public void findMyTaskList(){

String userId = "張三丰";

List<Task> list = processEngine.getTaskService()//

                .createTaskQuery()//

                .taskAssignee(userId)//指定我的任務查詢

                .list();

for(Task task:list ){

System.out.println("id="+task.getId());

System.out.println("name="+task.getName());

System.out.println("assinee="+task.getAssignee());

System.out.println("createTime="+task.getCreateTime());

System.out.println("executionId="+task.getExecutionId());

}

}

//完成任務

@Test

public void completeTask(){

String taskId = "3209";

processEngine.getTaskService()//

.complete(taskId);//

System.out.println("完成任務");

}

說明:

1) 張三丰是我的任務的辦理人

2) 可是這樣分配任務的辦理人不夠靈活,由於項目開發中任務的辦理人不要放置XML文件中。

16.1.3::分配我的任務方式二(使用流程變量)

1:流程圖中任務節點的配置

2:測試代碼

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//部署流程定義,啓動流程實例

@Test

public void testTask()throws Exception {

// 1發佈流程

InputStream inputStreamBpmn =this.getClass().getResourceAsStream("taskProcess.bpmn");

InputStream inputStreamPng =this.getClass().getResourceAsStream("taskProcess.png");

processEngine.getRepositoryService()//

.createDeployment()//

.addInputStream("userTask.bpmn", inputStreamBpmn)//

.addInputStream("userTask.png", inputStreamPng)//

.deploy();

// 2啓動流程

//啓動流程實例的同時,設置流程變量

Map<String, Object> variables =new HashMap<String, Object>();

variables.put("userID","張翠三");

ProcessInstance pi = processEngine.getRuntimeService()//

.startProcessInstanceByKey("taskProcess",variables);

System.out.println("pid:" + pi.getId());

}

//查詢個人我的任務列表

@Test

public void findMyTaskList(){

String userId = "張翠三";

List<Task> list = processEngine.getTaskService()//

                .createTaskQuery()//

                .taskAssignee(userId)//指定我的任務查詢

                .list();

for(Task task:list ){

System.out.println("id="+task.getId());

System.out.println("name="+task.getName());

System.out.println("assinee="+task.getAssignee());

System.out.println("createTime="+task.getCreateTime());

System.out.println("executionId="+task.getExecutionId());

}

}

//完成任務

@Test

public void completeTask(){

String taskId = "3209";

processEngine.getTaskService()//

.complete(taskId);//

System.out.println("完成任務");

}

說明:

1) 張翠山是我的任務的辦理人

2) 在開發中,能夠在頁面中指定下一個任務的辦理人,經過流程變量設置下一個任務的辦理人

16.1.4::分配我的任務方式三(使用類)

1:流程圖中任務節點的配置

此時流程圖的XML文件,如圖:

2:TaskListenerImpl類,用來設置任務的辦理人

public class TaskListenerImplimplements TaskListener {

 

/**指定我的任務和組任務的辦理人*/

@Override

public void notify(DelegateTask delegateTask) {

String assignee = "張無忌";

//指定我的任務

delegateTask.setAssignee(assignee);

}

 

}

3:測試代碼

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//部署流程定義,啓動流程實例

@Test

public void testTask()throws Exception {

// 1 發佈流程

InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn");

InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png");

processEngine.getRepositoryService()//

.createDeployment()//

.addInputStream("userTask.bpmn", inputStreamBpmn)//

.addInputStream("userTask.png", inputStreamPng)//

.deploy();

// 2 啓動流程

ProcessInstance pi = processEngine.getRuntimeService()//

.startProcessInstanceByKey("taskProcess");

System.out.println("pid:" + pi.getId());

}

//查詢個人我的任務列表

@Test

public void findMyTaskList(){

String userId = "張無忌";

List<Task> list = processEngine.getTaskService()//

                .createTaskQuery()//

                .taskAssignee(userId)//指定我的任務查詢

                .list();

for(Task task:list ){

System.out.println("id="+task.getId());

System.out.println("name="+task.getName());

System.out.println("assinee="+task.getAssignee());

System.out.println("createTime="+task.getCreateTime());

System.out.println("executionId="+task.getExecutionId());

}

}

//完成任務

@Test

public void completeTask(){

String taskId = "3408";

processEngine.getTaskService()//

.complete(taskId);//

System.out.println("完成任務");

}

 

//能夠分配我的任務從一我的到另外一我的(認領任務)

@Test

public void setAssigneeTask(){

//任務ID

String taskId = "3408";

//指定認領的辦理者

String userId = "周芷若";

processEngine.getTaskService()//

.setAssignee(taskId, userId);

}

說明:

1) 在類中使用delegateTask.setAssignee(assignee);的方式分配我的任務的辦理人,此時張無忌是下一個任務的辦理人

2) 經過processEngine.getTaskService().setAssignee(taskId, userId);將我的任務從一我的分配給另外一我的,此時張無忌再也不是下一個任務的辦理人,而換成了周芷若

3) 在開發中,能夠將每個任務的辦理人規定好,例如張三的領導是李四,李四的領導是王五,這樣張三提交任務,就能夠查詢出張三的領導是李四,經過類的方式設置下一個任務的辦理人

16.1.5:總結

我的任務及三種分配方式:

    1:在taskProcess.bpmn中直接寫 assignee=「張三丰"

    2:在taskProcess.bpmn中寫 assignee=「#{userID}」,變量的值要是String的。

         使用流程變量指定辦理人

    3,使用TaskListener接口,要使類實現該接口,在類中定義:

         delegateTask.setAssignee(assignee);// 指定我的任務的辦理人

    

 使用任務ID和辦理人從新指定辦理人:

     processEngine.getTaskService()//

                           .setAssignee(taskId, userId);

16.2:組任務

16.2.1:流程圖


16.2.2::分配組任務方式一(直接指定辦理人)

1:流程圖中任務節點的配置

 

2:測試代碼:

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//部署流程定義,啓動流程實例

@Test

public void testTask()throws Exception {

// 1 發佈流程

InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn");

InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png");

processEngine.getRepositoryService()//

.createDeployment()//

.addInputStream("userTask.bpmn", inputStreamBpmn)//

.addInputStream("userTask.png", inputStreamPng)//

.deploy();

// 2啓動流程

ProcessInstance pi = processEngine.getRuntimeService()//

.startProcessInstanceByKey("taskProcess");

System.out.println("pid:" + pi.getId());

}

//3查詢個人我的任務列表

@Test

public void findMyTaskList(){

String userId = "小A";

List<Task> list = processEngine.getTaskService()//

                .createTaskQuery()//

                .taskAssignee(userId)//指定我的任務查詢

                .list();

for(Task task:list ){

System.out.println("id="+task.getId());

System.out.println("name="+task.getName());

System.out.println("assinee="+task.getAssignee());

System.out.println("createTime="+task.getCreateTime());

System.out.println("executionId="+task.getExecutionId());

}

}

//4查詢組任務列表

@Test

public void findGroupList(){

String userId = "小A";

List<Task> list = processEngine.getTaskService()//

                .createTaskQuery()//

                .taskCandidateUser(userId)//指定組任務查詢

                .list();

for(Task task:list ){

System.out.println("id="+task.getId());

System.out.println("name="+task.getName());

System.out.println("assinee="+task.getAssignee());

System.out.println("createTime ="+task.getCreateTime());

System.out.println("executionId="+task.getExecutionId());

System.out.println("##################################");

}

}

//5查詢組任務成員列表

@Test

public void findGroupUser(){

String taskId = "3709";

List<IdentityLink> list = processEngine.getTaskService()//

                .getIdentityLinksForTask(taskId);

         //List<IdentityLink> list = processEngine.getRuntimeService()//

//.getIdentityLinksForProcessInstance(instanceId);

for(IdentityLink identityLink:list ){

System.out.println("userId="+identityLink.getUserId());

System.out.println("taskId="+identityLink.getTaskId());

System.out.println("piId="+identityLink.getProcessInstanceId());

System.out.println("######################");

}

}

//6查詢組任務成員歷史列表

@Test

public void findGroupHisUser(){

String taskId = "3709";

List<HistoricIdentityLink> list = processEngine.getHistoryService()//

.getHistoricIdentityLinksForTask(taskId);

        //List<HistoricIdentityLink> list = processEngine.getHistoryService()//

          // .getHistoricIdentityLinksForProcessInstance(processInstanceId);

for(HistoricIdentityLink identityLink:list ){

System.out.println("userId="+identityLink.getUserId());

System.out.println("taskId="+identityLink.getTaskId());

System.out.println("piId="+identityLink.getProcessInstanceId());

System.out.println("######################");

}

}

//完成任務

@Test

public void completeTask(){

String taskId = "3709";

processEngine.getTaskService()//

.complete(taskId);//

System.out.println("完成任務");

}

 

     /**將組任務分配給我的任務,拾取任務*/

//由1我的去完成任務

@Test

public void claim(){

//任務ID

String taskId = "5908";

//分配的辦理人

String userId = "小B";

processEngine.getTaskService()//

.claim(taskId, userId);

}

/**將我的任務回退到組任務(前提:以前組任務)*/

@Test

public void assignee(){

//任務ID

String taskId = "5508";

processEngine.getTaskService()//

.setAssignee(taskId, null);

}

/**向組任務中添加成員*/

@Test

public void addCadidateUser(){

//任務ID

String taskId = "5508";

//添加的成員

String userId = "小E";

processEngine.getTaskService()//

.addCandidateUser(taskId, userId);

}

/**從組任務中刪除成員*/

@Test

public void deleteCadidateUser(){

//任務ID

String taskId = "5508";

//添加的成員

String userId = "小D";

processEngine.getTaskService()//

.deleteCandidateUser(taskId, userId);

}

說明:

1) 小A,小B,小C,小D是組任務的辦理人

2) 可是這樣分配組任務的辦理人不夠靈活,由於項目開發中任務的辦理人不要放置XML文件中。

3) act_ru_identitylink表存聽任務的辦理人,包括我的任務和組任務,表示正在執行的任務

4) act_hi_identitylink表存聽任務的辦理人,包括我的任務和組任務,表示歷史任務

區別在於:若是是我的任務TYPE的類型表示participant(參與者)

 若是是組任務TYPE的類型表示candidate(候選者)和participant(參與者)

16.2.3::分配我的任務方式二(使用流程變量)

1:流程圖中任務節點的配置

2:測試代碼

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//部署流程定義,啓動流程實例

@Test

public void testTask()throws Exception {

// 1 發佈流程

InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn");

InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png");

processEngine.getRepositoryService()//

.createDeployment()//

.addInputStream("userTask.bpmn", inputStreamBpmn)//

.addInputStream("userTask.png", inputStreamPng)//

.deploy();

// 2啓動流程

//啓動流程實例,同時設置流程變量,用來指定組任務的辦理人

Map<String, Object> variables = new HashMap<String, Object>();

variables.put("userIDs","大大,小小,中中");

ProcessInstance pi = processEngine.getRuntimeService()//

.startProcessInstanceByKey("taskProcess",variables);

System.out.println("pid:" + pi.getId());

}

//查詢個人我的任務列表

@Test

public void findMyTaskList(){

String userId = "大大";

List<Task> list = processEngine.getTaskService()//

                .createTaskQuery()//

                .taskAssignee(userId)//指定我的任務查詢

                .list();

for(Task task:list ){

System.out.println("id="+task.getId());

System.out.println("name="+task.getName());

System.out.println("assinee="+task.getAssignee());

System.out.println("assinee="+task.getCreateTime());

System.out.println("executionId="+task.getExecutionId());

}

}

//查詢組任務列表

@Test

public void findGroupList(){

String userId = "大大";

List<Task> list = processEngine.getTaskService()//

                .createTaskQuery()//

                .taskCandidateUser(userId)//指定組任務查詢

                .list();

for(Task task:list ){

System.out.println("id="+task.getId());

System.out.println("name="+task.getName());

System.out.println("assinee="+task.getAssignee());

System.out.println("assinee="+task.getCreateTime());

System.out.println("executionId="+task.getExecutionId());

System.out.println("##################################");

}

}

//查詢組任務成員列表

@Test

public void findGroupUser(){

String taskId = "3709";

List<IdentityLink> list = processEngine.getTaskService()//

                .getIdentityLinksForTask(taskId);

for(IdentityLink identityLink:list ){

System.out.println("userId="+identityLink.getUserId());

System.out.println("taskId="+identityLink.getTaskId());

System.out.println("piId="+identityLink.getProcessInstanceId());

System.out.println("######################");

}

}

//查詢組任務成員歷史列表

@Test

public void findGroupHisUser(){

String taskId = "3709";

List<HistoricIdentityLink> list = processEngine.getHistoryService()//

.getHistoricIdentityLinksForTask(taskId);

for(HistoricIdentityLink identityLink:list ){

System.out.println("userId="+identityLink.getUserId());

System.out.println("taskId="+identityLink.getTaskId());

System.out.println("piId="+identityLink.getProcessInstanceId());

System.out.println("######################");

}

}

//完成任務

@Test

public void completeTask(){

String taskId = "3709";

processEngine.getTaskService()//

.complete(taskId);//

System.out.println("完成任務");

}

 

     /**將組任務分配給我的任務,拾取任務*/

//由1我的去完成任務

@Test

public void claim(){

//任務ID

String taskId = "5908";

//分配的辦理人

String userId = "小B";

processEngine.getTaskService()//

.claim(taskId, userId);

}

 

說明:

1) 大大,中中,小小是組任務的辦理人

2) 在開發中,能夠在頁面中指定下一個組任務的辦理人,經過流程變量設置下一個任務的辦理人

16.2.4::分配我的任務方式三(使用類)

1:流程圖中任務節點的配置

此時流程圖的XML文件,如圖:

2:TaskListenerImpl類,用來設置任務的辦理人

public class TaskListenerImplimplements TaskListener {

 

/**指定我的任務和組任務的辦理人*/

@Override

public void notify(DelegateTask delegateTask) {

String userId1 = "孫悟空";

String userId2 = "豬八戒";

//指定組任務

delegateTask.addCandidateUser(userId1);

delegateTask.addCandidateUser(userId2);

}

 

}

3:測試代碼

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//部署流程定義,啓動流程實例

@Test

public void testTask()throws Exception {

// 1 發佈流程

InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn");

InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png");

processEngine.getRepositoryService()//

.createDeployment()//

.addInputStream("userTask.bpmn", inputStreamBpmn)//

.addInputStream("userTask.png", inputStreamPng)//

.deploy();

// 2 啓動流程

ProcessInstance pi = processEngine.getRuntimeService()//

.startProcessInstanceByKey("taskProcess");

System.out.println("pid:" + pi.getId());

}

//查詢個人我的任務列表

@Test

public void findMyTaskList(){

String userId = "孫悟空";

List<Task> list = processEngine.getTaskService()//

                .createTaskQuery()//

                .taskAssignee(userId)//指定我的任務查詢

                .list();

for(Task task:list ){

System.out.println("id="+task.getId());

System.out.println("name="+task.getName());

System.out.println("assinee="+task.getAssignee());

System.out.println("assinee="+task.getCreateTime());

System.out.println("executionId="+task.getExecutionId());

}

}

//查詢組任務列表

@Test

public void findGroupList(){

String userId = "孫悟空";

List<Task> list = processEngine.getTaskService()//

                .createTaskQuery()//

                .taskCandidateUser(userId)//指定組任務查詢

                .list();

for(Task task:list ){

System.out.println("id="+task.getId());

System.out.println("name="+task.getName());

System.out.println("assinee="+task.getAssignee());

System.out.println("assinee="+task.getCreateTime());

System.out.println("executionId="+task.getExecutionId());

System.out.println("##################################");

}

}

//查詢組任務成員列表

@Test

public void findGroupUser(){

String taskId = "4008";

List<IdentityLink> list = processEngine.getTaskService()//

                .getIdentityLinksForTask(taskId);

for(IdentityLink identityLink:list ){

System.out.println("userId="+identityLink.getUserId());

System.out.println("taskId="+identityLink.getTaskId());

System.out.println("piId="+identityLink.getProcessInstanceId());

System.out.println("######################");

}

}

//查詢組任務成員歷史列表

@Test

public void findGroupHisUser(){

String taskId = "4008";

List<HistoricIdentityLink> list = processEngine.getHistoryService()//

.getHistoricIdentityLinksForTask(taskId);

for(HistoricIdentityLink identityLink:list ){

System.out.println("userId="+identityLink.getUserId());

System.out.println("taskId="+identityLink.getTaskId());

System.out.println("piId="+identityLink.getProcessInstanceId());

System.out.println("######################");

}

}

//完成任務

@Test

public void completeTask(){

String taskId = "4008";

processEngine.getTaskService()//

.complete(taskId);//

System.out.println("完成任務");

}

//將組任務分配給我的任務(認領任務)

@Test

public void claimTask(){

String taskId = "4008";

//我的任務的辦理人

String userId = "如來";

processEngine.getTaskService().claim(taskId, userId);

}

 

//能夠分配我的任務回退到組任務,(前提以前是個組任務)

@Test

public void setAssigneeTask(){

//任務ID

String taskId = "4008";

processEngine.getTaskService()//

.setAssignee(taskId, null);

}

//向組任務中添加成員

@Test

public void addUser(){

String taskId = "4008";

String userId = "沙和尚";

processEngine.getTaskService().addCandidateUser(taskId, userId);

}

 

//向組任務中刪除成員

@Test

public void removeUser(){

String taskId = "4008";

String userId = "沙和尚";

processEngine.getTaskService().deleteCandidateUser(taskId, userId);

}

說明:

1) 在類中使用delegateTask.addCandidateUser (userId);的方式分配組任務的辦理人,此時孫悟空和豬八戒是下一個任務的辦理人。

2) 經過processEngine.getTaskService().claim (taskId, userId);將組任務分配給我的任務,也叫認領任務,即指定某我的去辦理這個任務,此時由如來去辦理任務。

注意:認領任務的時候,能夠是組任務成員中的人,也能夠不是組任務成員的人,此時經過Type的類型爲participant來指定任務的辦理人

3) addCandidateUser()即向組任務添加成員,deleteCandidateUser()即刪除組任務的成員。

4) 在開發中,能夠將每個任務的辦理人規定好,例如張三的領導是李四和王五,這樣張三提交任務,由李四或者王五去查詢組任務,能夠看到對應張三的申請,李四或王五再經過認領任務(claim)的方式,由某我的去完成這個任務。

16.2.5:總結

組任務及三種分配方式:

    1:在taskProcess.bpmn中直接寫 candidate-users=「小A,小B,小C,小D"

    2:在taskProcess.bpmn中寫 candidate-users =「#{userIDs}」,變量的值要是String的。

         使用流程變量指定辦理人

              Map<String, Object> variables = new HashMap<String, Object>();

              variables.put("userIDs", "大大,小小,中中");

    3,使用TaskListener接口,使用類實現該接口,在類中定義:

            //添加組任務的用戶

delegateTask.addCandidateUser(userId1);

delegateTask.addCandidateUser(userId2);

組任務分配給我的任務(認領任務):

     processEngine.getTaskService().claim(taskId, userId);

我的任務分配給組任務:

     processEngine.getTaskService(). setAssignee(taskId, null);

向組任務添加人員:

     processEngine.getTaskService().addCandidateUser(taskId, userId);

向組任務刪除人員:

     processEngine.getTaskService().deleteCandidateUser(taskId, userId);

我的任務和組任務存放辦理人對應的表:

act_ru_identitylink表存聽任務的辦理人,包括我的任務和組任務,表示正在執行的任務

act_hi_identitylink表存聽任務的辦理人,包括我的任務和組任務,表示歷史任務

區別在於:若是是我的任務TYPE的類型表示participant(參與者)

 若是是組任務TYPE的類型表示candidate(候選者)和participant(參與者)

這裏注意:組任務在項目中最好的處理方式是先拾取(claim())任務,即指定某我的去辦理任務。這樣就能夠在正在執行(歷史的)任務表中能夠跟着當前任務的辦理人,不然該字段(ASSIGNEE)爲null,就沒法跟蹤當前辦理人。

 

第一種方式是固定的組任務的執行人

第二種方式是在代碼中經過流程變量的形式給組任務的執行人賦值,這樣作的缺點是在進入該節點以前,必須給組任務賦值候選人

第三種方式能夠在進入該組任務的時候,執行TaskListener,從而給組任務的候選人賦值。

      缺點一、若是在TaskListener中操做了數據庫,這意味着只要進入該節點就得操做數據庫一次。

      缺點二、這個類不能放入到spring容器中,因此該類中的方法不能使用spring的聲明式事務處理

      優勢:能夠在方法中引入servletConetxt或者ApplicationContext

 

 

16.3:工做流定義的角色組(瞭解)

16.3.1:流程圖

流程圖中任務節點的配置:

分配任務負責的組

使用 candidate groups 屬性指定 任務負責組

代碼: 

<userTask id=「usertask1」 name=「審批」 activiti:candidateGroups=「部門經理」>

</userTask>    

 

其中部門經理表示一個用戶組的角色

16.3.2:測試代碼

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//部署流程定義,啓動流程實例

@Test

public void testTask()throws Exception {

// 1 發佈流程

InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn");

InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png");

processEngine.getRepositoryService()//

.createDeployment()//

.addInputStream("userTask.bpmn", inputStreamBpmn)//

.addInputStream("userTask.png", inputStreamPng)//

.deploy();

/**在部署流程定義和啓動流程實例的中間,設置組任務的辦理人,向Activity表中存放組和用戶的信息*/

IdentityService identityService = processEngine.getIdentityService();//認證:保存組和用戶信息

identityService.saveGroup(new GroupEntity("部門經理"));//創建組

identityService.saveGroup(new GroupEntity("總經理"));//創建組

identityService.saveUser(new UserEntity("小張"));

identityService.saveUser(new UserEntity("小李"));

identityService.saveUser(new UserEntity("小王"));

identityService.createMembership("小張", "部門經理");//創建組和用戶關係

identityService.createMembership("小李", "部門經理");//創建組和用戶關係

identityService.createMembership("小王", "總經理");//創建組和用戶關係

 

// 2 啓動流程

ProcessInstance pi = processEngine.getRuntimeService()//

.startProcessInstanceByKey("taskProcess");

System.out.println("pid:" + pi.getId());

}

//查詢個人我的任務列表

@Test

public void findMyTaskList(){

String userId = "唐僧";

List<Task> list = processEngine.getTaskService()//

                .createTaskQuery()//

                .taskAssignee(userId)//指定我的任務查詢

                .list();

for(Task task:list ){

System.out.println("id="+task.getId());

System.out.println("name="+task.getName());

System.out.println("assinee="+task.getAssignee());

System.out.println("assinee="+task.getCreateTime());

System.out.println("executionId="+task.getExecutionId());

}

}

//查詢組任務列表

@Test

public void findGroupList(){

String userId = "小李";//小張,小李能夠查詢結果,小王不能夠,由於他不是部門經理

List<Task> list = processEngine.getTaskService()//

                .createTaskQuery()//

                .taskCandidateUser(userId)//指定組任務查詢

                .list();

for(Task task:list ){

System.out.println("id="+task.getId());

System.out.println("name="+task.getName());

System.out.println("assinee="+task.getAssignee());

System.out.println("assinee="+task.getCreateTime());

System.out.println("executionId="+task.getExecutionId());

System.out.println("##################################");

}

}

//查詢組任務成員列表

@Test

public void findGroupUser(){

String taskId = "4408";

List<IdentityLink> list = processEngine.getTaskService()//

                .getIdentityLinksForTask(taskId);

for(IdentityLink identityLink:list ){

System.out.println("userId="+identityLink.getUserId());

System.out.println("taskId="+identityLink.getTaskId());

System.out.println("piId="+identityLink.getProcessInstanceId());

System.out.println("######################");

}

}

//完成任務

@Test

public void completeTask(){

String taskId = "5108";

processEngine.getTaskService()//

.complete(taskId);//

System.out.println("完成任務");

}

}

16.3.3:分配任務負責的組(IdentityService)

/**在部署流程定義和啓動流程實例的中間,設置組任務的辦理人,向Activiti表中存放組和用戶的信息*/

IdentityService identityService = processEngine.getIdentityService();//認證:保存組和用戶信息

identityService.saveGroup(new GroupEntity("部門經理"));//創建組

identityService.saveGroup(new GroupEntity("總經理"));//創建組

identityService.saveUser(new UserEntity(「小張」));//創建用戶

identityService.saveUser(new UserEntity("小李")); //創建用戶

identityService.saveUser(new UserEntity("小王")); //創建用戶

identityService.createMembership("小張", "部門經理");//創建組和用戶關係

identityService.createMembership("小李", "部門經理");//創建組和用戶關係

identityService.createMembership(「小王」, 「總經理」);//創建組和用戶關係

表結構介紹

act_id_group:角色組表

act_id_user:用戶表:

act_id_membership:用戶角色表

指定組任務的辦理人,查詢組任務

String userId = 「小張」;//小張,小李能夠查詢結果,小王不能夠,由於他不是部門經理角色

List<Task> list = processEngine.getTaskService()//

                .createTaskQuery()//

                .taskCandidateUser(userId)//指定組任務查詢

                .list();

Activiti總結:

相關文章
相關標籤/搜索