日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

jbpm入门样例

發布時間:2024/1/17 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jbpm入门样例 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1.????? jBPM的簡介 jBPM是JBOSS下的一個開源java工作流項目,該項目提供eclipse插件,基于Hibernate實現數據持久化存儲。 參考 http://www.jboss.com/products/jbpm 2.????? jBPM和myeclipse的沖突 當eclipse安裝了myeclipse和jBPM時候,可能有沖突,詳細表如今jBPM的流程設計器不能在eclipse中使用。 3.????? Hibernate連接mysql數據庫的一般參數 以下的配置參數,依據須要能夠改動: jbpmtest是mysql中的schema的名字; GBK是字符集,能夠依據須要改動; username=root,mysql數據庫的用戶名是root password=mysql,mysql數據庫的用戶密碼是mysql ? hibernate.dialect=org.hibernate.dialect.MySQLDialect hibernate.connection.driver_class=com.mysql.jdbc.Driver hibernate.connection.url=jdbc:mysql://localhost/jbpmtest?useUnicode=true&characterEncoding=GBK hibernate.connection.username=root hibernate.connection.password=mysql ? hibernate.show_sql=true hibernate.c3p0.min_size=1 hibernate.c3p0.max_size=3 4.????? Hibernate連接Oracle數據庫的一般參數 hibernate.dialect=org.hibernate.dialect.Oracle9Dialect hibernate.connection.driver_class=oracle.jdbc.driver.OracleDriver hibernate.connection.url= jdbc:oracle:thin:@localhost:1521:orcl hibernate.connection.username=jbpm hibernate.connection.password=jbpm 5.????? 為jBPM創建數據庫表等內容 5.1.???????????? 為mysql創建數據庫以及數據內容 JbpmSessionFactory.buildJbpmSessionFactory().getJbpmSchema().dropSchema(); JbpmSessionFactory.buildJbpmSessionFactory().getJbpmSchema().createSchema(); 這2個語針對mysq有效. 5.2.???????????? 為oralce創建數據庫以及數據內容 JbpmSessionFactory.buildJbpmSessionFactory().getJbpmSchema().dropSchema(); JbpmSessionFactory.buildJbpmSessionFactory().getJbpmSchema().createSchema(); 上面的語句對oralce無效。 模型文件夾jBPM/jbpm_database/jBPM_oralce10g.pdm 是jBPM的Oralce模型,包括相應的Sequence的信息. 須要在數據庫中創建 Sequence name=hibernate_sequence http://wiki.jboss.org/wiki/Wiki.jsp?page=JbpmOnOracle 5.3.???????????? 流程信息保存到數據庫 JbpmSessionFactoryfactory = ?JbpmSessionFactory.buildJbpmSessionFactory(); JbpmSession session = factory.openJbpmSession(); GraphSession graphSession = ?session.getGraphSession(); session.beginTransaction(); /// new ProcessDefinition 實例 ProcessDefinition myProcessDefinition = null; ProcessInstance processInstance = new ProcessInstance(processDefinition); processInstance.getContextInstance().setVariable("myvar","xxx"); /// graphSession.saveProcessDefinition(myProcessDefinition); session.commitTransaction(); session.close(); jBPM和Hibernate,MySQL的使用中會遇到字符集的問題. 須要注意幾個地方。 5.4.???????????? 在Mysql安裝過程指定字符集 在Mysql安裝過程中指定對應的默認字符集是GBK 5.5.???????????? Hibernate.properties文件里的字符集設置 hibernate.connection.url=jdbc:mysql://localhost/jbpmtest?useUnicode=true&characterEncoding=GBK 5.6.???????????? hibernate.cfg.xml 文件里的字符集設置 <property name="hibernate.connection.url">jdbc:mysql://192.168.1.2/jbpmtest</property> 5.7.???????????? MySQL的配置文件的改動: my.ini中 default-character-set=GBK 注意有2處須要改動 6.????? 為流程定義變量 分成3種流程變量 全局變量(全局流程變量) 全局暫時變量(全局流程暫時變量) 局部變量(流程某個接點內有效的變量) @see?org.jbpm.context.exe.ContextInstance 眼下還沒有使用過局部變量(流程某個接點內有效的變量) 流程變量的定義 6.1.???????????? 流程變量的類型 ·???????? java.lang.String ·???????? java.lang.Boolean ·???????? java.lang.Character ·???????? java.lang.Float ·???????? java.lang.Double ·???????? java.lang.Long ·???????? java.lang.Byte ·???????? java.lang.Short ·???????? java.lang.Integer ·???????? java.util.Date ·???????? byte[] ·???????? java.io.Serializable ·???????? classes that are persistable with hibernate 全部基本類型的包裹類型,以及實現了Serializable的類型都能夠作為流程參數變量使用,注意參數類不能是一個類的內部類或者屬性類(除非包括參數類的類實現了Serializable接口) 參考 org.jbpm.context.exe.VariableInstance 6.2.???????????? 流程變量的使用 l???????? 變量的定義和獲取 void ContextInstance.setVariable(String variableName, Object value); void ContextInstance.setVariable(String variableName, Object value, Token token); Object ContextInstance.getVariable(String variableName); Object ContextInstance.getVariable(String variableName, Token token); l??????? Variables can be deleted with ContextInstance.deleteVariable(String variableName); ContextInstance.deleteVariable(String variableName, Token token); 6.3.???????????? Variable lifetime 一個變量在被定義后,在變量從ContextInstance刪除前,都能夠被訪問。當變量被刪除后,去獲取該變量將返回為空。 6.4.???????????? 自己定義類的實例作為流程變量 假設一個類的實例要作為流程變量使用,該類須要實現java.io.Serializable接口,而且定義序列化版本號. //一個能夠作為流程變量使用的類 class Wdz implements Serializable{ //為類指定序列化版本 private static final long serialVersionUID = 1L;???? private String name="wdz"; private int age=10; public String toString(){ return "name="+name+",age="+age;???? }???? } 上面的樣例中,假設把類Wdz作為類WdzParent內部類使用,然后當成流程變量使用,那類WdzParent必須 也實現Serializable接口,否則會有問題. 6.5.???????????? Transient variables 流程的歷史變量是不能持久化的,作用范圍是對整個流程全局有效的。 在ContextInstance類內部,採用的是一個Map來存儲TransientVariable的信息 參考代碼 org.jbpm.context.exe.ContextInstance 的源碼。 基本的相關方法 public void deleteTransientVariable(java.lang.String?name) public void setTransientVariable(java.lang.String?name, ???????????????????????????? ????java.lang.Object?value) public java.lang.Object getTransientVariable(java.lang.String?name) 6.6.???????????? Variables overloading 當一個變量和流實例關聯(變量名字=”wdz”,value=”test”),假設在設置一個變量 (變量名字=”wdz”,value= new Integer(10)) ,那最后變量(變量名字=”wdz)的值是Integer(10)。 這稱之為overload. 6.7.???????????? Variables overriding 假設父流程有變量A(值=”value1”),子流程又定義了變量A值=”value2”,那在子流程范圍內,獲取變量A的值,那結果是值=”value2”。這是遵循一般語言的局部變量在它的局部范圍內override上級變量。 6.8.???????????? 流程變量的持久化 它依賴于流程實例的持久化,非TransientVariable流程實例的持久化一起被保存。 保存在數據表jbpm_variableinstance 參考 org.jbpm.context.exe.VariableInstance 6.9.???????????? Customizing variable persistence (能夠進一步了解) User?java object <---> converter <---> ?variable instance 也就是自己定義類的持久化須要定義自己的converter和變量實例類 converter和變量實例類須要繼承org.jbpm.context.exe.VariableInstance converter須要實現org.jbpm.context.exe.Converter接口

