無錫制作網(wǎng)站公司賣友情鏈接的哪來那么多網(wǎng)站
Activiti7工作流
一、工作流介紹
1.1 概念
工作流(Workflow),就是通過計算機對業(yè)務(wù)流程自動化執(zhí)行管理。它主要解決的是“使在多個參與者之間按照某種預(yù)定義的規(guī)則自動進行傳遞文檔、信息或任務(wù)的過程,從而實現(xiàn)某個預(yù)期的業(yè)務(wù)目標(biāo),或者促使此目標(biāo)的實現(xiàn)”。
案例: 出差費用報銷
目標(biāo): 公司把出差費用轉(zhuǎn)賬到自己的賬戶中.
參與人: 申請人、部門主管、總經(jīng)理、財務(wù)
**
**
傳遞文件/執(zhí)行任務(wù)
**
**
什么是工作流系統(tǒng)?
一個軟件系統(tǒng)中具有工作流的功能,我們把它稱為工作流系統(tǒng)。
1.2 適用行業(yè)
消費品行業(yè),制造業(yè),電信服務(wù)業(yè),銀證險等金融服務(wù)業(yè),物流服務(wù)業(yè),物業(yè)服務(wù)業(yè),物業(yè)管理,大中型進出口貿(mào)易公司,政府事業(yè)機構(gòu),研究院所及教育服務(wù)業(yè)等,特別是大的跨國企業(yè)和集團公司。
1.3 應(yīng)用領(lǐng)域
企業(yè): 采購流程、合同審核流程
客戶: 客戶電話投訴處理流程
生活中: 住房貸款審批流程、辦理身份證、辦理準(zhǔn)生手續(xù)
行政: 出差審批、報銷流程、請假審批、用車流程、會議室申請
銀行業(yè): 信貸審批、信用卡發(fā)卡審批
人事: 員工培訓(xùn)、績效考核、職位變動
1.4 傳統(tǒng)實現(xiàn)方式
我們可以思考下,如果需要實現(xiàn)【出差費用報銷】工作流程,代碼應(yīng)該如何實現(xiàn)?
1.需要在發(fā)起申請的時候選擇每個階段由哪個人員進行審批(數(shù)據(jù)庫需要記錄)
2.我們需要在數(shù)據(jù)庫中設(shè)計一個狀態(tài)的字段【主管審批0,總經(jīng)理審批1,財務(wù)審批2】,主管審批通過之后把狀態(tài)修改為總經(jīng)理審批.(硬編碼的方式)
3.當(dāng)流程處于主管審批時,只有角色為主管的用戶才能看到這條審核數(shù)據(jù).
通過上面的描述,同學(xué)們會發(fā)現(xiàn),我們要實現(xiàn)這個流程控制,我們需要大量的代碼才能完成.【工作量大】
而且如果流程發(fā)生改變的情況下,我們編寫的代碼也需要進行調(diào)整【不靈活】
1.5 什么是工作流引擎
是一種按照預(yù)定義規(guī)則【需要符合BPMN規(guī)范】進行部署,將業(yè)務(wù)和節(jié)點的流程進行分離【特定形式進行關(guān)聯(lián)】,
實現(xiàn)節(jié)點的自動流轉(zhuǎn)的工作流框架.
1.需要將預(yù)定于的流程文件BPMN部署到工作流引擎中,會把節(jié)點,路徑信息存儲到數(shù)據(jù)庫中.
2.工作流引擎提供了大量的API對流程進行查詢處理,細節(jié)都是對應(yīng)用程序屏蔽的,大大提供開發(fā)效率
3.業(yè)務(wù)邏輯的處理和流程的流轉(zhuǎn)是分離的,是通過BusinessKey進行關(guān)聯(lián)的.
二、什么是Activiti7?
2.1 概述
- Alfresco 軟件在 2010 年 5 月 17 日宣布 Activiti 業(yè)務(wù)流程管理(BPM)開源項目的正式啟動, 其
首席架構(gòu)師由業(yè)務(wù)流程管理 BPM 的專家 Tom Baeyens 擔(dān)任, Tom Baeyens 就是原來 jbpm 的架構(gòu)師,
而 jbpm 是一個非常有名的工作流引擎,當(dāng)然 activiti 也是一個工作流引擎。 - Activiti 是一個工作流引擎, activiti 可以將業(yè)務(wù)系統(tǒng)中復(fù)雜的業(yè)務(wù)流程抽取出來,使用專門的
建模語言(BPMN2.0)進行定義,業(yè)務(wù)系統(tǒng)按照預(yù)先定義的流程進行執(zhí)行,實現(xiàn)了業(yè)務(wù)系統(tǒng)的業(yè)務(wù)
流程由 activiti 進行管理,減少業(yè)務(wù)系統(tǒng)由于流程變更進行系統(tǒng)升級改造的工作量,從而提高系統(tǒng)的
健壯性,同時也減少了系統(tǒng)開發(fā)維護成本。
官方網(wǎng)站: https://www.activiti.org
2.2 Activiti7內(nèi)部核心機制
- 1??業(yè)務(wù)流程圖要規(guī)范化,需要遵守一套標(biāo)準(zhǔn)。
- 2??業(yè)務(wù)流程圖本質(zhì)上就是一個XML文件,而XML可以存放所要的數(shù)據(jù)。
- 3??讀取業(yè)務(wù)流程圖的過程就是解析XML文件的過程。
- 4??讀取一個業(yè)務(wù)流程圖的結(jié)點就相當(dāng)于解析一個XML的結(jié)點,進一步將數(shù)據(jù)插入到MySQL表中,形成一條記錄。
- 5??將一個業(yè)務(wù)流程圖的所有節(jié)點都讀取并存入到MySQL表中。
- 6??后面只要讀取MySQL表中的記錄就相當(dāng)于讀取業(yè)務(wù)流程圖的一個節(jié)點。
- 7??業(yè)務(wù)流程的推進,后面就轉(zhuǎn)換為讀取表中的數(shù)據(jù),并且處理數(shù)據(jù),結(jié)束的時候這一行數(shù)據(jù)就可以刪除了。
2.3 BPMN
-
BPMN(Business Process Model And Notation),業(yè)務(wù)流程模型和符號,是由BPMI(Business Process Management Initiative)開發(fā)的一套的業(yè)務(wù)流程建模符號,使用BPMN提供的符號可以創(chuàng)建業(yè)務(wù)流程。2004年5月發(fā)布了BPMN1.0規(guī)范。BPMI于2005年9月并入OMG(The Object Management Group,對象管理組織)組織。OMG于2011年1月發(fā)布BPMN2.0的最終版本。
-
Activit就是使用BPMN2.0進行流程建模、流程執(zhí)行管理,它包括很多的建模符號。
-
一個BPMN的例子:
- 當(dāng)事人填寫請假單,啟動流程后把請假單ID綁定到流程中;
- 部門經(jīng)理對請假單進行審核;
- 然后人事經(jīng)理進行復(fù)核并進行備案;
- 最后請假流程結(jié)束。
思考: 我們看到的是一張圖片(png),但是應(yīng)用程序如何知道下一個節(jié)點應(yīng)該流向到哪里呢?拿到需要去解析png文件嗎?
-
BPMN其實是用XML表示業(yè)務(wù)流程的,上面的.bpmn文件使用文本編輯器打開:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 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" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1620716847764" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema"><process id="leave" isClosed="false" isExecutable="true" processType="None"><startEvent id="_2" name="StartEvent"/><userTask activiti:candidateUsers="lisi,wangwu" activiti:exclusive="true" id="_4" name="部門經(jīng)理審批"/><userTask activiti:assignee="rose" activiti:exclusive="true" id="_6" name="人事復(fù)批"/><endEvent id="_7" name="EndEvent"/><sequenceFlow id="_12" sourceRef="_6" targetRef="_7"/><sequenceFlow id="_13" sourceRef="_2" targetRef="_4"/><sequenceFlow id="_14" sourceRef="_4" targetRef="_6"/></process><bpmndi:BPMNDiagram documentation="background=#FFFFFF;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram"><bpmndi:BPMNPlane bpmnElement="leave"><bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2"><omgdc:Bounds height="32.0" width="32.0" x="175.0" y="185.0"/><bpmndi:BPMNLabel><omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/></bpmndi:BPMNLabel></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4"><omgdc:Bounds height="55.0" width="85.0" x="245.0" y="175.0"/><bpmndi:BPMNLabel><omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/></bpmndi:BPMNLabel></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="_6" id="Shape-_6"><omgdc:Bounds height="55.0" width="85.0" x="380.0" y="175.0"/><bpmndi:BPMNLabel><omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/></bpmndi:BPMNLabel></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="_7" id="Shape-_7"><omgdc:Bounds height="32.0" width="32.0" x="505.0" y="185.0"/><bpmndi:BPMNLabel><omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/></bpmndi:BPMNLabel></bpmndi:BPMNShape><bpmndi:BPMNEdge bpmnElement="_13" id="BPMNEdge__13" sourceElement="_2" targetElement="_4"><omgdi:waypoint x="207.0" y="201.0"/><omgdi:waypoint x="245.0" y="202.5"/><bpmndi:BPMNLabel><omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/></bpmndi:BPMNLabel></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="_12" id="BPMNEdge__12" sourceElement="_6" targetElement="_7"><omgdi:waypoint x="465.0" y="202.5"/><omgdi:waypoint x="505.0" y="201.0"/><bpmndi:BPMNLabel><omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/></bpmndi:BPMNLabel></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="_14" id="BPMNEdge__14" sourceElement="_4" targetElement="_6"><omgdi:waypoint x="330.0" y="202.5"/><omgdi:waypoint x="380.0" y="202.5"/><bpmndi:BPMNLabel><omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/></bpmndi:BPMNLabel></bpmndi:BPMNEdge></bpmndi:BPMNPlane></bpmndi:BPMNDiagram> </definitions>
2.4 Activiti如何使用
2.4.1 整合Activiti
- Activiti是一個工作流引擎,業(yè)務(wù)系統(tǒng)使用Activiti來對系統(tǒng)的業(yè)務(wù)流程進行自動化管理,為了方便業(yè)務(wù)系統(tǒng)訪問(操作)Activiti的接口或功能,通常將Activiti和業(yè)務(wù)系統(tǒng)的環(huán)境集成在一起。
2.4.2 業(yè)務(wù)流程建模
- 使用Activiti流程建模工具(Activity-designer)定義業(yè)務(wù)流程(.bpmn文件)。
- .bpmn文件就是業(yè)務(wù)流程定義文件,通過xml定義業(yè)務(wù)流程。
- 如果使用其他公司開發(fā)的工作引擎一般都提供了可視化的建模工具(Process Designer)用于生成流程定義文件,建模工具操作直觀,一般都支持圖形化拖拽方式、多窗口的用戶界面、豐富的過程圖形元素、過程元素拷貝、粘貼、刪除等功能。
2.4.3 部署業(yè)務(wù)流程
- 向Activiti部署業(yè)務(wù)流程定義(.bpmn文件)。
- 使用Activiti提供的API向Activiti中部署.bpmn文件(一般情況下還需要一起部署業(yè)務(wù)流程的圖片.png)。
2.4.4 啟動流程實例
- 啟動一個流程實例表示開始一次業(yè)務(wù)流程的運行,比如員工請假流程部署完成,如果張三要請假就可以啟動一個流程實例,如果李四要請假也需要啟動一個流程實例,兩個流程的執(zhí)行互不影響,就好比定義一個Java類,實例化兩個Java對象一樣,部署的流程就好比Java類,啟動一個流程實例就好比new一個Java對象。
2.4.5 查詢待辦任務(wù)
- 因為現(xiàn)在系統(tǒng)的業(yè)務(wù)流程已經(jīng)交給Activiti管理,通過Activiti就可以查詢當(dāng)前流程執(zhí)行到哪里了,當(dāng)前用戶需要辦理什么任務(wù)了,這些Activiti幫我們管理了,而不像傳統(tǒng)方式中需要我們在SQL語句中的WHERE條件中指定當(dāng)前查詢的狀態(tài)值是多少。
2.4.6 處理待辦任務(wù)
- 用戶查詢待辦任務(wù)后,就可以辦理某個任務(wù),如果這任務(wù)辦理完成還需要其他用戶辦理,比如采購單創(chuàng)建后由部門經(jīng)理審核,這個過程也是由Activiti幫我們完成了,不需要我們在代碼中硬編碼指定下一個任務(wù)辦理人了
2.4.7 結(jié)束流程
- 當(dāng)任務(wù)辦理完成沒有下一個任務(wù)/結(jié)點了,這個流程實例就完成了。
三、Activiti7環(huán)境
3.1 開發(fā)環(huán)境
Jdk1.8或以上版本
Mysql 5及以上的版本
Tomcat8.5
IDEA
Activiti 7.0.0.SR1
3.2 安裝Activiti流程設(shè)計器
3.2.1 在線安裝
在Plugins
中搜索actiBPM
,然后點擊Search in repositories
,無法在線安裝的同學(xué)請選擇本地安裝
會彈出如下窗口
安裝完成之后,點擊Restart IntelliJ IDEA
重啟IDEA即可
3.2.2 本地安裝
-
從IDEA官網(wǎng)下載
actiBPM.jar
包,下載地址:https://plugins.jetbrains.com/plugin/7429-actibpm/versions -
從本地安裝actiBPM
點擊
Install plugin from disk
后選擇下載好的actiBPM.jar
,然后重啟IDEA即可.
3.3 解決actiBPM中文亂碼
- 在IDEA中將File–>Settings–>Editor–>File Encodings修改為UTF-8
-
在IDEA的Help–>Edit Custom VM Options中末尾添加
-Dfile.encoding=UTF-8
- 在IDEA的安裝目錄的bin目錄下將idea.exe.vmoptions和idea64.exe.vmoptions兩個文件末尾添加
-Dfile.encoding=UTF-8
- 重啟IDEA即可。
3.4 Activiti支持的數(shù)據(jù)庫
-
Activiti的運行需要數(shù)據(jù)庫的支撐,支持如下:
- h2
- MySQL
- Oracle
- Db2
- postgres
- mssql
-
在Navicat工具中創(chuàng)建
activiti
的數(shù)據(jù)庫,用于后續(xù)的實驗.
四、集成Activiti7
4.1 創(chuàng)建Maven項目
- 通過IDEA創(chuàng)建Maven的Java工程。
4.2 添加Maven依賴
在Java工程中加入ProcessEngine所需要的jar包,包括:
- activiti-engine-7.0.0.GA.jar
- activiti依賴的jar包:mybatis、slf4j、log4j等
- activiti依賴的spring的jar包
- 數(shù)據(jù)庫驅(qū)動
- 第三方數(shù)據(jù)庫連接池dbcp
- 單元測試junit
pom.xml
文件
<properties><slf4j.version>1.6.6</slf4j.version><log4j.version>1.2.12</log4j.version><activiti.version>7.0.0.SR1</activiti.version></properties><dependencies><!-- activiti引擎 --><dependency><groupId>org.activiti</groupId><artifactId>activiti-engine</artifactId><version>${activiti.version}</version></dependency><!-- 整合Spring --><dependency><groupId>org.activiti</groupId><artifactId>activiti-spring</artifactId><version>${activiti.version}</version></dependency><!-- bpmn 模型處理 --><dependency><groupId>org.activiti</groupId><artifactId>activiti-bpmn-model</artifactId><version>${activiti.version}</version></dependency><!-- bpmn 轉(zhuǎn)換 --><dependency><groupId>org.activiti</groupId><artifactId>activiti-bpmn-converter</artifactId><version>${activiti.version}</version></dependency><!-- bpmn json數(shù)據(jù)轉(zhuǎn)換 --><dependency><groupId>org.activiti</groupId><artifactId>activiti-json-converter</artifactId><version>${activiti.version}</version></dependency><!-- bpmn 布局 --><dependency><groupId>org.activiti</groupId><artifactId>activiti-bpmn-layout</artifactId><version>${activiti.version}</version></dependency><!-- mysql驅(qū)動 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.40</version></dependency><!-- mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.5</version></dependency><!-- 鏈接池 --><dependency><groupId>commons-dbcp</groupId><artifactId>commons-dbcp</artifactId><version>1.4</version></dependency><!-- 單元測試 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><!-- log start --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>${slf4j.version}</version></dependency><!-- log end --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency><!--數(shù)據(jù)庫連接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.4</version></dependency></dependencies>
4.3 添加log4j日志配置
我們使用log4j日志包,可以對日志進行配置,在resources
下創(chuàng)建log4j.properties
,內(nèi)容如下:
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=./activiti.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n
4.4 添加核心配置文件
- 需要在
resource
目錄中添加配置文件activiti.cfg.xml
,內(nèi)容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
</beans>
- 需要在配置文件中配置如下信息
- 數(shù)據(jù)庫連接池
- Activiti單獨運行的ProcessEngine配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd"><!--數(shù)據(jù)庫連接池--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql:///activiti" /><property name="username" value="root" /><property name="password" value="admin" /></bean><!-- 默認id對應(yīng)的值 為processEngineConfiguration --><bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"><property name="dataSource" ref="dataSource"/><!--activiti數(shù)據(jù)庫表處理策略false(默認值):檢查數(shù)據(jù)庫的版本和依賴庫的版本,如果不匹配就拋出異常true:構(gòu)建流程引擎時,執(zhí)行檢查,如果需要就執(zhí)行更新。如果表不存在,就創(chuàng)建。create-drop:構(gòu)建流程引擎時創(chuàng)建數(shù)據(jù)庫報表,關(guān)閉流程引擎時就刪除這些表。drop-create:先刪除表再創(chuàng)建表。create:構(gòu)建流程引擎時創(chuàng)建數(shù)據(jù)庫表,關(guān)閉流程引擎時不刪除這些表--><property name="databaseSchemaUpdate" value="true"/></bean>
</beans>
4.5 測試
- 創(chuàng)建一個測試類,調(diào)用activiti的工具類,生成acitivti需要的數(shù)據(jù)庫表。代碼如下:
package cn.wolfcode.demo;import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.junit.Test;public class _01TestInit {@Testpublic void testInit(){ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();System.out.println(processEngine);}
}
4.6 數(shù)據(jù)庫表的命名規(guī)則
-
此時我們查看數(shù)據(jù)庫,發(fā)現(xiàn)25張表,結(jié)果如下所示:
Activiti的表都是以ACT_
開頭。第二部分是表示表的用途的兩個字母標(biāo)識。用途也和服務(wù)的API對應(yīng)。
ACT_RE_*
:'RE’表示Repository。這個前綴的表包含了流程定義和流程靜態(tài)資源(圖片、規(guī)則等等)。ACT_RU_*
:'RU’表示Runtime。這些運行時的表,包含流程實例,任務(wù)、變量,異步任務(wù)等運行中的數(shù)據(jù)。Activiti只在流程實例執(zhí)行過程中保存這些數(shù)據(jù),在流程結(jié)束時就會刪除這些記錄。這些運行時表可以一直很小并且速度很快。ACT_HI_*
:'HI’表示History。這些表包含歷史數(shù)據(jù),比如歷史流程實例,變量,任務(wù)等等。ACT_GE_*
:'GE’表示General。通用數(shù)據(jù),用于不同場景下。
五、流程引擎API
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
這行代碼默認是讀取resource
目錄下的activiti.cfg.xml
文件,這個文件本質(zhì)上就是spring的配置文件,加載之后會讀取配置文件中id名為processEngineConfiguration
的bean,通過這個配置對象可以獲取到流程引擎對象ProcessEngine
5.1 Service總覽
Service接口 | 說明 |
---|---|
RepositoryService | Activiti的資源管理接口 |
RuntimeService | Activiti的流程運行管理接口 |
TaskService | Activiti的任務(wù)管理接口 |
HistoryService | Activiti的歷史管理接口 |
ManagementService | Activiti的引擎管理接口 |
-
RepositoryService,是Activiti的資源管理接口,提供了管理和控制流程發(fā)布包和流程定義的操作。使用工作流建模工具設(shè)計的業(yè)務(wù)流程圖需要使用此Service將流程定義文件的內(nèi)容部署到計算機中。
-
RuntimeService,是Activiti的流程運行管理接口,可以從這個接口中獲取很多關(guān)于流程執(zhí)行相關(guān)的信息。
-
TaskService,是Activiti的任務(wù)管理接口,可以從這個接口中獲取任務(wù)的信息。
-
HistoryService,是Activiti的歷史管理類,可以查詢歷史信息,執(zhí)行流程時,引擎會包含很多數(shù)據(jù)(根據(jù)配置),比如流程實例啟動時間,任務(wù)的參與者,完成任務(wù)的時間,每個流程實例的執(zhí)行路徑,等等。
-
ManagementService,是Activiti的引擎管理接口,提供了對Activiti流程引擎的管理和維護功能,這些功能不在工作流驅(qū)動的應(yīng)用程序中使用,主要用于Activiti系統(tǒng)的日常維護。
六、Activiti7入門
6.1 業(yè)務(wù)流程建模
6.1.1 繪制流程圖
在resource
目錄下新建bpmn
目錄用于存放所有的流程文件 ,在bpmn
目錄下新建leave.bpmn
,內(nèi)容如下:
6.1.2 指定任務(wù)負責(zé)人
- 為每個任務(wù)結(jié)點指定負責(zé)人,如部門經(jīng)理的審核人是李四。
6.1.3 生成png格式流程圖
bpmn
文件本質(zhì)上是xml格式,我們打開看到的是圖片格式是因為我們在IDEA中安裝了actiBPM的插件.
如果我們把bpmn
文件部署到Web環(huán)境,那么就只能看到xml信息,無法看到類似上面的圖形了.
我們可以再部署之前,根據(jù)bpmn
文件生成png
文件,然后把bpmn
和png
文件同時部署到Web環(huán)境中.如果我們想查看流程圖的話,我們就可以通過Activiti把這個png
文件讀取出來. 接下來我們把bpmn
導(dǎo)出為png
文件
-
將
leave.bpmn
文件重命名為leave.xml
文件
-
右鍵點擊
leave.xml
文件 -->Diagrams
-->Show BPMN Designer...
- 點擊導(dǎo)出按鈕,保存在
resource/bpmn
同級目錄下
- 導(dǎo)出
png
之后,把leave.xml
更名為leave.bpmn
6.2 部署流程定義
- 使用RepositoryService部署流程定義
package cn.wolfcode.demo;import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.junit.Test;/*** Created by wolfcode*/
public class ActivitiTest {@Testpublic void testDeploy(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RepositoryService對象RepositoryService repositoryService = processEngine.getRepositoryService();//進行部署Deployment deployment = repositoryService.createDeployment().addClasspathResource("bpmn/leave.bpmn").addClasspathResource("bpmn/leave.png").name("請假流程").deploy();//輸出部署的一些信息System.out.println("流程部署ID:"+deployment.getId());System.out.println("流程部署名稱:"+deployment.getName());}
}
觀察日志發(fā)現(xiàn),進行部署會操作如下表.
- ACT_GE_PROPERTY 引擎屬性表
Preparing: update ACT_GE_PROPERTY SET REV_ = ?, VALUE_ = ? where NAME_ = ? and REV_ = ? Parameters: 2(Integer), 2501(String), next.dbid(String), 1(Integer)
- ACT_RE_PROCDEF 流程定義表
Preparing: insert into ACT_RE_PROCDEF(ID_, REV_, CATEGORY_, NAME_, KEY_, VERSION_, DEPLOYMENT_ID_, RESOURCE_NAME_, DGRM_RESOURCE_NAME_, DESCRIPTION_, HAS_START_FORM_KEY_, HAS_GRAPHICAL_NOTATION_ , SUSPENSION_STATE_, TENANT_ID_, ENGINE_VERSION_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) Parameters: leaveProcess:1:4(String), http://www.activiti.org/test(String), 請假流程(String), leaveProcess(String), 1(Integer), 1(String), bpmn/leave.bpmn(String), bpmn/leave.png(String), null, false(Boolean), true(Boolean), 1(Integer), (String), null
- ACT_RE_DEPLOYMENT 流程部署表
Preparing: insert into ACT_RE_DEPLOYMENT(ID_, NAME_, CATEGORY_, KEY_, TENANT_ID_, DEPLOY_TIME_, ENGINE_VERSION_) values(?, ?, ?, ?, ?, ?, ?) Parameters: 1(String), 請假流程(String), null, null, (String), 2021-06-02 11:01:44.838(Timestamp), null
- ACT_GE_BYTEARRAY 二進制資源表
Preparing: INSERT INTO ACT_GE_BYTEARRAY(ID_, REV_, NAME_, BYTES_, DEPLOYMENT_ID_, GENERATED_) VALUES (?, 1, ?, ?, ?, ?) , (?, 1, ?, ?, ?, ?) Parameters: 2(String), bpmn/leave.png(String), java.io.ByteArrayInputStream@7fe7c640(ByteArrayInputStream), 1(String), false(Boolean), 3(String), bpmn/leave.bpmn(String), java.io.ByteArrayInputStream@4c4748bf(ByteArrayInputStream), 1(String), false(Boolean)
6.3 啟動流程實例
- 流程定義部署在Activiti中之后就可以通過工作流管理業(yè)務(wù)流程了。
- 針對該流程,啟動一個流程表示發(fā)起一個新的請假申請單,這就相當(dāng)于Java類和Java對象的關(guān)系,類定義好之后需要new創(chuàng)建一個對象使用,當(dāng)然,也可以new多個對象。
- 對于請假申請流程,張三發(fā)起一個請假申請單需要啟動一個流程實例,李四發(fā)起一個請求申請單也需要啟動一個流程實例。
@Test
public void testStartProcess(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RuntimeService對象RuntimeService runtimeService = processEngine.getRuntimeService();//根據(jù)流程定義的key啟動流程實例,這個key是在定義bpmn的時候設(shè)置的ProcessInstance instance = runtimeService.startProcessInstanceByKey("leaveProcess");//獲取流程實例的相關(guān)信息System.out.println("流程定義的id = " + instance.getProcessDefinitionId());System.out.println("流程實例的id = " + instance.getId());
}
觀察日志發(fā)現(xiàn),啟動流程會操作如下表.
- ACT_HI_TASKINST 歷史任務(wù)表
Preparing: insert into ACT_HI_TASKINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, OWNER_, ASSIGNEE_, START_TIME_, CLAIM_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TASK_DEF_KEY_, FORM_KEY_, PRIORITY_, DUE_DATE_, CATEGORY_, TENANT_ID_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) Parameters: 2505(String), leaveProcess:1:4(String), 2501(String), 2502(String), 部門經(jīng)理審批(String), null, null, null, 李四(String), 2021-06-02 16:34:52.827(Timestamp), null, null, null, null, _4(String), null, 50(Integer), null, null, (String)
- ACT_HI_PROCINST 歷史流程實例表
Preparing: insert into ACT_HI_PROCINST ( ID_, PROC_INST_ID_, BUSINESS_KEY_, PROC_DEF_ID_, START_TIME_, END_TIME_, DURATION_, START_USER_ID_, START_ACT_ID_, END_ACT_ID_, SUPER_PROCESS_INSTANCE_ID_, DELETE_REASON_, TENANT_ID_, NAME_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) Parameters: 2501(String), 2501(String), null, leaveProcess:1:4(String), 2021-06-02 16:34:52.798(Timestamp), null, null, null, _2(String), null, null, null, (String), null
- ACT_HI_ACTINST 歷史活動信息表
Preparing: insert into ACT_HI_ACTINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, ACT_ID_, TASK_ID_, CALL_PROC_INST_ID_, ACT_NAME_, ACT_TYPE_, ASSIGNEE_, START_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TENANT_ID_ ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) , (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) Parameters: 2503(String), leaveProcess:1:4(String), 2501(String), 2502(String), _2(String), null, null, StartEvent(String), startEvent(String), null, 2021-06-02 16:34:52.815(Timestamp), 2021-06-02 16:34:52.816(Timestamp), 1(Long), null, (String), 2504(String), leaveProcess:1:4(String), 2501(String), 2502(String), _4(String), 2505(String), null, 部門經(jīng)理審批(String), userTask(String), 李四(String), 2021-06-02 16:34:52.817(Timestamp), null, null, null, (String)
- ACT_HI_IDENTITYLINK 歷史身份連接表
Preparing: insert into ACT_HI_IDENTITYLINK (ID_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_) values (?, ?, ?, ?, ?, ?) Parameters: 2506(String), participant(String), 李四(String), null, null, 2501(String)
- ACT_RU_EXECUTION 運行時執(zhí)行實例表
insert into ACT_RU_EXECUTION (ID_, REV_, PROC_INST_ID_, BUSINESS_KEY_, PROC_DEF_ID_, ACT_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_,IS_EVENT_SCOPE_, IS_MI_ROOT_, PARENT_ID_, SUPER_EXEC_, ROOT_PROC_INST_ID_, SUSPENSION_STATE_, TENANT_ID_, NAME_, START_TIME_, START_USER_ID_, IS_COUNT_ENABLED_, EVT_SUBSCR_COUNT_, TASK_COUNT_, JOB_COUNT_, TIMER_JOB_COUNT_, SUSP_JOB_COUNT_, DEADLETTER_JOB_COUNT_, VAR_COUNT_, ID_LINK_COUNT_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) , (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) Parameters: 2501(String), 2501(String), null, leaveProcess:1:4(String), null, true(Boolean), false(Boolean), true(Boolean), false(Boolean), false(Boolean), null, null, 2501(String), 1(Integer), (String), null, 2021-06-02 16:34:52.798(Timestamp), null, false(Boolean), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 2502(String), 2501(String), null, leaveProcess:1:4(String), _4(String), true(Boolean), false(Boolean), false(Boolean), false(Boolean), false(Boolean), 2501(String), null, 2501(String), 1(Integer), (String), null, 2021-06-02 16:34:52.813(Timestamp), null, false(Boolean), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer)
- ACT_RU_TASK 運行時任務(wù)表
Preparing: insert into ACT_RU_TASK (ID_, REV_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, PRIORITY_, CREATE_TIME_, OWNER_, ASSIGNEE_, DELEGATION_, EXECUTION_ID_, PROC_INST_ID_, PROC_DEF_ID_, TASK_DEF_KEY_, DUE_DATE_, CATEGORY_, SUSPENSION_STATE_, TENANT_ID_, FORM_KEY_, CLAIM_TIME_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) Parameters: 2505(String), 部門經(jīng)理審批(String), null, null, 50(Integer), 2021-06-02 16:34:52.817(Timestamp), null, 李四(String), null, 2502(String), 2501(String), leaveProcess:1:4(String), _4(String), null, null, 1(Integer), (String), null, null
- ACT_RU_IDENTITYLINK 運行時身份連接表
Preparing: insert into ACT_RU_IDENTITYLINK (ID_, REV_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_, PROC_DEF_ID_) values (?, 1, ?, ?, ?, ?, ?, ?) Parameters: 2506(String), participant(String), 李四(String), null, null, 2501(String), null
6.4 任務(wù)查詢
- 流程啟動后,各個任務(wù)的負責(zé)人就可以查詢自己當(dāng)前需要處理的任務(wù),查詢出來的任務(wù)都是該用戶的待辦任務(wù)。
@Test
public void testSelectTodoTaskList(){//任務(wù)負責(zé)人String assignee = "李四";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取TaskServiceTaskService taskService = processEngine.getTaskService();//獲取任務(wù)集合List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("leaveProcess").taskAssignee(assignee).list();//遍歷任務(wù)列表for(Task task:taskList){System.out.println("流程定義id = " + task.getProcessDefinitionId());System.out.println("流程實例id = " + task.getProcessInstanceId());System.out.println("任務(wù)id = " + task.getId());System.out.println("任務(wù)名稱 = " + task.getName());}
}
觀察日志發(fā)現(xiàn),查詢?nèi)蝿?wù)會操作如下表.
- ACT_RU_TASK 運行時任務(wù)表
- ACT_RE_PROCDEF 流程定義表
Preparing: select distinct RES.* from ACT_RU_TASK RES inner join ACT_RE_PROCDEF D on RES.PROC_DEF_ID_ = D.ID_ WHERE RES.ASSIGNEE_ = ? and D.KEY_ = ? order by RES.ID_ asc LIMIT ? OFFSET ? Parameters: 李四(String), leaveProcess(String), 2147483647(Integer), 0(Integer)
6.5 任務(wù)處理
- 任務(wù)負責(zé)人查詢待辦任務(wù),選擇任務(wù)進行處理,完成任務(wù)。
@Test
public void testCompleteTask(){//任務(wù)負責(zé)人String assignee = "李四";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取TaskServiceTaskService taskService = processEngine.getTaskService();//獲取任務(wù)集合List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("leaveProcess").taskAssignee(assignee).list();//遍歷任務(wù)列表for(Task task:taskList){taskService.complete(task.getId());}
}
觀察日志發(fā)現(xiàn),查詢?nèi)蝿?wù)會操作如下表.
- ACT_GE_PROPERTY 引擎屬性表
Preparing: update ACT_GE_PROPERTY SET REV_ = ?, VALUE_ = ? where NAME_ = ? and REV_ = ? Parameters: 4(Integer), 7501(String), next.dbid(String), 3(Integer)
- ACT_HI_TASKINST 歷史任務(wù)表
Preparing: insert into ACT_HI_TASKINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, OWNER_, ASSIGNEE_, START_TIME_, CLAIM_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TASK_DEF_KEY_, FORM_KEY_, PRIORITY_, DUE_DATE_, CATEGORY_, TENANT_ID_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) Parameters: 5002(String), leaveProcess:1:4(String), 2501(String), 2502(String), 人事復(fù)批(String), null, null, null, 王五(String), 2021-06-02 16:39:19.036(Timestamp), null, null, null, null, _5(String), null, 50(Integer), null, null, (String)
- ACT_HI_ACTINST 歷史活動信息表
Preparing: insert into ACT_HI_ACTINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, ACT_ID_, TASK_ID_, CALL_PROC_INST_ID_, ACT_NAME_, ACT_TYPE_, ASSIGNEE_, START_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TENANT_ID_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) Parameters: 5001(String), leaveProcess:1:4(String), 2501(String), 2502(String), _5(String), 5002(String), null, 人事復(fù)批(String), userTask(String), 王五(String), 2021-06-02 16:39:19.025(Timestamp), null, null, null, (String)
- ACT_HI_IDENTITYLINK 歷史身份連接表
Preparing: insert into ACT_HI_IDENTITYLINK (ID_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_) values (?, ?, ?, ?, ?, ?) Parameters: 5003(String), participant(String), 王五(String), null, null, 2501(String)
- ACT_RU_TASK 運行時任務(wù)表
Preparing: insert into ACT_RU_TASK (ID_, REV_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, PRIORITY_, CREATE_TIME_, OWNER_, ASSIGNEE_, DELEGATION_, EXECUTION_ID_, PROC_INST_ID_, PROC_DEF_ID_, TASK_DEF_KEY_, DUE_DATE_, CATEGORY_, SUSPENSION_STATE_, TENANT_ID_, FORM_KEY_, CLAIM_TIME_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) Parameters: 5002(String), 人事復(fù)批(String), null, null, 50(Integer), 2021-06-02 16:39:19.025(Timestamp), null, 王五(String), null, 2502(String), 2501(String), leaveProcess:1:4(String), _5(String), null, null, 1(Integer), (String), null, null
- ACT_RU_IDENTITYLINK 運行時身份連接表
Preparing: insert into ACT_RU_IDENTITYLINK (ID_, REV_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_, PROC_DEF_ID_) values (?, 1, ?, ?, ?, ?, ?, ?) Parameters: 5003(String), participant(String), 王五(String), null, null, 2501(String), null
- ACT_RU_EXECUTION 運行時執(zhí)行實例表
Preparing: update ACT_RU_EXECUTION set REV_ = ?, BUSINESS_KEY_ = ?, PROC_DEF_ID_ = ?, ACT_ID_ = ?, IS_ACTIVE_ = ?, IS_CONCURRENT_ = ?, IS_SCOPE_ = ?, IS_EVENT_SCOPE_ = ?, IS_MI_ROOT_ = ?, PARENT_ID_ = ?, SUPER_EXEC_ = ?, ROOT_PROC_INST_ID_ = ?, SUSPENSION_STATE_ = ?, NAME_ = ?, IS_COUNT_ENABLED_ = ?, EVT_SUBSCR_COUNT_ = ?, TASK_COUNT_ = ?, JOB_COUNT_ = ?, TIMER_JOB_COUNT_ = ?, SUSP_JOB_COUNT_ = ?, DEADLETTER_JOB_COUNT_ = ?, VAR_COUNT_ = ?, ID_LINK_COUNT_ = ? where ID_ = ? and REV_ = ? Parameters: 2(Integer), null, leaveProcess:1:4(String), _5(String), true(Boolean), false(Boolean), false(Boolean), false(Boolean), false(Boolean), 2501(String), null, 2501(String), 1(Integer), null, false(Boolean), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 2502(String), 1(Integer)
- ACT_HI_TASKINST 歷史任務(wù)表
Preparing: update ACT_HI_TASKINST set PROC_DEF_ID_ = ?, EXECUTION_ID_ = ?, NAME_ = ?, PARENT_TASK_ID_ = ?, DESCRIPTION_ = ?, OWNER_ = ?, ASSIGNEE_ = ?, CLAIM_TIME_ = ?, END_TIME_ = ?, DURATION_ = ?, DELETE_REASON_ = ?, TASK_DEF_KEY_ = ?, FORM_KEY_ = ?, PRIORITY_ = ?, DUE_DATE_ = ?, CATEGORY_ = ? where ID_ = ? Parameters: leaveProcess:1:4(String), 2502(String), 部門經(jīng)理審批(String), null, null, null, 李四(String), null, 2021-06-02 16:39:18.995(Timestamp), 266168(Long), null, _4(String), null, 50(Integer), null, null, 2505(String)
- ACT_HI_TASKINST 歷史任務(wù)表
Preparing: update ACT_HI_ACTINST set EXECUTION_ID_ = ?, ASSIGNEE_ = ?, END_TIME_ = ?, DURATION_ = ?, DELETE_REASON_ = ? where ID_ = ? Parameters: 2502(String), 李四(String), 2021-06-02 16:39:19.009(Timestamp), 266192(Long), null, 2504(String)
- ACT_RU_TASK 運行時任務(wù)表
Preparing: delete from ACT_RU_TASK where ID_ = ? and REV_ = ? Parameters: 2505(String), 1(Integer)
6.6 添加審批意見
- 在執(zhí)行任務(wù)之前可以給該任務(wù)添加審批意見,會存儲在歷史表中,我們后續(xù)可以審批歷史中查看到該意見
@Test
public void testAddComment(){//任務(wù)負責(zé)人String assignee = "王五";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取TaskServiceTaskService taskService = processEngine.getTaskService();//獲取任務(wù)集合List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("leaveProcess").taskAssignee(assignee).list();//遍歷任務(wù)列表for(Task task:taskList){//在任務(wù)執(zhí)行之前任務(wù)添加批注信息taskService.addComment(task.getId(),task.getProcessInstanceId(),task.getName()+"審批通過");taskService.complete(task.getId());}
}
觀察日志發(fā)現(xiàn),其余操作和任務(wù)處理的表是一致的,但是添加批注會往如下表中插入記錄:
Preparing: insert into ACT_HI_COMMENT (ID_, TYPE_, TIME_, USER_ID_, TASK_ID_, PROC_INST_ID_, ACTION_, MESSAGE_, FULL_MSG_) values (?, ?, ?, ?, ?, ?, ?, ?, ?) Parameters: 7501(String), comment(String), 2021-06-02 16:43:09.13(Timestamp), null, 5002(String), 2501(String), AddComment(String), 人事復(fù)批審批通過(String), java.io.ByteArrayInputStream@1b765a2c(ByteArrayInputStream)
6.6 查看歷史審批
- 用戶可以查看歷史審批記錄
@Test
public void testSelectHistoryTask(){//流程實例IDString processInstanceId = "2501";//任務(wù)審核人String taskAssignee = "王五";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取historyServiceHistoryService historyService = processEngine.getHistoryService();//獲取taskServiceTaskService taskService = processEngine.getTaskService();//獲取歷史審核信息List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery().activityType("userTask")//只獲取用戶任務(wù).processInstanceId(processInstanceId).taskAssignee(taskAssignee).finished().list();for(HistoricActivityInstance instance:list){System.out.println("任務(wù)名稱:"+instance.getActivityName());System.out.println("任務(wù)開始時間:"+instance.getStartTime());System.out.println("任務(wù)結(jié)束時間:"+instance.getEndTime());System.out.println("任務(wù)耗時:"+instance.getDurationInMillis());//獲取審核批注信息List<Comment> taskComments = taskService.getTaskComments(instance.getTaskId());if(taskComments.size()>0){System.out.println("審批批注:"+taskComments.get(0).getFullMessage());}}
}
七、Activiti7進階
7.1 流程定義相關(guān)
7.1.1 流程定義查詢
- 查詢流程相關(guān)信息,包含流程定義,流程部署,流程定義版本
@Test
public void testDefinitionQuery(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取倉庫服務(wù)RepositoryService repositoryService = processEngine.getRepositoryService();//獲取流程定義集合List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leaveProcess").list();//遍歷集合for (ProcessDefinition definition:processDefinitionList){System.out.println("流程定義ID:"+definition.getId());System.out.println("流程定義名稱:"+definition.getName());System.out.println("流程定義key:"+definition.getKey());System.out.println("流程定義版本:"+definition.getVersion());System.out.println("流程部署ID:"+definition.getDeploymentId());System.out.println("====================");}
}
7.1.2 流程資源下載
-
現(xiàn)在我們的流程資源文件已經(jīng)上傳到數(shù)據(jù)庫了,如果其他用戶想要查看這些資源文件,可以從數(shù)據(jù)庫中把資源文件下載到本地。
@Test public void testDownloadResource() throws Exception {//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取倉庫服務(wù)RepositoryService repositoryService = processEngine.getRepositoryService();//獲取流程定義集合List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leaveProcess").orderByProcessDefinitionVersion()//按照版本排序.desc()//降序.list();//獲取最新那個ProcessDefinition definition =list.get(0);//獲取部署IDString deploymentId = definition.getDeploymentId();//獲取bpmn的輸入流InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId,definition.getResourceName());//獲取png的輸入流InputStream pngInput = repositoryService.getResourceAsStream(deploymentId,definition.getDiagramResourceName());//設(shè)置bpmn輸入FileOutputStream bpmnOutPut = new FileOutputStream("D:/leave.bpmn");//設(shè)置png輸入FileOutputStream pngOutPut = new FileOutputStream("D:/leave.png");IOUtils.copy(bpmnInput,bpmnOutPut);IOUtils.copy(pngInput,pngOutPut); }
7.1.3 流程定義刪除
- 根據(jù)部署Id刪除對應(yīng)的流程定義
@Test
public void testDeleteDeploy(){//流程部署IdString deploymentId = "10001";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取倉庫服務(wù)RepositoryService repositoryService = processEngine.getRepositoryService();//刪除流程定義,如果該流程定義已有流程實例啟動則刪除時出錯repositoryService.deleteDeployment(deploymentId);//設(shè)置true 級聯(lián)刪除流程定義,即使該流程有流程實例啟動也可以刪除,設(shè)置為false非級別刪除方式,如果流程//repositoryService.deleteDeployment(deploymentId,true);
}
說明:
-
如果該流程定義下沒有正在運行的流程,則可以用普通刪除。
-
如果該流程定義下存在已經(jīng)運行的流程,使用普通刪除報錯,可用級聯(lián)刪除方法將流程及相關(guān)記錄全部刪除。
-
項目開發(fā)中級聯(lián)刪除操作一般只開放給超級管理員使用.
7.2 流程實例相關(guān)
7.2.1 什么是流程實例
用戶或程序按照流程定義內(nèi)容發(fā)起一個流程,這就是一個流程實例。
流程定義和流程實例的圖解:
7.2.2 BusinessKey(業(yè)務(wù)標(biāo)識)
- 小張要在5.1~5.10這段時間請假,請假理由為:回家相親.
- 小陳要在5.5~5.15這段時間請假,請假理由為:家里拆遷,回家辦手續(xù).
請問會創(chuàng)建幾個流程實例?
流程發(fā)起之后,目前設(shè)定的部門審批人都是李四,李四在審批之前需要看到申請人申請的時間和申請的理由,才能決定是否同意.
那么申請人的請假信息【請假時間、請假理由】是如何綁定到流程中的呢?
此時就需要使用到BusinessKey
- 啟動流程實例時,指定的businessKey,就會在act_run_execution表中存儲businessKey。
- BusinessKey:業(yè)務(wù)標(biāo)識,通常為業(yè)務(wù)表的主鍵,業(yè)務(wù)標(biāo)識和流程實例一一對應(yīng)。業(yè)務(wù)標(biāo)識來源于業(yè)務(wù)系統(tǒng)。存儲業(yè)務(wù)標(biāo)識就是根據(jù)業(yè)務(wù)標(biāo)識來關(guān)聯(lián)查詢業(yè)務(wù)系統(tǒng)的數(shù)據(jù)。比如:請假流程啟動一個流程實例,就可以將請假單的id作為業(yè)務(wù)標(biāo)識存儲到Activiti中,將來查詢Activiti的流程實例信息就可以獲取請假單的id從而關(guān)聯(lián)查詢業(yè)務(wù)系統(tǒng)數(shù)據(jù)庫得到請假單信息。
@Test
public void testStartProcess(){String businessKey = "8001";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RuntimeService對象RuntimeService runtimeService = processEngine.getRuntimeService();//根據(jù)流程定義的key啟動流程實例,這個key是在定義bpmn的時候設(shè)置的//在啟動流程的時候?qū)I(yè)務(wù)key加入進去ProcessInstance instance = runtimeService.startProcessInstanceByKey("leaveProcess",businessKey);//獲取流程實例的相關(guān)信息System.out.println("流程定義的id = " + instance.getProcessDefinitionId());System.out.println("流程實例的id = " + instance.getId());
}
觀察數(shù)據(jù)庫可以發(fā)現(xiàn),在activiti的act_ru_execution表,字段BUSINESS_KEY就是存放業(yè)務(wù)KEY的。
- 在用戶執(zhí)行任務(wù)的時候如何獲取
BusinessKey
并關(guān)聯(lián)對應(yīng)的業(yè)務(wù)信息呢?
@Test
public void testGetBusinessKey(){//任務(wù)負責(zé)人String assignee = "李四";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取TaskServiceTaskService taskService = processEngine.getTaskService();//獲取RuntimeServiceRuntimeService runtimeService = processEngine.getRuntimeService();//獲取任務(wù)集合List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("leaveProcess").taskAssignee(assignee).list();//遍歷任務(wù)列表for(Task task:taskList){System.out.println("流程定義id = " + task.getProcessDefinitionId());System.out.println("流程實例id = " + task.getProcessInstanceId());System.out.println("任務(wù)id = " + task.getId());System.out.println("任務(wù)名稱 = " + task.getName());//根據(jù)任務(wù)上的流程實例Id查詢出對應(yīng)的流程實例對象,從流程實例對象中獲取BusinessKeyProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();System.out.println("業(yè)務(wù)key:"+instance.getBusinessKey());System.out.println("===================");}
}
7.2.3 流程定義/實例掛起/激活
全部流程實例掛起場景:
-
例如公司制度改變過程中的流程, 總經(jīng)理更換過程中的流程,有100個人的流程, 70個人已經(jīng)完成,30個人流程正好在總經(jīng)理更換中,就需要掛起.
-
比如我們的業(yè)務(wù)流程為:
【開始節(jié)點】–>【A節(jié)點】–>【B節(jié)點】–>【C節(jié)點】–>【結(jié)束節(jié)點】
【C節(jié)點】的業(yè)務(wù)邏輯需要和外部接口交互,剛好外部接口出問題了,如果剩下的流程都走到【C節(jié)點】,執(zhí)行【C節(jié)點】的業(yè)務(wù)邏輯,那都會報錯,我們就可以把流程掛起,等待外部接口可用之后再重新激活流程.
- 業(yè)務(wù)流程發(fā)生改變,已經(jīng)發(fā)起的流程實例繼續(xù)按照舊的流程走,如果新發(fā)起的流程就按照新的業(yè)務(wù)流程走.這時候我們就需要掛起流程定義,但是不掛起流程實例.
- 操作流程定義為掛起狀態(tài),該操作定義下面的所有的流程實例將全部暫停。
- 流程定義為掛起狀態(tài),該流程定義下將不允許啟動新的流程實例,同時該流程定義下的所有流程實例將全部掛起暫停執(zhí)行
@Test
public void testSuspendAllProcessInstance(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RepositoryServiceRepositoryService repositoryService = processEngine.getRepositoryService();//獲取流程定義對象ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leaveProcess").singleResult();boolean suspended = processDefinition.isSuspended();//輸出流程定義狀態(tài)System.out.println("流程定義狀態(tài):"+(suspended ?"已掛起":"已激活"));String processDefinitionId = processDefinition.getId();if(suspended){//如果是掛起,可以執(zhí)行激活操作 ,參數(shù)1 :流程定義id ,參數(shù)2:是否激活流程實例,參數(shù)3:激活時間repositoryService.activateProcessDefinitionById(processDefinitionId,true,null);System.out.println("流程ID:"+processDefinitionId+",已激活");}else{//如果是激活,可以執(zhí)行掛起操作 ,參數(shù)1 :流程定義id ,參數(shù)2:是否暫停流程實例,參數(shù)3:激活時間repositoryService.suspendProcessDefinitionById(processDefinitionId,true,null);System.out.println("流程ID:"+processDefinitionId+",已掛起");}
}
- 查詢待辦任務(wù)的狀態(tài),如果是【已掛起】,前臺則不允許點擊【任務(wù)處理】按鈕
@Test
public void testSuspendStatus(){//任務(wù)負責(zé)人String assignee = "李四";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取TaskServiceTaskService taskService = processEngine.getTaskService();//獲取任務(wù)集合List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("leaveProcess").taskAssignee(assignee).list();//遍歷任務(wù)列表for(Task task:taskList){System.out.println("流程定義id = " + task.getProcessDefinitionId());System.out.println("流程實例id = " + task.getProcessInstanceId());System.out.println("任務(wù)id = " + task.getId());System.out.println("任務(wù)名稱 = " + task.getName());System.out.println("任務(wù)狀態(tài):"+(task.isSuspended()?"已掛起":"已激活"));System.out.println("===================");}
}
-
利用之前的測試用例,測試在流程掛起的情況是否能發(fā)起新的流程實例
org.activiti.engine.ActivitiException: Cannot start process instance. Process definition 請假流程 (id = leaveProcess:1:4) is suspended
-
利用之前的測試用例,測試在流程掛起的情況是否可以處理任務(wù)
org.activiti.engine.ActivitiException: Cannot complete a suspended task
單個流程實例掛起場景
評分流程:可設(shè)置多級評分,評分流程會按照從上往下的順序,依次評分;評分人必須在評分截至?xí)r間內(nèi)完成評分,否則不允許繼續(xù)評分,流程將會掛起,停止流轉(zhuǎn);
- 操作流程實例對象,針對單個流程執(zhí)行掛起操作,某個流程實例掛起則此流程不再執(zhí)行,完成該流程實例的當(dāng)前任務(wù)將報異常。
查詢所有的流程實例
@Test
public void testQueryProcessInstance(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RepositoryServiceRuntimeService runtimeService = processEngine.getRuntimeService();List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery().processDefinitionKey("leaveProcess").list();for(ProcessInstance processInstance:processInstanceList){System.out.println("流程實例Id:"+processInstance.getId()+",狀態(tài):"+(processInstance.isSuspended()?"已掛起":"已激活"));}
}
掛起某個流程實例
@Test
public void testSuspendSingleProcessInstance(){//流程實例IdString processInstanceId = "2501";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RepositoryServiceRuntimeService runtimeService = processEngine.getRuntimeService();//根據(jù)流程實例Id獲取流程實例對象ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();//狀態(tài)boolean suspended = processInstance.isSuspended();System.out.println("流程實例ID:"+processInstanceId+",狀態(tài):"+ (suspended?"已掛起":"已激活"));if(suspended){runtimeService.activateProcessInstanceById(processInstanceId);System.out.println("流程實例ID:"+processInstanceId+",狀態(tài)修改為已激活");}else{runtimeService.suspendProcessInstanceById(processInstanceId);System.out.println("流程實例ID:"+processInstanceId+",狀態(tài)修改為已掛起");}
}
7.3 任務(wù)分配負責(zé)人
7.3.1 固定分配
-
在進行業(yè)務(wù)流程建模的時候指定固定的任務(wù)負責(zé)人。
7.3.2 UEL表達式分配
Activiti 使用 UEL 表達式, UEL 是 java EE6 規(guī)范的一部分, UEL(Unified Expression Language)即 統(tǒng)一表達式語言。
IDEA中的actiBPM插件在修改Assignee存在bug,在界面上修改了,但是實際文件并沒有修改.所以我們需要借助編輯工具在xml文件中修改一下Assignee
-
修改流程定義之后重新進行部署
-
編寫代碼配置負責(zé)人
@Test
public void testStartProcess(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RuntimeService對象RuntimeService runtimeService = processEngine.getRuntimeService();Map<String,Object> variables = new HashMap<String, Object>();variables.put("assignee0","zhangsan");variables.put("assignee1","lisi");//根據(jù)流程定義的key啟動流程實例,這個key是在定義bpmn的時候設(shè)置的ProcessInstance instance = runtimeService.startProcessInstanceByKey("leaveProcess",variables);//獲取流程實例的相關(guān)信息System.out.println("流程定義的id = " + instance.getProcessDefinitionId());System.out.println("流程實例的id = " + instance.getId());
}
執(zhí)行成功后,可以在act_ru_variable表中看到剛才map中的數(shù)據(jù)
7.3.3 監(jiān)聽器分配
- 任務(wù)監(jiān)聽器是發(fā)生對應(yīng)的任務(wù)相關(guān)事件時執(zhí)行自定義的Java邏輯或表達式。
- 任務(wù)相關(guān)事件包括:
- Event:
- Create:任務(wù)創(chuàng)建后觸發(fā)。
- Assignment:任務(wù)分配后觸發(fā)。
- Delete:任務(wù)完成后觸發(fā)。
- All:所有事件發(fā)生都觸發(fā)。
- Event:
-
自定義一個任務(wù)監(jiān)聽器類,然后此類必須實現(xiàn)org.activiti.engine.delegate.TaskListener接口
package cn.wolfcode;import org.activiti.engine.delegate.DelegateTask; import org.activiti.engine.delegate.TaskListener;/*** Created by wolfcode*/ public class AssigneeTaskListener implements TaskListener {public void notify(DelegateTask delegateTask) {if(delegateTask.getName().equals("部門經(jīng)理審批")){delegateTask.setAssignee("趙六");}else if(delegateTask.getName().equals("部門經(jīng)理審批")){delegateTask.setAssignee("孫七");}} }
-
在bpmn文件中配置監(jiān)聽器
- 在實際開發(fā)中,一般也不使用監(jiān)聽器分配方式,太麻煩了。
7.4 流程變量
7.4.1 什么是流程變量?
- 流程變量在Activiti中是一個非常重要的角色,流程運轉(zhuǎn)有時需要靠流程變量,業(yè)務(wù)系統(tǒng)和Activiti結(jié)合時少不了流程變量,流程變量就是Activiti在管理工作流時根據(jù)管理需要而設(shè)置的變量。
- 比如在請假流程流轉(zhuǎn)時如果請假天數(shù)>3天則有總經(jīng)理審批,否則由人事直接審批,請假天數(shù)就可以設(shè)置流程變量,在流程流轉(zhuǎn)時使用。
注意:雖然流程變量中可以存儲業(yè)務(wù)數(shù)據(jù),可以通過Activiti的API查詢流程變量從而實現(xiàn)查詢業(yè)務(wù)數(shù)據(jù),但是不建議這么使用,因為業(yè)務(wù)數(shù)據(jù)查詢由業(yè)務(wù)系統(tǒng)負責(zé),Activiti設(shè)置流程變量是為了流程執(zhí)行需要而創(chuàng)建的。
7.4.2 流程變量類型
注意:
如果將POJO存儲到流程變量中,必須實現(xiàn)序列化接口Serializable,為了防止由于新增字段無法反序列化。
7.4.3 流程變量的作用域
流程變量的作用域范圍可以是一個流程實例(ProcessInstance)、一個任務(wù)(Task)或一個執(zhí)行實例(Execution)。
- global變量: 流程變量的作用域范圍的默認值是流程實例,作用域范圍最大。
- local變量 : 流程變量的作用域范圍如果僅僅針對一個任務(wù)或一個執(zhí)行實例,那么作用域范圍沒有流程實例大
實際開發(fā)中一般不用local變量,了解即可.
7.4.4 流程變量的使用方法
-
在屬性上使用UEL表達式
可以在 assignee 處設(shè)置 UEL 表達式,表達式的值為任務(wù)的負責(zé)人,比如: ${assignee}, assignee 就是一個流程變量名稱。
Activiti獲取UEL表達式的值,即流程變量assignee的值 ,將assignee的值作為任務(wù)的負責(zé)人進行任務(wù)分配
-
在連線上使用UEL表達式
可以在連線上設(shè)置UEL表達式,決定流程走向。
比如:${price<10000} 。price就是一個流程變量名稱,uel表達式結(jié)果類型為布爾類型。
如果UEL表達式是true,要決定 流程執(zhí)行走向。
7.4.5 使用global變量控制流程
需求:員工創(chuàng)建請假流程申請單,由部門經(jīng)理審批,部門經(jīng)理審批通過后請假3天以下(含3天)的由人事經(jīng)理直接審批,3天以上的由總經(jīng)理審批,總經(jīng)理審批通過再通過人事經(jīng)理審批。
- 在連線處添加判斷條件
本次畫BPMN文件的時候?qū)⒉块T經(jīng)理的assignee設(shè)置為李四,總經(jīng)理審批的assignee設(shè)置為王五,總經(jīng)理審批的assignee設(shè)置為王五,人事復(fù)批存檔設(shè)置為趙六。
package cn.wolfcode.demo;import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Created by wolfcode*/
public class VariablesTest {/*** 部署*/@Testpublic void testDeploy(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RepositoryService對象RepositoryService repositoryService = processEngine.getRepositoryService();//進行部署Deployment deployment = repositoryService.createDeployment().addClasspathResource("bpmn/leave-variables.bpmn").name("請假流程").deploy();//輸出部署的一些信息System.out.println("流程部署ID:"+deployment.getId());System.out.println("流程部署名稱:"+deployment.getName());}@Testpublic void testStartProcess(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RuntimeService對象RuntimeService runtimeService = processEngine.getRuntimeService();Map<String,Object> variables = new HashMap<String,Object>();variables.put("day",2);//根據(jù)流程定義的key啟動流程實例,這個key是在定義bpmn的時候設(shè)置的ProcessInstance instance = runtimeService.startProcessInstanceByKey("leaveVariablesProcess",variables);//獲取流程實例的相關(guān)信息System.out.println("流程定義的id = " + instance.getProcessDefinitionId());System.out.println("流程實例的id = " + instance.getId());}@Testpublic void testSelectTodoTaskList(){//任務(wù)負責(zé)人String assignee = "李四";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取TaskServiceTaskService taskService = processEngine.getTaskService();//獲取任務(wù)集合List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("leaveVariablesProcess").taskAssignee(assignee).list();//遍歷任務(wù)列表for(Task task:taskList){System.out.println("流程定義id = " + task.getProcessDefinitionId());System.out.println("流程實例id = " + task.getProcessInstanceId());System.out.println("任務(wù)id = " + task.getId());System.out.println("任務(wù)名稱 = " + task.getName());}}@Testpublic void testCompleteTask(){//任務(wù)負責(zé)人String assignee = "李四";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取TaskServiceTaskService taskService = processEngine.getTaskService();//獲取任務(wù)集合List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("leaveVariablesProcess").taskAssignee(assignee).list();//遍歷任務(wù)列表for(Task task:taskList){taskService.complete(task.getId());}}
}
注意事項:
1.如果UEL表達式中流程變量名不存在則報錯。
2.如果如果UEL表達式都不符合條件,流程報錯。
3.如果連接不設(shè)置條件/條件都滿足,每個連線都會走.
7.5 任務(wù)候選人
在流程定義中在任務(wù)結(jié)點的 assignee 固定設(shè)置任務(wù)負責(zé)人,在流程定義時將參與者固定設(shè)置在.bpmn 文件中,如果臨時任務(wù)負責(zé)人變更則需要修改流程定義,系統(tǒng)可擴展性差。
針對這種情況可以給任務(wù)設(shè)置多個候選人,可以從候選人中選擇參與者來完成任務(wù)。
7.5.1 設(shè)置任務(wù)候選人
- 在流程圖中任務(wù)節(jié)點的配置中設(shè)置 candidate-users(候選人),多個候選人之間用逗號分開。
-
查看bpmn文件
-
我們可以看到部門經(jīng)理的審核人已經(jīng)設(shè)置為 lisi,wangwu 這樣的一組候選人,可以使用activiti:candiateUsers=”用戶 1,用戶 2,用戶 3”的這種方式來實現(xiàn)設(shè)置一組候選人
7.5.2 部署&啟動流程
package cn.wolfcode.demo;import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Created by wolfcode*/
public class CandidateTest {/*** 部署*/@Testpublic void testDeploy(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RepositoryService對象RepositoryService repositoryService = processEngine.getRepositoryService();//進行部署Deployment deployment = repositoryService.createDeployment().addClasspathResource("bpmn/leave-candidate.bpmn").name("請假流程-候選人").deploy();//輸出部署的一些信息System.out.println("流程部署ID:"+deployment.getId());System.out.println("流程部署名稱:"+deployment.getName());}//啟動流程@Testpublic void testStartProcess(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RuntimeService對象RuntimeService runtimeService = processEngine.getRuntimeService();//根據(jù)流程定義的key啟動流程實例,這個key是在定義bpmn的時候設(shè)置的ProcessInstance instance = runtimeService.startProcessInstanceByKey("leaveCandidateProcess");//獲取流程實例的相關(guān)信息System.out.println("流程定義的id = " + instance.getProcessDefinitionId());System.out.println("流程實例的id = " + instance.getId());}
}
7.5.3 查詢候選人任務(wù)
//查詢候選任務(wù)
@Test
public void testSelectCandidateTaskList(){//任務(wù)負責(zé)人String candidateUser = "李四";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取TaskServiceTaskService taskService = processEngine.getTaskService();//獲取任務(wù)集合List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("leaveCandidateProcess").taskCandidateUser(candidateUser).list();//遍歷任務(wù)列表for(Task task:taskList){System.out.println("流程定義id = " + task.getProcessDefinitionId());System.out.println("流程實例id = " + task.getProcessInstanceId());System.out.println("任務(wù)id = " + task.getId());System.out.println("任務(wù)名稱 = " + task.getName());}
}
7.5.4 領(lǐng)取候選人任務(wù)
@Test
public void testClaimTask(){//任務(wù)IDString taskId = "2505";String assignee = "張三";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取TaskServiceTaskService taskService = processEngine.getTaskService();//領(lǐng)取任務(wù)taskService.claim(taskId,assignee);
}
7.5.4 完成任務(wù)
如果候選任務(wù)沒有進行領(lǐng)取就直接完成的話,那么在歷史記錄中就不會記錄是哪個用戶執(zhí)行了這個任務(wù).
所以對于這種候選人的任務(wù),我們需要先領(lǐng)取再完成.
//執(zhí)行任務(wù)
@Test
public void testCompleteTask(){//任務(wù)IDString taskId = "2505";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取TaskServiceTaskService taskService = processEngine.getTaskService();taskService.complete(taskId);
}
7.6 網(wǎng)關(guān)
7.6.1 排他網(wǎng)關(guān)
排他網(wǎng)關(guān)(ExclusiveGateway)(異或網(wǎng)關(guān)或基于數(shù)據(jù)的排他網(wǎng)關(guān)),用來在流程中實現(xiàn)決策。當(dāng)流程執(zhí)行到這個網(wǎng)關(guān)的時候,所有分支都會判斷條件是否為true,如果為true則執(zhí)行該分支。
注意:
排他網(wǎng)關(guān)只會選擇一個為true的分支執(zhí)行(即使有兩個分支條件都為true,排他網(wǎng)關(guān)也只會選擇一條分支去執(zhí)行,選擇序號小的路徑執(zhí)行)。
本次畫BPMN文件的時候?qū)⒉块T經(jīng)理的assignee設(shè)置為李四,總經(jīng)理審批的assignee設(shè)置為王五,總經(jīng)理審批的assignee設(shè)置為王五,人事復(fù)批存檔設(shè)置為趙六。
package cn.wolfcode.demo;import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.After;
import org.junit.Test;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Created by wolfcode*/
public class EGatewayTest {/*** 部署*/@Testpublic void testDeploy(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RepositoryService對象RepositoryService repositoryService = processEngine.getRepositoryService();//進行部署Deployment deployment = repositoryService.createDeployment().addClasspathResource("bpmn/leave-EGateway.bpmn").name("請假流程-排他網(wǎng)關(guān)").deploy();//輸出部署的一些信息System.out.println("流程部署ID:"+deployment.getId());System.out.println("流程部署名稱:"+deployment.getName());}@Testpublic void testStartProcess(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RuntimeService對象RuntimeService runtimeService = processEngine.getRuntimeService();Map<String,Object> variables = new HashMap<String,Object>();variables.put("day",0);//根據(jù)流程定義的key啟動流程實例,這個key是在定義bpmn的時候設(shè)置的ProcessInstance instance = runtimeService.startProcessInstanceByKey("leaveEGatewayProcess",variables);//獲取流程實例的相關(guān)信息System.out.println("流程定義的id = " + instance.getProcessDefinitionId());System.out.println("流程實例的id = " + instance.getId());}@Testpublic void testCompleteTask(){//任務(wù)負責(zé)人String assignee = "張三";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取TaskServiceTaskService taskService = processEngine.getTaskService();//獲取任務(wù)集合List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("leaveEGatewayProcess").taskAssignee(assignee).list();//遍歷任務(wù)列表for(Task task:taskList){taskService.complete(task.getId());}}
}
7.6.2 并行網(wǎng)關(guān)
并行網(wǎng)關(guān)(InclusiveGateway)允許將流程分成多條分支,也可以把多條分支匯聚到一起,并行網(wǎng)關(guān)的功能是基于進入和外出的順序流的。
并行網(wǎng)關(guān)不會解析條件。即使順序流中定義了條件,也會被忽略
本次畫BPMN文件的時候?qū)⒓夹g(shù)經(jīng)理的assignee設(shè)置為李四,項目經(jīng)理審批的assignee設(shè)置為王五,人事復(fù)批的assignee設(shè)置為王五
package cn.wolfcode.demo;import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Created by wolfcode*/
public class PGatewayTest {/*** 部署*/@Testpublic void testDeploy(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RepositoryService對象RepositoryService repositoryService = processEngine.getRepositoryService();//進行部署Deployment deployment = repositoryService.createDeployment().addClasspathResource("bpmn/leave-PGateway.bpmn").name("請假流程-并行網(wǎng)關(guān)").deploy();//輸出部署的一些信息System.out.println("流程部署ID:"+deployment.getId());System.out.println("流程部署名稱:"+deployment.getName());}@Testpublic void testStartProcess(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RuntimeService對象RuntimeService runtimeService = processEngine.getRuntimeService();Map<String,Object> variables = new HashMap<String,Object>();//根據(jù)流程定義的key啟動流程實例,這個key是在定義bpmn的時候設(shè)置的ProcessInstance instance = runtimeService.startProcessInstanceByKey("leavePGatewayProcess");//獲取流程實例的相關(guān)信息System.out.println("流程定義的id = " + instance.getProcessDefinitionId());System.out.println("流程實例的id = " + instance.getId());}//完成任務(wù)@Testpublic void testCompleteTask(){//任務(wù)負責(zé)人String assignee = "張三";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取TaskServiceTaskService taskService = processEngine.getTaskService();//獲取任務(wù)集合List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("leavePGatewayProcess").taskAssignee(assignee).list();//遍歷任務(wù)列表for(Task task:taskList){taskService.complete(task.getId());}}
}
7.6.3 包含網(wǎng)關(guān)
包含網(wǎng)關(guān)可以看做是排他網(wǎng)關(guān)和并行網(wǎng)關(guān)的結(jié)合體。
需求:出差申請大于3天需要由項目經(jīng)理審批,小于3等于天由技術(shù)經(jīng)理審批,出差申請必須經(jīng)過人事助理審批。
本次畫BPMN文件的時候?qū)⒓夹g(shù)經(jīng)理的assignee設(shè)置為張三,項目經(jīng)理的assignee設(shè)置為李四,人事助理的assignee設(shè)置為王五,人事復(fù)批存檔設(shè)置為趙六。
package cn.wolfcode.demo;import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Created by wolfcode*/
public class IGatewayTest {/*** 部署*/@Testpublic void testDeploy(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RepositoryService對象RepositoryService repositoryService = processEngine.getRepositoryService();//進行部署Deployment deployment = repositoryService.createDeployment().addClasspathResource("bpmn/leave-IGateway.bpmn").name("請假流程-包含網(wǎng)關(guān)").deploy();//輸出部署的一些信息System.out.println("流程部署ID:"+deployment.getId());System.out.println("流程部署名稱:"+deployment.getName());}@Testpublic void testStartProcess(){//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取RuntimeService對象RuntimeService runtimeService = processEngine.getRuntimeService();Map<String,Object> variables = new HashMap<String,Object>();variables.put("day",5);//根據(jù)流程定義的key啟動流程實例,這個key是在定義bpmn的時候設(shè)置的ProcessInstance instance = runtimeService.startProcessInstanceByKey("leaveIGatewayProcess",variables);//獲取流程實例的相關(guān)信息System.out.println("流程定義的id = " + instance.getProcessDefinitionId());System.out.println("流程實例的id = " + instance.getId());}//完成任務(wù)@Testpublic void testCompleteTask(){//任務(wù)負責(zé)人String assignee = "王五";//創(chuàng)建ProcessEngine對象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//獲取TaskServiceTaskService taskService = processEngine.getTaskService();//獲取任務(wù)集合List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("leaveIGatewayProcess").taskAssignee(assignee).list();//遍歷任務(wù)列表for(Task task:taskList){taskService.complete(task.getId());}}
}