天天看點

Activiti7 通過代碼動态生成工作流

作者:會寫Java的阿偉

前言

最近項目有用到Activiti工作流,但是需求有點特殊,需要通過參數去生成BPMN圖,查閱了資料後,能實作簡單的工作流生成,那接下來看看如何通過代碼動态生成工作流的吧。

一.設計思路

1.以普通的請假流程為例

Activiti7 通過代碼動态生成工作流

(1)生成開始節點加第1個任務和調整申請任務(拒絕或者退回操作)以及其排他網關

(2)循環審批清單,生成第2至第N-1個任務,并每個任務後都有1個排他網關,用于連接配接調整申請任務

(3)最後1個節點,後面無排他任務,故需要單獨處理

二.具體實作代碼

List<String> roles=new ArrayList<>();
        roles.add("1508574");
        roles.add("13765234");
        roles.add("18834222");
        listMap.put("province",roles);
          for (String auditRole : processParamsDto.getAuditRoles()) {
        if (auditRole.equals(processParamsDto.getAuditRoles().get(0))) {
            //開始連線
            process.addFlowElement(createUserTask("task".concat("_").concat(auditRole), "審批".concat(auditRole), auditRole));
            process.addFlowElement(createSequenceFlow("start", "task".concat("_").concat(auditRole), null));
            //正常的 第一個網關 process.addFlowElement(createExclusiveGateway("exclusiveGateWay".concat("_").concat(auditRole), "exclusiveGateWay".concat("_").concat(auditRole)));
            //第一個排他網關連線 任務->排他網關
            process.addFlowElement(createSequenceFlow("task".concat("_").concat(auditRole), "exclusiveGateWay".concat("_").concat(auditRole), null));
            //重新申請分支  建立重新申請任務
            process.addFlowElement(createUserTask("task".concat("_").concat("重新申請"), "指定人".concat("審批"), "${startBy}"));
            //申請網關->申請任務
            process.addFlowElement(createSequenceFlow("exclusiveGateWay".concat("_").concat(auditRole), "task".concat("_").concat("重新申請"), "${flag==false}"));
            //申請網關
            process.addFlowElement(createExclusiveGateway("exclusiveGateWay".concat("_").concat("重新申請"), "exclusiveGateWay".concat("_").concat("重新申請")));
            //申請任務->申請網關
            process.addFlowElement(createSequenceFlow("task".concat("_").concat("重新申請"),"exclusiveGateWay".concat("_").concat("重新申請"), null));

        } else if (!auditRole.equals(processParamsDto.getAuditRoles().get(processParamsDto.getAuditRoles().size() - 1))) {
            //建立排他網關  每個任務後都有一個排他網關

            //第二個任務至第size-1個任務
            process.addFlowElement(createUserTask("task".concat("_").concat(auditRole), "審批".concat(auditRole), auditRole));
            //第一個網關->第二個任務  任務之前的節點 網關->第二個任務....第N個任務 true
            process.addFlowElement(createSequenceFlow("exclusiveGateWay".concat("_").concat(getPreAuditRole(auditRole,processParamsDto.getAuditRoles())), "task".concat("_").concat(auditRole), "${flag==true}"));
            //網關->申請任務 false
            process.addFlowElement(createExclusiveGateway("exclusiveGateWay".concat("_").concat(auditRole), "exclusiveGateWay(目前)".concat("_").concat(auditRole)));
            process.addFlowElement(createSequenceFlow("task".concat("_").concat(auditRole), "exclusiveGateWay".concat("_").concat(auditRole), null));

            //排他網關—>重新申請任務
            process.addFlowElement(createSequenceFlow("exclusiveGateWay".concat("_").concat(auditRole), "task".concat("_").concat("重新申請"),"#{flag==false}"));

        } else if (auditRole.equals(processParamsDto.getAuditRoles().get(processParamsDto.getAuditRoles().size() - 1))) {
            String lastNode=processParamsDto.getAuditRoles().get(processParamsDto.getAuditRoles().size() - 1);
            System.out.println("目前節點"+lastNode);
            process.addFlowElement(createUserTask("task".concat(lastNode), "審批".concat(auditRole), auditRole));
            process.addFlowElement(createSequenceFlow("exclusiveGateWay".concat("_").concat(getPreAuditRole(auditRole,processParamsDto.getAuditRoles())),"task".concat(lastNode),"#{flag==true}"));

            process.addFlowElement(createEndEvent());
            process.addFlowElement(createSequenceFlow("task".concat(processParamsDto.getAuditRoles().get(processParamsDto.getAuditRoles().size() - 1)), "end", "${flag==true}"));     process.addFlowElement(createSequenceFlow("exclusiveGateWay".concat("_").concat("重新申請"), "end", "${flag==false}"));
  process.addFlowElement(createSequenceFlow("exclusiveGateWay".concat("_").concat("重新申請"), "task".concat("_").concat(processParamsDto.getAuditRoles().get(0)), "${flag==true}"));
        }

    }     
     new BpmnAutoLayout(model).execute();
    //定義并設定流程變量
    Map<String, Object> variables = new HashMap<>();
        variables.put("flag", 1 == 2);
    //deploy
    Deployment deployment = repositoryService.createDeployment().addBpmnModel("process/dynamic-model.bpmn", model).name("Dynamic process deployment").key("test_bpmn").deploy();
processEngine.getRuntimeService().startProcessInstanceByKey(processDefinition.getKey(), variables);
InputStream inputStreamXml = processEngine.getRepositoryService().getResourceAsStream(deployment.getId(), "process/dynamic-model.bpmn");
//儲存到本地,友善檢視生成後的檔案
 FileUtils.copyInputStreamToFile(inputStreamXml, new File("D:\bpmn_data\process.bpmn.xml"));           

三.注意事項

1.activiti-bpmn-layout.jar

//BPMN圖布局自動調整需要添加
<dependency>
   <groupId>org.activiti</groupId>
   <artifactId>activiti-bpmn-layout</artifactId>
   <version>7.1.0.M4</version>
</dependency>           

2.mxgraph-all.jar

//需要手動添加,其自帶的mxgraph找不到方法,原因待确認,有時間去提個issue問問
<dependency>
   <groupId>com.mxgraph</groupId>
   <artifactId>mxgraph-all</artifactId>
   <version>4.2.2</version>
   <scope>system</scope>
</dependency>           

3.使用了layout和不使用的生成的圖對比

Activiti7 通過代碼動态生成工作流

四.總結

通過代碼生成的BPMN圖其實很亂,即使加了BpmnAutoLayout方法去調整布局,但是不影響流程正常使用。還有就是看了一遍源碼,沒有找到子流程(SubProcess的子任務)的生成方法,暫時不支援生成子流程,待我再多研究研究。

後話

簡單流程通過代碼生成沒問題,複雜流程還是建議用工具繪圖,通過代碼生成有時候容易出問題。畢竟有一些節點不能連線,而且複雜流程對于一些退回操作不是很友好,實作起來很麻煩。

繼續閱讀