?

工作流盡管還在不成熟的發展階段,甚至還沒有一個公認的規范標準。但其應用卻已經在高速展開,這說明市場對工作流框架的需求是急迫而巨大的。

??? 我們公司的后臺短信管理系統涉及短信編發、領導層層審核等操作,這是一個比較典型的工作流系統。過去我們用的工作流引擎是 shark ,然后在使用后發現其過于龐大,后臺數據庫操作頻繁而未進行優化,直接導致的后果就是前臺操作緩慢。于是經研究決定,將工作流引擎由 shark 換成 jBPM

??? jBPM 之前是一個開源軟件,后增加 JBoss 組織。正好我們公司也是用 JBoss 的。只是 jBPM 并沒有綁定在 JBOSS 上, Tomcat 等也能夠使用它。

??? jBPM 的正處在不斷發展中,做為開源軟件的特點,其設計變化往往非常大。所以一些過去的資料可能已經不適用了。于是作者依據自己的使用經驗,又一次整理出這份文檔,以備學習參考。

注:本文使用的 jBPM 版本號為 3.1.1

環境準備

1、安裝JDK

全部 JAVA 開發第一個須要安裝的,沒什么好說的。記得把系統變量 JAVA_HOME 設上。

2、安裝Ant

Ant 是使用 jBPM 必須的一個工具。 jBPM 中的非常多操作都要用到 Ant

安裝方法:

1 )先下載: http://archive.apache.org/dist/ant/binaries/ ,選一個如: apache-ant-1.6.5-bin.zip

2 )解壓到 D:/ant (當然其它文件夾也能夠)。

3 )設置例如以下系統變量: ANT_HOME=d:/ant

4 )把 %ANT_HOME%/bin 增加到系統變量 PATH 中。

3、安裝Eclipse

Eclipse 不是開發 jBPM 必須的工具,但它是對 jBPM 開發非常有幫助的工具,特別是 jBPM 提供了一個 Eclipse 插件用來輔助開發 jBPM 。關于 Eclipse 的安裝不贅述了,本文用的版本號是: Eclipse3.2

?

安裝 jBPM

jBPM 的下載地址: http://www.jboss.com/products/jbpm/downloads  

l?????????? JBoss jBPM jBPM 的軟件包

