Activiti學習筆記三:管理流程定義

衣舞晨風發表於2016-09-03

一、BPMN 2.0根節

點是definitions節點。 這個元素中,可以定義多個流程定義(不過我們建議每個檔案只包含一個流程定義, 可以簡化開發過程中的維護難度)。
注意:
definitions元素 最少也要包含xmlns 和 targetNamespace的宣告。 targetNamespace可以是任意值,它用來對流程例項進行分類。

二、流程定義檔案

流程定義文件有兩部分組成:

  1. bpmn檔案
    流程規則檔案。在部署後,每次系統啟動時都會被解析,把內容封裝成流程定義放入專案快取中。Activiti框架結合這個xml檔案自動管理流程,流程的執行就是按照bpmn檔案定義的規則執行的,bpmn檔案是給計算機執行用的。
  2. 展示流程圖的圖片
    在系統裡需要展示流程的進展圖片,圖片是給使用者看的

三、部署流程定義(classpath路徑載入檔案)

/** 部署流程定義(從classpath) */
    @Test
    public void deploymentProcessDefinition_classpath() {
        Deployment deployment = processEngine.getRepositoryService()// 與流程定義和部署物件相關的Service
                .createDeployment()// 建立一個部署物件
                .name("流程定義")// 新增部署的名稱
                .addClasspathResource("diagrams/helloworld.bpmn")// 從classpath的資源中載入,一次只能載入一個檔案
                .addClasspathResource("diagrams/helloworld.png")// 從classpath的資源中載入,一次只能載入一個檔案
                .deploy();// 完成部署
        System.out.println("部署ID:" + deployment.getId());//
        System.out.println("部署名稱:" + deployment.getName());//
    }

說明:

說明:
1) 先獲取流程引擎物件:在建立時會自動載入classpath下的activiti.cfg.xml

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

2) 首先獲得預設的流程引擎,通過流程引擎獲取了一個RepositoryService物件(倉庫物件)
3) 由倉庫的服務物件產生一個部署物件配置物件,用來封裝部署操作的相關配置。
4) 這是一個鏈式程式設計,在部署配置物件中設定顯示名,上傳流程定義規則檔案
5) 向資料庫表中存放流程定義的規則資訊。
6) 這一步在資料庫中將操作三張表:
a) act_re_deployment(部署物件表)
存放流程定義的顯示名和部署時間,每部署一次增加一條記錄
b) act_re_procdef(流程定義表)
存放流程定義的屬性資訊,部署每個新的流程定義都會在這張表中增加一條記錄。
注意:當流程定義的key相同的情況下,使用的是版本升級
c) act_ge_bytearray(資原始檔表)
儲存流程定義相關的部署資訊。即流程定義文件的存放地。每部署一次就會增加兩條記錄,一條是關於bpmn規則檔案的,一條是圖片的(如果部署時只指定了bpmn一個檔案,activiti會在部署時解析bpmn檔案內容自動生成流程圖)。兩個檔案不是很大,都是以二進位制形式儲存在資料庫中。

四、部署流程定義(zip格式檔案)

/** 部署流程定義(從zip) */
    @Test
    public void deploymentProcessDefinition_zip() {
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("diagrams/helloWorld.zip");
        ZipInputStream zipInputStream = new ZipInputStream(in);
        Deployment deployment = processEngine.getRepositoryService()// 與流程定義和部署物件相關的Service
                .createDeployment()// 建立一個部署物件
                .name("流程定義")// 新增部署的名稱
                .addZipInputStream(zipInputStream)// 指定zip格式的檔案完成部署
                .deploy();// 完成部署
        System.out.println("部署ID:" + deployment.getId());//
        System.out.println("部署名稱:" + deployment.getName());//
    }

將.bpmn檔案、.png檔案壓縮成zip格式的檔案,使用zip的輸入流用作部署流程定義
這裡寫圖片描述

五、檢視流程定義

/** 查詢流程定義 */
    @Test
    public void findProcessDefinition() {
        List<ProcessDefinition> list = processEngine.getRepositoryService()// 與流程定義和部署物件相關的Service
                .createProcessDefinitionQuery()// 建立一個流程定義的查詢
                /** 指定查詢條件,where條件 */
                // .deploymentId(deploymentId)//使用部署物件ID查詢
                // .processDefinitionId(processDefinitionId)//使用流程定義ID查詢
                // .processDefinitionKey(processDefinitionKey)//使用流程定義的key查詢
                // .processDefinitionNameLike(processDefinitionNameLike)//使用流程定義的名稱模糊查詢

                /** 排序 */
                .orderByProcessDefinitionVersion().asc()// 按照版本的升序排列
                // .orderByProcessDefinitionName().desc()//按照流程定義的名稱降序排列

                /** 返回的結果集 */
                .list();// 返回一個集合列表,封裝流程定義
        // .singleResult();//返回惟一結果集
        // .count();//返回結果集數量
        // .listPage(firstResult, maxResults);//分頁查詢
        if (list != null && list.size() > 0) {
            for (ProcessDefinition pd : list) {
                System.out.println("流程定義ID:" + pd.getId());// 流程定義的key+版本+隨機生成數
                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("#########################################################");
            }
        }
    }

