摘要:介紹什么是是由軟件在年月日發布的業務流程管理框架,它是覆蓋了業務流程管理工作流服務協作等領域的一個開源的靈活的易擴展的可執行流程語言框架。第二部分是表示表的用途的兩個字母標識。
Activiti介紹 什么是Activiti?
Activiti5是由Alfresco軟件在2010年5月17日發布的業務流程管理(BPM)框架,它是覆蓋了業務流程管理、工作流、服務協作等領域的一個開源的、靈活的、易擴展的可執行流程語言框架。Activiti基于Apache許可的開源BPM平臺,創始人Tom Baeyens是JBoss jBPM的項目架構師,它特色是提供了eclipse插件,開發人員可以通過插件直接繪畫出業務
流程圖。.
我們即將學習的是一個業務流程管理框架, 常見開源工作流引擎框架 : OSWorkFlow、jBPM(jboss business process management),Activiti工作流(是對jBPM升級)。一般我們稱作為工作流框架..
為什么要學習Activiti那我們為什么要學習業務流程管理框架呢???學習它干嘛???工作流(Workflow),就是“業務過程的部分或整體在計算機應用環境下的自動化”
我們來提出一個常見的需求來更好地理解:
我們在學生時代,肯定會遇到請假寫請假條的情況,如果學校的請假抓得非常嚴,就需要經過多層的同意才能確定能不能請假..
班主任->任課老師->教學總監->校長這么一個流程,首先我們先明確一點:我們作為一個學生,不可能直接跳過老師,去找校長申請請假的【校長是你隨便找的嗎??】
因此我們請假的流程是一步一步的,并不能做跳躍
也就是說,當班主任沒有批準請假的時候,即使你去找任課老師了,任課老師會讓你回去找班主任的,作為任課老師了,只關注班主任有沒有批準你請假,同理,作為校長,只關注教學總監有沒有批準你請假!
進一步說:當教學總監還沒有批準你請假時,你請假的請求是不會出現在校長的范圍里的。
其實是非常好理解的,就是一步步往下執行,當還沒有執行到自己處理的點子上時,是不會有對應的處理請求的。分工有序
對上面的請假流程進行分析,如果我們沒有使用框架,而把這么一個請假流程寫到我們的網站中,我們會怎么做呢??
我們需要維護一個變量,來不斷傳遞過去給下一個處理者...如果一切正常,需求不會變,并沒有條件的處理。這是我們非常希望看到的...但是,如果有條件判斷【請假三天以下、請假三天以上的處理方式不一樣】,需求會變【不需要校長批準了,教學總監批準完,你就能夠請假了】,那么我們的代碼就會變得亂
基于這么一個原因,我們是需要學習一個框架來幫我們完成工作流的...
采用工作流管理系統的優點
1、提高系統的柔性,適應業務流程的變化
2、實現更好的業務過程控制,提高顧客服務質量
3、降低系統開發和維護成本
一、快速入門Activiti首先我們來梳理一下Activiti的開發步驟:
我們要用到一個工作流,首先就要把這個工作流定義出來【也就是工作流的步驟的怎么樣的】,Activiti支持以“圖”的方式來定義工作流
定義完工作流,就要部署到起來【我們可以聯想到Tomcat,我們光下載了Tomcat是沒有用的,要把它部署起來】
隨后我們就執行該工作流,該工作流就隨著我們定義的步驟來一一執行!
1.1BPMN業務流程建模與標注(Business Process Model and Notation,BPMN) ,描述流程的基本符號,包括這些圖元如何組合成一個業務流程圖(Business Process Diagram)
BPMN這個就是我們所謂把工作流定義出來的流程圖..
1.2數據庫相關我們在執行工作流步驟的時候會涉及到很多數據【執行該流程的人是誰、所需要的參數是什么、包括想查看之前流程執行的記錄等等】,因此我們會需要用到數據庫的表來保存數據...
由于我們使用的是Activiti框架,這個框架會自動幫我們把對應的數據庫表創建起來,它涉及的表有23個,但是常用的并不是很多,因此也不用很慌...
下面就列舉一下表的情況
Activiti的后臺是有數據庫的支持,所有的表都以ACT_開頭。 第二部分是表示表的用途的兩個字母標識。 用途也和服務的API對應。 ACT_RE_*: "RE"表示repository。 這個前綴的表包含了流程定義和流程靜態資源 (圖片,規則,等等)。 ACT_RU_*: "RU"表示runtime。 這些運行時的表,包含流程實例,任務,變量,異步任務,等運行中的數據。 Activiti只在流程實例執行過程中保存這些數據, 在流程結束時就會刪除這些記錄。 這樣運行時表可以一直很小速度很快。 ACT_ID_*: "ID"表示identity。 這些表包含身份信息,比如用戶,組等等。 ACT_HI_*: "HI"表示history。 這些表包含歷史數據,比如歷史流程實例, 變量,任務等等。 ACT_GE_*: 通用數據, 用于不同場景下,如存放資源文件。1.3搭建配置環境
我這里使用的Intellij idea來使用Activiti,首先,我們得下載插件來使用Activiti【因為定義流程圖需要用到插件】
詳情可以看這篇博文:http://blog.sina.com.cn/s/blog_4b3196670102woix.html
Activiti插件中文亂碼問題:
http://www.cnblogs.com/mymelody/p/6049291.html
流程之前的連線是通過圖中的藍色小點點拖動來進行連接的...
導入對應的jar包
activation-1.1.jar
activiti-bpmn-converter-5.13.jar
activiti-bpmn-layout-5.13.jar
activiti-bpmn-model-5.13.jar
activiti-common-rest-5.13.jar
activiti-engine-5.13.jar
activiti-json-converter-5.13.jar
activiti-rest-5.13.jar
activiti-simple-workflow-5.13.jar
activiti-spring-5.13.jar
aopalliance-1.0.jar
commons-dbcp-1.4.jar
commons-email-1.2.jar
commons-fileupload-1.2.2.jar
commons-io-2.0.1.jar
commons-lang-2.4.jar
commons-pool-1.5.4.jar
h2-1.3.170.jar
hamcrest-core-1.3.jar
jackson-core-asl-1.9.9.jar
jackson-mapper-asl-1.9.9.jar
javaGeom-0.11.0.jar
jcl-over-slf4j-1.7.2.jar
jgraphx-1.10.4.2.jar
joda-time-2.1.jar
junit-4.11.jar
log4j-1.2.17.jar
mail-1.4.1.jar
mybatis-3.2.2.jar
mysql-connector-java.jar
org.restlet.ext.fileupload-2.0.15.jar
org.restlet.ext.jackson-2.0.15.jar
org.restlet.ext.servlet-2.0.15.jar
org.restlet-2.0.15.jar
slf4j-api-1.7.2.jar
slf4j-log4j12-1.7.2.jar
spring-aop-3.1.2.RELEASE.jar
spring-asm-3.1.2.RELEASE.jar
spring-beans-3.1.2.RELEASE.jar
spring-context-3.1.2.RELEASE.jar
spring-core-3.1.2.RELEASE.jar
spring-expression-3.1.2.RELEASE.jar
spring-jdbc-3.1.2.RELEASE.jar
spring-orm-3.1.2.RELEASE.jar
spring-tx-3.1.2.RELEASE.jar
1.4開發步驟上面已經說過了,我們要想使用Activiti就需要有數據庫的支持,雖然Activiti是自動幫我們創建對應的數據庫表,但是我們是需要配置數據庫的信息的。我們配置數據庫的信息,接著拿到Activiti最重要的API------Activiti引擎
1.4.1得到工作流引擎Activiti提供使用代碼的方式來配置數據庫的信息:
@Test public void createActivitiEngine(){ /* *1.通過代碼形式創建 * - 取得ProcessEngineConfiguration對象 * - 設置數據庫連接屬性 * - 設置創建表的策略 (當沒有表時,自動創建表) * - 通過ProcessEngineConfiguration對象創建 ProcessEngine 對象*/ //取得ProcessEngineConfiguration對象 ProcessEngineConfiguration engineConfiguration=ProcessEngineConfiguration. createStandaloneProcessEngineConfiguration(); //設置數據庫連接屬性 engineConfiguration.setJdbcDriver("com.mysql.jdbc.Driver"); engineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/activitiDB?createDatabaseIfNotExist=true" + "&useUnicode=true&characterEncoding=utf8"); engineConfiguration.setJdbcUsername("root"); engineConfiguration.setJdbcPassword("root"); // 設置創建表的策略 (當沒有表時,自動創建表) // public static final java.lang.String DB_SCHEMA_UPDATE_FALSE = "false";//不會自動創建表,沒有表,則拋異常 // public static final java.lang.String DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop";//先刪除,再創建表 // public static final java.lang.String DB_SCHEMA_UPDATE_TRUE = "true";//假如沒有表,則自動創建 engineConfiguration.setDatabaseSchemaUpdate("true"); //通過ProcessEngineConfiguration對象創建 ProcessEngine 對象 ProcessEngine processEngine = engineConfiguration.buildProcessEngine(); System.out.println("流程引擎創建成功!"); }
Activiti也可以通過配置文件來配置數據庫的信息,加載配置文件從而得到工作流引擎
/**2. 通過加載 activiti.cfg.xml 獲取 流程引擎 和自動創建數據庫及表 * ProcessEngineConfiguration engineConfiguration= ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml"); //從類加載路徑中查找資源 activiti.cfg.xm文件名可以自定義 ProcessEngine processEngine = engineConfiguration.buildProcessEngine(); System.out.println("使用配置文件Activiti.cfg.xml獲取流程引擎"); */
activiti.cfg.xml
上面的那種加載配置文件方式,配置文件的名字是可以自定義的,如果我們配置文件的名字默認就是activiti.cfg.xml的話,也是放在類路徑下,我們就可以使用默認的方式來進行加載了!
@Test public void createActivitiEngine(){ /** * 3. 通過ProcessEngines 來獲取默認的流程引擎 */ // 默認會加載類路徑下的 activiti.cfg.xml ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); System.out.println("通過ProcessEngines 來獲取流程引擎"); }1.4.2定義工作流
定義工作流就需要我們剛才下載的插件了,我們是使用圖形的方式來定義工作流的....
在每個流程中,我們都可以指定對應的處理人是誰,交由誰處理
1.4.3部署工作流我們上面已經定義了工作流了,工作流引擎我們也已經拿到了,接下來就是把工作流部署到工作流引擎中了
@Test public void deploy() { //獲取倉庫服務 :管理流程定義 RepositoryService repositoryService = processEngine.getRepositoryService(); Deployment deploy = repositoryService.createDeployment()//創建一個部署的構建器 .addClasspathResource("LeaveActiviti.bpmn")//從類路徑中添加資源,一次只能添加一個資源 .name("請求單流程")//設置部署的名稱 .category("辦公類別")//設置部署的類別 .deploy(); System.out.println("部署的id"+deploy.getId()); System.out.println("部署的名稱"+deploy.getName()); }
相對應的數據庫表就會插入數據、涉及到的數據庫表后面會詳細說明。現在我們只要了解到,我們工作流引擎執行操作會有數據庫表記錄
1.4.4執行工作流指定指定工作流就是我們定義時工作流程表的id
@Test public void startProcess(){ //指定執行我們剛才部署的工作流程 String processDefiKey="leaveBill"; //取運行時服務 RuntimeService runtimeService = processEngine.getRuntimeService(); //取得流程實例 ProcessInstance pi = runtimeService.startProcessInstanceByKey(processDefiKey);//通過流程定義的key 來執行流程 System.out.println("流程實例id:"+pi.getId());//流程實例id System.out.println("流程定義id:"+pi.getProcessDefinitionId());//輸出流程定義的id }1.4.5根據代理人查詢當前任務的信息
剛才我們已經開始了工作流了,隨后工作流應該去到了申請請假的流程,申請請假的處理人是鐘福成,我們可以查詢出對應的信息:
//查詢任務 @Test public void queryTask(){ //任務的辦理人 String assignee="鐘福成"; //取得任務服務 TaskService taskService = processEngine.getTaskService(); //創建一個任務查詢對象 TaskQuery taskQuery = taskService.createTaskQuery(); //辦理人的任務列表 List1.4.6處理任務list = taskQuery.taskAssignee(assignee)//指定辦理人 .list(); //遍歷任務列表 if(list!=null&&list.size()>0){ for(Task task:list){ System.out.println("任務的辦理人:"+task.getAssignee()); System.out.println("任務的id:"+task.getId()); System.out.println("任務的名稱:"+task.getName()); } } }
我們現在處理流程去到“申請請假”中,處理人是鐘福成...接著就是鐘福成去處理任務,根據任務的id使得流程繼續往下走
任務的id剛才我們已經查詢出來了【上面】,我們如果是在web端操作數據的話,那么只要傳遞過去就行了!
//完成任務 @Test public void compileTask(){ String taskId="304"; //taskId:任務id processEngine.getTaskService().complete(taskId); System.out.println("當前任務執行完畢"); }
當我們處理完該任務的時候,就到了批準【班主任】任務了,我們查詢一下是不是如我們想象的效果:
我們按照定義的工作流程圖一步一步往下走,最終把流程走完
二、流程定義細講管理流程定義主要涉及到以下的4張表:
-- 流程部署相關的表 SELECT * FROM act_ge_bytearray # 通用字節資源表 SELECT * FROM act_ge_property # 通用屬性表,可以生成部署id SELECT * FROM act_re_deployment #部署表 SELECT * FROM act_re_procdef # 流程定義表2.1PNG資源
在Eclipse中Activiti插件會自動生成一個BPMN與之對應的PNG圖片,是需要通過加載PNG圖片的
@Test public void deploy() { //獲取倉庫服務 :管理流程定義 RepositoryService repositoryService = processEngine.getRepositoryService(); Deployment deploy = repositoryService.createDeployment()//創建一個部署的構建器 .addClasspathResource("LeaveActiviti.bpmn")//從類路徑中添加資源,一次只能添加一個資源 .name("請求單流程")//設置部署的名稱 .category("辦公類別")//設置部署的類別 .deploy(); System.out.println("部署的id"+deploy.getId()); System.out.println("部署的名稱"+deploy.getName()); }
而我們的Intellij idea插件不會自動生成PNG圖片,但是我們在加載BPMN文件的時候,好像會自動插入PNG圖片,數據庫是有對應的記錄的【我們是沒有手動加載PNG圖片資源的】
我們查看一下
//查看bpmn 資源圖片 @Test public void viewImage() throws Exception{ String deploymentId="201"; String imageName=null; //取得某個部署的資源的名稱 deploymentId ListresourceNames = processEngine.getRepositoryService().getDeploymentResourceNames(deploymentId); // buybill.bpmn buybill.png if(resourceNames!=null&&resourceNames.size()>0){ for(String temp :resourceNames){ if(temp.indexOf(".png")>0){ imageName=temp; } } } /** * 讀取資源 * deploymentId:部署的id * resourceName:資源的文件名 */ InputStream resourceAsStream = processEngine.getRepositoryService() .getResourceAsStream(deploymentId, imageName); //把文件輸入流寫入到文件中 File file=new File("d:/"+imageName); FileUtils.copyInputStreamToFile(resourceAsStream, file); }
可惜的是,查看出來的圖片的中文數據會亂碼...
2.2查看流程定義我們當時候查詢流程定義是通過我們設置流程圖的id來查看的....其實我們可以通過其他的屬性來查詢...并且可以查詢出更加詳細的數據
//查看流程定義 @Test public void queryProcessDefination(){ String processDefiKey="buyBill";//流程定義key //獲取流程定義列表 List2.3資源來自ZIPlist = processEngine.getRepositoryService().createProcessDefinitionQuery() //查詢 ,好比where // .processDefinitionId(proDefiId) //流程定義id // 流程定義id : buyBill:2:704 組成 : proDefikey(流程定義key)+version(版本)+自動生成id .processDefinitionKey(processDefiKey)//流程定義key 由bpmn 的 process 的 id屬性決定 // .processDefinitionName(name)//流程定義名稱 由bpmn 的 process 的 name屬性決定 // .processDefinitionVersion(version)//流程定義的版本 .latestVersion()//最新版本 //排序 .orderByProcessDefinitionVersion().desc()//按版本的降序排序 //結果 // .count()//統計結果 // .listPage(arg0, arg1)//分頁查詢 .list(); //遍歷結果 if(list!=null&&list.size()>0){ for(ProcessDefinition temp:list){ System.out.print("流程定義的id: "+temp.getId()); System.out.print("流程定義的key: "+temp.getKey()); System.out.print("流程定義的版本: "+temp.getVersion()); System.out.print("流程定義部署的id: "+temp.getDeploymentId()); System.out.println("流程定義的名稱: "+temp.getName()); } } }
我們還可以加載的是ZIP類型的資源數據
//部署流程定義,資源來自zip格式 @Test public void deployProcessDefiByZip(){ InputStream in=getClass().getClassLoader().getResourceAsStream("BuyBill.zip"); Deployment deploy = processEngine.getRepositoryService() .createDeployment() .name("采購流程") .addZipInputStream(new ZipInputStream(in)) .deploy(); System.out.println("部署名稱:"+deploy.getName()); System.out.println("部署id:"+deploy.getId()); }2.4刪除流程定義
//刪除流程定義 @Test public void deleteProcessDefi(){ //通過部署id來刪除流程定義 String deploymentId="101"; processEngine.getRepositoryService().deleteDeployment(deploymentId); }
再次查詢的時候,已經沒有101這個流程定義的數據了。
三、流程實例與任務執行細講流程實例與任務執行的常用表有以下幾個:
-- 流程實例與任務 SELECT * FROM act_ru_execution # 流程執行對象信息 SELECT * FROM act_ru_task # 正在運行的任務表 SELECT * FROM act_hi_procinst # 歷史流程實例表 SELECT * FROM act_hi_taskinst # 歷史流程任務表
這里就簡單簡述一下流程實例與流程對象的區別:
(1)如果是單例流程,執行對象ID就是流程實例ID
(2)如果一個流程有分支和聚合,那么執行對象ID和流程實例ID就不相同
(3)一個流程中,流程實例只有1個,執行對象可以存在多個。
3.1開始流程@Test public void startProcess(){ String processDefiKey="leaveActiviti";//bpmn 的 process id屬性 ProcessInstance pi = processEngine.getRuntimeService() .startProcessInstanceByKey(processDefiKey); System.out.println("流程執行對象的id:"+pi.getId());//Execution 對象 System.out.println("流程實例的id:"+pi.getProcessInstanceId());//ProcessInstance 對象 System.out.println("流程定義的id:"+pi.getProcessDefinitionId());//默認執行的是最新版本的流程定義 }3.2查看正在運行的任務
//查詢正在運行任務 @Test public void queryTask(){ //取得任務服務 TaskService taskService = processEngine.getTaskService(); //創建一個任務查詢對象 TaskQuery taskQuery = taskService.createTaskQuery(); //辦理人的任務列表 Listlist = taskQuery.list(); //遍歷任務列表 if(list!=null&&list.size()>0){ for(Task task:list){ System.out.println("任務的辦理人:"+task.getAssignee()); System.out.println("任務的id:"+task.getId()); System.out.println("任務的名稱:"+task.getName()); } } }
查詢SELECT * FROM act_ru_task 表
3.3獲取流程實例的狀態有的時候,我們需要判斷它是在該流程,還是該流程已經結束了。我們可以根據獲取出來的對象是否為空來進行判斷
//獲取流程實例的狀態 @Test public void getProcessInstanceState(){ String processInstanceId="605"; ProcessInstance pi = processEngine.getRuntimeService() .createProcessInstanceQuery() .processInstanceId(processInstanceId) .singleResult();//返回的數據要么是單行,要么是空 ,其他情況報錯 //判斷流程實例的狀態 if(pi!=null){ System.out.println("該流程實例"+processInstanceId+"正在運行... "+"當前活動的任務:"+pi.getActivityId()); }else{ System.out.println("當前的流程實例"+processInstanceId+" 已經結束!"); } }3.4查看歷史流程實例的信息
//查看歷史執行流程實例信息 @Test public void queryHistoryProcInst(){ Listlist = processEngine.getHistoryService() .createHistoricProcessInstanceQuery() .list(); if(list!=null&&list.size()>0){ for(HistoricProcessInstance temp:list){ System.out.println("歷史流程實例id:"+temp.getId()); System.out.println("歷史流程定義的id:"+temp.getProcessDefinitionId()); System.out.println("歷史流程實例開始時間--結束時間:"+temp.getStartTime()+"-->"+temp.getEndTime()); } } }
查詢表:
3.5查看歷史實例執行任務信息@Test public void queryHistoryTask(){ String processInstanceId="605"; Listlist = processEngine.getHistoryService() .createHistoricTaskInstanceQuery() .processInstanceId(processInstanceId) .list(); if(list!=null&&list.size()>0){ for(HistoricTaskInstance temp:list){ System.out.print("歷史流程實例任務id:"+temp.getId()); System.out.print("歷史流程定義的id:"+temp.getProcessDefinitionId()); System.out.print("歷史流程實例任務名稱:"+temp.getName()); System.out.println("歷史流程實例任務處理人:"+temp.getAssignee()); } } }
給予對應的實例id就可以查詢出執行到哪個任務了...
3.6執行任務根據任務的id,就可以把該任務執行了。
@Test public void compileTask(){ String taskId="608"; //taskId:任務id processEngine.getTaskService().complete(taskId); System.out.println("當前任務執行完畢"); }四、流程變量細講
流程變量涉及到的數據庫表:
act_ru_variable:正在執行的流程變量表 act_hi_varinst:流程變量歷史表
流程變量在工作流中扮演著一個非常重要的角色。例如:請假流程中有請假天數、請假原因等一些參數都為流程變量的范圍。流程變量的作用域范圍是只對應一個流程實例。也就是說各個流程實例的流程變量是不相互影響的。流程實例結束完成以后流程變量還保存在數據庫中(存放到流程變量的歷史表中)。
4.1設置流程變量我們有兩種服務可以設置流程變量,TaskService【任務服務】和RuntimeService【運行時服務】
場景
在流程開始的時候設置流程變量
在完成某個任務的時候設置流程變量
使用TaskService設置服務
使用RuntimeService設置服務
作用:
傳遞業務參數
動態指定代理人【我們快速入門的例子是固定在流程定義圖上寫上代理人的】
指定連接【決定流程往哪邊走】
4.2流程變量支持類型如果我們使用JavaBean來作為流程的變量,那么我們需要將JavaBean實現Serializable接口。
Javabean類型設置獲取流程變量,除了需要這個javabean實現了Serializable接口外,還要求流程變量對象的屬性不能發生變化,否則拋出異常。解決方案,固定序列化ID
4.3setVariable和setVariableLocal的區別 4.4例子//模擬流程變量設置 @Test public void getAndSetProcessVariable(){ //有兩種服務可以設置流程變量 // TaskService taskService = processEngine.getTaskService(); // RuntimeService runtimeService = processEngine.getRuntimeService(); /**1.通過 runtimeService 來設置流程變量 * executionId: 執行對象 * variableName:變量名 * values:變量值 */ // runtimeService.setVariable(executionId, variableName, values); // runtimeService.setVariableLocal(executionId, variableName, values); //設置本執行對象的變量 ,該變量的作用域只在當前的execution對象 // runtimeService.setVariables(executionId, variables); //可以設置多個變量 放在 MapMap /**2. 通過TaskService來設置流程變量 * taskId:任務id */ // taskService.setVariable(taskId, variableName, values); // taskService.setVariableLocal(taskId, variableName, values); //// 設置本執行對象的變量 ,該變量的作用域只在當前的execution對象 // taskService.setVariables(taskId, variables); //設置的是Map /**3. 當流程開始執行的時候,設置變量參數 * processDefiKey: 流程定義的key * variables: 設置多個變量 Map */ // processEngine.getRuntimeService() // .startProcessInstanceByKey(processDefiKey, variables) /**4. 當任務完成時候,可以設置流程變量 * taskId:任務id * variables: 設置多個變量 Map */ // processEngine.getTaskService().complete(taskId, variables); /** 5. 通過RuntimeService取變量值 * exxcutionId: 執行對象 * */ // runtimeService.getVariable(executionId, variableName);//取變量 // runtimeService.getVariableLocal(executionId, variableName);//取本執行對象的某個變量 // runtimeService.getVariables(variablesName);//取當前執行對象的所有變量 /** 6. 通過TaskService取變量值 * TaskId: 執行對象 * */ // taskService.getVariable(taskId, variableName);//取變量 // taskService.getVariableLocal(taskId, variableName);//取本執行對象的某個變量 // taskService.getVariables(taskId);//取當前執行對象的所有變量 }
//設置流程變量值 @Test public void setVariable(){ String taskId="1804";//任務id //采用TaskService來設置流程變量 //1. 第一次設置流程變量 // TaskService taskService = processEngine.getTaskService(); // taskService.setVariable(taskId, "cost", 1000);//設置單一的變量,作用域在整個流程實例 // taskService.setVariable(taskId, "申請時間", new Date()); // taskService.setVariableLocal(taskId, "申請人", "何某某");//該變量只有在本任務中是有效的 //2. 在不同的任務中設置變量 // TaskService taskService = processEngine.getTaskService(); // taskService.setVariable(taskId, "cost", 5000);//設置單一的變量,作用域在整個流程實例 // taskService.setVariable(taskId, "申請時間", new Date()); // taskService.setVariableLocal(taskId, "申請人", "李某某");//該變量只有在本任務中是有效的 /** * 3. 變量支持的類型 * - 簡單的類型 :String 、boolean、Integer、double、date * - 自定義對象bean */ TaskService taskService = processEngine.getTaskService(); //傳遞的一個自定義bean對象 AppayBillBean appayBillBean=new AppayBillBean(); appayBillBean.setId(1); appayBillBean.setCost(300); appayBillBean.setDate(new Date()); appayBillBean.setAppayPerson("何某某"); taskService.setVariable(taskId, "appayBillBean", appayBillBean); System.out.println("設置成功!"); }
//查詢流程變量 @Test public void getVariable(){ String taskId="1804";//任務id // TaskService taskService = processEngine.getTaskService(); // Integer cost=(Integer) taskService.getVariable(taskId, "cost");//取變量 // Date date=(Date) taskService.getVariable(taskId, "申請時間");//取本任務中的變量 //// Date date=(Date) taskService.getVariableLocal(taskId, "申請時間");//取本任務中的變量 // String appayPerson=(String) taskService.getVariableLocal(taskId, "申請人");//取本任務中的變量 //// String appayPerson=(String) taskService.getVariable(taskId, "申請人");//取本任務中的變量 // // System.out.println("金額:"+cost); // System.out.println("申請時間:"+date); // System.out.println("申請人:"+appayPerson); //讀取實現序列化的對象變量數據 TaskService taskService = processEngine.getTaskService(); AppayBillBean appayBillBean=(AppayBillBean) taskService.getVariable(taskId, "appayBillBean"); System.out.println(appayBillBean.getCost()); System.out.println(appayBillBean.getAppayPerson()); }
public class AppayBillBean implements Serializable{ private Integer id; private Integer cost;//金額 private String appayPerson;//申請人 private Date date;//申請日期 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getCost() { return cost; } public void setCost(Integer cost) { this.cost = cost; } public String getAppayPerson() { return appayPerson; } public void setAppayPerson(String appayPerson) { this.appayPerson = appayPerson; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }五、連線
上面我們已將學過了流程變量了,可以在【任務服務、運行時服務、流程開始、完成某個任務時設置流程變量】,而我們的連接就是流程變量的實際應用了....
5.1定義流程圖我們并不是所有的流程都是按一條的路徑來走的,我們有的時候會根據條件來走不同的路。當然了,最終該流程是會一步步走完....
例子:
重要的信息交由老板來處理,不重要的信息交由經理來處理
表達式的結果必須是布爾型
#{variable=="value"}
${variable==value}
5.2測試我在任務完成時設置流程變量為不重要,那么跳到下一個流程時就是經理來進行處理
當我設置為重要的時候,那么就是交由老板來處理
六、排他網關上面我們使用連線的時候用了兩個條件 : 要么條件是“重要”,要么條件是“不重要”....如果有另一種情況呢???就是用戶把條件輸入錯了,寫成“不知道重不重要”,那么我們的流程怎么走???豈不是奔潰了???
因此,我們要有一條默認的路來走,就是當該變量不符合任何的條件時,我們也有一條默認的路
值得注意的是:如果是在Eclipse中使用插件的BPMN流程圖,如果使用了排他網關,那么在Idea下是解析不了的...
解決:
我們只要重新定義BPMN流程圖的排他網關就行了,idea中的Activiti插件是不用制定默認流程的,只要我們不設置條件,那就是默認的連接線
6.1測試public class ExclusiveGetWay { private ProcessEngine processEngine = ProcessEngines .getDefaultProcessEngine(); // 部署流程定義,資源來在bpmn格式 @Test public void deployProcessDefi() { Deployment deploy = processEngine.getRepositoryService() .createDeployment().name("排他網關流程") .addClasspathResource("ExclusiveGateway.bpmn") .deploy(); System.out.println("部署名稱:" + deploy.getName()); System.out.println("部署id:" + deploy.getId()); } // 執行流程,開始跑流程 @Test public void startProcess() { String processDefiKey = "bankBill";// bpmn 的 process id屬性 ProcessInstance pi = processEngine.getRuntimeService() .startProcessInstanceByKey(processDefiKey); System.out.println("流程執行對象的id:" + pi.getId());// Execution 對象 System.out.println("流程實例的id:" + pi.getProcessInstanceId());// ProcessInstance // 對象 System.out.println("流程定義的id:" + pi.getProcessDefinitionId());// 默認執行的是最新版本的流程定義 } // 查詢正在運行任務 @Test public void queryTask() { // 取得任務服務 TaskService taskService = processEngine.getTaskService(); // 創建一個任務查詢對象 TaskQuery taskQuery = taskService.createTaskQuery(); // 辦理人的任務列表 Listlist = taskQuery.list(); // 遍歷任務列表 if (list != null && list.size() > 0) { for (Task task : list) { System.out.println("任務的辦理人:" + task.getAssignee()); System.out.println("任務的id:" + task.getId()); System.out.println("任務的名稱:" + task.getName()); } } } // 完成任務 @Test public void compileTask() { String taskId = "2404"; Map params=new HashMap (); params.put("visitor", 6); // taskId:任務id processEngine.getTaskService().complete(taskId, params); // processEngine.getTaskService().complete(taskId); System.out.println("當前任務執行完畢"); } }
我們指定的值并不是VIP也不是后臺,那么就會自動去普通窗口中處理
七、拓展閱讀并行網關:
等待活動:
用戶任務:
使用流程變量指定處理人:
我們在快速入門的例子中,是在定義流程圖中硬性指定處理人,其實這么干是不夠靈活的,我們學了流程變量之后,我們是可以靈活地指定處理人的....
@Test public void deployProcessDefi() { Deployment deploy = processEngine.getRepositoryService() .createDeployment().name("用戶任務指定流程") .addClasspathResource("AppayBill.bpmn") .deploy(); System.out.println("部署名稱:" + deploy.getName()); System.out.println("部署id:" + deploy.getId()); } // 執行流程,開始跑流程 @Test public void startProcess() { String processDefiKey = "appayBill";// bpmn 的 process id屬性 Mapparams=new HashMap (); params.put("userID", "王某某"); ProcessInstance pi = processEngine.getRuntimeService() .startProcessInstanceByKey(processDefiKey, params); System.out.println("流程執行對象的id:" + pi.getId());// Execution 對象 System.out.println("流程實例的id:" + pi.getProcessInstanceId());// ProcessInstance // 對象 System.out.println("流程定義的id:" + pi.getProcessDefinitionId());// 默認執行的是最新版本的流程定義 } // 查詢正在運行任務 @Test public void queryTask() { String assignee="王某某";//指定任務處理人 // 取得任務服務 TaskService taskService = processEngine.getTaskService(); // 創建一個任務查詢對象 TaskQuery taskQuery = taskService.createTaskQuery(); // 辦理人的任務列表 List list = taskQuery .taskAssignee(assignee) .list(); // 遍歷任務列表 if (list != null && list.size() > 0) { for (Task task : list) { System.out.println("任務的辦理人:" + task.getAssignee()); System.out.println("任務的id:" + task.getId()); System.out.println("任務的名稱:" + task.getName()); } } }
使用類指定:
組任務:
直接指定辦理人
使用流程變量
使用類
總結如果一個業務需要多方面角色進行處理的話,那么我們最好就是用工作流框架。因為如果其中一個環節的需求發生了變化的話,我們要是沒有用到工作流。那就需要修改很多的代碼。十分麻煩。
Activiti工作流框架快速入門:
定義工作流,使用插件來把我們的流程圖畫出來。這個流程圖就是我們定義的工作流。
工作流引擎是工作流的核心,能夠讓我們定義出來的工作流部署起來。
由于我們使用工作流的時候是有很多數據產生的,因此Activiti是將數據保存到數據庫表中的。這些數據庫表由Actitviti創建,由Activiti維護。
部署完的工作流是需要手動去執行該工作流的。
根據由誰處理當前任務,我們就可以查詢出具體的任務信息。
根據任務的id,我們就可以執行任務了。
流程定義涉及到了四張數據庫表
我們可以通過API把我們的流程定義圖讀取出來
可以根據查詢最新版本的流程定義
刪除流程定義
部署流程定義的時候也可以是ZIP文件
流程在運行中,涉及到兩個對象,四張數據庫表:
流程實例
流程任務
流程實例可以有多個,流程對象只能有一個。
如果流程沒有分支的話,那么流程實例就等于流程對象
基于這么兩個對象,我們就可以做很多事情了
獲取流程實例和任務的歷史信息
判斷流程實例是否為空來判斷流程是否結束了
查看正在運行服務的詳細信息
通過流程實例來開啟流程
流程變量:它涉及到了兩張表。流程變量實際上就是我們的條件。
流程變量的作用域只在流程實例中。
我們可以在流程開始的時候設置流程變量,在任務完成的時候設置流程變量。
運行時服務和流程任務都可以設置流程變量。
通過連線我們可以在其中設置條件,根據不同的條件流程走不同的分支
如果沒有設置默認的條件,當條件不吻合的時候,那么流程就走不下去了,因此需要排他網關來設置一條默認的路徑。
如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同學,可以關注微信公眾號:Java3y
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/68843.html
摘要:基于許可的開源平臺,創始人是的項目架構師,它特色是提供了插件,開發人員可以通過插件直接繪畫出業務流程圖。二工作流引擎對象,這是工作的核心。五總結工作流的概念就先介紹這么多了,更多的去官網查看,下一節將用一個入門的實例來對工作流進行講解。 文章源碼托管:https://github.com/OUYANGSIHA...歡迎 star ?。。?一、activiti介紹 Activiti5是由...
摘要:事實也確實如此,可以配置數據庫,其中存儲了流程運行時的相關信息。在初學之時,了解所有的數據庫表的含義對理解工作機制是有很大幫助的,總共涉及的表格總共有個通用數據,用于存放數據。強行回顧了一下前兩天的學習歷程。 1、關于Activiti 初學activiti我關心的它是什么東西、有什么功能、怎么實現?先來看一張流程圖感受一下: showImg(https://segmentfault.c...
摘要:當一個根級的結束時,就會進行上述的緩存對象統一的持久化。解決的辦法也很簡單,改為監聽,判斷是否時需要修改的任務實體即可。這樣后面要進行駁回時,只要通過這樣關系表,馬上就可以定位到要駁回到的任務了。 1.前言 本文內容主要為以下兩點,因為內容有交叉,所以會放在一起介紹。 1.以自由跳轉為基礎實現不改變原先任務id的駁回關于Activiti6動態跳轉可以查看我的另一篇文章Activiti...
摘要:文章源碼托管歡迎一前言在上一節中,通過一個入門程序,把的環境準備好了,這一節,將整合,并且部署一個最簡單的流程圖。測試結果四總結這一節通過整合,繪制簡單的文件,然后成功部署了文件。 文章源碼托管:https://github.com/OUYANGSIHA...歡迎 star ?。?! 一、前言 在上一節中,通過一個入門程序,把activiti的環境準備好了,這一節,將整合spring,并...
摘要:創建和設置項目創建一個名為的項目以下稱為,其中包含以下依賴項文件當然,將替換為下載的版本,例如,如果你下載的軟件包是,那么的值將是。 創建和設置Maven項目 創建一個名為ActivitiDeveloperQuickStart的Java項目(以下稱為$quickStartJavaProjectName),其中包含以下Maven依賴項: 文件:$mvnProject/pom.xml ...
閱讀 1566·2021-09-22 15:52
閱讀 3472·2021-09-22 14:59
閱讀 2852·2021-09-02 15:12
閱讀 980·2021-08-20 09:35
閱讀 1585·2019-08-30 14:09
閱讀 2717·2019-08-30 13:56
閱讀 1656·2019-08-26 18:27
閱讀 3370·2019-08-26 13:37