l?????????? JBoss jBPM Starters Kit  是一個綜合包,它包含了 jBPM 軟件包、開發插件、一個配置好了的基于 JBoss jBPM 演示樣例、一些數據庫配置文件演示樣例。

l?????????? JBoss jBPM Process Designer Plugin  是輔助開發 jBPM Eclipse 插件。

l?????????? JBoss jBPM BPEL Extension jBPM 關于 BPEL 的擴展包

本指南選擇下載: JBoss jBPM Starters Kit 。下載后解壓到 D:/jbpm-starters-kit-3.1 ,文件夾下含有五個子文件夾:

l?????????? jbpm   jBPM 的軟件包

l?????????? jbpm-bpel 僅僅含有一個網頁

l?????????? jbpm-db 各種數據庫 hibernate 配置文件演示樣例,有些還包括了對應的 jdbc 驅動程序。

l?????????? jbpm-designer  輔助開發 jBPM Eclipse 插件,詳細在 jbpm-gpd-feature 子文件夾中

l?????????? jbpm-server  一個已經配置好了的基于 JBoss jBPM 演示樣例 .

?

感覺下工作流

前面我們說了,在 JBoss jBPM Starters Kit jbpm-server 文件夾是一個已經配置好的了 jBPM 演示樣例,那么讓我們來感覺一下 jBPM 做出的東西吧。

?

雙擊 jbpm-server 文件夾下的 start.bat 文件,啟動 JBoss 服務。這時會打開一個 DOS 窗體,啟動完畢后,日志會不斷輸出,當中最后一句是“ 13:55:39,937 DEBUG [StaticNotifier] going to wait for (CMD_EXECUTOR, java.lang.Object@1df59bd) ”,這表示 jBPM 在開始工作了,它不斷進行輪詢。

打開網頁: http://localhost:8080/jbpm/  得到例如以下畫面

?

這是一個已經用 jBPM 開發好的用戶定單流程,具有下單、審核、估價等流程。它所用的數據庫是一個內置的數據庫。

cookie monster 用戶登錄,選擇“ create new web sale order ”能夠創建一個定單。例如以下圖所看到的,在圖左邊是填寫的定單情況,右邊一整個定貨流程的示意圖,紅色框表示流程進行到哪一步了。填寫好定單好,選擇“ Save and Close Task ”,完畢定單提交。

?

選擇右上角的“ Login as another user ”以另外一個username ernie 登錄。這時能夠看到 ernie 用戶的任務列表中多了一項。

?

點進去后,顯演示樣例如以下畫面。這個演示樣例對中文的支持不好,全都顯示成了 unicode 碼了。無論這什么多,反正知道是這么回事即可了。在 comment 項填寫意見,選 OK button,進入到下一步。假設選擇 more info needed button,則打回給 cookie monster 用戶改動定單。

?

以下的流程,這里就不再贅述了。在這個非常標準的工作流演示樣例中,我們基本能夠看到 jBPM 的應用范圍還是比較廣的。并且從這個演示樣例,我們是看不出有 jBPM 的,也就是說 jBPM 在后臺起著作用。

從這個樣例,還看不出 jBPM 的優勢。只是,假設在一個流程不確定,常常須要變動的項目中, jBPM 的優點將會顯然出來。應用 jBPM 后,改變流程僅僅需改變流程描寫敘述文件,這將在后面的內容提到。

這是一個已做好的演示樣例,接下來我們將仿造這個實例來開發一個請假流程。
?

4 數據庫初始化

jBPM 須要數據庫支持, jBPM 會把自己的一個初始化數據存儲到數據庫,同一時候工作流的數據也是存儲到數據庫中的。 jBPM 使用 Hibernate 來做為自己的存儲層,因此僅僅要是 Hibernate 支持的數據庫, jBPM 也就支持。

?

本文先以 MySQL 為例,然后再以 Oracle 為例,來談談 jBPM 的數據庫初始化操作。

?

注:在上面的 JBoss 自帶的演示樣例中,并沒有設置數據庫,那是由于 jBPM 默認使用的是內存數據庫 hsqldb

4.1? MySQL

?

1 、首先安裝 MySQL

MySQL 的安裝比較簡單,網上也有非常多文章,本文不再贅述。本指南所用 MySQL 版本號為 MySQL 4.1 for windows )。再找一個 MySQL client,目的是方便查看數據庫中的數據,本文推薦使用 MySQL 站點上免費提供的“ MySQL Query Brower ”,當然你用其它的client也行,比方 MySQL-Front

?

2 、建庫

MySQL 中創建一個庫,庫名: jbpm

?

3 、生成建表的 SQL 語句并建表

jbpm-starters-kit-3.1.1下的子文件夾 jbpm 改名為 jbpm.3 ,否則在運行以下的 ant 命令時會報如 jbpm.3 文件夾不存在的錯誤:

D:/jbpm-starters-kit-3.1.1/jbpm-db/build.xml:361: The following error occurred while executing this line:

D:/jbpm-starters-kit-3.1.1/jbpm-db/build.xml:68: Basedir D:/jbpm-starters-kit-3.1.1/jbpm.3 does not exist

?