1) 流程定義和部署物件相關的Service都是RepositoryService。
2) 建立流程定義查詢物件,可以在ProcessDefinitionQuery上設定查詢的相關引數
3) 呼叫ProcessDefinitionQuery物件的list方法,執行查詢,獲得符合條件的流程定義列表
4) 由執行結果可以看出:
流程定義Key和Name的值為:bpmn檔案process節點的id和name的屬性值

<process id="helloWorld" name="helloWorldProcess" isExecutable="true">

5) key屬性被用來區別不同的流程定義。
6) 帶有特定key的流程定義第一次部署時,version為1。之後每次部署都會在當前最高版本號上加1
7) Id的值的生成規則為:{processDefinitionKey}:{processDefinitionVersion}:{generated-id}, 這裡的generated-id是一個自動生成的唯一的數字
8) 重複部署一次,deploymentId的值以一定的形式變化
規則act_ge_property表生成

六、刪除流程定義

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

/** 刪除流程定義 */
    @Test
    public void deleteProcessDefinition() {
        // 使用部署ID,完成刪除
        String deploymentId = "10001";
        /**
         * 不帶級聯的刪除 只能刪除沒有啟動的流程,如果流程啟動,就會丟擲異常
         */
        // processEngine.getRepositoryService()//
        // .deleteDeployment(deploymentId);

        /**
         * 級聯刪除 不管流程是否啟動,都能可以刪除
         */
        processEngine.getRepositoryService()//
                .deleteDeployment(deploymentId, true);
        System.out.println("刪除成功!");
    }

說明:
1) 因為刪除的是流程定義,而流程定義的部署是屬於倉庫服務的,所以應該先得到RepositoryService
2) 如果該流程定義下沒有正在執行的流程,則可以用普通刪除。如果是有關聯的資訊,用級聯刪除。專案開發中使用級聯刪除的情況比較多,刪除操作一般只開放給超級管理員使用。

七、獲取流程定義文件的資源(檢視流程圖附件)

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

/**
     * 檢視流程圖
     * 
     * @throws IOException
     */
    @Test
    public void viewPic() throws IOException {
        /** 將生成圖片放到資料夾下 */
        String deploymentId = "801";
        // 獲取圖片資源名稱
        List<String> list = processEngine.getRepositoryService()//
                .getDeploymentResourceNames(deploymentId);
        // 定義圖片資源的名稱
        String resourceName = "";
        if (list != null && list.size() > 0) {
            for (String name : list) {
                if (name.indexOf(".png") >= 0) {
                    resourceName = name;
                }
            }
        }

        // 獲取圖片的輸入流
        InputStream in = processEngine.getRepositoryService()//
                .getResourceAsStream(deploymentId, resourceName);

        // 將圖片生成到D盤的目錄下
        File file = new File("D:/" + resourceName);
        // 將輸入流的圖片寫到D盤下
        FileUtils.copyInputStreamToFile(in, file);
    }

說明:
1) deploymentId為流程部署ID
2) resourceName為act_ge_bytearray表中NAME_列的值
3) 使用repositoryService的getDeploymentResourceNames方法可以獲取指定部署下得所有檔案的名稱
4) 使用repositoryService的getResourceAsStream方法傳入部署ID和資源圖片名稱可以獲取部署下指定名稱檔案的輸入流
5) 最後的有關IO流的操作,使用FileUtils工具的copyInputStreamToFile方法完成流程流程到檔案的拷貝,將資原始檔以流的形式輸出到指定資料夾下

八、查詢最新版本的流程定義

/*** 附加功能:查詢最新版本的流程定義 */
    @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+版本+隨機生成數
                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("#########################################################");
            }
        }
    }

九、刪除流程定義(刪除key相同的所有不同版本的流程定義)

/** 附加功能:刪除流程定義(刪除key相同的所有不同版本的流程定義) */
    @Test
    public void deleteProcessDefinitionByKey() {
        // 流程定義的key
        String processDefinitionKey = "helloworld";
        // 先使用流程定義的key查詢流程定義,查詢出所有的版本
        List<ProcessDefinition> list = processEngine.getRepositoryService()//
                .createProcessDefinitionQuery()//
                .processDefinitionKey(processDefinitionKey)// 使用流程定義的key查詢
                .list();
        // 遍歷,獲取每個流程定義的部署ID
        if (list != null && list.size() > 0) {
            for (ProcessDefinition pd : list) {
                // 獲取部署ID
                String deploymentId = pd.getDeploymentId();
                processEngine.getRepositoryService()//
                        .deleteDeployment(deploymentId, true);
            }
        }
    }

十、總結

Deployment 部署物件
1、一次部署的多個檔案的資訊。對於不需要的流程可以刪除和修改。
2、對應的表:
act_re_deployment:部署物件表
act_re_procdef:流程定義表
act_ge_bytearray:資原始檔表
act_ge_property:主鍵生成策略表

ProcessDefinition 流程定義
1、解析.bpmn後得到的流程定義規則的資訊,工作流系統就是按照流程定義的規則執行的。
demo原始碼下載:http://download.csdn.net/detail/xunzaosiyecao/9620838

本文部分內容整理自itcast講義,在此表示感謝。
作者:jiankunking 出處:http://blog.csdn.net/jiankunking

相關文章