jbpm的使用

 

Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8 整合例子(附完整的請假流程例子)。javascript

1.       jbpm4.4 測試環境搭建html

2.       Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1. 整合環境搭建java

3.       jbpm4.4 基礎知識mysql

4.       整合過程當中常見問題的解決程序員

5.       請假流程例子( s2sh+jbpm web

6.       總結及參考文章spring

jbpm4.4 測試環境搭建sql

剛接觸 jbpm 第一件事就是快速搭建環境,測試 jbpm 所給的例子。 Jbpm 是一個工做流引擎框架,若是沒有 javaEE 開發環境, jbpm 也提供了安裝腳本( ant ),一鍵提供安裝運行環境。同時也能夠將 jbpm 整合到 eclipse 或者 myeclipse 中。數據庫

 

快速搭建環境的步驟是:apache

1.       安裝 jbpm-myeclipse 插件,這個插件隨 jbpm4.4 一塊兒發佈,位於 jbpm-4.4/install/src/gpd 目錄下,這個安裝好後,就能夠在myeclipse 中編輯流程圖了(可視化流程設計)

   myeclipse->help->myeclipse configuration centre->software->add site->add from archive file 選擇jbpm-4.4/install/src/gpd 下的jbpm-gpd-site.zip

安裝這個插件應該注意斷網,避免其到網上更新。同時注意:須要選擇

雙擊每一項,確保每一項被加入到了

(說明:事實上不用選完,帶source 的部件不用選擇,爲了省事就所有選擇了)

 

提示:若是安裝時不斷網,jbpm 插件會自動到網上更新。同時會彈出一個錯誤窗口,安裝速度異常緩慢。安裝完成後,myeclipse 的references 菜單會變得面目全非。

2.       搭建 jbpm 運行環境。

3 .而後配置jpdl 支持

4. 肯定是否配置jbpm 正確

在myeclipse->new->other->

關於myeclipse 中配置jbpm 請參考jbpm 的幫助文檔,文檔給的是在eclipse 下配置jbpm 。

 

5. 測試運行環境:

新建一個 java 項目,將 jbpm-4.4/examples 下的 src 目錄, copy 到項目中。而後引入相關 jar 包, jbpm.jar lib 下的全部包,先不考慮 jar 包選擇問題。 Src 中包括了 jbpm 中的基本元素的使用。如 start state end sql script fork join 等。而後跟着 jbpm 的幫助文檔,一點一點的學習。

說說以上文件的做用:第一個是 jbpm 的配置文件,在這個文件又引入其餘的文件,在被引入的文件有一個文件包含了

           <hibernate-configuration> <cfg resource="jbpm.hibernate.cfg.xml" />

           </hibernate-configuration> <hibernate-session-factory />

用於建立 hibernate sessionfactory 並交給 jbpm IOC 容器管理。

第二個文件是 hibernate 配置文件,裏面包含了 jbpm 框架須要的表的 hbm.xml 配置文件。

 

 

 

Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1. 整合環境搭建

個人開發環境:

tomcat6.0.28+mysql5.1.30+ Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8+myeclipse8.6+java jdk 6.0.23

在搭建環境以前,先認識一下 jbpm    JBPM 在管理流程時,是須要數據庫表的支持的,由於底層的邏輯有那麼複雜。默認下載下來的配置,使用的是( hsqldb )內存數據庫。實際應用中,咱們就須要鏈接到咱們的數據庫裏來。因此要事先建好相關的表,相應的 sql 文件在 /jbpm-4.4/install/src/db 下,固然,你也可使用 hibernate hibernate.hbm2ddl.auto 自動建表,本人建議本身用建表語句,會少不少麻煩(本人在此處可沒少碰麻煩)。 若是不結合其餘的框架進行整個開發( 如:spring 、hibernate),JBPM4 也有本身的一套IOC 容器, 能後將本身的服務配置到IOC 容器中, 可以很容易的運行容器所配置的服務, 這樣它也可以在代碼中減小一陀一陀的工廠類等代碼的調用, 下降了偶核性, 可是若是結合spring 框架來進行整個開發的話, 那麼就有兩個容器, 兩個SessionFactory, 可是系統中只考慮一個容器來。對服務進行管理, 那麼咱們就要將jbpm4 的服務移植到spring 的IOC 容器中, 讓spring 來進行統一管理, 這樣經過spring 的容器來管理服務、事務。

 

整合目標:將jbpm4 的IOC 移植到Spring 中,讓spring 管理一個sessionfactory ,同時須要明確一點的是:jbpm4 對外提供服務是 ProcessEngine 。如:

    private RepositoryService repositoryService ;

    private ExecutionService executionService ;

    private HistoryService historyService ;

    private TaskService taskService ;

    private IdentityService identityService ;

上面這些服務就是經過 ProcessEngine 得到的。

Spring 配置文件:

<!--jbpm4.4 工做流   -->

    < bean id = "springHelper" class = "org.jbpm.pvm.internal.processengine.SpringHelper" >

       < property name = "jbpmCfg" value = "jbpm.cfg.xml" />

    </ bean >

 

    < bean id = "sessionFactory"

       class = "org.springframework.orm.hibernate3.LocalSessionFactoryBean" >

       <!--

           <property name="configLocation">

           <value>classpath:jbpm.hibernate.cfg.xml</value> </property>

       -->

       < property name = "dataSource" ref = "dataSource" />

       < property name = "hibernateProperties" >

           < props >

              < prop key = "hibernate.dialect" > org.hibernate.dialect.MySQLInnoDBDialect </ prop >

              < prop key = "hibernate.show_sql" > true </ prop >

              < prop key = "hibernate.connection.pool_size" > 1 </ prop >

              < prop key = "hibernate.format_sql" > true </ prop >

              < prop key = "hibernate.hbm2ddl.auto" > update </ prop >

              <!--

              <prop key="hibernate.current_session_context_class">thread</prop>

              -->

              </ props >

       </ property >

 

       < property name = "mappingLocations" >

           < list >

              < value > classpath:jbpm.execution.hbm.xml </ value >

              < value > classpath:jbpm.history.hbm.xml </ value >

              < value > classpath:jbpm.identity.hbm.xml </ value >

               < value > classpath:jbpm.repository.hbm.xml </ value >

              < value > classpath:jbpm.task.hbm.xml </ value >

           </ list >

       </ property >

    </ bean >

    < bean

       class = "org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >

       < property name = "locations" value = "classpath:jdbc.properties" ></ property >

    </ bean >

 

    < bean id = "dataSource"

       class = "org.springframework.jdbc.datasource.DriverManagerDataSource" >

       < property name = "driverClassName" value = "${jdbc.driverClassName}" />

       < property name = "url" value = "${jdbc.url}" />

       < property name = "username" value = "${jdbc.username}" />

       < property name = "password" value = "${jdbc.password}" />

    </ bean >

Jar 包選擇:(沒有選擇,因此會有不少無用的)

 

基礎知識:

jbpm4.4 目錄 install/src/db/create 下有:

這些 sql 腳本所建立的表是 jbpm 能正常工做所必須的。咱們能夠直接運行這些 sql 在數據庫創建起相關的表(共 18 張,以下):

每張表對應的含義:

1 JBPM4_DEPLOYMENT

2 JBPM4_DEPLOYPROP

3 JBPM4_LOB :存儲 上傳一個包含 png jpdl.xml zip 的相關數據
jbpm4_deployment
表多了一條記錄
jbpm4_deployprop
表多了四條記錄 , 對應 langid,pdid,pdkey,pdversion
jbpm4_lob
表多了二條記錄 , 保存流程圖 png 圖片和 jpdl.xml

4 JBPM4_HIST_PROCINST

5 JBPM4_HIST_ACTINST 分別存放的是 Process Instance Activity Instance 的歷史記

6 JBPM4_EXECUTION 主要是存放 JBPM4 的執行信息, Execution 機制代替了 JBPM3 Token 機制(詳細參閱 JBPM4 PVM 機制)。

7 JBPM4_TASK 存放須要人來完成的 Activities ,須要人來參與完成的 Activity 被稱爲 Task

8 JBPM4_PARTICIPATION 存放 Participation 的信息, Participation 的種類有 Candidate Client Owner Replaced Assignee Viewer 。而具體的 Participation 既能夠是單一用戶,也能夠是用戶組。

9 JBPM4_SWIMLANE Swim Lane 是一種 Runtime Process Role 。經過 Swim Lane ,多個 Task 能夠一次分配到同一 Actor 身上。

10 JBPM4_VARIABLE 存的是進行時的臨時變量。

11 JBPM4_HIST_DETAIL 保存 Variable 的變動記錄。

12 JBPM4_HIST_VAR 保存歷史的變量。

13 JBPM4_HIST_TASKTask 的歷史信息。

14 JBPM4_ID_GROUP

15 JBPM_ID_MEMBERSHIP

16 JBPM4_ID_USER 這三張表很常見了,基本的權限控制,關於用戶認證方面建議仍是本身開發一套, JBPM4 的功能太簡單了,使用中有不少須要難以知足。

17 JBPM4_JOB 存放的是 Timer 的定義。

18 JBPM4_PROPERTY

你能夠直接運行腳本,整合中有hibernate ,因此就用hibernate 自動建立。事實上jbpm 也是採用的hibernate 做爲其持久化工具。

 

jbpm 4.4 中一些概念( 轉自family168)

1, 流程定義(ProcessDefinition): 對整個流程步驟的描述., 至關於咱們在編程過程過程用到的類, 是個抽象的概念.

2. 流程實例(ProcessInstance) 表明着流程定義的特殊執行例子, 至關於咱們常見的對象. 他是類的特殊化.

最典型的屬性就是跟蹤當前節點的指針.

3. 流程引擎(ProcessEngine), 服務接口能夠從 ProcessEngine 中得到, 它是從 Configuration 構建的, 以下:

ProcessEngine processEngine = new Configuration()
      .buildProcessEngine();

從流程引擎中能夠得到以下的服務:

RepositoryService repositoryService = processEngine.getRepositoryService();
ExecutionService executionService = processEngine.getExecutionService();
TaskService taskService = processEngine.getTaskService();
HistoryService historyService = processEngine.getHistoryService();
ManagementService managementService = processEngine.getManagementService();

4. 部署流程(Deploying a process):

RepositoryService 包含了用來管理髮布資源的全部方法,

以下能夠發佈流程定義.

String deploymentid = repositoryService.createDeployment()

    .addResourceFromClasspath("*.jpdl.xml")

    .deploy();

這個id 的格式是(key)-{version}.

5. 刪除流程定義:

repositoryService.deleteDeployment(deploymentId); 能夠用級聯的方式, 也能夠remove

 

6. 啓動一個新的流程實例:

 

 

 

 

 

ProcessInstance processInstance = executionService.startProcessInstanceByKey("key");

 

若是啓動指定版本的流程定義 , 用下面的方法 :

 

ProcessInstance processInstance =executionService.startProcessInstanceById("ID");

 

7. 使用變量

當一個新的流程實例啓動時就會提供一組對象參數。 將這些參數放在variables 變量裏, 而後能夠在流程實例建立和啓動時使用。

Map<String,Object> variables = new HashMap<String,Object>();

variables.put("customer", "John Doe");

variables.put("type", "Accident");

variables.put("amount", new Float(763.74));

 

ProcessInstance processInstance =

    executionService.startProcessInstanceByKey("ICL", variables);

8. 執行等待的流向:

當使用一個 state 活動時,執行(或流程實例) 會在到達state 的時候進行等待,

直到一個signal (也叫外部觸發器)出現。 signalExecution 方法能夠被用做這種狀況。

執行經過一個執行id (字符串)來引用。

executionService.signalExecutionById(executionId);

9.TaskService 任務服務:

TaskService 的主要目的是提供對任務列表的訪問途徑。 例子代碼會展現出如何爲id 爲 johndoe

用戶得到任務列表:

List<Task> taskList = taskService.findPersonalTasks("johndoe");

 

 

JBPM4 –ProcessEngine

在jBPM 內部經過各類服務相互做用。 服務接口能夠從ProcessEngine 中得到, 它是從Configuration 構建的。

得到ProcessEngine : processEngine =Configuration.getProcessEngine ();

 

JBPM4 – RepositoryService

RepositoryService 包含了用來管理髮布資源的全部方法。

部署流程

String deploymentid = repositoryService.createDeployment() 
    .addResourceFromClasspath("org/jbpm/examples/services/Order.jpdl.xml") 
    .deploy(); 

ZipInputStream zis = new ZipInputStream( this .getClass()

              .getResourceAsStream( "/com/jbpm/source/leave.zip" ));

// 發起流程,僅僅就是預約義任務,即在系統中建立一個流程,這是全局的,與具體的登錄 用戶無關。而後,在啓動流程時,才與登錄用戶關聯起來

String did = repositoryService .createDeployment()

              .addResourcesFromZipInputStream(zis).deploy();
經過上面的 addResourceFromClass 方法,流程定義 XML 的內容能夠從文件,網址,字符串,輸入流或 zip 輸入流中得到。

每次部署都包含了一系列資源。每一個資源的內容都是一個字節數組。 jPDL 流程文件都是以 .jpdl.xml 做爲擴展名的。其餘資源是任務表單和 java 類。

部署時要用到一系列資源,默認會得到多種流程定義和其餘的歸檔類型。 jPDL 發佈器會自動識別後綴名是 .jpdl.xml 的流程文件。

在部署過程當中,會把一個 id 分配給流程定義。這個 id 的格式爲 {key}-{version} key version 之間使用連字符鏈接。

若是沒有提供 key (指在流程定義文件中,對流程的定義),會在名字的基礎自動生成。生成的 key 會把全部不是字母和數字的字符替換成下劃線。

同一個名稱只能關聯到一個 key ,反之亦然。

若是沒有爲流程文件提供版本號, jBPM 會自動爲它分配一個版本號。請特別注意那些已經部署了的名字相同的流程文件的版本號。它會比已經部署的同一個 key 的流程定義裏最大的版本號還大。沒有部署相同 key 的流程定義的版本號會分配爲 1

刪除流程定義

刪除一個流程定義會把它從數據庫中刪除。

repositoryService.deleteDeployment(deploymentId); 

若是在發佈中的流程定義還存在活動的流程實例,這個方法就會拋出異常。

若是但願級聯刪除一個發佈中流程定義的全部流程實例,可使用 deleteDeploymentCascade

JBPM4 – TaskService

TaskService 的主要目的是提供對任務列表的訪問途徑。 例子代碼會展現出如何爲 id johndoe 的用戶得到任務列表

List<Task> taskList = taskService.findPersonalTasks("johndoe"); 

通常來講,任務會對應一個表單,而後顯示在一些用戶接口中。 表單須要能夠讀寫與任務相關的數據。

// read task variables 
Set<String> variableNames = taskService.getVariableNames(taskId); 
variables = taskService.getVariables(taskId, variableNames); 

// write task variables 
variables = new HashMap<String, Object>(); 
variables.put("category", "small"); 
variables.put("lires", 923874893); 
taskService.setVariables(taskId, variables); 


taskSerice
也用來完成任務。
taskService.completeTask(taskId); 
taskService.completeTask(taskId, variables); 
taskService.completeTask(taskId, outcome); 
taskService.completeTask(taskId, outcome, variables); 

這些 API 容許提供一個變量 map ,它在任務完成以前做爲流程變量添加到流程裏。 它也可能提供一個 外出 outcome」 ,這會用來決定哪一個外出轉移會被選中。 邏輯以下所示:

若是一個任務擁有一個沒用名稱的外向轉移:
taskService.getOutcomes() 返回包含一個 null 值集合,。
taskService.completeTask(taskId)
會使用這個外向轉移。
taskService.completeTask(taskId, null)
會使用這個外向轉移。
taskService.completeTask(taskId, "anyvalue")
會拋出一個異常。

若是一個任務擁有一個有名字的外向轉移:
taskService.getOutcomes() 返回包含這個轉移名稱的集合。
taskService.completeTask(taskId)
會使用這個單獨的外向轉移。
taskService.completeTask(taskId, null)
會拋出一個異常(由於這裏沒有無名稱的轉移)。
taskService.completeTask(taskId, "anyvalue")
會拋出一個異常。
taskService.completeTask(taskId, "myName")
會根據給定的名稱使用轉移。

若是一個任務擁有多個外向轉移,其中一個轉移沒有名稱,其餘轉移都有名稱:
taskService.getOutcomes() 返回包含一個 null 值和其餘轉移名稱的集合。
taskService.completeTask(taskId)
會使用沒有名字的轉移。
taskService.completeTask(taskId, null)
會使用沒有名字的轉移。
taskService.completeTask(taskId, "anyvalue")
會拋出異常。
taskService.completeTask(taskId, "myName")
會使用名字爲 'myName' 的轉移。

若是一個任務擁有多個外向轉移,每一個轉移都擁有惟一的名字:
taskService.getOutcomes() 返回包含全部轉移名稱的集合。
taskService.completeTask(taskId)
會拋出異常,由於這裏沒有無名稱的轉移。
taskService.completeTask(taskId, null)
會拋出異常,由於這裏沒有無名稱的轉移。
taskService.completeTask(taskId, "anyvalue")
會拋出異常。
taskService.completeTask(taskId, "myName")
會使用名字爲 'myName' 的轉移。

任務能夠擁有一批候選人。候選人能夠是用戶也能夠是用戶組。用戶能夠接收本身是候選人的任務。接收任務的意思是用戶會被設置爲被分配給任務的人。在那以後,其餘用戶就不能接收這個任務了。

人們不該該在任務作工做,除非他們被分配到這個任務上。用戶界面應該顯示錶單,若是他們被分配到這個任務上,就容許用戶完成任務。對於有了候選人,可是尚未分配的任務,惟一應該暴露的操做就是 接收任務

 

JBPM4 – ExecutionService

最新的流程實例 -- ByKey
下面是爲流程定義啓動一個新的流程實例的最簡單也是 最經常使用的方法:

ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL");

上面 service 的方法會去查找 key ICL 的最新版本的流程定義, 而後在最新的流程定義裏啓動流程實例。

key ICL 的流程部署了一個新版本, startProcessInstanceByKey 方法會自動切換到最新部署的版本。

原來已經啓動的流程,仍是按照啓動時刻的版本執行。


指定流程版本 -- ById
換句話說,你若是想根據特定的版本啓動流程實例, 即可以使用流程定義的 id 啓動流程實例。以下所示:

ProcessInstance processInstance = executionService.startProcessInstanceById ("ICL-1");


使用 key

咱們能夠爲新啓動的流程實例分配一個 key( 注意: 這個 key 不是 process key ,而是啓動的 instance key ) ,這個 key 是用戶執行的時候定義的,有時它會做爲 業務 key」 引用。一個業務 key 必須在流程定義的全部版本範圍內是惟一的。一般很容易在業務流程領域找到這種 key 。好比,一個訂單 id 或者一個保險單號。
ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL", "CL92837");

// 2 個參數:
// 
第一個參數 processkey ,經過這個 key 啓動 process 的一個實例
// 
第二個參數爲這裏所說的實例 key(instance key)

key 能夠用來建立流程實例的 id ,格式爲 {process-key}.{execution-id} 。因此上面的代碼會建立一個 id ICL.CL92837 的流向( execution )。

若是沒有提供用戶定義的 key ,數據庫就會把主鍵做爲 key 這樣可使用以下方式得到 id
ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL");
String pid = processInstance.getId();

最好使用一個用戶定義的 key 特別在你的應用代碼中,找到這樣的 key 並不困難。提供給一個用戶定義的 key ,你能夠組合流向的 id ,而不是執行一個基於流程變量的搜索 - 那種方式太消耗資源了。

使用變量

當一個新的流程實例啓動時就會提供一組對象參數。 將這些參數放在 variables 變量裏, 而後能夠在流程實例建立和啓動時使用。
Map<String,Object> variables = new HashMap<String,Object>();
variables.put("customer", "John Doe");
variables.put("type", "Accident");
variables.put("amount", new Float(763.74));

ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL", variables);

啓動 instance

啓動 instance ,必需要知道 processdefinition 的信息: processdefinition 能夠經過 2 種方式獲取:
ByKey
:經過 ProcessKey ,啓動該 Process 的最新版本
ById
  經過 Process ID ,啓動該 Process 的特定的版本

其餘的參數,其他還能夠在啓動 Instance 的時候,給流程 2 個參數:
InstanceKey
:這個 instanceKey 必須在整個流程定義的全部範圍版本中惟一,若是用戶不給於提供,系統也會本身生成;
一個 Map<String, ?> 表:啓動流程時候給予的變量信息

執行等待的流向

當使用一個 state 活動時,執行(或流程實例)會在到達 state 的時候進行等待,直到一個 signal (也叫外部觸發器)出現。 signalExecution 方法能夠被用做這種狀況。執行經過一個執行 id (字符串)來引用。

在一些狀況下,到達 state 的執行會是流程實例自己。可是這不是一直會出現的狀況。在定時器和同步的狀況,流程是執行樹形的根節點。因此咱們必須確認你的 signal 做用在正確的流程路徑上。

得到正確的執行的比較好的方法是給 state 活動分配一個事件監聽器,像這樣:
<state name="wait"> 
  <on event="start"> 
    <event-listener class="org.jbpm.examples.StartExternalWork" /> 
  </on> 
  ... 
</state> 

在事件監聽器 StartExternalWork 中,你能夠執行那些須要額外完成的部分。在這個事件監聽器裏,你也能夠經過 execution.getId() 得到確切的流程 id 。那個流程 id ,在額外的工做完成後,你會須要它來提供給 signal 操做的:

executionService.signalExecutionById (executionId); 

這裏有一個可選的(不是太推薦的)方式,來得到流程 id ,當流程到達 state 活動的時候。只可能經過這種方式得到執行 id ,若是你知道哪一個 JBPM API 調用了以後,流程會進入 state 活動:

// assume that we know that after the next call 
// the process instance will arrive in state external work 
ProcessInstance processInstance = executionService.startProcessInstanceById(processDefinitionId); 

// or ProcessInstance processInstance = 
//  executionService.signalProcessInstanceById(executionId); 
Execution execution = processInstance.findActiveExecutionIn("external work"); 
String executionId = execution.getId(); 

 

JBPM4 – HistoryService

在流程實例執行的過程當中,會不斷觸發事件。從那些事件中,運行和完成流程的歷史信息會被收集到歷史表中。

HistoryService 提供了 對那些信息的訪問功能。

若是想查找某一特定流程定義的全部流程實例, 能夠像這樣操做:

List<HistoryProcessInstance> historyProcessInstances = historyService 
  .createHistoryProcessInstanceQuery() 
  .processDefinitionId("ICL-1") 
  .orderAsc(HistoryProcessInstanceQuery.PROPERTY_STARTTIME) 
  .list(); 

單獨的活動流程也能夠做爲 HistoryActivityInstance 保存到歷史信息中。

List<HistoryActivityInstance> histActInsts = historyService 
    .createHistoryActivityInstanceQuery() 
    .processDefinitionId("ICL-1") 
    .activityName("a") 
    .list(); 

也可使用簡易方法 avgDurationPerActivity choiceDistribution 。能夠經過 javadocs 得到這些方法的更多信息。

有時,咱們須要得到指定流程實例已通過的節點的完整列表。下面的查詢語句能夠用來得到全部已經執行的節點列表:

List<HistoryActivityInstance> histActInsts = historyService 
    .createHistoryActivityInstanceQuery() 
    .processInstanceId("ICL.12345") 
    .list(); 

上面的查詢與經過 execution id 查詢有一些不一樣。有時 execution id 和流程實例 id 是不一樣的, 當一個節點中使用了定時器, execution id 中就會使用額外的後綴, 這就會致使當咱們經過 execution id 查詢時, 這個節點不會出如今結果列表中。

 

整合過程當中常見問題的解決

錯誤 1 java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/index_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature

錯誤的解決辦法。( Tomcat6.0.28

exception

javax.servlet.ServletException: java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/OnDuty/wfmanage_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature org.apache.jasper.servlet.JspServlet.service(JspServlet.java:275) javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

 

root cause

java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/OnDuty/wfmanage_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature org.apache.jsp.OnDuty.wfmanage_jsp._jspInit(wfmanage_jsp.java:27) org.apache.jasper.runtime.HttpJspBase.init(HttpJspBase.java:52) org.apache.jasper.servlet.JspServletWrapper.getServlet(JspServletWrapper.java:159) org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:329) org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342) org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267) javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

 