DOS 窗下,進入 D:/jbpm-starters-kit-3.1.1/jbpm-db 文件夾,運行例如以下命令:

ant mysql.scripts

?

運行成功后,在 D:/jbpm-starters-kit-3.1.1/jbpm-db/build/mysql/scripts 文件夾里生成了四個 sql 文件,它們做什么用的一看名字就知道了。在 MySQL client中運行“ mysql.create.sql ”腳本,這樣將在 jbpm 庫中創建一個個的數據表。

?

?

4.2? Oracle

先安裝好 Oracle server。我們公司有現存的 Oracle server,也提供給了我一個屬于我自己的username,一登錄就能夠隨意在我的庫之下創建表了。所以這一步就省了,沒有的自個先裝好吧。

訪問 Oracle 推薦用“ PLSQL Developer ”。只是要連接 Oracle 還要在本機上裝上 Oracle 自己的client程序,里面提供了 JDBC 包和一些配置。要連接server還得配置一下,我一般都是不用 GUI 而直接改 tnsnames.ora 文件,在我的電腦里此文件的文件夾地址是: D:/oracle/ora92/network/ADMIN/tnsnames.ora ,內容例如以下 ( 兩面有兩個配置了 )

# TNSNAMES.ORA Network Configuration File: E:/oracle/ora92/network/admin/tnsnames.ora

# Generated by Oracle configuration tools.

?

WXXRDB_192.168.3.2 =

? (DESCRIPTION =

??? (ADDRESS_LIST =

????? (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.3.2)(PORT = 1521))

??? )

??? (CONNECT_DATA =

????? (SID = wxxrDB)

????? (SERVER = DEDICATED)

??? )

? )

?

WXXRDB_192.168.4.2 =

? (DESCRIPTION =

??? (ADDRESS_LIST =

????? (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.4.2)(PORT = 1521))

??? )

??? (CONNECT_DATA =

????? (SID = wxxrDB)

????? (SERVER = DEDICATED)

??? )

? )

?

前面都是 Oracle 的一些知識,不會的 Google 一下吧。最后配置好后,用 PLSQL Developer 輸入你的username和password聯接到 Oracle ,就算 OK 了。

?

參考上面 MySQL 的步驟,基本一樣:

1?????? jbpm 改名為 jbpm.3 (或者改動jbpm-db文件夾下的build.properties文件)

2?????? 再運行 ant oracle.scripts

3?????? jbpm-db/build/oracle/scripts 文件夾的 oracle.create.sql 腳本,在 Oracle 中生成 jBPM 的全部表。在“ PLSQL Developer ”中能夠新建一個 Command Windows 窗體然后輸入命令: @D:/jbpm-starters-kit-3.1.1/jbpm-db/build/oracle/scripts/oracle.create.sql

(假設報錯,就將報錯的地方凝視掉)

5  安裝 jBPM Eclipse 開發插件

有個輔助工具開發起來方便一點,僅僅只是如今 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

?

6   jBPM Hello World

6.1 新建jBPM項目

主菜單“文件->新建->項目”,在彈出的對話框里,有“ Process Project ”項,例如以下圖所看到的:


選上好,單擊“下一步”,起個名“ myjbpm ”,然后就能夠單擊“完畢”了。然后就生成了例如以下圖所看到的的一個項目結構: ?

這個項目和通常 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 client程序,這些代碼都是要我們以后開發中來寫的。但本文不準備用 JSP GUI Swing SWT )來做演示樣例,而是用 JUnit 代碼來做使用 jBPM client來演示。由于 jBPM 實際上是一個后臺框架,至于前臺是 JSP 還是 Swing 還是無界面的 java.class 都是無關緊要的。在教程里用無界面的 java.class 來做client則更方便一些,假設進一步採用 JUnit ,則這種 java.class 同一時候還具備了單元測試的功能。以后就是用 JSP 寫了 WEB 頁面,我們還是能夠用這些 JUnit 程序來做單元測試,避免了頻繁的鼠標點按 WEB 頁面這種力氣活。所以在 jBPM 自帶的英文教程里都是一個 JUnit 程序,不仔佃看還真摸不著頭腦。

?

6.2 改動hibernate.cfg.xml

??? 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 的client,而且 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

?

6.3 完好庫引用

??? 盡管 jBPM 在創建項目之初給我們設置好了庫引用,例如以下圖

但后面執行時還是報一些 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 包的庫引用

?

6.4 開始HellorWorld

這里是一個非常easy的請假流程,請假人提交假單給經理審批,經理審批后結束。要說明的是,這個流程并不嚴謹,比方經理不通過流程應該到哪?只是這并不防礙拿它來做演示樣例,螃蟹還得一個一個的吃。我們先拿這一桿子捅究竟的流程做一個最簡單的演示樣例,從總體上對 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" />

?????? </transition>

??? </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 。其代碼例如以下:

package cn.com.chengang.jbpm;

?

import org.jbpm.graph.def.ActionHandler;

import org.jbpm.graph.exe.ExecutionContext;

?

