天天看點

jBPM開發入門指南(3)

有個輔助工具開發起來友善一點,隻不過現在 jBPM 的開發工具插件功能還不算太強,也就一個“項目建立向導”的功能,讓你:

(1)不用再去配置 classpath 庫的引用了

(2)直接得到了一個 jBPM 的項目初始結構

其實吧,開發 jBPM 也不需要什麼插件工具,在熟練了以後,庫引用了項目初始結構都可以手工建立。

插件不用再去下載下傳了, jbpm-starters-kit-3.1.1 包裡就有,目錄位址如下: D:\jbpm-starters-kit-3.1.1\jbpm-designer\jbpm-gpd-feature\eclipse ,插件的安裝方式是連結式還是直接複制式,任選吧。不懂的就去看看《 Eclipse 從入門精通》這本書,在前面章節都有講到。另外,注明一下 Eclipse 的版本我是用 3.2 ,插件和 Eclispe 版本相關的,要注意了。

如果安裝成功,則 Eclipse 首選項裡多了一個 JBoss jBPM ,另外我們也需要到這個 jBPM 的首選項裡做一些配置工作――指定 jBPM 的安裝路徑(如下圖所示)。這個配置主要是為了找到 jbpm 下的各種 jar 包,好讓 Eclipse 設定項目的庫引用。本文指向路徑是 d:\jbpm-starters-kit-3.1.1\jbpm.3

jBPM開發入門指南(3)

主菜單“檔案->建立->項目”,在彈出的對話框裡,有“ Process Project ”項,如下圖所示:

jBPM開發入門指南(3)

選上好,單擊“下一步”,起個名“ myjbpm ”,然後就可以單擊“完成”了。然後就生成了如下圖所示的一個項目結構: 

jBPM開發入門指南(3)

這個項目和通常 Eclipse 的項目結構有點不同,不過這是一個現在非常流行的項目結構, src/java 存放源檔案, test/java 存放相應的 JUnit 單元測試代碼。如果你用 Maven 來編譯建構項目,對這種目錄結構一定不陌生。

項目建立起了,介紹一下裡面的檔案吧:

l           MessageActionHandler ,自動生成的一個 ActionHandler 。不想要可以删掉。

l           ehcache.xml  cache 的配置檔案,裡面有很詳解的英文說明。沒有必要可以不用改它。

l           hibernate.cfg.xml   jBPM 是用 Hibernate 進行工作流的資料存儲的,這個就是 Hibernate 的配置檔案。後面我們将講到如何配置這個檔案。

l           jbpm.cfg.xml   jbpm 本身的配置檔案。現在是空的,它用的是預設配置,你想知道有哪些配置就去看這個檔案 D:\jbpm-starters-kit-3.1.1\jbpm.3\src\java.jbpm\org\jbpm\default.jbpm.cfg.xml

l           log4j.properties  這個是日志 API 包 log4j 的配置檔案,用過 log4j 的都知道。

l           SimpleProcessTest.java  這個是對最重要的流程配置檔案的 processdefinition.xml 單元測試代碼。這裡表揚一點, jBPM 的優良設計使得它的可測試性非常之高,喜歡寫 t 單元測試的人有福了。

l           gpd.xml  用于生成流程圖的定義檔案。都是一些方框的坐标和長寬

l           processdefinition.xml  這個是對最重要的流程配置檔案,以後寫流程要經常和它打交道。

l           processimage.jpg  一個流程圖 

從項目結構來看,我們沒有看到 JSP 網頁程式,也沒有看到 GUI 用戶端程式,這些代碼都是要我們以後開發中來寫的。但本文不準備用 JSP 、 GUI ( Swing 、 SWT )來做示例,而是用 JUnit 代碼來做使用 jBPM 用戶端來示範。因為 jBPM 實際上是一個背景架構,至于前台是 JSP 還是 Swing 還是無界面的 java.class 都是無關緊要的。在教程裡用無界面的 java.class 來做用戶端則更友善一些,如果進一步采用 JUnit ,則這樣的 java.class 同時還具備了單元測試的功能。以後就是用 JSP 寫了 WEB 頁面,我們還是可以用這些 JUnit 程式來做單元測試,避免了頻繁的滑鼠點按 WEB 頁面這樣的力氣活。是以在 jBPM 自帶的英文教程裡都是一個 JUnit 程式,不仔佃看還真摸不着頭腦。

       hibernate.cfg.xml 的預設設定是用 HSQL ,這是一個記憶體資料庫,這種記憶體資料庫用來代替項目實際所用的資料庫來做單元測試挺不錯的。不過我們這裡是要試試用 MySQL 、 Oracle ,那就改一下設定吧。

注:配置值可參考 D:\jbpm-starters-kit-3.1.1\jbpm-db 對應子目錄下的 hibernate.properties 檔案。

1 、 MySQL 的更改如下:

<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/jbpm</property>

