各位好,下面由我來為大家介紹開源工作流引擎JBPM的初始化使用方法。
首先當你想學一個框架的時候一定是你要有項目來用他了,OK,那麼你項目當中的流程是什麼你應該清楚吧,那麼當你清楚了這些的時候我們就開始我們這個最簡單的例子吧。
假如我們現在有這麼一個例子,公司員工想報銷點出差費,那麼他要將他的申請提交給他的第一級領導——部門主管去審批。
然後部門主管審批完了之後還要交給這個部門主管的上級公司老總進行審批。那麼針對這個簡單的流程,我們應該從哪裡下手呢?
首先第一件事情就是寫流程定義文件,那麼這個文件我們用什麼來寫呢,他就是一個符合某個語法的XML文件,幸運的是jbpm給我們提供了一個集成的開發環境讓我們來用。
首先去官網上下一個jbpm-jpdl-suite-3.2.GA包,解壓後你會發現他裡面有一個designer文件夾,那個裡面就是我們寫流程定義文件的開發環境,他是一個eclipse的插件。
但是好像他給我們的那個eclipse版本有問題,建議大家從新下一個eclipse-SDK-3.2.1-win32.zip這個版本的eclipse,然後覆蓋他給我們提供的那個。
准備工作做完了,那麼我們就開始吧,首先我們打開解壓目錄下的designer文件夾中的designer.bat文件,他彈出一個eclipse,然後我們就用這個東西來開發我們的流程定義文件了。
打開之後你就會看見一個他的小例子,不過我們不去用他,我們自己新建一個工程。右鍵-new-other-jBoss jbpm-process project。這個時候你會看見他彈出一個對話框,輸入你的工程名字,然後點擊next,這個時候你會發現他已經把jbpm加載進去了,記住要選中 Generate simple ......。
工程建立完了,我們開始建立我們的流程定義文件。在工程裡面你會發現src/main/jpdl這個source folder,然後你會看見他裡面已經有了一個流程定義文件了,但是我們不去用他的。
我們自己建立一個,右鍵src/main/jpdl,然後new-other- jBoss jbpm-process definition。這個時候他就會彈出一個對話框,起一個你要寫的流程定義文件的名字輸入進去,OK,可以了。這個時候你打開你建立的那個文件夾,裡 面就有processdefinition.XML文件,ok,打開他。
在右面的圖裡面你就可以看到一張什麼都沒有的白紙,我們看看這部分左面的那些東西,什麼start,end,tasknode,fork,join。
那我們來解釋一下這是個什麼東西呢,我們看看我們的需求,員工要寫一個報銷單,然後交給部門主管來處理,那麼部門主管就應該算是一個tasknode,他就是一個任務節點。
start和end其實就是一個虛狀態,當我們寫完報銷單的時候我們就提交了,這個時候他就到了第一個tasknode這個節點了。然後他審批完了還要交給總經理審批,那麼他又是一個tasknode,然後總經理審批完了結束,ok,是一個end。
start--》tasknode(部門主管審批)--》tasknode(總經理審批)--》end。
如果覺得看的有點模糊可以看看我傳上來的那個圖。然後你在這個試圖框的下面可以看到有個source,點擊一下,就會發現他已經自動的給你生成XML代碼了。
但是這樣還是有點不夠,我們只是定義了一個tasknode節點,並沒有定義tasknode節點的任務由誰來做。那麼我們還要定義一個tasknode節點是由誰來做的:
那麼這段代碼是這麼寫的:
<?xml version="1.0" encoding="UTF-8"?> <process-definition XMLns="" name="test1"> <start-state name="start"> <transition name="" to="部門經理審批"></transition> </start-state> <task-node name="部門經理審批"> <task> <assigment actorId="部門經理"></assigment> </task> <transition name="" to="總經理審批"></transition> </task-node> <task-node name="總經理審批"> <task> <assigment actorId="總經理"></assigment> </task> <transition name="" to="end1"></transition> </task-node> <end-state name="end1"></end-state> </process-definition>
這樣的話我們的流程定義文件就定義完了,但是這只是把文件定義完了,系統並不知道啊,所以我們還要把我們的文件部署到系統中去。
首先我們在src/main/Java裡面新建立一個包,然後建立一個class,隨便起個名字,就叫 TestJBPM_01吧,那麼在這個類裡面我們要做的是什麼呢?我們要先導入表,因為jbpm要運行就要用到很多個表,ok,那麼我們這個裡面導入表和 hibernate導入表是差不多的,它的代碼是這樣的:
package com.jbpm.test; import junit.framework.TestCase; import org.jbpm.JbpmConfiguration; public class TestJbpm_01 extends TestCase { public void testJbpm(){ //創建jbpm數據庫表。他就像hibernate裡面的哪個export一樣。 實際上他就是hibernate裡面的哪個export。 //應為他映射了很多個表,所以我們就能創建那麼多個表。 JbpmConfiguration.getInstance().createSchema(); } }
然後呢我們就開始部署我們的流程定義文件,我們將這個文件當中的內容呢放到數據庫當中去,當我們以後再用的時候呢我們就隨時的將它加載出來。
package com.jbpm.test; import junit.framework.TestCase; import org.jbpm.JbpmConfiguration; import org.jbpm.JbpmContext; import org.jbpm.graph.def.ProcessDefinition; public class TestJbpm_02 extends TestCase { //jbpmConfiguration對象的創建 static JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance(); public void testJbpm(){ //然後我們把processDefinition裡面相關的對象持久化到數據庫裡面去。 //流程定義文件裡面有很多個概念,他有node,有transition, 還有processDefinition,那麼我們不需要一個 //一個保存,jbpm把保存這麼多對象的方法封裝成一個接口,叫做deployProcessDefinition。 我們只要調用這個 //方法,傳一個processDefinition對象,我們就能將他們存入到數據庫裡面去。 //這個首先第一步我們要得到一個processDefinition對象,然後我們把他部署到流程中去。 ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource("testJBPM/testJbpm.XML"); //我們要存就必須獲得一個session對象,而jbpm已經把session對象封裝到一個 JbpmContext對象裡面了。 //那麼這個jbpmContext對象是怎麼得到的呢,我們要先有一個jbpmConfiguration對象, 我們要對數據庫進行 //操作的時候一定要有jbpmConfiguration這個對象, 用他來創建一個類似於hibernate當中的session一樣的 //對象——jbpmContext。他是我們對數據庫所有的操作的一個接口。 JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try{ //然後部署的操作已經由jbpmContext給我們創建好了, 我們只需要調一下他的一個方法就可以了。 jbpmContext.deployProcessDefinition(processDefinition); }finally{ //最後我們還要對他close一下,就像我們用hibernate的時候要close session一樣。 jbpmContext.close(); } } }
第二步我們也做完了,那麼現在我們開始做第三步,也就是說,我們流程定義文件寫好了,現在我們的系統當中有了這樣一個報銷流程。
那麼就開始實際的去用她吧,一個人小報銷了,那麼她就要寫一個報銷的申請,但是這個 報銷的申請寫完了存到數據庫當中了還不能算完了,應該和我們的這個流程關聯起來啊,那麼她應該怎麼去關聯呢,我們在建立這個申請單這個類的時候應該定義一 個processInstanceId屬性,她是一個long型的。
記錄這我們的這個流程實例的id,那麼什麼是流程實例 (processInstance)呢,她是我們工作流當中第二重要的概念,他和流程定義的關系就相當於對象和類之間的關系,類是一個抽象的東西,她定義 完了是什麼也干不了的,要想用她內部定義的東西我們就要new出一個實例來,當然這個裡面也是這樣的。
那麼也就是說,當我們創建這個報銷申請的時候我們就要先根據這個流程‘new’出一個流程實例來存到數據庫當中,然後在把她的id傳給報銷申請對象然後再將這個報銷申請對象存到數據庫當中。那麼這個代碼是這樣的:
package com.jbpm.test; import junit.framework.TestCase; import org.hibernate.Session; public class TestJbpm_03 extends TestCase { public void testJbpm(){ Session session = null; try{ session = HibernateUtil.getSession(); session.beginTransaction(); Document doc = new Document(); doc.setTitle("title3"); doc.setContent("this is content3"); session.save(doc); session.getTransaction().commit(); }catch(Exception e){ e.printStackTrace(); session.getTransaction().rollback(); }finally{ HibernateUtil.closeSession(session); } } }
package com.jbpm.test; import junit.framework.TestCase; import org.jbpm.JbpmConfiguration; import org.jbpm.JbpmContext; import org.jbpm.graph.def.ProcessDefinition; import org.jbpm.graph.exe.ProcessInstance; /** /* /*將申請單和流程實例綁定 **/ public class TestJbpm_04 extends TestCase { static JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance(); public void testJbpm(){ JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); jbpmContext.setSessionFactory(HibernateUtil.getSessionFactory()); try { ProcessDefinition processDefinition = jbpmContext.getGraphSession().findLatestProcessDefinition("testJbpm"); ProcessInstance processInstance = new ProcessInstance(processDefinition); jbpmContext.save(processInstance); //將我們的document和instance綁定。 long processInstanceId = processInstance.getId(); Document document = (Document)jbpmContext.getSession().load(Document.class,1); document.setProcessInstanceId(processInstanceId); jbpmContext.getSession().update(document); processInstance.getContextInstance().setVariable("document", document.getId()); }catch(Exception e){ e.printStackTrace(); }finally{ jbpmContext.close(); } } }
現在我們的申請已經和實例關聯起來了,那麼接下來的下一步就開始用啦,就是讓 這個申請流轉起來吧,那麼她應該怎麼去流轉呢,嘿嘿,jbpm給我們提供一個signal方法,每當執行一次這個方法的時候她就流轉一下到下一個節點,你 可以打印出當前節點試一下,看看是不是執行一次你的當前節點就換一下。這段代碼是這樣的:
package com.jbpm.test; import junit.framework.TestCase; import org.jbpm.JbpmConfiguration; import org.jbpm.JbpmContext; import org.jbpm.graph.exe.ProcessInstance; public class TestJbpm_05 extends TestCase { static JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance(); public void testJbpm(){ JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); jbpmContext.setSessionFactory(HibernateUtil.getSessionFactory()); try{ Document document = (Document)jbpmContext.getSession().load(Document.class, 3); long processInstanceId = document.getProcessInstanceId(); ProcessInstance processInstance = jbpmContext.getProcessInstance(processInstanceId); processInstance.signal(); }finally{ jbpmContext.close(); } } }