public class RequestAction implements ActionHandler {

?

??? private static final long serialVersionUID = 1L;

?

??? private String reason;

?

??? public String getReason() {

?????? return reason;

??? }

?

??? public void setReason(String reason) {

?????? this .reason = reason;

??? }

?

??? public void execute(ExecutionContext context) throws Exception {

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

??? }

?

}

?

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

?

?

package cn.com.chengang.jbpm;

?

import org.jbpm.graph.def.ActionHandler;

import org.jbpm.graph.exe.ExecutionContext;

public class ConfirmAction implements ActionHandler {

?

??? private static final long serialVersionUID = 1L;

?

??? public void execute(ExecutionContext context) throws Exception {

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

??? }

?

}

?

OK ,后臺的程序就算寫完了(前臺client的程序還沒寫),以下開始部署。

?

6.5 部署processdefinition.xml

??? 我們要把 processdefinition.xml 的流程定義的數據部署到數據庫中,由于 jBPM 在正式執行的時候不是去讀 processdefinition.xml 文件,而是去讀數據庫中的流程定義。 ?? 這里寫了一個個 JUnit 程序來部署 processdefinition.xml ,當然你用普通的 Java Main 也能夠。

package com.sample;

?

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.InputStream;

?

import junit.framework.TestCase;

?

import org.jbpm.JbpmConfiguration;

import org.jbpm.JbpmContext;

import org.jbpm.graph.def.ProcessDefinition;

?

/**

?* 部署 processdefinition.xml

? *

?* @author chengang

? *

? */

public class DeployProcessTest extends TestCase {

??? /**

??? ?* 在本方法運行完成后,檢查 jbpm_processdefinition 表會多了一條記錄

??? ? *

??? ?* @throws FileNotFoundException

??? ? */

??? public void testDeployProcessDefinition() throws FileNotFoundException {

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

?????? JbpmConfiguration config = JbpmConfiguration.getInstance();

?????? // 創建一個 jbpm 容器

?????? JbpmContext jbpmContext = config.createJbpmContext();

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

?????? InputStream is = new FileInputStream("processes/simple/processdefinition.xml");

?????? ProcessDefinition processDefinition = ProcessDefinition.parseXmlInputStream(is);

?????? // 利用容器的方法將流程定義數據部署到數據庫上

?????? jbpmContext.deployProcessDefinition(processDefinition);

?????? // 關閉 jbpmContext

?????? jbpmContext.close();

??? }

?

}

?

執行此程序,在控制臺打印了一些日志,通過。假設出錯,仔佃閱讀出錯信息以推斷錯誤原因,并確定你依照前面兩節:“改動 hibernate.cfg.xml ”和“完好庫引用”的內容做好了設置。

