activiti(三):關於流程實例的一些操作


前文:activiti(二):關於流程部署和刪除的一些操作

目錄:activiti 目錄

一、啟動流程實例

啟動流程的方法多種,這里詳細介紹啟動流程的整個過程!

1.1 操作流程實例的門面接口

我們已知,流程的部署和流程實例數據的門面接口是:RepositoryService

操作流程實例的門面接口是:RuntimeService。在源碼中這個類上沒有備注,只有些作者名稱,但是我們根據方法可以分析出來,RuntimeService有哪些作用

此接口與流程部署和定義操作的接口RepositoryService一樣;
提供了豐富的操作實例的方式,重點分為:
1)startxxx:以start開頭的啟動流程實例方法。
2)deleteProcessInstance:刪除正在執行的流程
3)getxxx:以get開頭的獲取流程實例(活動中或者等待中)相關信息,id列表,實例列表等等
4)trigger:觸發器形式,可以指定流程ID,和一些參數,指定流程執行。
5)builder:獲取流程實例構造器
6)一些其他操作:流程構造器、參數的獲取,修改,添加等等

1.2 前置知識

  • 部署一個流程代碼(隨便選擇一個方式部署)

         /**
         * 部署一個流程並返回部署的ID,
         * 部署表:act_re_deployment 插入一條數據,並在資源表中記錄對應的資源(圖片文件、bpmn文件),二進制存儲。並將流程的數據插入流程數據表
         * 資源表:act_ge_bytearray 插入對應的資源數據,可能多條,看傳入多少文件。
         * 流程數據表:act_re_procdef 插入流程對應的定義數據。
         * @author caodahuan
         * @date 2019/8/29
         * @return java.lang.String
         */
        private String deployProcess(){
            // 1. 獲取到部署新流程的構造器
            DeploymentBuilder builder = ProcessEngines.getDefaultProcessEngine().getRepositoryService().createDeployment();
    
            // 2. 選擇部署方式為:通過資源文件進行部署
            builder.addClasspathResource("apply.bpmn");
            builder.addClasspathResource("apply.png");
    
            // 3. 設置一些需要的參數(非必須)
            builder.key("key"); // 設置key,可重復但不建議重復,可用來啟動流程
            builder.name("報銷流程"); // 設置流程名稱
            builder.category("3"); // 流程類型
    
            // 4. 部署流程
            Deployment deploy = builder.deploy();
            System.out.println(deploy.getId());
            return deploy.getId();
        }
    
  • 獲取流程定義數據

        /**
         * 獲取到流程定義,返回表中數據
         * 流程定義數據在表act_re_procdef表中。
         * @author caodahuan
         * @date 2019/8/29
         * @return void
         */
        private ProcessDefinition getDefinition() {
            // 1. 部署流程並返回流程ID
            String deploymentId = this.deployProcess();
    
            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
            ProcessDefinitionQuery query = processEngine.getRepositoryService().createProcessDefinitionQuery();
            query.orderByDeploymentId();
            query.desc();
            query.deploymentId(deploymentId);
            List<ProcessDefinition> list = query.list();
    
            if (!CollectionUtils.isEmpty(list)) {
                return list.get(0);
            }
    
            return null;
        }
    