緣由是項目中WEB-INF/lib 中的三個jar 包 (juel.jar, juel-engine.jar, juel-impl.jar ) 和tomcat6 下lib 中jar 包( el-api.jar ) 衝突

解決方法: 

方法一:換成tomcat5.5 一點問題也沒有了(有新版本了還用老版本?)

 

方法二:將 juel.jar, juel-engine.jar, juel-impl.jar 這三個包複製到tomcat6 下lib 中,並刪除原來的 el-api.jar ,切記要把WEB-INF/lib 中的juel.jar, juel-engine.jar, juel-impl.jar 刪除。否則仍是要衝突。

錯誤 2 org.jbpm.api.JbpmException: No unnamed transitions were found for the task '??'

若是一個任務擁有一個沒用名稱的外向轉移:

taskService.getOutcomes() 返回包含一個 null 值集合,。 taskService.completeTask(taskId) 會使用這個外向轉移。 taskService.completeTask(taskId, null) 會使用這個外向轉移。 taskService.completeTask(taskId, "anyvalue") 會拋出一個異常。

若是一個任務擁有一個有名字的外向轉移:

gtaskService.getOutcomes() 返回包含這個轉移名稱的集合。 taskService.completeTask(taskId) 會使用這個單獨的外向轉移。 taskService.completeTask(taskId, null) 會拋出一個異常(由於這裏沒有無名稱的轉移)。 taskService.completeTask(taskId, "anyvalue") 會拋出一個異常。 taskService.completeTask(taskId, "myName") 會根據給定的名稱使用轉移。