?(假設拋出異常09:32:43,791 [main] ERROR ErrorCounter : *** ERROR: line 3:45: expecting "set", found 't'
09:32:43,822 [main] ERROR ErrorCounter : *** ERROR: line 3:45: expecting "set", found 't'
09:32:43,869 [main] ERROR ErrorCounter : *** ERROR: line 3:50: unexpected token: t
09:32:43,931 [main] ERROR SessionFactoryImpl : Error in named query: SchedulerSession.deleteTimersForProcessInstance
org.hibernate.hql.ast.QuerySyntaxError: unexpected token: t near line 3, column 50 [
?????
??????? delete from org.jbpm.scheduler.exe.Timer t
??????? where t.processInstance = :processInstance
?????
??? ]
?at org.hibernate.hql.ast.ErrorCounter.throwQueryException(ErrorCounter.java:63)
?at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:215)
?at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:127)
?at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:83)
?at org.hibernate.impl.SessionFactoryImpl.getQuery(SessionFactoryImpl.java:427)
?at org.hibernate.impl.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:388)
?at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:291)
?at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1005)
?at org.jbpm.persistence.db.DbPersistenceServiceFactory.getSessionFactory(DbPersistenceServiceFactory.java:93)
?at org.jbpm.persistence.db.DbPersistenceService.getSessionFactory(DbPersistenceService.java:74)
?at org.jbpm.persistence.db.DbPersistenceService.getSession(DbPersistenceService.java:78)
?at org.jbpm.persistence.db.DbPersistenceService.getGraphSession(DbPersistenceService.java:201)
?at org.jbpm.JbpmContext.getGraphSession(JbpmContext.java:427)
?at org.jbpm.JbpmContext.deployProcessDefinition(JbpmContext.java:166)
?at com.hanxr.jbpm.action.DeployProcessTest.testDeployProcessDefinition(DeployProcessTest.java:35)
?at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
?at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
?at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
?at java.lang.reflect.Method.invoke(Method.java:324)
?at junit.framework.TestCase.runTest(TestCase.java:154)
?at junit.framework.TestCase.runBare(TestCase.java:127)
?at junit.framework.TestResult$1.protect(TestResult.java:106)
?at junit.framework.TestResult.runProtected(TestResult.java:124)
?at junit.framework.TestResult.run(TestResult.java:109)
?at junit.framework.TestCase.run(TestCase.java:118)
?at junit.framework.TestSuite.runTest(TestSuite.java:208)
?at junit.framework.TestSuite.run(TestSuite.java:203)
?at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
?at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
?at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: line 3:50: unexpected token: t
?at org.hibernate.hql.antlr.HqlBaseParser.deleteStatement(HqlBaseParser.java:242)
?at org.hibernate.hql.antlr.HqlBaseParser.statement(HqlBaseParser.java:139)
?at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:209)
?... 28 more
09:32:43,947 [main] ERROR SessionFactoryImpl : Error in named query: SchedulerSession.suspendTimersForToken
org.hibernate.hql.ast.QuerySyntaxError: expecting "set", found 't' near line 3, column 45 [
?????
??????? update org.jbpm.scheduler.exe.Timer t
??????? set t.isSuspended = true
??????? where t.token = :token
?????
??? ]
?at org.hibernate.hql.ast.ErrorCounter.throwQueryException(ErrorCounter.java:63)
?at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:215)
?at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:127)
?at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:83)
?at org.hibernate.impl.SessionFactoryImpl.getQuery(SessionFactoryImpl.java:427)
?at org.hibernate.impl.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:388)
?at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:291)
?at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1005)
?at org.jbpm.persistence.db.DbPersistenceServiceFactory.getSessionFactory(DbPersistenceServiceFactory.java:93)
?at org.jbpm.persistence.db.DbPersistenceService.getSessionFactory(DbPersistenceService.java:74)
?at org.jbpm.persistence.db.DbPersistenceService.getSession(DbPersistenceService.java:78)
?at org.jbpm.persistence.db.DbPersistenceService.getGraphSession(DbPersistenceService.java:201)
?at org.jbpm.JbpmContext.getGraphSession(JbpmContext.java:427)
?at org.jbpm.JbpmContext.deployProcessDefinition(JbpmContext.java:166)
?at com.hanxr.jbpm.action.DeployProcessTest.testDeployProcessDefinition(DeployProcessTest.java:35)
?at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
?at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
?at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
?at java.lang.reflect.Method.invoke(Method.java:324)
?at junit.framework.TestCase.runTest(TestCase.java:154)
?at junit.framework.TestCase.runBare(TestCase.java:127)
?at junit.framework.TestResult$1.protect(TestResult.java:106)
?at junit.framework.TestResult.runProtected(TestResult.java:124)
?at junit.framework.TestResult.run(TestResult.java:109)
?at junit.framework.TestCase.run(TestCase.java:118)
?at junit.framework.TestSuite.runTest(TestSuite.java:208)
?at junit.framework.TestSuite.run(TestSuite.java:203)
?at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
?at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
?at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: line 3:45: expecting "set", found 't'
?at antlr.Parser.match(Parser.java:211)
?at org.hibernate.hql.antlr.HqlBaseParser.setClause(HqlBaseParser.java:337)
?at org.hibernate.hql.antlr.HqlBaseParser.updateStatement(HqlBaseParser.java:183)
?at org.hibernate.hql.antlr.HqlBaseParser.statement(HqlBaseParser.java:133)
?at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:209)
?... 28 more
09:32:43,947 [main] ERROR SessionFactoryImpl : Error in named query: SchedulerSession.resumeTimersForToken
org.hibernate.hql.ast.QuerySyntaxError: expecting "set", found 't' near line 3, column 45 [
?????
??????? update org.jbpm.scheduler.exe.Timer t
??????? set t.isSuspended = false
??????? where t.token = :token
?????
??? ]
?at org.hibernate.hql.ast.ErrorCounter.throwQueryException(ErrorCounter.java:63)
?at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:215)
?at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:127)
?at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:83)
?at org.hibernate.impl.SessionFactoryImpl.getQuery(SessionFactoryImpl.java:427)
?at org.hibernate.impl.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:388)
?at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:291)
?at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1005)
?at org.jbpm.persistence.db.DbPersistenceServiceFactory.getSessionFactory(DbPersistenceServiceFactory.java:93)
?at org.jbpm.persistence.db.DbPersistenceService.getSessionFactory(DbPersistenceService.java:74)
?at org.jbpm.persistence.db.DbPersistenceService.getSession(DbPersistenceService.java:78)
?at org.jbpm.persistence.db.DbPersistenceService.getGraphSession(DbPersistenceService.java:201)
?at org.jbpm.JbpmContext.getGraphSession(JbpmContext.java:427)
?at org.jbpm.JbpmContext.deployProcessDefinition(JbpmContext.java:166)
?at com.hanxr.jbpm.action.DeployProcessTest.testDeployProcessDefinition(DeployProcessTest.java:35)
?at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
?at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
?at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
?at java.lang.reflect.Method.invoke(Method.java:324)
?at junit.framework.TestCase.runTest(TestCase.java:154)
?at junit.framework.TestCase.runBare(TestCase.java:127)
?at junit.framework.TestResult$1.protect(TestResult.java:106)
?at junit.framework.TestResult.runProtected(TestResult.java:124)
?at junit.framework.TestResult.run(TestResult.java:109)
?at junit.framework.TestCase.run(TestCase.java:118)
?at junit.framework.TestSuite.runTest(TestSuite.java:208)
?at junit.framework.TestSuite.run(TestSuite.java:203)
?at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
?at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
?at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: line 3:45: expecting "set", found 't'
?at antlr.Parser.match(Parser.java:211)
?at org.hibernate.hql.antlr.HqlBaseParser.setClause(HqlBaseParser.java:337)
?at org.hibernate.hql.antlr.HqlBaseParser.updateStatement(HqlBaseParser.java:183)
?at org.hibernate.hql.antlr.HqlBaseParser.statement(HqlBaseParser.java:133)
?at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:209)
?... 28 more
則改動JBossIDE-1.5.1.GA-ALL/eclipse/plugins/org.jbpm.core_3.0.8.1/build/jbpm-3.1-beta3.jar/org/jbpm/db/hibernate.queries.hbm.xml文件

