Activiti最全入门教程
工作流(Workflow),就是“業(yè)務過程的部分或整體在計算機應用環(huán)境下的自動化”,它主要解決的是“使在多個參與者之間按照某種預定義的規(guī)則傳遞文檔、信息或任務的過程自動進行,從而實現(xiàn)某個預期的業(yè)務目標,或者促使此目標的實現(xiàn)”。?
工作流管理系統(tǒng)(Workflow Management System, WfMS)是一個軟件系統(tǒng),它完成工作量的定義和管理,并按照在系統(tǒng)中預先定義好的工作流規(guī)則進行工作流實例的執(zhí)行。工作流管理系統(tǒng)不是企業(yè)的業(yè)務系統(tǒng),而是為企業(yè)的業(yè)務系統(tǒng)的運行提供了一個軟件的支撐環(huán)境。?
工作流管理聯(lián)盟(WfMC,Workflow Management Coalition)給出的關于工作流管理系統(tǒng)的定義是:工作流管理系統(tǒng)是一個軟件系統(tǒng),它通過執(zhí)行經(jīng)過計算的流程定義去支持一批專門設定的業(yè)務流程。工作流管理系統(tǒng)被用來定義、管理、和執(zhí)行工作流程。?
工作流管理系統(tǒng)的目標:管理工作的流程以確保工作在正確的時間被期望的人員所執(zhí)行——在自動化進行的業(yè)務過程中插入人工的執(zhí)行和干預。?
3:Activiti介紹?
Activiti5是由Alfresco軟件在2010年5月17日發(fā)布的業(yè)務流程管理(BPM)框架,它是覆蓋了業(yè)務流程管理、工作流、服務協(xié)作等領域的一個開源的、靈活的、易擴展的可執(zhí)行流程語言框架。Activiti基于Apache許可的開源BPM平臺,創(chuàng)始人Tom Baeyens是JBoss jBPM的項目架構師,它特色是提供了eclipse插件,開發(fā)人員可以通過插件直接繪畫出業(yè)務?
流程圖。?
3.1:工作流引擎?
ProcessEngine對象,這是Activiti工作的核心。負責生成流程運行時的各種實例及數(shù)據(jù)、監(jiān)控和管理流程的運行。?
3.2:BPMN?
業(yè)務流程建模與標注(Business Process Model and Notation,BPMN) ,描述流程的基本符號,包括這些圖元如何組合成一個業(yè)務流程圖(Business Process Diagram)
3.3:數(shù)據(jù)庫(先了解后看)?
Activiti數(shù)據(jù)庫支持:?
Activiti的后臺是有數(shù)據(jù)庫的支持,所有的表都以ACT_開頭。 第二部分是表示表的用途的兩個字母標識。 用途也和服務的API對應。?
ACT_RE_*: ‘RE’表示repository。 這個前綴的表包含了流程定義和流程靜態(tài)資源 (圖片,規(guī)則,等等)。?
ACT_RU_*: ‘RU’表示runtime。 這些運行時的表,包含流程實例,任務,變量,異步任務,等運行中的數(shù)據(jù)。 Activiti只在流程實例執(zhí)行過程中保存這些數(shù)據(jù), 在流程結束時就會刪除這些記錄。 這樣運行時表可以一直很小速度很快。?
ACT_ID_*: ‘ID’表示identity。 這些表包含身份信息,比如用戶,組等等。?
ACT_HI_*: ‘HI’表示history。 這些表包含歷史數(shù)據(jù),比如歷史流程實例, 變量,任務等等。?
ACT_GE_*: 通用數(shù)據(jù), 用于不同場景下,如存放資源文件。
表結構操作:?
3.3.1:資源庫流程規(guī)則表?
1) act_re_deployment 部署信息表?
2) act_re_model 流程設計模型部署表?
3) act_re_procdef 流程定義數(shù)據(jù)表?
3.3.2:運行時數(shù)據(jù)庫表?
1) act_ru_execution 運行時流程執(zhí)行實例表?
2) act_ru_identitylink 運行時流程人員表,主要存儲任務節(jié)點與參與者的相關信息?
3) act_ru_task 運行時任務節(jié)點表?
4) act_ru_variable 運行時流程變量數(shù)據(jù)表?
3.3.3:歷史數(shù)據(jù)庫表?
1) act_hi_actinst 歷史節(jié)點表?
2) act_hi_attachment 歷史附件表?
3) act_ih_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 用戶信息表?
這四張表很常見,基本的組織機構管理,關于用戶認證方面建議還是自己開發(fā)一套,組件自帶的功能太簡單,使用中有很多需求難以滿足?
3.3.5:通用數(shù)據(jù)表?
1) act_ge_bytearray 二進制數(shù)據(jù)表?
2) act_ge_property 屬性數(shù)據(jù)表存儲整個流程引擎級別的數(shù)據(jù),初始化表結構時,會默認插入三條記錄,?
3.4:activiti.cfg.xml(activiti的配置文件)?
Activiti核心配置文件,配置流程引擎創(chuàng)建工具的基本參數(shù)和數(shù)據(jù)庫連接池參數(shù)。?
定義數(shù)據(jù)庫配置參數(shù):?
? jdbcUrl: 數(shù)據(jù)庫的JDBC URL。?
? jdbcDriver: 對應不同數(shù)據(jù)庫類型的驅動。?
? jdbcUsername: 連接數(shù)據(jù)庫的用戶名。?
? jdbcPassword: 連接數(shù)據(jù)庫的密碼。?
基于JDBC參數(shù)配置的數(shù)據(jù)庫連接 會使用默認的MyBatis連接池。 下面的參數(shù)可以用來配置連接池(來自MyBatis參數(shù)):?
? jdbcMaxActiveConnections: 連接池中處于被使用狀態(tài)的連接的最大值。默認為10。?
? jdbcMaxIdleConnections: 連接池中處于空閑狀態(tài)的連接的最大值。?
? jdbcMaxCheckoutTime: 連接被取出使用的最長時間,超過時間會被強制回收。 默認為20000(20秒)。?
? jdbcMaxWaitTime: 這是一個底層配置,讓連接池可以在長時間無法獲得連接時, 打印一條日志,并重新嘗試獲取一個連接。(避免因為錯誤配置導致沉默的操作失敗)。 默認為20000(20秒)。?
示例數(shù)據(jù)庫配置:?
也可以使用javax.sql.DataSource。 (比如,Apache Commons的DBCP):?
?
3.5:logging.properties(日志處理)?
日志的配置文件,Activiti操作數(shù)據(jù)庫的時候,整合的日志文件?
4:準備環(huán)境?
4.1:activiti5 軟件環(huán)境?
1) JDK1.6或者更高版本?
2) 支持的數(shù)據(jù)庫有:h2, mysql, oracle, postgres, mssql, db2等。?
3) 支持activiti5運行的jar包?
4) 開發(fā)環(huán)境為Eclipse3.7或者以上版本,myeclipse為8.6版本?
4.2:相關資源下載?
1) JDK可以到sun的官網(wǎng)下載?
http://www.oracle.com/technetwork/java/javase/downloads/index.html?
2) 數(shù)據(jù)庫,例如:mysql可以在官網(wǎng)上下載。?
http://www.mysql.com?
3) activiti也可以到Activiti官方網(wǎng)站下載得到。?
http://activiti.org/download.html?
4) Eclipse3.7或者MyEclipse8.6也可以到相應的網(wǎng)站上獲得下載。?
4.3:安裝流程設計器(eclipse插件)?
4.3.1:安裝方式一?
在有網(wǎng)絡的情況下,安裝流程設計器步驟如下:?
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.3.2:安裝方式二?
在沒有網(wǎng)絡的情況下,安裝流程設計器步驟如下:?
1) 解壓老師發(fā)給大家的 壓縮包?
2) 把壓縮包中的內容放入eclipse根目錄的dropins文件夾下?
3) 重啟eclipse,點擊新建工程new->Other…打開面板,如果看到下圖內容:?
?
說明安裝成功了?
4.4:對流程設計器的使用說明?
打開菜單Windows->Preferences->Activiti->Save下流程流程圖片的生成方式:?
?
雖然流程引擎在單獨部署bpmn文件時會自動生成圖片,但在實際開發(fā)過程中,自動生成的圖片會導致和BPMN中的坐標有出入,在實際項目中展示流程當前位置圖會有問題。?
所在完成以上配置后,會由我們自己來管理流程圖片。在發(fā)布流程時把流程規(guī)則文件和流程圖片一起上傳就行了。?
4.5:準備Activiti5開發(fā)環(huán)境?
4.5.1:添加Activiti5的jar包?
在activiti-5.13->wars目錄下是一些示例項目,解壓activiti-rest項目,導入activiti-rest目錄中WEB-INF\lib下所有包。添加到classpath中。?
由于我們使用的是Mysql數(shù)據(jù)庫,Mysql數(shù)據(jù)庫的鏈接驅動Activiti官方包中并沒有提供,需要我們自己導入。手動導入mysql-connector-java.jar,添加到classpath下。?
4.5.2:初始化數(shù)據(jù)庫?
在Activiti中,在創(chuàng)建核心的流程引擎對象時會自動建表。如果程序正常執(zhí)行,mysql會自動建庫,然后創(chuàng)建23張表。
4.5.3:添加并制定配置文件?
在Actiiti5中定制流程必定會操作到數(shù)據(jù)庫,如果都像上面那樣寫一大段代碼會非常麻煩,所以我們可以把數(shù)據(jù)庫連接配置寫入配置文件。?
在Activiti5的官方示例中并沒有現(xiàn)成的配置文件,所以先得找到activiti-rest\WEB-INF\classes下有:
4.5.3.1:activiti-context.xml :?
一個類似spring結構的配置文件,清空內容后改名為activiti.cfg.xml,用來做流程引擎的相關配置。?
按照上面代碼配置ProcessEngineConfiguration對象,主要定義數(shù)據(jù)庫的連接配置和建表策略,配置文件代碼如下:?
Java代碼如下:?
createProcessEngineConfigurationFromResource的參數(shù)值為我們添加的配置文件activiti.cfg.xml的名稱,執(zhí)行java代碼,流程引擎對象創(chuàng)建成功運行后數(shù)據(jù)庫會自動建表。
/**使用代碼創(chuàng)建工作流需要的23張表*/
@Test
public void createTable(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
//連接數(shù)據(jù)庫的配置
processEngineConfiguration.setJdbcDriver("com.mysql.jdbc.Driver");
processEngineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/shareniu?useUnicode=true&characterEncoding=utf8");
processEngineConfiguration.setJdbcUsername("root");
processEngineConfiguration.setJdbcPassword("root");
/**
public static final String DB_SCHEMA_UPDATE_FALSE = "false";不能自動創(chuàng)建表,需要表存在
public static final String DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop";先刪除表再創(chuàng)建表
public static final String DB_SCHEMA_UPDATE_TRUE = "true";如果表不存在,自動創(chuàng)建表
*/
processEngineConfiguration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
//工作流的核心對象,ProcessEnginee對象
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
System.out.println("processEngine:"+processEngine);
}
/**使用配置文件創(chuàng)建工作流需要的23張表*/
@Test
public void createTable_2(){
// ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
// //工作流的核心對象,ProcessEnginee對象
// ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
ProcessEngine processEngine = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml") //
.buildProcessEngine();
System.out.println("processEngine:"+processEngine);
}
4.5.3.2:log4j.properties 日志配置文件?
把兩個文件放入resource目錄下即可。
5:核心API?
5.1:ProcessEngine?
說明:?
1) 在Activiti中最核心的類,其他的類都是由他而來。?
2) 產(chǎn)生方式:
在前面看到了兩種創(chuàng)建ProcessEngine(流程引擎)的方式,而這里要簡化很多,調用ProcessEngines的getDefaultProceeEngine方法時會自動加載classpath下名為activiti.cfg.xml文件。?
3) 可以產(chǎn)生RepositoryService
4) 可以產(chǎn)生RuntimeService
5) 可以產(chǎn)生TaskService
各個Service的作用:?
RepositoryService 管理流程定義?
RuntimeService 執(zhí)行管理,包括啟動、推進、刪除流程實例等操作?
TaskService 任務管理?
HistoryService 歷史管理(執(zhí)行完的數(shù)據(jù)的管理)?
IdentityService 組織機構管理?
FormService 一個可選服務,任務表單管理?
ManagerService
5.2:RepositoryService?
是Activiti的倉庫服務類。所謂的倉庫指流程定義文檔的兩個文件:bpmn文件和流程圖片。?
1) 產(chǎn)生方式
2) 可以產(chǎn)生DeploymentBuilder,用來定義流程部署的相關參數(shù)
3) 刪除流程定義
5.3:RuntimeService?
是activiti的流程執(zhí)行服務類。可以從這個服務類中獲取很多關于流程執(zhí)行相關的信息。?
5.4:TaskService?
是activiti的任務服務類。可以從這個類中獲取任務的信息。?
5.5:HistoryService?
是activiti的查詢歷史信息的類。在一個流程執(zhí)行完成后,這個對象為我們提供查詢歷史信息。?
5.6:ProcessDefinition?
流程定義類。可以從這里獲得資源文件等。?
5.7:ProcessInstance?
代表流程定義的執(zhí)行實例。如范冰冰請了一天的假,她就必須發(fā)出一個流程實例的申請。一個流程實例包括了所有的運行節(jié)點。我們可以利用這個對象來了解當前流程實例的進度等信息。流程實例就表示一個流程從開始到結束的最大的流程分支,即一個流程中流程實例只有一個。?
5.8:Execution?
Activiti用這個對象去描述流程執(zhí)行的每一個節(jié)點。在沒有并發(fā)的情況下,Execution就是同ProcessInstance。流程按照流程定義的規(guī)則執(zhí)行一次的過程,就可以表示執(zhí)行對象Execution。?
如圖為ProcessInstance的源代碼:?
從源代碼中可以看出ProcessInstance就是Execution。但在現(xiàn)實意義上有所區(qū)別:?
?
在單線流程中,如上圖的貸款流程,ProcessInstance與Execution是一致的。?
?
這個例子有一個特點:wire money(匯錢)和archive(存檔)是并發(fā)執(zhí)行的。 這個時候,總線路代表ProcessInstance,而分線路中每個活動代表Execution。?
總結:?
* 一個流程中,執(zhí)行對象可以存在多個,但是流程實例只能有一個。?
* 當流程按照規(guī)則只執(zhí)行一次的時候,那么流程實例就是執(zhí)行對象。
6:HelloWorld程序(模擬流程的執(zhí)行)?
6.1:流程圖:
?
6.2:部署流程定義?
?
這里使用RepositoryService部署流程定義?
addClasspathResource表示從類路徑下加載資源文件,一次只能加載一個文件?
6.3:啟動流程實例?
?
這里使用RuntimeService啟動流程實例?
6.4:查看我的個人任務?
?
這里使用TaskService完成任務的查詢?
6.5:完成我的個人任務?
?
這里使用TaskService完成任務的辦理
7:管理流程定義?
7.1:設計流程定義文檔?
7.1.1:流程圖?
?
7.1.2:bpmn文件?
BPMN 2.0根節(jié)點是definitions節(jié)點。 這個元素中,可以定義多個流程定義(不過我們建議每個文件只包含一個流程定義, 可以簡化開發(fā)過程中的維護難度)。 一個空的流程定義看起來像下面這樣。注意,definitions元素 最少也要包含xmlns 和 targetNamespace的聲明。 targetNamespace可以是任意值,它用來對流程實例進行分類。?
?
說明:流程定義文檔有兩部分組成:?
1) bpmn文件?
流程規(guī)則文件。在部署后,每次系統(tǒng)啟動時都會被解析,把內容封裝成流程定義放入項目緩存中。Activiti框架結合這個xml文件自動管理流程,流程的執(zhí)行就是按照bpmn文件定義的規(guī)則執(zhí)行的,bpmn文件是給計算機執(zhí)行用的。?
2) 展示流程圖的圖片?
在系統(tǒng)里需要展示流程的進展圖片,圖片是給用戶看的。
7.2:部署流程定義(classpath路徑加載文件)?
?
說明:?
1) 先獲取流程引擎對象:在創(chuàng)建時會自動加載classpath下的activiti.cfg.xml
2) 首先獲得默認的流程引擎,通過流程引擎獲取了一個RepositoryService對象(倉庫對象)?
3) 由倉庫的服務對象產(chǎn)生一個部署對象配置對象,用來封裝部署操作的相關配置。?
4) 這是一個鏈式編程,在部署配置對象中設置顯示名,上傳流程定義規(guī)則文件?
5) 向數(shù)據(jù)庫表中存放流程定義的規(guī)則信息。?
6) 這一步在數(shù)據(jù)庫中將操作三張表:?
a) act_re_deployment(部署對象表)?
存放流程定義的顯示名和部署時間,每部署一次增加一條記錄。?
?
Deployment deployment = processEngine.getRepositoryService()//?
.createDeployment().name(“入門程序”)//?
.addClasspathResource(“hello/helloworld.bpmn”)// 從classpath的資源中加載,一次只能加載一個文件?
// .addClasspathResource(“diagrams/helloworld.png”)//?
// 從classpath的資源中加載,一次只能加載一個文件?
.deploy();?
b) act_re_procdef(流程定義表)?
存放流程定義的屬性信息,部署每個新的流程定義都會在這張表中增加一條記錄。?
注意:當流程定義的key相同的情況下,使用的是版本升級?
?
對應的封裝類:
public interface ProcessDefinition {
String getId();
String getCategory();
String getName();
String getKey();
String getDescription();
int getVersion();
String getResourceName();
String getDeploymentId();
String getDiagramResourceName();
boolean hasStartFormKey();
boolean isSuspended();
}
代碼的操作:?
/* 查詢流程定義?/
@Test
public void findProcessDefinition() {
List<ProcessDefinition> list = processEngine.getRepositoryService()// 與流程定義和部署對象相關的Service
.createProcessDefinitionQuery()// 創(chuàng)建一個流程定義的查詢
/** 指定查詢條件,where條件 */
// .deploymentId(deploymentId)//使用部署對象ID查詢
// .processDefinitionId(processDefinitionId)//使用流程定義ID查詢
// .processDefinitionKey(processDefinitionKey)//使用流程定義的key查詢
// .processDefinitionNameLike(processDefinitionNameLike)//使用流程定義的名稱模糊查詢
/** 排序 */
.orderByProcessDefinitionVersion().asc()// 按照版本的升序排列
// .orderByProcessDefinitionName().desc()//按照流程定義的名稱降序排列
/** 返回的結果集 */
.list();// 返回一個集合列表,封裝流程定義
// .singleResult();//返回惟一結果集
// .count();//返回結果集數(shù)量
// .listPage(firstResult, maxResults);//分頁查詢
if (list != null && list.size() > 0) {
for (ProcessDefinition pd : list) {
System.out.println("流程定義ID:" + pd.getId());// 流程定義的key+版本+隨機生成數(shù)
System.out.println("流程定義的名稱:" + pd.getName());// 對應helloworld.bpmn文件中的name屬性值
System.out.println("流程定義的key:" + pd.getKey());// 對應helloworld.bpmn文件中的id屬性值
System.out.println("流程定義的版本:" + pd.getVersion());// 當流程定義的key值相同的相同下,版本升級,默認1
System.out.println("資源名稱bpmn文件:" + pd.getResourceName());
System.out.println("資源名稱png文件:" + pd.getDiagramResourceName());
System.out.println("部署對象ID:" + pd.getDeploymentId());
System.out
.println("#########################################################");
}
}
}
程序的輸出:?
流程定義ID:helloworld:1:4?
流程定義的名稱:helloworldProcess?
流程定義的key:helloworld?
流程定義的版本:1?
資源名稱bpmn文件:hello/helloworld.bpmn?
資源名稱png文件:hello/helloworld.helloworld.png?
部署對象ID:1?
c) act_ge_bytearray(資源文件表)?
存儲流程定義相關的部署信息。即流程定義文檔的存放地。每部署一次就會增加兩條記錄,一條是關于bpmn規(guī)則文件的,一條是圖片的(如果部署時只指定了bpmn一個文件,activiti會在部署時解析bpmn文件內容自動生成流程圖)。兩個文件不是很大,都是以二進制形式存儲在數(shù)據(jù)庫中。?
7.3:部署流程定義(zip格式文件)?
?
?
將?
壓縮成zip格式的文件,使用zip的輸入流用作部署流程定義
7.4:查看流程定義?
查詢流程定義的信息?
?
結果:?
?
再部署一次運行結果為:?
?
可以看到流程定義的key值相同的情況下,版本是從1開始逐次升級的?
流程定義的Id是【key:版本:生成ID】?
說明:?
1) 流程定義和部署對象相關的Service都是RepositoryService。?
2) 創(chuàng)建流程定義查詢對象,可以在ProcessDefinitionQuery上設置查詢的相關參數(shù)?
3) 調用ProcessDefinitionQuery對象的list方法,執(zhí)行查詢,獲得符合條件的流程定義列表?
4) 由運行結果可以看出:?
Key和Name的值為:bpmn文件process節(jié)點的id和name的屬性值?
?
5) key屬性被用來區(qū)別不同的流程定義。?
6) 帶有特定key的流程定義第一次部署時,version為1。之后每次部署都會在當前最高版本號上加1?
7) Id的值的生成規(guī)則為:{processDefinitionKey}:{processDefinitionVersion}:{generated-id}, 這里的generated-id是一個自動生成的唯一的數(shù)字?
8) 重復部署一次,deploymentId的值以一定的形式變化?
規(guī)則act_ge_property表生成?
?
7.5:刪除流程定義?
刪除部署到activiti中的流程定義。?
?
說明:?
1) 因為刪除的是流程定義,而流程定義的部署是屬于倉庫服務的,所以應該先得到RepositoryService?
2) 如果該流程定義下沒有正在運行的流程,則可以用普通刪除。如果是有關聯(lián)的信息,用級聯(lián)刪除。項目開發(fā)中使用級聯(lián)刪除的情況比較多,刪除操作一般只開放給超級管理員使用。?
7.6:獲取流程定義文檔的資源(查看流程圖附件)?
查詢出流程定義文檔。主要查的是圖片,用于顯示流程用。?
?
說明:?
1) deploymentId為流程部署ID?
2) resourceName為act_ge_bytearray表中NAME_列的值?
3) 使用repositoryService的getDeploymentResourceNames方法可以獲取指定部署下得所有文件的名稱?
4) 使用repositoryService的getResourceAsStream方法傳入部署ID和資源圖片名稱可以獲取部署下指定名稱文件的輸入流?
5) 最后的有關IO流的操作,使用FileUtils工具的copyInputStreamToFile方法完成流程流程到文件的拷貝,將資源文件以流的形式輸出到指定文件夾下?
7.7:附加功能:查詢最新版本的流程定義?
?
Key value保存 key 為key value為流程定義?
代碼:?
/*附加功能:查詢最新版本的流程定義*/
@Test
public void findLastVersionProcessDefinition(){
List<ProcessDefinition> list = processEngine.getRepositoryService()//
.createProcessDefinitionQuery()//
.orderByProcessDefinitionVersion().asc()//使用流程定義的版本升序排列
.list();
/**
* Map<String,ProcessDefinition>
map集合的key:流程定義的key
map集合的value:流程定義的對象
map集合的特點:當map集合key值相同的情況下,后一次的值將替換前一次的值
*/
Map<String, ProcessDefinition> map = new LinkedHashMap<String, ProcessDefinition>();
if(list!=null && list.size()>0){
for(ProcessDefinition pd:list){
map.put(pd.getKey(), pd);
}
}
List<ProcessDefinition> pdList = new ArrayList<ProcessDefinition>(map.values());
if(pdList!=null && pdList.size()>0){
for(ProcessDefinition pd:pdList){
System.out.println("流程定義ID:"+pd.getId());//流程定義的key+版本+隨機生成數(shù)
System.out.println("流程定義的名稱:"+pd.getName());//對應helloworld.bpmn文件中的name屬性值
System.out.println("流程定義的key:"+pd.getKey());//對應helloworld.bpmn文件中的id屬性值
System.out.println("流程定義的版本:"+pd.getVersion());//當流程定義的key值相同的相同下,版本升級,默認1
System.out.println("資源名稱bpmn文件:"+pd.getResourceName());
System.out.println("資源名稱png文件:"+pd.getDiagramResourceName());
System.out.println("部署對象ID:"+pd.getDeploymentId());
System.out.println("#########################################################");
}
}
}
7.8:附加功能:刪除流程定義(刪除key相同的所有不同版本的流程定義)?
@Test
public void deleteProcessDefinitionByKey() {
// 流程定義的key
String processDefinitionKey = "helloworld";
// 先使用流程定義的key查詢流程定義,查詢出所有的版本
List<ProcessDefinition> list = processEngine.getRepositoryService()//
.createProcessDefinitionQuery()//
.processDefinitionKey(processDefinitionKey).list();//
// 遍歷,獲取每個流程定義的部署ID
if (list != null && list.size() > 0) {
for(ProcessDefinition pd:list){
//獲取部署ID
String deploymentId = pd.getDeploymentId();
processEngine.getRepositoryService()//
.deleteDeployment(deploymentId, true);
}
}
}
7.9:總結?
Deployment 部署對象?
1、一次部署的多個文件的信息。對于不需要的流程可以刪除和修改。?
2、對應的表:?
act_re_deployment:部署對象表?
act_re_procdef:流程定義表?
act_ge_bytearray:資源文件表?
act_ge_property:主鍵生成策略表
ProcessDefinition 流程定義?
1、解析.bpmn后得到的流程定義規(guī)則的信息,工作流系統(tǒng)就是按照流程定義的規(guī)則執(zhí)行的。
8:流程實例、任務的執(zhí)行?
8.1:流程圖?
?
8.2:部署流程定義?
?
8.3:啟動流程實例?
說明:?
1) 操作數(shù)據(jù)庫的act_ru_execution表,如果是用戶任務節(jié)點,同時也會在act_ru_task添加一條記錄?
act_ru_execution表,#正在執(zhí)行的執(zhí)行對象表 任務結束的之前只有 一個 變化的字段是act_id?
8.4:查詢我的個人任務?
@Test
public void findMyPersonalTask(){
String assignee = "王五";
List<Task> list = processEngine.getTaskService()//與正在執(zhí)行的任務管理相關的Service
.createTaskQuery()//創(chuàng)建任務查詢對象
/**查詢條件(where部分)*/
.taskAssignee(assignee)//指定個人任務查詢,指定辦理人
// .taskCandidateUser(candidateUser)//組任務的辦理人查詢
// .processDefinitionId(processDefinitionId)//使用流程定義ID查詢
// .processInstanceId(processInstanceId)//使用流程實例ID查詢
// .executionId(executionId)//使用執(zhí)行對象ID查詢
/**排序*/
.orderByTaskCreateTime().asc()//使用創(chuàng)建時間的升序排列
/**返回結果集*/
// .singleResult()//返回惟一結果集
// .count()//返回結果集的數(shù)量
// .listPage(firstResult, maxResults);//分頁查詢
.list();//返回列表
if(list!=null && list.size()>0){
for(Task task:list){
System.out.println("任務ID:"+task.getId());
System.out.println("任務名稱:"+task.getName());
System.out.println("任務的創(chuàng)建時間:"+task.getCreateTime());
System.out.println("任務的辦理人:"+task.getAssignee());
System.out.println("流程實例ID:"+task.getProcessInstanceId());
System.out.println("執(zhí)行對象ID:"+task.getExecutionId());
System.out.println("流程定義ID:"+task.getProcessDefinitionId());
System.out.println("########################################################");
}
}
}
輸出:?
任務ID:504?
任務名稱:提交申請?
任務的創(chuàng)建時間:Sat Aug 09 08:50:20 CST 2014?
任務的辦理人:張三?
流程實例ID:501?
執(zhí)行對象ID:501?
流程定義ID:helloworld:1:404?
接口:
public interface Task {
int DEFAULT_PRIORITY = 50;
String getId(); String getName();
void setName(String name);
String getDescription();
void setDescription(String description);
int getPriority();
void setPriority(int priority);
String getOwner();
void setOwner(String owner);
String getAssignee();
void setAssignee(String assignee); DelegationState getDelegationState();
void setDelegationState(DelegationState delegationState);
String getProcessInstanceId();
String getExecutionId();
String getProcessDefinitionId();
Date getCreateTime();
String getTaskDefinitionKey();
Date getDueDate();
void setDueDate(Date dueDate);
void delegate(String userId);
void setParentTaskId(String parentTaskId);
String getParentTaskId();
boolean isSuspended();
Map<String, Object> getTaskLocalVariables();
Map<String, Object> getProcessVariables();
}
說明:?
1) 因為是任務查詢,所以從processEngine中應該得到TaskService?
2) 使用TaskService獲取到任務查詢對象TaskQuery?
3) 為查詢對象添加查詢過濾條件,使用taskAssignee指定任務的辦理者(即查詢指定用戶的代辦任務),同時可以添加分頁排序等過濾條件?
4) 調用list方法執(zhí)行查詢,返回辦理者為指定用戶的任務列表?
5) 任務ID、名稱、辦理人、創(chuàng)建時間可以從act_ru_task表中查到。?
6) Execution與ProcessInstance見5.6和5.7章節(jié)的介紹。在這種情況下,ProcessInstance相當于Execution?
7) 如果assignee屬性為部門經(jīng)理,結果為空。因為現(xiàn)在流程只到了”填寫請假申請”階段,后面的任務還沒有執(zhí)行,即在數(shù)據(jù)庫中沒有部門經(jīng)理可以辦理的任務,所以查詢不到。?
8) 一個Task節(jié)點和Execution節(jié)點是1對1的情況,在task對象中使用Execution_來表示他們之間的關系?
9) 任務ID在數(shù)據(jù)庫表act_ru_task中對應“ID_”列
附加:?
在activiti任務中,主要分為兩大類查詢任務(個人任務和組任務):?
1.確切指定了辦理者的任務,這個任務將成為指定者的私有任務,即個人任務。?
2.無法指定具體的某一個人來辦理的任務,可以把任務分配給幾個人或者一到 多個小組,讓這個范圍內的用戶可以選擇性(如有空余時間時)來辦理這類任務,即組任務。?
先知道個人任務的查詢和辦理,組任務的操作后面講
8.5:辦理任務?
說明:?
1) 是辦理任務,所以從ProcessEngine得到的是TaskService。?
2) 當執(zhí)行完這段代碼,再以員工的身份去執(zhí)行查詢的時候,會發(fā)現(xiàn)這個時候已經(jīng)沒有數(shù)據(jù)了,因為正在執(zhí)行的任務中沒有數(shù)據(jù)。?
3) 對于執(zhí)行完的任務,activiti將從act_ru_task表中刪除該任務,下一個任務會被插入進來。?
4) 以”部門經(jīng)理”的身份進行查詢,可以查到結果。因為流程執(zhí)行到部門經(jīng)理審批這個節(jié)點了。?
5) 再執(zhí)行辦理任務代碼,執(zhí)行完以后以”部門經(jīng)理”身份進行查詢,沒有結果。?
6) 重復第3和4步直到流程執(zhí)行完。?
act_ru_task表:?
8.6:查詢流程狀態(tài)(判斷流程正在執(zhí)行,還是結束)?
?
/* 查詢流程狀態(tài)(判斷流程正在執(zhí)行,還是結束)?/
@Test
public void isProcessEnd() {
String processInstanceId = "501";
ProcessInstance pi = processEngine.getRuntimeService()// 表示正在執(zhí)行的流程實例和執(zhí)行對象
.createProcessInstanceQuery()// 創(chuàng)建流程實例查詢
.processInstanceId(processInstanceId)// 使用流程實例ID查詢
.singleResult();
if (pi == null) {
System.out.println("流程已經(jīng)結束");
} else {
System.out.println("流程沒有結束");
}
}
在流程執(zhí)行的過程中,創(chuàng)建的流程實例ID在整個過程中都不會變,當流程結束后,流程實例將會在正在執(zhí)行的執(zhí)行對象表中(act_ru_execution)被刪除
說明:
1) 因為是查詢流程實例,所以先獲取runtimeService?
2) 創(chuàng)建流程實例查詢對象,設置實例ID過濾參數(shù)?
3) 由于一個流程實例ID只對應一個實例,使用singleResult執(zhí)行查詢返回一個唯一的結果,如果結果數(shù)量大于1,則拋出異常?
4) 判斷指定ID的實例是否存在,如果結果為空,則代表流程結束,實例在正在執(zhí)行的執(zhí)行對象表中已被刪除,轉換成歷史數(shù)據(jù)。?
8.7:附加功能:查詢歷史任務(后面講)?
?
/*查詢歷史任務(后面講)/
@Test
public void findHistoryTask(){
String taskAssignee = "張三";
List<HistoricTaskInstance> list = processEngine.getHistoryService()//與歷史數(shù)據(jù)(歷史表)相關的Service
.createHistoricTaskInstanceQuery()//創(chuàng)建歷史任務實例查詢
.taskAssignee(taskAssignee)//指定歷史任務的辦理人
.list();
if(list!=null && list.size()>0){
for(HistoricTaskInstance hti:list){
System.out.println(hti.getId()+" "+hti.getName()+" "+hti.getProcessInstanceId()+" "+hti.getStartTime()+" "+hti.getEndTime()+" "+hti.getDurationInMillis());
System.out.println("################################");
}
}
}
表《HistoricTaskInstance》?
8.8:附加功能:查詢歷史流程實例(后面講)
?
8.9:總結?
Execution 執(zhí)行對象?
按流程定義的規(guī)則執(zhí)行一次的過程.?
對應的表:?
act_ru_execution: 正在執(zhí)行的信息?
act_hi_procinst:已經(jīng)執(zhí)行完的歷史流程實例信息?
act_hi_actinst:存放歷史所有完成的活動?
ProcessInstance 流程實例?
特指流程從開始到結束的那個最大的執(zhí)行分支,一個執(zhí)行的流程中,流程實例只有1個。
注意?
(1)如果是單例流程,執(zhí)行對象ID就是流程實例ID?
(2)如果一個流程有分支和聚合,那么執(zhí)行對象ID和流程實例ID就不相同?
(3)一個流程中,流程實例只有1個,執(zhí)行對象可以存在多個。
Task 任務?
執(zhí)行到某任務環(huán)節(jié)時生成的任務信息。?
對應的表:?
act_ru_task:正在執(zhí)行的任務信息?
act_hi_taskinst:已經(jīng)執(zhí)行完的歷史任務信息
9:流程變量?
9.1:流程圖?
?
流程變量在整個工作流中扮演很重要的作用。例如:請假流程中有請假天數(shù)、請假原因等一些參數(shù)都為流程變量的范圍。流程變量的作用域范圍是只對應一個流程實例。也就是說各個流程實例的流程變量是不相互影響的。流程實例結束完成以后流程變量還保存在數(shù)據(jù)庫中。?
例如:?
即:
9.2:部署流程定義?
?
說明:?
? 輸入流加載資源文件的3種方式?
?
9.3:啟動流程實例?
?
9.4:設置流程變量?
說明:?
1) 流程變量的作用域就是流程實例,所以只要設置就行了,不用管在哪個階段設置?
2) 基本類型設置流程變量,在taskService中使用任務ID,定義流程變量的名稱,設置流程變量的值。?
3) Javabean類型設置流程變量,需要這個javabean實現(xiàn)了Serializable接口?
4) 設置流程變量的時候,向act_ru_variable這個表添加數(shù)據(jù)
9.5:獲取流程變量?
說明:?
1) 流程變量的獲取針對流程實例(即1個流程),每個流程實例獲取的流程變量時不同的?
2) 使用基本類型獲取流程變量,在taskService中使用任務ID,流程變量的名稱,獲取流程變量的值。?
3) Javabean類型設置獲取流程變量,除了需要這個javabean實現(xiàn)了Serializable接口外,還要求流程變量對象的屬性不能發(fā)生變化,否則拋出異常。?
解決方案,在javabean對象中添加:?
private static final long serialVersionUID = 6757393795687480331L;?
9.6:模擬流程變量的設置和獲取的場景?
?
說明:?
1) RuntimeService對象可以設置流程變量和獲取流程變量?
2) TaskService對象可以設置流程變量和獲取流程變量?
3) 流程實例啟動的時候可以設置流程變量?
4) 任務辦理完成的時候可以設置流程變量?
5) 流程變量可以通過名稱/值的形式設置單個流程變量?
6) 流程變量可以通過Map集合,同時設置多個流程變量?
Map集合的key表示流程變量的名稱?
Map集合的value表示流程變量的值
9.7:查詢歷史的流程變量?
?
說明:?
1)歷史的流程變量查詢,指定流程變量的名稱,查詢act_hi_varinst表(也可以針對,流程實例ID,執(zhí)行對象ID,任務ID查詢)
9.8:流程變量的支持的類型?
如圖是從官網(wǎng)列出來的流程變量的類型:?
?
從圖中可以看出包括了大部分封裝類型和Date、String和實現(xiàn)了Serializable接口的類的類型。?
9.9:總結?
? 1:流程變量?
在流程執(zhí)行或者任務執(zhí)行的過程中,用于設置和獲取變量,使用流程變量在流程傳遞的過程中傳遞業(yè)務參數(shù)。?
對應的表:?
act_ru_variable:正在執(zhí)行的流程變量表?
act_hi_varinst:流程變量歷史表
? 2:擴展知識:setVariable和setVariableLocal的區(qū)別?
setVariable:設置流程變量的時候,流程變量名稱相同的時候,后一次的值替換前一次的值,而且可以看到TASK_ID的字段不會存放任務ID的值?
setVariableLocal:?
1:設置流程變量的時候,針對當前活動的節(jié)點設置流程變量,如果一個流程中存在2個活動節(jié)點,對每個活動節(jié)點都設置流程變量,即使流程變量的名稱相同,后一次的版本的值也不會替換前一次版本的值,它會使用不同的任務ID作為標識,存放2個流程變量值,而且可以看到TASK_ID的字段會存放任務ID的值?
例如act_hi_varinst 表的數(shù)據(jù):不同的任務節(jié)點,即使流程變量名稱相同,存放的值也是不同的。?
如圖:?
2:還有,使用setVariableLocal說明流程變量綁定了當前的任務,當流程繼續(xù)執(zhí)行時,下個任務獲取不到這個流程變量(因為正在執(zhí)行的流程變量中沒有這個數(shù)據(jù)),所有查詢正在執(zhí)行的任務時不能查詢到我們需要的數(shù)據(jù),此時需要查詢歷史的流程變量。
10:流程執(zhí)行歷史記錄?
10.1:查詢歷史流程實例?
查找按照某個流程定義的規(guī)則一共執(zhí)行了多少次流程?
?
10.2:查詢歷史活動?
某一次流程的執(zhí)行一共經(jīng)歷了多少個活動?
?
10.3:查詢歷史任務?
某一次流程的執(zhí)行一共經(jīng)歷了多少個任務?
?
10.4:查詢歷史流程變量?
某一次流程的執(zhí)行一共設置的流程變量?
?
10.5:總結?
由于數(shù)據(jù)庫中保存著歷史信息以及正在運行的流程實例信息,在實際項目中對已完成任務的查看頻率遠不及對代辦和可接任務的查看,所以在activiti采用分開管理,把正在運行的交給RuntimeService、TaskService管理,而歷史數(shù)據(jù)交給HistoryService來管理。?
這樣做的好處在于,加快流程執(zhí)行的速度,因為正在執(zhí)行的流程的表中數(shù)據(jù)不會很大。
總結
以上是生活随笔為你收集整理的Activiti最全入门教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java数据结构和算法(七)——链表
- 下一篇: activiti工作流引擎入门教程