Android開發(fā)之a(chǎn)ctiviti節(jié)點(diǎn)跳轉(zhuǎn)
activiti使用的時候,通常需要跟業(yè)務(wù)緊密的結(jié)合在一起,有些業(yè)務(wù)非常的復(fù)雜,比如一個簡單的采購流程:流程如下:
供應(yīng)商上新商品的時候,提交商務(wù)審核,商務(wù)審核通過提交運(yùn)營審核,審核失敗退回供應(yīng)商。
運(yùn)營審核成功提交合同簽訂。交運(yùn)營審核審核失敗退回商務(wù)審核或者直接退回供應(yīng)商。
合同簽訂審核通過結(jié)束,合同簽訂審核不通過返回運(yùn)營審核或者退回商務(wù)審核,或者退回供應(yīng)商。
上面的流程就出現(xiàn)了一個問題,什么問題呢?
我們來觀察一下退回線的問題。
1.商務(wù)審核退回供應(yīng)商上新。
2.運(yùn)營審核可能退回商務(wù)審核,運(yùn)營審核可能退回供應(yīng)商上新。
3.合同簽訂可能退回運(yùn)營審核,合同簽訂可能退回商務(wù)審核,合同簽訂可能退回供應(yīng)商上新。
4....
假如以后我們的流程在添加新的部門審核,是不是我們的退回線更加的多了。其實(shí)就是n!的問題,難道我們沒添加一個節(jié)點(diǎn),就要畫很多的退回線嗎?這顯然是一個糟糕的設(shè)計。oh my god.
存在的問題就是,我們要是想讓我們的流程更加的通用,我們可能在設(shè)計的時候,需要添加很多的退回線控制,防止業(yè)務(wù)變化,流程跟起來變化,這就是應(yīng)對了變化,同時在增加了冗余設(shè)計。
那有沒有一種更好的方式,能解決上面的問題呢?很顯然這就是我們本章要解決的問題。
1.1.1. activiti節(jié)點(diǎn)跳轉(zhuǎn)實(shí)現(xiàn)
實(shí)現(xiàn)之前,我們考慮幾個問題。
1.當(dāng)前流程在哪一個節(jié)點(diǎn)。
2.流程需要跳轉(zhuǎn)的目標(biāo)節(jié)點(diǎn)。
3.跳轉(zhuǎn)到目標(biāo)節(jié)點(diǎn)之后,需要添加變量嗎?有可能需要把,總不能無緣無故的跳轉(zhuǎn)到了目標(biāo)節(jié)點(diǎn)。痕跡肯定要記錄。
4.跳轉(zhuǎn)到目標(biāo)節(jié)點(diǎn),那當(dāng)前節(jié)點(diǎn)配置的任務(wù)監(jiān)聽需要觸發(fā)嗎?(可參考 activiti監(jiān)聽器使用).當(dāng)前節(jié)點(diǎn)跳轉(zhuǎn)到目標(biāo)節(jié)點(diǎn)的時候,如果當(dāng)前節(jié)點(diǎn)配置了任務(wù)監(jiān)聽業(yè)務(wù),調(diào)轉(zhuǎn)到目標(biāo)節(jié)點(diǎn)之前,這些當(dāng)前的任務(wù)節(jié)點(diǎn)的是否觸發(fā)任務(wù)監(jiān)聽業(yè)務(wù)必須能支持靈活配置。
上面的思考點(diǎn),也是我們接下來需要重點(diǎn)講解的內(nèi)容。那下面就開始我們的設(shè)計吧。
1.1.1.1. 流程圖
下面我們先定義一個流程如下圖所示:
1.1.1.2. xml
下面我們先定義一個xml定義如下所示:
<?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="daling"> <process id="daling" name="name_daling" isExecutable="true" activiti:candidateStarterUsers="a,b,c,d"> <userTask id="usertask2" name="usertask2" activiti:assignee="c"></userTask> <userTask id="usertask3" name="usertask3"></userTask> <sequenceFlow id="flow4" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow> <userTask id="usertask4" name="usertask4"></userTask> <sequenceFlow id="flow5" sourceRef="usertask3" targetRef="usertask4"></sequenceFlow> <userTask id="usertask5" name="usertask5"></userTask> <sequenceFlow id="flow6" sourceRef="usertask4" targetRef="usertask5"></sequenceFlow> <endEvent id="endevent1" name="End"></endEvent> <sequenceFlow id="flow7" sourceRef="usertask5" targetRef="endevent1"></sequenceFlow> <startEvent id="startevent1" name="Start"></startEvent> <sequenceFlow id="flow8" sourceRef="startevent1" targetRef="usertask2"></sequenceFlow> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_daling"> <bpmndi:BPMNPlane bpmnElement="daling" id="BPMNPlane_daling"> <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2"> <omgdc:Bounds height="55.0" width="105.0" x="300.0" y="90.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3"> <omgdc:Bounds height="55.0" width="105.0" x="450.0" y="90.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="usertask4" id="BPMNShape_usertask4"> <omgdc:Bounds height="55.0" width="105.0" x="600.0" y="90.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="usertask5" id="BPMNShape_usertask5"> <omgdc:Bounds height="55.0" width="105.0" x="750.0" y="90.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1"> <omgdc:Bounds height="35.0" width="35.0" x="900.0" y="100.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1"> <omgdc:Bounds height="35.0" width="35.0" x="140.0" y="90.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4"> <omgdi:waypoint x="405.0" y="117.0"></omgdi:waypoint> <omgdi:waypoint x="450.0" y="117.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5"> <omgdi:waypoint x="555.0" y="117.0"></omgdi:waypoint> <omgdi:waypoint x="600.0" y="117.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6"> <omgdi:waypoint x="705.0" y="117.0"></omgdi:waypoint> <omgdi:waypoint x="750.0" y="117.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7"> <omgdi:waypoint x="855.0" y="117.0"></omgdi:waypoint> <omgdi:waypoint x="900.0" y="117.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8"> <omgdi:waypoint x="175.0" y="107.0"></omgdi:waypoint> <omgdi:waypoint x="300.0" y="117.0"></omgdi:waypoint> </bpmndi:BPMNEdge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>
1.1.1.3. 代碼實(shí)現(xiàn)
package com.daling.ch1.jd; import java.util.Iterator; import java.util.Map; import org.activiti.engine.impl.context.Context; import org.activiti.engine.impl.interceptor.Command; import org.activiti.engine.impl.interceptor.CommandContext; import org.activiti.engine.impl.persistence.entity.ExecutionEntity; import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager; import org.activiti.engine.impl.persistence.entity.TaskEntity; import org.activiti.engine.impl.pvm.process.ActivityImpl; /** * * JD節(jié)點(diǎn)的跳轉(zhuǎn) * 分享牛原創(chuàng)(尊重原創(chuàng) 轉(zhuǎn)載對的時候第一行請注明,轉(zhuǎn)載出處來自分享牛http://blog.csdn.net/qq_30739519) */ public class JDJumpTaskCmd implements Command<Void> { protected String executionId; protected ActivityImpl desActivity; protected Map<String, Object> paramvar; protected ActivityImpl currentActivity; /** * 分享牛原創(chuàng)(尊重原創(chuàng) 轉(zhuǎn)載對的時候第一行請注明,轉(zhuǎn)載出處來自分享牛http://blog.csdn.net/qq_30739519) */ public Void execute(CommandContext commandContext) { ExecutionEntityManager executionEntityManager = Context .getCommandContext().getExecutionEntityManager(); // 獲取當(dāng)前流程的executionId,因?yàn)樵诓l(fā)的情況下executionId是唯一的。 ExecutionEntity executionEntity = executionEntityManager .findExecutionById(executionId); executionEntity.setVariables(paramvar); executionEntity.setEventSource(this.currentActivity); executionEntity.setActivity(this.currentActivity); // 根據(jù)executionId 獲取Task Iterator<TaskEntity> localIterator = Context.getCommandContext() .getTaskEntityManager() .findTasksByExecutionId(this.executionId).iterator(); while (localIterator.hasNext()) { TaskEntity taskEntity = (TaskEntity) localIterator.next(); // 觸發(fā)任務(wù)監(jiān)聽 taskEntity.fireEvent("complete"); // 刪除任務(wù)的原因 Context.getCommandContext().getTaskEntityManager() .deleteTask(taskEntity, "completed", false); } executionEntity.executeActivity(this.desActivity); return null; } /** * 構(gòu)造參數(shù) 可以根據(jù)自己的業(yè)務(wù)需要添加更多的字段 * 分享牛原創(chuàng)(尊重原創(chuàng) 轉(zhuǎn)載對的時候第一行請注明,轉(zhuǎn)載出處來自分享牛http://blog.csdn.net/qq_30739519) * @param executionId * @param desActivity * @param paramvar * @param currentActivity */ public JDJumpTaskCmd(String executionId, ActivityImpl desActivity, Map<String, Object> paramvar, ActivityImpl currentActivity) { this.executionId = executionId; this.desActivity = desActivity; this.paramvar = paramvar; this.currentActivity = currentActivity; } }
1.1.1.4. 使用
我們先讓流程運(yùn)轉(zhuǎn)到usertask3節(jié)點(diǎn)的時候開始測試跳轉(zhuǎn)。
怎么使用上面的JDJumpTaskCmd類呢,直接new JDJumpTaskCmd()調(diào)用,肯定不行了,因?yàn)閍ctiviti引擎程序沒有獲取,肯定報錯,正確的的使用方式如下:
1.1.1.4.1. 第一種方式
我們先來觀察一下數(shù)據(jù)庫ACT_RU_TASK表任務(wù)的記錄信息,方便我們的操作,數(shù)據(jù)庫記錄如下圖所示:
可以看到當(dāng)前的節(jié)點(diǎn)在usertask3,我們現(xiàn)在把usertask3跳轉(zhuǎn)到usertask5節(jié)點(diǎn),看是否能成功,因?yàn)閡sertask3到usertask5沒有連線,如果成功了,就說明我們這個方法正確。
執(zhí)行下面的代碼,根據(jù)自己的數(shù)據(jù)庫信息修改相對應(yīng)的值即可。
Map<String, Object> vars = new HashMap<String, Object>(); String[] v = { "shareniu1", "shareniu2", "shareniu3", "shareniu4" }; vars.put("assigneeList", Arrays.asList(v)); //分享牛原創(chuàng)(尊重原創(chuàng) 轉(zhuǎn)載對的時候第一行請注明,轉(zhuǎn)載出處來自分享牛http://blog.csdn.net/qq_30739519) RepositoryService repositoryService = demo.getRepositoryService(); ReadOnlyProcessDefinition processDefinitionEntity = (ReadOnlyProcessDefinition) repositoryService .getProcessDefinition("daling:29:137504"); // 目標(biāo)節(jié)點(diǎn) ActivityImpl destinationActivity = (ActivityImpl) processDefinitionEntity .findActivity("usertask5"); String executionId = "137509"; // 當(dāng)前節(jié)點(diǎn) ActivityImpl currentActivity = (ActivityImpl)processDefinitionEntity .findActivity("usertask3"); demo.getManagementService().executeCommand( new JDJumpTaskCmd(executionId, destinationActivity, vars, currentActivity));
執(zhí)行上面的代碼之后,我們看一下數(shù)據(jù)庫中的記錄。
節(jié)點(diǎn)確實(shí)跳轉(zhuǎn)到了usertask5。ok了這個方法確實(shí)可以沒問題,下面說一下第二種方式執(zhí)行executeCommand命令。
1.1.1.4.2. 第二種方式
Map<String, Object> vars = new HashMap<String, Object>(); String[] v = { "shareniu1", "shareniu2", "shareniu3", "shareniu4" }; vars.put("assigneeList", Arrays.asList(v)); //分享牛原創(chuàng)(尊重原創(chuàng) 轉(zhuǎn)載對的時候第一行請注明,轉(zhuǎn)載出處來自分享牛http://blog.csdn.net/qq_30739519) CommandExecutor commandExecutor = taskServiceImpl .getCommandExecutor(); commandExecutor.execute(new JDJumpTaskCmd(executionId, destinationActivity, vars, currentActivity));
上面的兩種方式都可以執(zhí)行自定義的Command子類。讀者選擇自己喜歡使用的方式即可。
1.1.2. 小結(jié)
1.任意節(jié)點(diǎn)的跳轉(zhuǎn),前提是節(jié)點(diǎn)必須在模板定義中。
2.任意節(jié)點(diǎn)的跳轉(zhuǎn)暫時不能跨流程跳轉(zhuǎn)。
3.任意節(jié)點(diǎn)的跳轉(zhuǎn)不需要連線即可、
4.任意節(jié)點(diǎn)的跳轉(zhuǎn)可以實(shí)現(xiàn)回退、轉(zhuǎn)辦、轉(zhuǎn)閱、越級上報、一步到底等等功能,關(guān)于這些更多的實(shí)戰(zhàn),我們將在最后的工作流實(shí)戰(zhàn)項(xiàng)目中一步步封裝。使用。
以上所述是小編給大家介紹的activiti節(jié)點(diǎn)跳轉(zhuǎn)的相關(guān)知識,希望對大家有所幫助!
相關(guān)文章
Android實(shí)現(xiàn)3D標(biāo)簽云效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)3D標(biāo)簽云效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-05-05FlowLayout流式布局實(shí)現(xiàn)搜索清空歷史記錄
這篇文章主要為大家詳細(xì)介紹了FlowLayout流式布局實(shí)現(xiàn)搜索清空歷史記錄,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-12-12android從系統(tǒng)圖庫中取圖片的實(shí)例代碼
這篇文章主要介紹了android從系統(tǒng)圖庫中取圖片的方法,涉及Android讀取及選擇圖片等相關(guān)操作技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-07-07Android屬性動畫實(shí)現(xiàn)布局的下拉展開效果
這篇文章主要為大家詳細(xì)介紹了Android屬性動畫實(shí)現(xiàn)布局的下拉展開效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-07-07Android基于OpenCV實(shí)現(xiàn)非真實(shí)渲染
非真實(shí)感渲染(Non Photorealistic Rendering,簡稱NPR),是指利用計算機(jī)模擬各種視覺藝術(shù)的繪制風(fēng)格,也用于發(fā)展新的繪制風(fēng)格。比如模擬中國畫、水彩、素描、油畫、版畫等藝術(shù)風(fēng)格。本文將講解Android基于OpenCV實(shí)現(xiàn)非真實(shí)渲染的方法2021-06-06Android仿360桌面手機(jī)衛(wèi)士懸浮窗效果
這篇文章主要介紹了Android仿360手機(jī)衛(wèi)士懸浮窗效果的桌面實(shí)現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05Java和Android的LRU緩存及實(shí)現(xiàn)原理
本文主要介紹 Java和Android的LRU緩存及實(shí)現(xiàn)原理,這里整理了詳細(xì)的資料,有興趣的小伙伴可以參考下便于學(xué)習(xí)理解2016-08-08