? <query name="SchedulerSession.deleteTimersForProcessInstance">
????? <![CDATA[
??????? delete from org.jbpm.scheduler.exe.Timer t
??????? where t.processInstance = :processInstance
????? ]]>
??? </query>

??? <query name="SchedulerSession.suspendTimersForToken">
????? <![CDATA[
??????? update org.jbpm.scheduler.exe.Timer t
??????? set t.isSuspended = true
??????? where t.token = :token
????? ]]>
??? </query>

??? <query name="SchedulerSession.resumeTimersForToken">
????? <![CDATA[
??????? update org.jbpm.scheduler.exe.Timer t
??????? set t.isSuspended = false
??????? where t.token = :token
????? ]]>
??? </query>

改為:
? <query name="SchedulerSession.deleteTimersForProcessInstance">
????? <![CDATA[
??????? delete from org.jbpm.scheduler.exe.Timer
??????? where processInstance = :processInstance
????? ]]>
??? </query>

??? <query name="SchedulerSession.suspendTimersForToken">
????? <![CDATA[
??????? update org.jbpm.scheduler.exe.Timer
??????? set isSuspended = true
??????? where token = :token
????? ]]>
??? </query>

??? <query name="SchedulerSession.resumeTimersForToken">
????? <![CDATA[
??????? update org.jbpm.scheduler.exe.Timer
??????? set isSuspended = false
??????? where token = :token
????? ]]>
??? </query>

)

6.6 從數據庫中的查看部署效果

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

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




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

jbpm_processdefinition

一個流程定義文件相應一條記錄,可記錄多個流程定義文件,可記錄一個流程定義文件的對個版本號。

jbpm_action

記錄 ActionHandler 的對象實例(以名稱為標識)

jbpm_delegation

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

jbpm_envent

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

jbpm_node

流程結點

jbpm_transition

流程的轉向定義

jbpm_variableaccess

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

?

jBPM 的client開發

有了前面的 HelloWorld 后臺流程,我們就要開始client程序了。正如前面提到的,本文不寫 JSP ,而改採用 JUnit 的形式,輸出則用 System.out.println 。舉一反三,知道在方法中輸入及用 println 輸出,在 JSP SWING GUI 界面還不是一樣嘛。

?

這個 JUnit client,我們就借用創建項目時自己主動生成的 SimpleProcessTest.java 了,改寫后例如以下:

package com.sample;

?

import junit.framework.TestCase;

?

import org.jbpm.JbpmConfiguration;

import org.jbpm.JbpmContext;

import org.jbpm.context.exe.ContextInstance;

import org.jbpm.graph.def.ProcessDefinition;

import org.jbpm.graph.exe.ProcessInstance;

?