<property name="hibernate.connection.username">root</property>

<property name="hibernate.connection.password">123456</property>

2 、 Oracle 的更改如下:

<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>

<property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>

<property name="hibernate.connection.url">jdbc:oracle:thin:@192.168.123.10:1521:wxxrDB</property>

<property name="hibernate.connection.username">chengang</property>

<property name="hibernate.connection.password">chengang</property>

如果你裝了 Oracle 的用戶端,并且 D:\oracle\ora92\network\ADMIN\tnsnames.ora 裡做了如下的設定

WXXRDB_192.168.123.10 =

  (DESCRIPTION =

    (ADDRESS_LIST =

      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.123.10)(PORT = 1521))

    )

    (CONNECT_DATA =

      (SID = wxxrDB)

      (SERVER = DEDICATED)

  )

則 Oracle 的 hibernate.connection.url 項也可以設為: jdbc:oracle:oci:@WXXRDB_192.168.123.10

       雖然 jBPM 在建立項目之初給我們設定好了庫引用,如下圖

jBPM開發入門指南(3)

但後面運作時還是報一些 NoClassDefFoundError 異常,如沒有對 hibernate3.jar 的引用導緻下面的錯誤

java.lang.NoClassDefFoundError: org/hibernate/Session

    at org.jbpm.persistence.db.DbPersistenceServiceFactory.openService(DbPersistenceServiceFactory.java:55)

    at org.jbpm.svc.Services.getService(Services.java:136)

    .......

是以我們要為本文的執行個體完善庫引用。主要是把 MySQL 和 Oracle 的 JDBC 庫、以及 Hibernate 的 hibernate3.jar 加入到項目的庫引用中。

(1)       找到缺少的 jar 包

l           mysql 的 jdbc 包,在 D:\jbpm-starters-kit-3.1.1\jbpm-db\mysql\lib 目錄裡

l           oracle 的 jdbc 包, jbmp 中沒有包含(可能是沒拿到 oracle 授權),我們可以自已去 oracle 網站上下載下傳,或者去 oracle 安裝目錄 D:\oracle\ora92\jdbc\lib 找 ojdbc14.jar (我們公司用的是 Oracle9i )

l           Hibernate3.jar 在目錄 D:\jbpm-starters-kit-3.1.1\jbpm.3\lib\hibernate 裡。

(2)       在項目裡建立一個 lib 目錄,将這三個 jar 複制到 lib 目錄。

(3)       如下圖設定三 jar 包的庫引用

jBPM開發入門指南(3)

這裡是一個很簡單的請假流程,請假人送出假單給經理審批,經理審批後結束。要說明的是,這個流程并不嚴謹,比如經理不通過流程應該到哪?不過這并不防礙拿它來做示例,螃蟹還得一個一個的吃。我們先拿這一杆子捅到底的流程做一個最簡單的示例,從整體上對 jBPM 工作流開發有概念先。然後我們再慢慢豐富。

1 、定義流程

流程的定義檔案是 processdefinition.xml ,這個是一個關鍵檔案, jBPM 的很大一部份内容都是關于它的。在這裡我們把原來自動生成的内容,稍做改動:

<?xml version="1.0" encoding="GBK"?>

<process-definition xmlns="urn:jbpm.org:jpdl-3.1" name="helloworld">

    <!-- 申請 -->

    <start-state name="request">

        <task>

            <controller>

                <variable name="name" />

                <variable name="day" />

                <variable name="note" />

            </controller>

        </task>

        <!-- 流程轉向 -->

        <transition name="to_confirm" to="confirm">

            <action name="requestAction"

                class ="cn.com.chengang.jbpm.RequestAction">

                <reason> 我要請假 </reason>

            </action>

        </transition>

    </start-state>

    <!-- 審批 -->

    <state name="confirm">

        <transition name="to_end" to="end">

            <action name="finishAction"

                class ="cn.com.chengang.jbpm.ConfirmAction" />

    </state>

    <!-- 結束 -->

    <end-state name="end" />

</process-definition>

說明:

流程的名稱改成了 helloworld 。(呵呵,也就是這裡和 helloworld 有關了)

<controller> 标簽定義了三個資料:姓名、請假天數、說明。

<transition> 标簽定了 request 節點的一個流程轉向,這裡是轉到 confirm 節點。

<action> 标簽定義了流程由一個節點轉到另一個節點時,所要執行的動作,動作封裝在一個 ActionHandler 類中。比如這裡當 request 到 confirm 結點時将執行 RequestAction 類的 execute 方法。

FinishAction 下面還有一個 <reason> (請假理由),它對應于 FinshAction 的屬性 String reason 。

2 、 編寫 ActionHandler

       在上面 processdefinition.xml 裡我們定義了兩個 ActionHandler : RequestAction 、 ConfirmAction 。其代碼如下:

<b>package </b>cn.com.chengang.jbpm;