1.3 啟動已經部署好的流程實例

  • 先定義一個獲取實例操作接口的方法

        /**
         * 獲取到操作流程實例的總接口
         * @author caodahuan
         * @date 2019/8/29
         * @return void
         */
        public RuntimeService getService(){
    
            // 1. 先獲取流程引擎
            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    
            /*
             * 2. 獲取操作實例的接口
             * 此接口與流程部署和定義操作的接口RepositoryService一樣;
             * 提供了對豐富的操作方式,重點分為:
             * 1)startxxx:以start開頭的啟動流程實例方法。
             * 2)deleteProcessInstance:刪除正在執行的流程
             * 3)getxxx:以get開頭的獲取流程實例(活動中或者等待中)相關信息,id列表,實例列表等等
             * 4)trigger:觸發器形式,可以指定流程ID,和一些參數,指定流程執行。
             * 5)builder:獲取流程實例構造器
             * 6)一些其他操作:流程構造器、參數的獲取,修改,添加等等
             *
             */
            RuntimeService runtimeService = processEngine.getRuntimeService();
    
            return runtimeService;
        }
    
  • 方法一:根據流程定義表中的ID啟動。此處ID,取流程定義數據表:act_re_procdef表中對應數據ID。

        /**
         * 啟動流程實例:
         * 方法一:根據流程定義的ID;
         * 已經知道,在部署流程的時候,我們將流程的數據寫到了表:act_re_prcodef
         * 通過表act_re_prcodef獲取到流程,然后啟動流程!
         * @author caodahuan
         * @date 2019/8/29
         * @return void
         */
        @Test
        public void startMethodOne(){
    
            // 1. 獲取到操作流程數據的接口
            RuntimeService service = getService();
    
            /*
             * 2. 根據ID啟動流程,返回的是啟動流程后的實例
             * 部署流程后,流程數據其實存儲在act_re_procdef表中。根據id啟動,即根據act_re_procdef表的id啟動。
             * 1)根據流程獲取流程定義數據的ID
             * 2)根據ID啟動流程
             */
            // 部署好的流程定義數據
            ProcessDefinition definition = this.getDefinition();
            System.out.println(definition.getId());
            /*
             * 根據流程定義數據表中的ID啟動流程
             * 啟動流程后:操作以下表(可以在整個過程中觀察這些表,看看效果,理解更深入)
             * 1、正在執行的流程實例表:
             * act_ru_execution(正在執行的流程實例表):表示執行中的流程,會插入2條數據,一條父數據表示流程,
             * 一條子數據表示正在執行的流程進展。(完成的實例將被刪除)
             * act_ru_task(正在執行的任務表):表示正在執行的任務。(完成的任務將被刪除)
             * 歷史表:
             * act_hi_taskinst(任務歷史表):插入一條數據,通過execution_id_關聯到流程執行表act_ru_execution;
             * (此表存儲已經完成的和正在執行的流程節點)如果end_time有值,表示已經結束(歷史);沒值,表示正在執行的節點。
             * act_hi_procinst(實例歷史表):插入一條數據,通過proc_def_id_關聯到流程定義表act_re_procdef;
             * (此表存儲已經完成的和正在執行的實例)如果end_time有值,表示已經結束(歷史);沒值,表示正在執行的實例。
             * act_hi_actinst(元素歷史表):插入2條數據,一條startEvent數據,啟動元素完成。一條userTask,正在執行元素。
             * (此表存儲已經完成的和正在執行的元素)如果end_time有值,表示已經結束(歷史);沒值,表示正在執行的元素。
             */
            service.startProcessInstanceById(definition.getId());
        }
    
  • 方法二:根據流程定義數據的key啟動:act_re_procdef表中key

        /**
         * 方法二:根據流程定義(act_re_procdef)中的KEY啟動流程實例
         * 通過方法一知道了總的流程,此處就不再展示完整的獲取流程。直接從表中獲取KEY值。
         * @author caodahuan
         * @date 2019/8/30 
         * @return void 
         */
        @Test
        public void startMethodTwo(){
    
            // 1. 獲取流程實例操作接口
            RuntimeService service = getService();
    
            // 2. 從表中已經知道了key
            ProcessInstance apply = service.startProcessInstanceByKey("apply");
        }
    
  • 方法三:通過ProcessInstanceBuilder

         /**
         * 方法三:通過ProcessInstanceBuilder來啟動流程
         * @author caodahuan
         * @date 2019/9/3 
         * @return void 
         */
        @Test
        public void queryInstanceByBuilder(){
            
            // 1.操作接口
            RuntimeService service = getService();
            
            // 2.獲取流程構建器(builder就是用來操作實例的構建器)
            ProcessInstanceBuilder processInstanceBuilder = service.createProcessInstanceBuilder();
            
            // 3.填充參數,通過definitionID或者definitionKey啟動,但是可以設置流程參數!
            processInstanceBuilder.name("自定義builder啟動");
            processInstanceBuilder.businessKey("appxx");
            processInstanceBuilder.processDefinitionId("apply:3:115004");
            
            // 4.啟動流程
            ProcessInstance instance = processInstanceBuilder.start();
            System.out.println(instance.getId());
        }
    
  • 方法四:還有多種啟動方法:

1.4 查詢已經啟動的流程實例(ProcessInstance)

  • 方法一:根據查詢條件,查詢流程list

    	/**
         * 方法一:根據流程實例查詢器:ProcessInstanceQuery得到list
         * 如果用過mybatis提供的Example查詢接口,大概能很容易理解這種處理方式。
         * @author caodahuan
         * @date 2019/9/3
         * @return void
         */
        @Test
        public void queryInstanceList(){
            // 1. 獲取到操作實例的接口
            RuntimeService service = getService();
    
            // 2. 構建一個查詢器,它專用來查詢實例
            ProcessInstanceQuery processInstanceQuery = service.createProcessInstanceQuery();
    
            // 3. 如果查詢得到list,必須排序;
            processInstanceQuery = processInstanceQuery.processDefinitionKey("apply");
            processInstanceQuery.orderByProcessDefinitionId();
            processInstanceQuery.asc();
            List<ProcessInstance> list = processInstanceQuery.list();
    
            list.forEach(l -> System.out.println(l.getId()));
        }
    
  • 方法二:查詢得到唯一記錄singleResult

    	/**
         * 方法二:根據流程實例查詢器:ProcessInstanceQuery得到singleResult
         * 可以通過查詢list的方式,然后判斷list的size == 1,再直接調用singleResult。
         * 並不是只有ID才能得到唯一數據,都可以調用singleResult,只不過,如果得到的不是唯一數據,會報異常!
         * @author caodahuan
         * @date 2019/9/3
         * @return void
         */
        @Test
        public void queryInstanceSingle(){
            // 1. 獲取到操作實例的接口
            RuntimeService service = getService();
    
            // 2. 構建一個查詢器,它專用來查詢實例
            ProcessInstanceQuery processInstanceQuery = service.createProcessInstanceQuery();
    
            // 3. 如果查詢可得到唯一條目,可使用singleResult()直接得到實例。
            // 通過多條件得到唯一數據
            processInstanceQuery = processInstanceQuery.processDefinitionKey("apply");
            processInstanceQuery.processInstanceBusinessKey("ap");
            ProcessInstance processInstance = processInstanceQuery.singleResult();
            System.out.println(processInstance.getId());
    
            // 更靠譜的是通過id得到唯一數據
            processInstanceQuery.processInstanceId("155005").singleResult();
        }	
    
  • 完成一個流程后,下列表的情況(更細節的數據變化,需要在完成每一個任務的時候觀察表數據的變化才能有深入體會,依然是這幾張表)

