<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                [TOC] ***** > 本節我們介紹Activiti提供的 7大Service接口。先了解這7個service的用途,有利于我們更好的學習activiti。 我們不會專門介紹這幾個Service接口的所有API方法,而是通過實例的方式直接使用這些API,在實踐中熟悉這些API。此處貼出官方的javadocs文檔地址:[https://www.activiti.org/javadocs/](https://www.activiti.org/javadocs/) ![](https://img.kancloud.cn/a1/04/a104c6c80fb7e8623a6fa64b205780f6_1464x613.png) ## 1、流程模型 我們通過使用下面這個請假流程模型來練習這7個Activiti Service。 ### 1.1 流程圖 流程節點的具體內容,本章節我們不介紹如何畫流程圖,而是先以一個實例來熟悉一下Activiti的使用過程。 ![](https://img.kancloud.cn/71/eb/71ebb109f20a3648dcb31de1a3f5240f_2288x1105.png) 簡要介紹一下,以上流程圖的使用場景,這是一個請假流程: * 請假當事人發起流程后,流程流轉到`部門經理審批`節點,部門經理選擇同意,則流轉到`人事審批`節點,否則流轉到`調整申請`節點,當事人可以在`調整申請`節點修改請假信息,重新申請流程或者結束流程。 * 當部門經理同意后,流程到達`人事審批`節點,這個節點的操作和`部門經理審批`節點邏輯是一樣的。 * 當人事經理審批同意后,流程流轉到銷假節點,當事人在這個節點處理銷假信息,然后結束流程。 ### 1.2 流程定義 以下是上面流程圖對應的定義文件。(省略部分位置信息,初學看不懂沒關系,了解工作流程就行) ``` <?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 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" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.kafeitu.me/activiti/leave"> <process id="leave" name="請假流程-普通表單" isExecutable="true"> <documentation>請假流程演示</documentation> <startEvent id="startevent1" name="Start" activiti:initiator="applyUserId"></startEvent> <userTask id="deptLeaderVerify" name="部門領導審批" activiti:candidateGroups="deptLeader"></userTask> <exclusiveGateway id="exclusivegateway5" name="Exclusive Gateway"></exclusiveGateway> <userTask id="modifyApply" name="調整申請" activiti:assignee="${applyUserId}"></userTask> <userTask id="hrVerify" name="人事審批" activiti:candidateGroups="hr"></userTask> <exclusiveGateway id="exclusivegateway6" name="Exclusive Gateway"></exclusiveGateway> <userTask id="reportBack" name="銷假" activiti:assignee="${applyUserId}"> <extensionElements> <activiti:taskListener event="complete" delegateExpression="${reportBackEndProcessor}"></activiti:taskListener> </extensionElements> </userTask> <endEvent id="endevent1" name="End"></endEvent> <exclusiveGateway id="exclusivegateway7" name="Exclusive Gateway"></exclusiveGateway> <sequenceFlow id="flow2" sourceRef="startevent1" targetRef="deptLeaderVerify"></sequenceFlow> <sequenceFlow id="flow3" sourceRef="deptLeaderVerify" targetRef="exclusivegateway5"></sequenceFlow> <sequenceFlow id="flow4" name="不同意" sourceRef="exclusivegateway5" targetRef="modifyApply"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!deptLeaderApproved}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow5" name="同意" sourceRef="exclusivegateway5" targetRef="hrVerify"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${deptLeaderApproved}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow6" sourceRef="hrVerify" targetRef="exclusivegateway6"></sequenceFlow> <sequenceFlow id="flow7" name="同意" sourceRef="exclusivegateway6" targetRef="reportBack"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${hrApproved}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow8" sourceRef="reportBack" targetRef="endevent1"></sequenceFlow> <sequenceFlow id="flow9" name="不同意" sourceRef="exclusivegateway6" targetRef="modifyApply"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!hrApproved}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow10" name="重新申請" sourceRef="exclusivegateway7" targetRef="deptLeaderVerify"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${reApply}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow11" sourceRef="modifyApply" targetRef="exclusivegateway7"></sequenceFlow> <sequenceFlow id="flow12" name="結束流程" sourceRef="exclusivegateway7" targetRef="endevent1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!reApply}]]></conditionExpression> </sequenceFlow> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_leave"> <bpmndi:BPMNPlane bpmnElement="leave" id="BPMNPlane_leave"> <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1"> //........................ </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions> ``` ### 1.3 節點審批人員約定 | 用戶名 | ACT\_ID\_USER(表) |ACT\_ID\_GROUP(表)| | --- | --- |--- | | 發起人(startmen) | 任意 | 任意 | | 部門領導 | deptmen | deptLeader | | 人事領導 | hrmen | hr | ## 2、單元測試 我們以單元測試的形式演示這個請假流程的工作過程。 ### 2.1 獲取流程引擎及各個Service接口 只有先獲取了流程引擎,才能獲取7大Service接口。 ``` package com.sxdx.workflow.activiti.rest; import org.activiti.engine.*; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import static org.junit.Assert.assertNotNull; @SpringBootTest @RunWith(SpringRunner.class) public class ActivitiServiceTest { private ProcessEngine processEngine; private IdentityService identityService; private RepositoryService repositoryService; private RuntimeService runtimeService; private TaskService taskService; private HistoryService historyService; @Test public void before(){ ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration .createStandaloneProcessEngineConfiguration(); processEngineConfiguration.setJdbcDriver("com.mysql.cj.jdbc.Driver"); processEngineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/activiti-demo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true"); processEngineConfiguration.setJdbcUsername("root"); processEngineConfiguration.setJdbcPassword("xxxxxxx"); //如果表不存在,則自動創建表 processEngineConfiguration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE); processEngine = processEngineConfiguration.buildProcessEngine(); System.out.println(processEngine.toString()); repositoryService = processEngine.getRepositoryService(); identityService = processEngine.getIdentityService(); runtimeService = processEngine.getRuntimeService(); taskService = processEngine.getTaskService(); historyService = processEngine.getHistoryService(); assertNotNull(processEngine); } } ``` 測試結果:查看 activiti-demo 數據庫(單元測試庫),可以看到生成了28張表。 ![](https://img.kancloud.cn/b0/3f/b03f9e463e106b92d5dff30bede46659_398x754.png) ### 2.2 初始化審批人 此處我們通過代碼方式,向數據庫中插入流程所需的用戶信息。 ~~~ package com.sxdx.workflow.activiti.rest; import org.activiti.engine.*; import org.activiti.engine.identity.User; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @SpringBootTest @RunWith(SpringRunner.class) public class ActivitiServiceTest { private ProcessEngine processEngine; private IdentityService identityService; private RepositoryService repositoryService; private RuntimeService runtimeService; private TaskService taskService; private HistoryService historyService; /** * 獲取流程引擎及各個Service */ @Before public void before(){ ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration .createStandaloneProcessEngineConfiguration(); processEngineConfiguration.setJdbcDriver("com.mysql.cj.jdbc.Driver"); processEngineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/activiti-demo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true"); processEngineConfiguration.setJdbcUsername("root"); processEngineConfiguration.setJdbcPassword("gaoyipeng"); //如果表不存在,則自動創建表 processEngineConfiguration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE); processEngine = processEngineConfiguration.buildProcessEngine(); System.out.println(processEngine.toString()); repositoryService = processEngine.getRepositoryService(); identityService = processEngine.getIdentityService(); runtimeService = processEngine.getRuntimeService(); taskService = processEngine.getTaskService(); historyService = processEngine.getHistoryService(); assertNotNull(processEngine); } /** * 初始化審批人 act_id_user: deptmen, hrmen */ @Test public void initUser(){ User deptmen = identityService.newUser("deptmen"); deptmen.setFirstName("部門領導"); identityService.saveUser(deptmen); User hrmen = identityService.newUser("hrmen"); hrmen.setFirstName("人事領導"); identityService.saveUser(hrmen); assertEquals(2,identityService.createUserQuery().count()); } } ~~~ 執行結果: ![](https://img.kancloud.cn/ba/28/ba280fe262a36cd45ea67ba51f354acf_639x176.png) ### 2.3 初始化組 此處我們通過代碼方式,向數據庫中插入流程所需的用戶組信息。 ~~~ /** * 初始化組 act_id_group: deptLeader, hr * 在Activiti中組分為2種: * assignment:普通的崗位角色,是用戶分配業務中的功能權限 * security-role: 安全角色,全局管理用戶組織及整個流程的狀態 * 如果使用Activiti提供的Explorer,需要security-role才能看到manage頁簽,需要assignment才能claim任務 */ @Test public void initGroup(){ Group deptLeader = identityService.newGroup("deptLeader"); deptLeader.setName("deptLeader"); //擴展字段 deptLeader.setType("assignment"); identityService.saveGroup(deptLeader); Group hr = identityService.newGroup("hr"); hr.setName("hr"); hr.setType("assignment"); identityService.saveGroup(hr); assertEquals(2,identityService.createGroupQuery().count()); } ~~~ 執行結果: ![](https://img.kancloud.cn/aa/db/aadb1d284847e673b2b1f9fbaba94b1e_616x185.png) ### 2.4 初始化人員、組的關系 ``` /** * 初始化人員、組的關系 */ @Test public void initMemberShip(){ identityService.createMembership("deptmen","deptLeader"); identityService.createMembership("hrmen","hr"); } ~ ``` 執行結果: ![](https://img.kancloud.cn/72/52/7252e7bd7bd2d9f9dd6d025ff0d254a8_868x201.png) API 補充: ``` //刪除user identityService.deleteUser(userId); //刪除group identityService.deleteGroup(groupId); //刪除user、group關聯關系 identityService.deleteMembership( userId, groupId); ``` ### 2.5 部署流程定義 流程圖準備好后,需要部署流程才能進行后續操作。 將下載好的leave.bpmn放到`src/main/resources`目錄下,github代碼中已經包含了 ![](https://img.kancloud.cn/34/5d/345d16b0f2802a68bd56b4eef40fdb77_478x481.png) ~~~ /** * 部署流程定義 */ @Test public void deployTest(){ Deployment deployment = repositoryService.createDeployment() .addClasspathResource("leave.bpmn") .deploy(); assertNotNull(deployment); } ~~~ 執行結果: ![](https://img.kancloud.cn/d9/ba/d9ba6017bb7130dd99bb3a9ca551ca19_825x163.png) ![](https://img.kancloud.cn/f0/ed/f0ed566b210f5ef0ae54f37235dc7457_1285x179.png) 數據表中已經生成了數據,說明流程已經部署成功。 ### 2.6 發起審批 ``` /** * 發起流程 */ @Test public void submitApplyTest(){ String applyUserId = "startmen"; //設置流程啟動發起人,在流程開始之前設置,會自動在表ACT_HI_PROCINST 中的START_USER_ID_中設置用戶ID identityService.setAuthenticatedUserId(applyUserId); runtimeService.startProcessInstanceByKey("leave"); } ``` 執行結果如下(說明流程已經發起成功): ![](https://img.kancloud.cn/ac/28/ac2844eb4d8e394dd102412bf88b124f_1399x146.png) ![](https://img.kancloud.cn/3e/83/3e837f042b185827ed279e796eaa95d2_764x145.png) ### 2.7 部門領導獲取待辦 ``` /** * 獲取待辦 */ @Test public void getTaskTodo(){ //根據當前人id查詢待辦任務 List<Task> taskList = taskService.createTaskQuery() .processDefinitionKey("leave") .taskAssignee("deptmen") .active().list(); //根據當前人未簽收的任務 List<Task> taskList1 = taskService.createTaskQuery() .processDefinitionKey("leave") .taskCandidateUser("deptmen") .active().list(); List<Task> list = new ArrayList<>(); list.addAll(taskList); list.addAll(taskList1); System.out.println("-------"+list.get(0).toString()+"----"+list.get(0).getName()); assertEquals(1,list.size()); Task task = list.get(0); } ``` 斷點截圖(顯示了部門領導節點需要處理的審批記錄): ![](https://img.kancloud.cn/d4/55/d455dbb493ebc029e9378ad89793fcb1_1671x1202.png) ### 2.8 部門領導審批通過流程 接下來添加審批代碼 ~~~ /** * 獲取待辦并通過 */ @Test public void getTaskTodo(){ //根據當前人id查詢待辦任務 List<Task> taskList = taskService.createTaskQuery() .processDefinitionKey("leave") .taskAssignee("deptmen") .active().list(); //根據當前人未簽收的任務 List<Task> taskList1 = taskService.createTaskQuery() .processDefinitionKey("leave") .taskCandidateUser("deptmen") .active().list(); List<Task> list = new ArrayList<>(); list.addAll(taskList); list.addAll(taskList1); System.out.println("-------"+list.get(0).toString()+"----"+list.get(0).getName()); assertEquals(1,list.size()); Task task = list.get(0); //審批流程 ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() .processDefinitionKey("leave") .singleResult(); // 添加批注 identityService.setAuthenticatedUserId("deptmen"); taskService.addComment(task.getId(), processInstance.getId(), "deptmen【同意】了"); Map<String, Object> variables = new HashMap<>(); variables.put("deptLeaderApproved", true); // 只有簽收任務,act_hi_taskinst 表的 assignee 字段才不為 null taskService.claim(task.getId(), "deptmen"); taskService.complete(task.getId(), variables); } ~~~ 執行結果:可以看到審批意見了,部門領導已經審批通過了。 ![](https://img.kancloud.cn/22/47/224708d09dda7898c8a7233eb3dd2f6f_1300x190.png) ### 2.9 獲取已辦 ~~~ /** * 獲取已完成的流程 */ @Test public void getCompileTask(){ List<HistoricTaskInstance> taskInstanceList = historyService.createHistoricTaskInstanceQuery() .processDefinitionKey("leave") .taskAssignee("deptmen") .finished().list(); for (HistoricTaskInstance instance :taskInstanceList) { System.out.println(instance.getProcessInstanceId()+"--"+instance.getName()+"--"+instance.getAssignee()); } } ~~~ 執行結果:可以看到 5001 這條流程,部門經理已經審批過了。 ![](https://img.kancloud.cn/10/9c/109cf7953a3f3b0a0105b6d0f1266da8_982x506.png) ### 2.10 獲取審批意見 ~~~ /** * 獲取審批意見 */ @Test public void getHistoryComment(){ //獲取流程實例對象 ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() .processDefinitionKey("leave").singleResult(); //獲取歷史活動集合 List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery() .processInstanceId(processInstance.getId()) .activityType("userTask") .finished() .list(); for (HistoricActivityInstance historicActivityInstance:historicActivityInstanceList ) { List<Comment> commentList = taskService.getTaskComments(historicActivityInstance.getTaskId(), "comment"); for (int i = 0; i < commentList.size(); i++) { System.out.println(commentList.get(i).getProcessInstanceId()+"---"+ commentList.get(i).getUserId() +"批復內容:" + commentList.get(i).getFullMessage()); } } } ~~~ ![](https://img.kancloud.cn/9d/72/9d72d8d52498b73f59f01f6127088cde_871x433.png) **請記住這個5001,獲取流程圖時會用到。** ## 3、獲取流程圖 這個是比較固定的代碼,不做詳解介紹。只做演示。添加代碼如下 ![](https://img.kancloud.cn/80/d7/80d712ee60e55e654186df8ddc1663b7_575x561.png) 訪問API:[http://localhost:8080/process/read-resource/5001](http://localhost:8080/process/read-resource/5001),pProcessInstanceId是流程實例:5001(**act\_hi\_procinst**表ID\_) ~~~ @RequestMapping(value = "/read-resource/{pProcessInstanceId}") public void readResource(@PathVariable("pProcessInstanceId")String pProcessInstanceId, HttpServletResponse response) throws Exception { // 設置頁面不緩存 response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); String processDefinitionId = ""; ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(pProcessInstanceId).singleResult(); if(processInstance == null) { HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(pProcessInstanceId).singleResult(); processDefinitionId = historicProcessInstance.getProcessDefinitionId(); } else { processDefinitionId = processInstance.getProcessDefinitionId(); } ProcessDefinitionQuery pdq = repositoryService.createProcessDefinitionQuery(); ProcessDefinition pd = pdq.processDefinitionId(processDefinitionId).singleResult(); String resourceName = pd.getDiagramResourceName(); if(resourceName.endsWith(".png") && StringUtils.isEmpty(pProcessInstanceId) == false) { getActivitiProccessImage(pProcessInstanceId,response); //ProcessDiagramGenerator.generateDiagram(pde, "png", getRuntimeService().getActiveActivityIds(processInstanceId)); } else { // 通過接口讀取 InputStream resourceAsStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), resourceName); // 輸出資源內容到相應對象 byte[] b = new byte[1024]; int len = -1; while ((len = resourceAsStream.read(b, 0, 1024)) != -1) { response.getOutputStream().write(b, 0, len); } } } ~~~ ~~~ /** * 獲取流程圖像,已執行節點和流程線高亮顯示 */ public void getActivitiProccessImage(String pProcessInstanceId, HttpServletResponse response) { //logger.info("[開始]-獲取流程圖圖像"); try { // 獲取歷史流程實例 HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() .processInstanceId(pProcessInstanceId).singleResult(); if (historicProcessInstance == null) { //throw new BusinessException("獲取流程實例ID[" + pProcessInstanceId + "]對應的歷史流程實例失敗!"); } else { // 獲取流程定義 ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService) .getDeployedProcessDefinition(historicProcessInstance.getProcessDefinitionId()); // 獲取流程歷史中已執行節點,并按照節點在流程中執行先后順序排序 List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery() .processInstanceId(pProcessInstanceId).orderByHistoricActivityInstanceId().asc().list(); // 已執行的節點ID集合 List<String> executedActivityIdList = new ArrayList<String>(); int index = 1; //logger.info("獲取已經執行的節點ID"); for (HistoricActivityInstance activityInstance : historicActivityInstanceList) { executedActivityIdList.add(activityInstance.getActivityId()); //logger.info("第[" + index + "]個已執行節點=" + activityInstance.getActivityId() + " : " +activityInstance.getActivityName()); index++; } BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId()); // 已執行的線集合 List<String> flowIds = new ArrayList<String>(); // 獲取流程走過的線 (getHighLightedFlows是下面的方法) flowIds = getHighLightedFlows(bpmnModel,processDefinition, historicActivityInstanceList); // // 獲取流程圖圖像字符流 // ProcessDiagramGenerator pec = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator(); // //配置字體 // InputStream imageStream = pec.generateDiagram(bpmnModel, "png", executedActivityIdList, flowIds,"宋體","微軟雅黑","黑體",null,2.0); Set<String> currIds = runtimeService.createExecutionQuery().processInstanceId(pProcessInstanceId).list() .stream().map(e->e.getActivityId()).collect(Collectors.toSet()); ICustomProcessDiagramGenerator diagramGenerator = (ICustomProcessDiagramGenerator) processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator(); InputStream imageStream = diagramGenerator.generateDiagram(bpmnModel, "png", executedActivityIdList, flowIds, "宋體", "宋體", "宋體", null, 1.0, new Color[] { WorkflowConstants.COLOR_NORMAL, WorkflowConstants.COLOR_CURRENT }, currIds); response.setContentType("image/png"); OutputStream os = response.getOutputStream(); int bytesRead = 0; byte[] buffer = new byte[8192]; while ((bytesRead = imageStream.read(buffer, 0, 8192)) != -1) { os.write(buffer, 0, bytesRead); } os.close(); imageStream.close(); } //logger.info("[完成]-獲取流程圖圖像"); } catch (Exception e) { System.out.println(e.getMessage()); //logger.error("【異常】-獲取流程圖失敗!" + e.getMessage()); //throw new BusinessException("獲取流程圖失敗!" + e.getMessage()); } } ~~~ ~~~ private List<String> getHighLightedFlows(BpmnModel bpmnModel, ProcessDefinitionEntity processDefinitionEntity, List<HistoricActivityInstance> historicActivityInstances) { // 高亮流程已發生流轉的線id集合 List<String> highLightedFlowIds = new ArrayList<>(); // 全部活動節點 List<FlowNode> historicActivityNodes = new ArrayList<>(); // 已完成的歷史活動節點 List<HistoricActivityInstance> finishedActivityInstances = new ArrayList<>(); for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) { FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true); historicActivityNodes.add(flowNode); if (historicActivityInstance.getEndTime() != null) { finishedActivityInstances.add(historicActivityInstance); } } FlowNode currentFlowNode = null; FlowNode targetFlowNode = null; // 遍歷已完成的活動實例,從每個實例的outgoingFlows中找到已執行的 for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) { // 獲得當前活動對應的節點信息及outgoingFlows信息 currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true); List<SequenceFlow> sequenceFlows = currentFlowNode.getOutgoingFlows(); /** * 遍歷outgoingFlows并找到已已流轉的 滿足如下條件認為已已流轉: 1.當前節點是并行網關或兼容網關,則通過outgoingFlows能夠在歷史活動中找到的全部節點均為已流轉 2.當前節點是以上兩種類型之外的,通過outgoingFlows查找到的時間最早的流轉節點視為有效流轉 */ if ("parallelGateway".equals(currentActivityInstance.getActivityType()) || "inclusiveGateway".equals(currentActivityInstance.getActivityType())) { // 遍歷歷史活動節點,找到匹配流程目標節點的 for (SequenceFlow sequenceFlow : sequenceFlows) { targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true); if (historicActivityNodes.contains(targetFlowNode)) { highLightedFlowIds.add(targetFlowNode.getId()); } } } else { List<Map<String, Object>> tempMapList = new ArrayList<>(); for (SequenceFlow sequenceFlow : sequenceFlows) { for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) { if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) { Map<String, Object> map = new HashMap<>(); map.put("highLightedFlowId", sequenceFlow.getId()); map.put("highLightedFlowStartTime", historicActivityInstance.getStartTime().getTime()); tempMapList.add(map); } } } if (!CollectionUtils.isEmpty(tempMapList)) { // 遍歷匹配的集合,取得開始時間最早的一個 long earliestStamp = 0L; String highLightedFlowId = null; for (Map<String, Object> map : tempMapList) { long highLightedFlowStartTime = Long.valueOf(map.get("highLightedFlowStartTime").toString()); if (earliestStamp == 0 || earliestStamp >= highLightedFlowStartTime) { highLightedFlowId = map.get("highLightedFlowId").toString(); earliestStamp = highLightedFlowStartTime; } } highLightedFlowIds.add(highLightedFlowId); } } } return highLightedFlowIds; } ~~~ 獲取的流程圖如下: ![](https://img.kancloud.cn/be/15/be1555ff016ca2293dea4a38965be9b3_1911x1006.png) 本節到此結束。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看