<b>import </b>org.jbpm.graph.def.ActionHandler;

<b>import </b>org.jbpm.graph.exe.ExecutionContext;

<b>public </b><b>class </b>RequestAction <b>implements</b> ActionHandler {

    <b>private</b> <b>static</b> <b>final</b> <b>long</b> serialVersionUID = 1L;

    <b>private </b>String reason;

    <b>public </b>String getReason() {

        <b>return</b> reason;

    }

    <b>public </b><b>void </b>setReason(String reason) {

        <b>this </b>.reason = reason;

    <b>public </b><b>void </b>execute(ExecutionContext context) <b>throws</b> Exception {

        context.getContextInstance().setVariable("note", reason);

}

說明: ExecutionContext 是一個貫通流程的容器。它是個大寶箱,裡面啥玩意都有,後面将更深入的提到。這裡的 reasion 就是 processdefinition.xml 中的 ” 我要請假 ”

<b>public </b><b>class </b>ConfirmAction <b>implements</b> ActionHandler {

    <b>private </b><b>static </b><b>final </b><b>long </b>serialVersionUID = 1L;

        context.getContextInstance().setVariable("note", " 準假 " );

OK ,背景的程式就算寫完了(前台用戶端的程式還沒寫),下面開始部署。

       我們要把 processdefinition.xml 的流程定義的資料部署到資料庫中,因為 jBPM 在正式運作的時候不是去讀 processdefinition.xml 檔案,而是去讀資料庫中的流程定義。 這裡寫了一個個 JUnit 程式來部署 processdefinition.xml ,當然你用普通的 Java Main 也可以。

<b>package </b>com.sample;

<b>import </b>java.io.FileInputStream;

<b>import </b>java.io.FileNotFoundException;

<b>import </b>java.io.InputStream;

<b>import </b>junit.framework.TestCase;

<b>import </b>org.jbpm.JbpmConfiguration;

<b>import </b>org.jbpm.JbpmContext;

<b>import </b>org.jbpm.graph.def.ProcessDefinition;

/**

 * 部署 processdefinition.xml

  *

 * <b>@author</b> chengang

  */

<b>public </b><b>class </b>DeployProcessTest <b>extends</b> TestCase {

    /**

     * 在本方法執行完畢後,檢查 jbpm_processdefinition 表會多了一條記錄

      *

     * <b>@throws</b> FileNotFoundException

      */

    <b>public </b><b>void </b>testDeployProcessDefinition() <b>throws</b> FileNotFoundException {

        // 從 jbpm.cfg.xml 取得 jbpm 的配置

        JbpmConfiguration config = JbpmConfiguration.getInstance();

        // 建立一個 jbpm 容器

        JbpmContext jbpmContext = config.createJbpmContext();

        // 由 processdefinition.xml 生成相對應的流程定義類 ProcessDefinition

        InputStream is = <b>new</b> FileInputStream("processes/simple/processdefinition.xml");

        ProcessDefinition processDefinition = ProcessDefinition.parseXmlInputStream(is);

        // 利用容器的方法将流程定義資料部署到資料庫上

        jbpmContext.deployProcessDefinition(processDefinition);

        // 關閉 jbpmContext

        jbpmContext.close();

運作此程式,在控制台列印了一些日志,通過。如果出錯,仔佃閱讀出錯資訊以判斷錯誤原因,并确定你按照前面兩節:“修改 hibernate.cfg.xml ”和“完善庫引用”的内容做好了設定。

無論是 MySQL 還是 Oracle ,查詢 jbpm_processdefinition 表,你會發現多了一條記錄,如下圖 ( 以 PLSQL Developer 的顯示為例 )

jBPM開發入門指南(3)

依次檢查各表我們可以發現有如下變化:

jBPM開發入門指南(3)
jBPM開發入門指南(3)
jBPM開發入門指南(3)
jBPM開發入門指南(3)
jBPM開發入門指南(3)
jBPM開發入門指南(3)

并由此簡單判斷出各表的作用,表中各字段的作用由字段名也能知曉一二。

jbpm_processdefinition

一個流程定義檔案對應一條記錄,可記錄多個流程定義檔案,可記錄一個流程定義檔案的對個版本。

jbpm_action

記錄 ActionHandler 的對象執行個體(以名稱為辨別)

jbpm_delegation

記錄了 ActionHandler 全類名,以便于用反射方式來加載

jbpm_envent

它的 transition 引用了 Jbpm_transition 表的 id ,再看其它字段,估計此表是表示流程轉向事件的一個執行個體,或者是一個各表之間的聯接表。

jbpm_node

流程結點

jbpm_transition

流程的轉向定義

jbpm_variableaccess

流程中攜帶的變量。 ACCESS 字段是這些變量的讀寫權限

 作者簡介

陳剛,廣西桂林人,著作有《Eclipse從入門到精通》

您可以通過其部落格了解更多資訊和