完成任務(會在任務操作中再述)

完成任務方法

  • 方法一:直接通過taskId來完成任務
/**
     * 完成任務1:通過taskId來完成
     * 因為完成通過TaskService。
     * @author caodahuan
     * @date 2019/8/30
     * @return void
     */
    @Test
    public void complete(){

        // 1. 獲取到流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        /*
         * 2. 對於任務的操作:TaskService。
         * 操作任務表:act_ru_task,此表已經介紹過:存儲正在執行的任務,一旦任務執行完,則從此表中移除。
         */
        TaskService taskService = processEngine.getTaskService();
        taskService.complete("107502");
    }

  • 方法二:在實際中通過代碼獲取task任務,再獲取到ID

    
        /**
         * 完成任務實例:實際操作中都是通過查庫來獲取任務,完成任務。
         * @author caodahuan
         * @date 2019/9/2
         * @return void
         */
        @Test
        public void complete1(){
            /*
             * 啟動流程
             */
            // 1. 獲取到操作流程數據的接口
            RuntimeService service = getService();
    
            /*
             * 2. 根據ID啟動流程,返回的是啟動流程后的實例
             * 部署流程后,流程數據其實存儲在act_re_procdef表中。根據id啟動,即根據act_re_procdef表的id啟動。
             * 1)根據流程獲取流程定義數據的ID
             * 2)根據ID啟動流程
             */
            // 部署好的流程定義數據(返回流程實例)
            ProcessDefinition definition = this.getDefinition();
            ProcessInstance instance = service.startProcessInstanceById(definition.getId());
    
            // 3. 獲取任務操作接口
            TaskService taskService = ProcessEngines.getDefaultProcessEngine().getTaskService();
    
            // 4. 由於complete方法是通過taskId來執行,那么先獲取Task詳情。
            // 4.1 獲取任務查詢器(這個已經見過多次了)
            TaskQuery taskQuery = taskService.createTaskQuery();
    
            // 4.2 查詢任務(通過流程實例來獲取任務,部署流程時,已經得到了流程實例)
            Task task = taskQuery.processInstanceId(instance.getId()).singleResult();
    
            // 4.3 通過任務ID來執行任務
            taskService.complete(task.getId());
        }
    
  • 方法三:介紹其他完成任務方法

    /**
         * 其他完成任務方法
         * @author caodahuan
         * @date 2019/9/2
         * @return void
         */
        @Test
        public void completeOther(){
    
            // 1. 獲取任務操作接口
            TaskService taskService = ProcessEngines.getDefaultProcessEngine().getTaskService();
    
            // 直接ID完成任務(已經描述)
            taskService.complete("112509");
    
            // 完成並設置變量:參數1=taskId,參數2=流程變量
            Map<String, Object> params = new HashMap<>();
            params.put("haha","enlo");
            taskService.complete("127503",params);
    
            // 完成並設置變量:參數1=taskId,參數2=流程變量,參數3=瞬時變量
            // 為啥不能用呢,報錯:java.lang.ClassCastException,待解決!
            taskService.complete("127503",params,params);
    
            // 完成並設置變量:參數1=taskId,參數2=流程變量,參數3=是否為本地變量
            //如果為true,通過的變量將會隨着本任務存亡(本任務結束,變量刪除,稱之為任務變量(局部)),默認為false,即為complete(String,Map)
            // 那么這時候的變量為流程變量(全局)
            taskService.complete("127503",params,false);
        }
    

    關於流程變量:(傳遞上下文)

    按照作用域可分為:

    • 流程變量(全局變量):整個流程都可獲取到。
    • 本地變量:本任務節點可獲取,下個任務節點就拿不到了。

    按照是否存庫:

    • 持久變量:在act_ru_variable和act_hi_varinst中插入變量數據
    • 瞬時變量(activiti 6):只有轉成持久變量才會存庫


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM