介紹工作流
網上工作流的定義一大堆,這里就不去復制了,通俗的理解,工作流就是類似OA系統中請假審批、報銷審批等一系列流程,下級提交的申請只有直系領導才能審批,其他人是沒有權限的,而只有直系領導審批通過后,直系領導的直系領導才可以看到申請,並進行審批,以此類推。。。
而Activiti工作流就可以實現類似的功能,本筆記將以最簡單的方式讓你明白怎么使用Activiti工作流,直接上代碼
准備環境
1) JDK1.6或者更高版本
2) 支持的數據庫有:h2, mysql, oracle, postgres, mssql, db2等。
3) 支持activiti5運行的jar包
4) 開發環境為Eclipse3.7或者以上版本,myeclipse為8.6版本
安裝流程設計器(eclipse插件)
方案一:
在有網絡的情況下,安裝流程設計器步驟如下:
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…打開面板,如果看到下圖內容:
說明安裝成功了。
方案二
在沒有網絡的情況下,安裝流程設計器步驟如下:
首先下載離線插件包:
https://files.cnblogs.com/files/lm970585581/activiti.zip
將壓縮包解壓后
這兩個文件夾復制到Eclipse根目錄下 ,重啟即可
注意:
打開菜單Windows->Preferences->Activiti->Save下流程流程圖片的生成方式:
雖然流程引擎在單獨部署bpmn文件時會自動生成圖片,但在實際開發過程中,自動生成的圖片會導致和BPMN中的坐標有出入,在實際項目中展示流程當前位置圖會有問題。
所在完成以上配置后,會由我們自己來管理流程圖片。在發布流程時把流程規則文件和流程圖片一起上傳就行了。
准備Activiti5開發環境
在activiti-5.13->wars目錄下是一些示例項目,解壓activiti-rest項目,導入activiti-rest目錄中WEB-INF\lib下所有包。添加到classpath中。
另外需要根據我們正在使用的數據庫添加相應的數據庫jar包
初始化數據庫
可以在activiti-rest\WEB-INF\classes下找到配置文件:如下
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"> <property name="jdbcDriver" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://192.168.220.130:3306/activiti?useUnicode=true&characterEncoding=utf8"></property> <property name="jdbcUsername" value="root"></property> <property name="jdbcPassword" value="root"></property> <!-- 創建表的策略 --> <property name="databaseSchemaUpdate" value="true"></property> </bean> </beans>
調用以下java代碼,即可把需要的表創建出來
import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngineConfiguration; import org.junit.Test; public class CreateTable { @Test public void testCreateTable(){ ProcessEngine processEngine = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml") .buildProcessEngine(); } }
HelloWorld程序
先畫請假流程圖
注意:
properties=>General中的ID和NAME可以設置每個步驟的名稱:
每個審批過程的properties=>Main config=>Assignee:設置能夠審批的對象,這里部門經理審批設置為:張三,總經理審批設置為:李四
保存后,在根目錄下生成:
JAVA程序如下:
import java.util.List; import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngineConfiguration; import org.activiti.engine.ProcessEngines; import org.activiti.engine.task.Task; import org.junit.Test; /** * 1、部署流程圖 * 2、啟動流程實例 * 3、發起申請 * 4、審批 * @author zd * */ public class HelloWorld { /** * 部署流程圖 */ @Test public void testDeploy(){ //產生流程引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //獲取倉庫流程的實例 processEngine.getRepositoryService() .createDeployment() .addClasspathResource("qingjia.bpmn") .addClasspathResource("qingjia.png") .deploy(); /** * 這里使用RepositoryService部署流程定義 addClasspathResource表示從類路徑下加載資源文件,一次只能加載一個文件 */ } /** * 啟動流程實例 pi=process instance */ @Test public void testStartPI(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); processEngine.getRuntimeService() .startProcessInstanceById("qingjia:1:4");//ID在act_re_procdef這個表中可以看到 //這里使用RuntimeService啟動流程實例 } /** * 完成任務 */ @Test public void testFinishTask(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); processEngine.getTaskService() .complete("104");//act_ru_task表中獲取 } /** * 根據張三查詢任務 */ @Test public void testQueryTask(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //查詢任務列表 List<Task> tasks = processEngine.getTaskService() .createTaskQuery() .taskAssignee("張三") .list(); for (Task task : tasks) { System.out.println(task.getName()); } } }
流程定義
import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import java.util.zip.ZipInputStream; import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngines; import org.activiti.engine.repository.Deployment; import org.activiti.engine.repository.ProcessDefinition; import org.junit.Test; import org.springframework.transaction.annotation.Transactional; /** * pd=process definition * @author zd * 1、把流程圖部署到activiti的引擎中 重點 * classpath * inputstream * zipinputstream * 2、對流程圖進行刪除 重點 * 3、獲取到流程圖和bpmn文件 重點 * 4、查詢 了解 * 查詢部署 * 查詢流程定義 */ public class PDTest { /** * 涉及到的表 * act_ge_bytearray * 1、說明 * 該表存儲了bpmn文件和png圖片 * 從字段可以看出,根據deploymentID可以查詢bpmn文件和png圖片 * 2、字段 * name_:存儲該文件的路徑名稱 * deploymentid_id_:部署表的ID * byte_:存放值(bpmn和png) * act_re_deployment * 1、說明 * 該表存儲了部署的動作 * 2、字段 * ID_:部署ID 主鍵 * act_re_procdef * 1、說明 * 流程定義表 * 2、字段 * id: 是由${name}:${version}:隨機數 確定唯一的流程 * name_: 流程定義名稱 * key_: 流程定義名稱 * version_: 某一個流程定義的版本 * deployment_id_:部署表的ID * * 說明: * 1、根據deploymentID-->查詢圖片和bpmn文件 * 2、根據deploymentID-->查詢流程定義 * 3、只要流程名稱不變,部署一次,版本號加1,id就發生變化,生成了一個新的deploymentID * 4、所以deploymentID和pdid是一一對應的關系 */ @Test public void testDeployFromClasspath(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); processEngine.getRepositoryService() .createDeployment() .addClasspathResource("qingjia.bpmn") .addClasspathResource("qingjia.png") .deploy(); } /** * 通過inputStream的方式部署 */ @Test public void testDeployFromInputStream(){ InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("qingjia.bpmn"); ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); processEngine.getRepositoryService() .createDeployment() .addInputStream("qingjia.bpmn", inputStream) .deploy(); } /** * 通過zip的方式部署 */ @Test public void testDeployFromZip(){ InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("qingjia.zip"); ZipInputStream zipInputStream = new ZipInputStream(inputStream); ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); processEngine.getRepositoryService() .createDeployment() .addZipInputStream(zipInputStream) .deploy(); } /** * 把查詢出來的圖片放到E盤的根目錄下 */ @Test public void testShowImage() throws Exception{ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); InputStream inputStream = processEngine.getRepositoryService() /** * 參數為pdid */ .getProcessDiagram("qingjia:1:4"); /** * 得到一個圖片 */ // OutputStream outputStream = new FileOutputStream("e:/processimg.png"); // for(int b=-1;(b=inputStream.read())!=-1;){ // outputStream.write(b); // } // inputStream.close(); // outputStream.close(); /***************************************************************************************/ /** * 第一個參數為deploymentId * 第二個參數為resourceName */ /********************************************************************************/ /** * 得到的是一個圖片 */ // InputStream inputStream2 = processEngine.getRepositoryService() // .getResourceAsStream("101", "qingjia.png"); // // OutputStream outputStream2 = new FileOutputStream("e:/processimg2.png"); // for(int b=-1;(b=inputStream2.read())!=-1;){ // outputStream2.write(b); // } // inputStream2.close(); // outputStream2.close(); /**********************************************************************************/ /** * 得到的是bpmn文件 */ InputStream inputStream3 = processEngine.getRepositoryService() .getProcessModel("qingjia:1:4"); OutputStream outputStream3 = new FileOutputStream("e:/processimg3.bpmn"); for(int b=-1;(b=inputStream3.read())!=-1;){ outputStream3.write(b); } inputStream3.close(); outputStream3.close(); /*************************************************************************************/ } /** * 查詢流程部署 */ @Test public void testQueryDeploy(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); List<Deployment> deployments = processEngine.getRepositoryService() .createDeploymentQuery() .list(); for (Deployment deployment : deployments) { System.out.println(deployment.getId()); } } /** * 根據部署ID查詢部署 一個結果 */ @Test public void testQueryDeployById(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); Deployment deployment = processEngine.getRepositoryService() .createDeploymentQuery() .deploymentId("1") .singleResult(); System.out.println(deployment.getId()); } /** * 查詢所有的流程定義 */ @Test public void testQueryPD(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); List<ProcessDefinition> processDefinitions = processEngine.getRepositoryService() .createProcessDefinitionQuery() .list(); for (ProcessDefinition processDefinition : processDefinitions) { System.out.println(processDefinition.getKey()); System.out.println(processDefinition.getId()); System.out.println(processDefinition.getVersion()); } } /** * 按照版本的從高到低進行排序 */ @Test public void testQueryPDByVersion(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); List<ProcessDefinition> processDefinitions = processEngine.getRepositoryService() .createProcessDefinitionQuery() .orderByProcessDefinitionVersion() .desc() .list(); for (ProcessDefinition processDefinition : processDefinitions) { System.out.println(processDefinition.getKey()); System.out.println(processDefinition.getId()); System.out.println(processDefinition.getVersion()); } } /** * 根據pdid查詢流程定義 * 根據 pdkey查詢流程定義 */ //略。。 /** * 刪除 */ @Test public void testDelete(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); processEngine.getRepositoryService() //.deleteDeployment("");//該方法只能刪除流程定義,一般不會使用 .deleteDeployment("1", true);//該方法不僅能夠刪除流程定義,而且能夠刪除正在運行的流程實例 } }
流程實例、任務的執行
import java.util.List; import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngines; import org.activiti.engine.history.HistoricActivityInstance; import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.impl.bpmn.parser.handler.ProcessParseHandler; import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.activiti.engine.impl.pvm.process.ActivityImpl; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; import org.junit.Test; /** * pi=process instance * @author zd * 1、啟動流程實例 * 2、完成任務 * 3、任務的查詢 * 1、根據任務的執行人查詢任務 * 2、可以根據任務查詢任務的執行人 * 3、查看歷史任務 * 4、怎么樣查看流程實例是否結束 */ public class PITest { /** * 啟動流程實例 * 涉及到的表 * act_hi_actinst hi:history actinst:action instance * 1、概念 * 所有的正在執行的或者已經完成的節點 * 2、字段 * act_type_:為節點的類型 * end_time_: 如果有值,說明該節點已經結束了 * act_hi_procinst procinst:process instance * 1、概念 * 所有的正在執行的或者已經完成的流程實例 * 2、字段 * end_time_:如果該字段有值,說明這個流程實例已經結束了 * end_act_id_:說明該流程實例是在哪個節點結束的 * act_hi_taskinst taskinst:task instance * 1、概念 * 所有的正在執行的或者已經完成的任務節點 * 2、字段 * end_time_:如果該字段有值,說明任務已經完成了 * delete_reason:如果該值為completed,說明該任務處於完成的狀態 * act_ru_execution ru:runtime * 1、概念 * 代表正在執行的流程實例 * 2、字段 * id_:主鍵 executionid * proc_inst_id_: process instanceid * proc_def_id_:pdid * act_id_:當前的流程實例正在執行的節點的ID的值 * act_ru_task * 1、概念 * 代表正在執行的任務 * 2、字段 * id_:主鍵 任務ID * execution_id_:piid,executionid * name_:任務名稱 * 3、說明 * 該表是一個臨時表,該表中的任務完成以后,這一行會被刪除掉 * */ @Test public void testStartPI(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); ProcessInstance pi = processEngine.getRuntimeService() .startProcessInstanceById("qingjia:1:304"); System.out.println(pi.getId()); } /** * 查詢所有的正在執行的流程實例 */ @Test public void testQueryPI(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); List<ProcessInstance> processInstances = processEngine.getRuntimeService() .createProcessInstanceQuery() .list(); for (ProcessInstance processInstance : processInstances) { System.out.println(processInstance.getActivityId()); System.out.println(processInstance.getId()); } } /** * 查詢當前正在執行的節點 */ @Test public void testQueryActivity(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); List<String> strings = processEngine.getRuntimeService() .getActiveActivityIds("401"); for (String string : strings) { System.out.println(string); } } /** *獲取當前的流程實例正在運行的節點的坐標 */ @Test public void getPix(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); /** * processDefinitionEntity代表流程圖對象的實體 * * 根據pdid獲取到流程定義實體 */ ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity)processEngine.getRepositoryService() .getProcessDefinition("qingjia:1:304"); List<String> strings = processEngine.getRuntimeService() .getActiveActivityIds("401"); //piid for (String string : strings) { /** * ActivityImpl代表流程圖上的每一個節點 */ ActivityImpl activityImpl = processDefinitionEntity.findActivity(string); /** * 獲取到正在執行的流程節點的坐標 */ System.out.println(activityImpl.getHeight()); System.out.println(activityImpl.getWidth()); System.out.println(activityImpl.getX()); System.out.println(activityImpl.getY()); } } /** * 查詢所有的任務 */ @Test public void testQueryAllTask(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); List<Task> tasks = processEngine.getTaskService() .createTaskQuery() .list(); for (Task task : tasks) { System.out.println(task.getId()); System.out.println(task.getName()); } } /** * 完成任務 * 需要一個參數:taskId */ @Test public void testFinishTask(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); processEngine.getTaskService() .complete("602"); } /** * 根據任務的執行人查看任務 */ @Test public void testQueryTaskByAssignee(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); List<Task> tasks = processEngine.getTaskService() .createTaskQuery() .taskAssignee("張三") .list(); for (Task task : tasks) { System.out.println(task.getId()); System.out.println(task.getName()); } } /** * 根據任務的執行人查看任務,並且按照時間的倒敘排序 */ @Test public void testQueryTaskByAssigneeByTime_DESC(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); List<Task> tasks = processEngine.getTaskService() .createTaskQuery() .taskAssignee("張三") .orderByTaskCreateTime() .desc() .list(); for (Task task : tasks) { System.out.println(task.getId()); System.out.println(task.getName()); } } /** * 根據piid判斷流程實例是否結束 */ @Test public void testQueryPIByPIID(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); ProcessInstance pi = processEngine.getRuntimeService() .createProcessInstanceQuery() .processInstanceId("401") .singleResult(); if(pi==null){ System.out.println("該流程實例已經結束了"); }else{ System.out.println("該流程實例正在執行中"); } } /** * 查詢已經完成的任務 */ @Test public void testQueryHistoryTask(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); List<HistoricTaskInstance> historicTaskInstances = processEngine.getHistoryService() .createHistoricTaskInstanceQuery() .finished() .list(); for (HistoricTaskInstance historicTaskInstance : historicTaskInstances) { System.out.println(historicTaskInstance.getAssignee()); System.out.println(historicTaskInstance.getName()); System.out.println(historicTaskInstance.getId()); } } /** * 查詢已經完成的activityimpl */ @Test public void testQueryHistoryActivityImpl(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); List<HistoricActivityInstance> historicActivityInstances = processEngine.getHistoryService() .createHistoricActivityInstanceQuery() .list(); for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) { System.out.println(historicActivityInstance.getActivityName()); } } }