若是一個任務擁有多個外向轉移,其中一個轉移沒有名稱,其餘轉移都有名稱:

taskService.getOutcomes() 返回包含一個 null 值和其餘轉移名稱的集合。 taskService.completeTask(taskId) 會使用沒有名字的轉移。 taskService.completeTask(taskId, null) 會使用沒有名字的轉移。 taskService.completeTask(taskId, "anyvalue") 會拋出異常。 taskService.completeTask(taskId, "myName") 會使用名字爲 'myName' 的轉移。

若是一個任務擁有多個外向轉移,每一個轉移都擁有惟一的名字:

taskService.getOutcomes() 返回包含全部轉移名稱的集合。 taskService.completeTask(taskId) 會拋出異常,由於這裏沒有無名稱的轉移。 taskService.completeTask(taskId, null) 會拋出異常,由於這裏沒有無名稱的轉移。 taskService.completeTask(taskId, "anyvalue") 會拋出異常。 taskService.completeTask(taskId, "myName") 會使用名字爲 'myName' 的轉移。

 

解決方案:

 

根據以上分析,可獲得解決方案:

 

1 、只擁有一個外向轉移時(對應上文所述 1 2 狀況):

 

Map map = new HashMap();

map.put("",…… // 各類參數

taskService.setVariables(taskId,map);

taskService.completeTask(taskId);

 

3 、擁有多個外向轉移時(上文 3 4 種狀況):

Map map = new HashMap();

map.put("",…… // 各類參數

taskService.setVariables(taskId,map);

 

// 如想轉移至有名稱的外向轉移:

taskService.completeTask(taskId," 外向轉移名稱 ");

 

// 如想轉移至無名稱的外向轉移:

taskService.completeTask(taskId);

錯誤3 :*.jpdl.xml 中文亂碼問題。

在myeclipse 的配置文件myeclipse.ini 中加入:

-DFile.encoding=UTF-8

 

請假流程例子( s2sh+jbpm

 

流程圖:

 

<? xml version = "1.0" encoding = "UTF-8" ?>

 

< process name = "leave" xmlns = "http://jbpm.org/4.4/jpdl" >

   < start g = "214,37,48,48" name = "start1" >

      < transition g = "-47,-17" name = "to 申請 " to = " 申請 " />

   </ start >

   < task assignee = "#{owner}" form = "request.html" g = "192,126,92,52" name = " 申請 " >

      < transition g = "-71,-17" name = "to 經理審批 " to = " 經理審批 " />

   </ task >

   < task assignee = "manager" form = "manager.html" g = "194,241,92,52" name = " 經理審批 " >

      < transition g = "-29,-14" name = " 批准 " to = "exclusive1" />

      < transition g = "105,267;103,152:-47,-17" name = " 駁回 " to = " 申請 " />

   </ task >

   < decision expr = "#{day > 3 ? ' 老闆審批 ' : ' 結束 '}" g = "218,342,48,48" name = "exclusive1" >

      < transition g = "415,367:-47,-17" name = " 老闆審批 " to = " 老闆審批 " />

      < transition g = "-31,-16" name = " 結束 " to = "end1" />

   </ decision >

   < end g = "219,499,48,48" name = "end1" />

   < task assignee = "boss" form = "boss.html" g = "370,408,92,52" name = " 老闆審批 " >

      < transition g = "415,524:-91,-18" name = " 結束 " to = "end1" />

   </ task >

</ process >

步驟:

發佈流程:將畫好的流程圖,發佈到jbpm 框架中(放到jbpm 數據庫中),這個流程是全局的,與用戶無關。發佈流程後會返回一個流程id ,咱們會用流程id 獲得 ProcessDefinition 流程定義。 發佈方法以下:

public void deploy() {

       // repositoryService.createDeployment().addResourceFromClasspath(

       // "/com /jbpm /source/leave.jpdl.xml").deploy();

       ZipInputStream zis = new ZipInputStream( this .getClass()

              .getResourceAsStream( "/com/jbpm/source/leave.zip" ));

       // 發起流程,僅僅就是預約義任務,即在系統中建立一個流程,這是全局的,與具體的登錄 用戶無關。而後,在啓動流程時,才與登錄用戶關聯起來

       String did = repositoryService .createDeployment()

              .addResourcesFromZipInputStream(zis).deploy();

    }

啓動流程:流程定義好後,並不能用,咱們須要將其實例化,實例化流程將關聯用戶,同時將實例寫入數據庫中。啓動流程方法以下:

public void start(String id, Map<String , Object> map) {

       executionService .startProcessInstanceById(id, map);

    }

流程一旦啓動就經過start 節點,流到下一個任務節點。

獲取待辦任務列表:不一樣的用戶登陸後經過以下方式得到本身的待辦任務

    public List<Task> getTasks(String roleName) {

       return taskService .findPersonalTasks(roleName);

    }

在流程中每個任務節點都關聯了一個 action 請求,用於處理待辦任務的視圖( view

很少說了,哥就相信源碼: http://download.csdn.net/source/3223403

 

另外一例子

http://zwllxs.iteye.com/blog/726303

 

 

 

總結及參考文章:

參考文章:http://www.blogjava.net/paulwong/archive/2009/09/07/294114.html

http://zjkilly.iteye.com/blog/738426

http://fish119.iteye.com/blog/779379

 

http://alimama.iteye.com/blog/567651

其餘參考資料: family168 網, http://code.google.com/p/family168/downloads/list

 

控制流程活動:

原子活動:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2011-07-24 16:20 SIMONE 閱讀(15082) 評論(1)   編輯   收藏 所屬分類: JAVA
 
相關文章
相關標籤/搜索