public class SimpleProcessTest extends TestCase {

?

??? private JbpmConfiguration config = JbpmConfiguration.getInstance();

??? private JbpmContext ctx = config.createJbpmContext();

??? // helloworld 相應于 jbpm_processdefinition 表的 name 字段值,也即 processdefinition.xml name

??? // 這個值得取比較耗時,實際項目里最好和“數據庫的 JDBC 連接”一樣,讓它共享,不要頻繁打開關閉。

??? private ProcessDefinition processDefinition = ctx.getGraphSession().findLatestProcessDefinition("helloworld");

?

??? public void testNewRequest() {

?????? long id = newRequest();

?????? System.out.println("id=" + id);

?????? checkNewRequest(id);

?????? confirmRequest(id);

?????? checkconfirmRequest(id);

?????? ctx.close();// 關閉 jbpm 容器

??? }

?

??? /**

??? ? * 創建一個請假單

??? ? *

??? ? * @return

??? ? */

??? private long newRequest() {

?????? // 創建一個新流程

?????? ProcessInstance pi = processDefinition.createProcessInstance();

?????? // 取得流程的數據環境

?????? ContextInstance ci = pi.getContextInstance();

?????? // 創建一張請假單

?????? ci.setVariable("name", " 陳剛 www.chengang.com.cn" );

?????? ci.setVariable("day", 2);

?????? assertEquals(null, ci.getVariable("note"));

?????? // 請假申請結束,轉到下一個流程結點

?????? pi.signal();

?????? return pi.getId();

??? }

?

??? /**

??? ? * 檢查請假單的數據

??? ? *

??? ? * @param id

??? ? */

??? private void checkNewRequest(long id) {

?????? // 從數據庫提取原流程

?????? ProcessInstance pi = ctx.loadProcessInstance(id);

?????? // 取得流程的數據環境

?????? ContextInstance ci = pi.getContextInstance();

?????? // 創建一張請假單

?????? assertEquals(" 陳剛 www.chengang.com.cn" , ci.getVariable("name"));

?????? assertEquals(Integer.valueOf(2), ci.getVariable("day"));

?????? assertEquals(" 我要請假 " , ci.getVariable("note"));

?

?????? // 當前是結點為 confirm

?????? assertEquals(pi.getRootToken().getNode().getName(), "confirm");

?????? // 流程還沒結束

?????? assertFalse(pi.hasEnded());

??? }

?

??? /**

??? ? * 審批陳剛的請假申請

??? ? *

??? ? * @param id

??? ? */

??? private void confirmRequest(long id) {

?????? ProcessInstance pi = ctx.loadProcessInstance(id);

?????? ContextInstance ci = pi.getContextInstance();

?????? // 不通過

?????? ci.setVariable("note", " 不準請假,繼續加班 " );

?????? // 審批結束,到下一個流程結點

?????? pi.signal();

??? }

?

??? private void checkConfirmRequest(long id) {

?????? ProcessInstance pi = ctx.loadProcessInstance(id);

?????? ContextInstance ci = pi.getContextInstance();

?????? // ConfirmAction 類在 signal 后運行,所以覆蓋了經理的審批意見

?????? assertEquals(" 準假 " , ci.getVariable("note"));

?

?????? // 當前是結點為 end

?????? assertEquals(pi.getRootToken().getNode().getName(), "end");

?????? // 流程結束了

?????? assertTrue(pi.hasEnded());

??? }

?

}

?


?

轉載于:https://www.cnblogs.com/mfrbuaa/p/3915504.html

總結

以上是生活随笔為你收集整理的jbpm入门样例的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 黄色污小说 | 久久精品国产久精国产 | 日韩精品欧美精品 | 野花视频在线观看免费 | 久操热| 日批免费观看视频 | 又污又黄的视频 | 欧美精品一区二区在线观看 | 亚洲不卡视频在线观看 | 日本a在线播放 | h无码动漫在线观看 | 亚洲综合激情五月久久 | 中日韩精品视频在线观看 | 在线看一区二区 | 不卡黄色| 久久免费少妇高潮99精品 | 久久在线看 | www.com欧美 | 欧美日韩中文 | 日韩一区高清 | 奇米影视777四色 | 成人禁污污啪啪入口 | 美女av网| 日韩欧美字幕 | 韩国午夜影院 | www.69pao.com| 日韩免费在线 | 超碰人人草人人干 | 国产一级做a爱片久久毛片a | 91精品人妻一区二区三区蜜桃欧美 | 国产免费一区二区三区在线播放 | 中日韩在线| 久久超碰精品 | 午夜三区 | 黄a在线| 精品一区二区三区视频在线观看 | 天堂影视av | 成人xx视频| 好屌妞视频这里只有精品 | 高清黄色一级片 | 精品一二三区久久aaa片 | 日本国产亚洲 | 国产区高清 | 亚洲欧美日韩成人 | 日韩 国产 欧美 | 白俄罗斯毛片 | 欧美日韩看片 | 黄网视频在线观看 | 综合热久久 | 日韩美女中文字幕 | 黄色三级网 | 欧美日韩精品一区二区三区视频播放 | 成人免费视频网址 | 狠狠爱成人 | 亚洲性天堂 | 日本伦理在线 | 亚洲黄色免费观看 | 欧美激情一区二区三区 | 亚洲AV不卡无码一区二区三区 | 国产乱淫精品一区二区三区毛片 | 成人国产免费 | 二级毛片在线观看 | www.三级.com| 捆绑无遮挡打光屁股 | 中国丰满老妇xxxxx交性 | 国产黄色一区二区 | 国产毛片毛片毛片毛片毛片毛片 | 久草免费在线 | 成了校长的性脔h文 | 国产又黄又嫩又滑又白 | 麻豆传媒网站在线观看 | 国产精品亚洲AV色欲三区不卡 | 久久这里只有精品首页 | 中文在线亚洲 | 免费黄网站在线看 | 黄色com| 午夜剧场福利 | 欧美少妇一区二区三区 | 国产调教视频 | 91精品国产高清一区二区三密臀 | 欧美黄色免费在线观看 | 超碰在线公开 | 日本在线一级片 | 黄色一级视频免费 | 亚洲色偷精品一区二区三区 | 久久av一区二区三区 | 亚洲天堂av电影 | 99热2| 91久久精品国产91久久性色tv | 久久久久久艹 | 亚洲av综合色区无码一区爱av | 亚洲色图第一区 | 亚洲午夜久久 | 短篇山村男同肉耽h | 黄色网页网站 | 国产美女极度色诱视频www | 欧美激情五月 | 中文字幕22页 | 97免费人妻无码视频 |