<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 495,comments - 227,trackbacks - 0

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

    1.       jbpm4.4 測試環(huán)境搭建

    2.       Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1. 整合環(huán)境搭建

    3.       jbpm4.4 基礎(chǔ)知識

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

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

    6.       總結(jié)及參考文章

    jbpm4.4 測試環(huán)境搭建

    剛接觸 jbpm 第一件事就是快速搭建環(huán)境,測試 jbpm 所給的例子。 Jbpm 是一個工作流引擎框架,如果沒有 javaEE 開發(fā)環(huán)境, jbpm 也提供了安裝腳本( ant ),一鍵提供安裝運行環(huán)境。同時也可以將 jbpm 整合到 eclipse 或者 myeclipse 中。

     

    快速搭建環(huán)境的步驟是:

    1.       安裝 jbpm-myeclipse 插件,這個插件隨 jbpm4.4 一起發(fā)布,位于 jbpm-4.4/install/src/gpd 目錄下,這個安裝好后,就可以在myeclipse 中編輯流程圖了(可視化流程設(shè)計)

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

    安裝這個插件應(yīng)該注意斷網(wǎng),避免其到網(wǎng)上更新。同時注意:需要選擇

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

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

     

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

    2.       搭建 jbpm 運行環(huán)境。

    3 .然后配置jpdl 支持

    4. 確定是否配置jbpm 正確

    在myeclipse->new->other->

    關(guān)于myeclipse 中配置jbpm 請參考jbpm 的幫助文檔,文檔給的是在eclipse 下配置jbpm 。

     

    5. 測試運行環(huán)境:

    新建一個 java 項目,將 jbpm-4.4/examples 下的 src 目錄, copy 到項目中。然后引入相關(guān) jar 包, jbpm.jar lib 下的所有包,先不考慮 jar 包選擇問題。 Src 中包括了 jbpm 中的基本元素的使用。如 start state end sql script fork join 等。然后跟著 jbpm 的幫助文檔,一點一點的學(xué)習(xí)。

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

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

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

    用于創(chuàng)建 hibernate sessionfactory 并交給 jbpm IOC 容器管理。

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

     

     

     

    Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1. 整合環(huán)境搭建

    我的開發(fā)環(huán)境:

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

    在搭建環(huán)境之前,先認(rèn)識一下 jbpm    JBPM 在管理流程時,是需要數(shù)據(jù)庫表的支持的,因為底層的邏輯有那么復(fù)雜。默認(rèn)下載下來的配置,使用的是( hsqldb )內(nèi)存數(shù)據(jù)庫。實際應(yīng)用中,我們就需要連接到我們的數(shù)據(jù)庫里來。所以要事先建好相關(guān)的表,相應(yīng)的 sql 文件在 /jbpm-4.4/install/src/db 下,當(dāng)然,你也可以使用 hibernate hibernate.hbm2ddl.auto 自動建表,本人建議自己用建表語句,會少很多麻煩(本人在此處可沒少碰麻煩)。 如果不結(jié)合其他的框架進(jìn)行整個開發(fā)( 如:spring 、hibernate),JBPM4 也有自己的一套IOC 容器, 能后將自己的服務(wù)配置到IOC 容器中, 能夠很容易的運行容器所配置的服務(wù), 這樣它也能夠在代碼中減少一陀一陀的工廠類等代碼的調(diào)用, 降低了偶核性, 但是如果結(jié)合spring 框架來進(jìn)行整個開發(fā)的話, 那么就有兩個容器, 兩個SessionFactory, 但是系統(tǒng)中只考慮一個容器來。對服務(wù)進(jìn)行管理, 那么我們就要將jbpm4 的服務(wù)移植到spring 的IOC 容器中, 讓spring 來進(jìn)行統(tǒng)一管理, 這樣通過spring 的容器來管理服務(wù)、事務(wù)。

     

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

        private RepositoryService repositoryService ;

        private ExecutionService executionService ;

        private HistoryService historyService ;

        private TaskService taskService ;

        private IdentityService identityService ;

    上面這些服務(wù)就是通過 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 包選擇:(沒有選擇,所以會有很多無用的)

     

    基礎(chǔ)知識:

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

    這些 sql 腳本所創(chuàng)建的表是 jbpm 能正常工作所必須的。我們可以直接運行這些 sql 在數(shù)據(jù)庫建立起相關(guān)的表(共 18 張,如下):

    每張表對應(yīng)的含義:

    1 JBPM4_DEPLOYMENT

    2 JBPM4_DEPLOYPROP

    3 JBPM4_LOB :存儲 上傳一個包含 png jpdl.xml zip 的相關(guān)數(shù)據(jù)
    jbpm4_deployment
    表多了一條記錄
    jbpm4_deployprop
    表多了四條記錄 , 對應(yīng) 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 的執(zhí)行信息, Execution 機(jī)制代替了 JBPM3 Token 機(jī)制(詳細(xì)參閱 JBPM4 PVM 機(jī)制)。

    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 存的是進(jìn)行時的臨時變量。

    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 這三張表很常見了,基本的權(quán)限控制,關(guān)于用戶認(rèn)證方面建議還是自己開發(fā)一套, JBPM4 的功能太簡單了,使用中有很多需要難以滿足。

    17 JBPM4_JOB 存放的是 Timer 的定義。

    18 JBPM4_PROPERTY

    你可以直接運行腳本,整合中有hibernate ,所以就用hibernate 自動創(chuàng)建。事實上jbpm 也是采用的hibernate 作為其持久化工具。

     

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

    1, 流程定義(ProcessDefinition): 對整個流程步驟的描述., 相當(dāng)于我們在編程過程過程用到的類, 是個抽象的概念.

    2. 流程實例(ProcessInstance) 代表著流程定義的特殊執(zhí)行例子, 相當(dāng)于我們常見的對象. 他是類的特殊化.

    最典型的屬性就是跟蹤當(dāng)前節(jié)點的指針.

    3. 流程引擎(ProcessEngine), 服務(wù)接口可以從 ProcessEngine 中獲得, 它是從 Configuration 構(gòu)建的, 如下:

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

    從流程引擎中可以獲得如下的服務(wù):

    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 包含了用來管理發(fā)布資源的所有方法,

    如下可以發(fā)布流程定義.

    String deploymentid = repositoryService.createDeployment()

        .addResourceFromClasspath("*.jpdl.xml")

        .deploy();

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

    5. 刪除流程定義:

    repositoryService.deleteDeployment(deploymentId); 可以用級聯(lián)的方式, 也可以remove

     

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

     

     

     

     

     

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

     

    如果啟動指定版本的流程定義 , 用下面的方法 :

     

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

     

    7. 使用變量

    當(dāng)一個新的流程實例啟動時就會提供一組對象參數(shù)。 將這些參數(shù)放在variables 變量里, 然后可以在流程實例創(chuàng)建和啟動時使用。

    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. 執(zhí)行等待的流向:

    當(dāng)使用一個 state 活動時,執(zhí)行(或流程實例) 會在到達(dá)state 的時候進(jìn)行等待,

    直到一個signal (也叫外部觸發(fā)器)出現(xiàn)。 signalExecution 方法可以被用作這種情況。

    執(zhí)行通過一個執(zhí)行id (字符串)來引用。

    executionService.signalExecutionById(executionId);

    9.TaskService 任務(wù)服務(wù):

    TaskService 的主要目的是提供對任務(wù)列表的訪問途徑。 例子代碼會展示出如何為id 為 johndoe

    用戶獲得任務(wù)列表:

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

     

     

    JBPM4 –ProcessEngine

    在jBPM 內(nèi)部通過各種服務(wù)相互作用。 服務(wù)接口可以從ProcessEngine 中獲得, 它是從Configuration 構(gòu)建的。

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

     

    JBPM4 – RepositoryService

    RepositoryService 包含了用來管理發(fā)布資源的所有方法。

    部署流程

    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" ));

    // 發(fā)起流程,僅僅就是預(yù)定義任務(wù),即在系統(tǒng)中創(chuàng)建一個流程,這是全局的,與具體的登陸 用戶無關(guān)。然后,在啟動流程時,才與登陸用戶關(guān)聯(lián)起來

    String did = repositoryService .createDeployment()

                  .addResourcesFromZipInputStream(zis).deploy();
    通過上面的 addResourceFromClass 方法,流程定義 XML 的內(nèi)容可以從文件,網(wǎng)址,字符串,輸入流或 zip 輸入流中獲得。

    每次部署都包含了一系列資源。每個資源的內(nèi)容都是一個字節(jié)數(shù)組。 jPDL 流程文件都是以 .jpdl.xml 作為擴(kuò)展名的。其他資源是任務(wù)表單和 java 類。

    部署時要用到一系列資源,默認(rèn)會獲得多種流程定義和其他的歸檔類型。 jPDL 發(fā)布器會自動識別后綴名是 .jpdl.xml 的流程文件。

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

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

    同一個名稱只能關(guān)聯(lián)到一個 key ,反之亦然。

    如果沒有為流程文件提供版本號, jBPM 會自動為它分配一個版本號。請?zhí)貏e注意那些已經(jīng)部署了的名字相同的流程文件的版本號。它會比已經(jīng)部署的同一個 key 的流程定義里最大的版本號還大。沒有部署相同 key 的流程定義的版本號會分配為 1

    刪除流程定義

    刪除一個流程定義會把它從數(shù)據(jù)庫中刪除。

    repositoryService.deleteDeployment(deploymentId); 

    如果在發(fā)布中的流程定義還存在活動的流程實例,這個方法就會拋出異常。

    如果希望級聯(lián)刪除一個發(fā)布中流程定義的所有流程實例,可以使用 deleteDeploymentCascade

    JBPM4 – TaskService

    TaskService 的主要目的是提供對任務(wù)列表的訪問途徑。 例子代碼會展示出如何為 id johndoe 的用戶獲得任務(wù)列表

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

    一般來說,任務(wù)會對應(yīng)一個表單,然后顯示在一些用戶接口中。 表單需要可以讀寫與任務(wù)相關(guān)的數(shù)據(jù)。

    // 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
    也用來完成任務(wù)。
    taskService.completeTask(taskId); 
    taskService.completeTask(taskId, variables); 
    taskService.completeTask(taskId, outcome); 
    taskService.completeTask(taskId, outcome, variables); 

    這些 API 允許提供一個變量 map ,它在任務(wù)完成之前作為流程變量添加到流程里。 它也可能提供一個 外出 outcome” ,這會用來決定哪個外出轉(zhuǎn)移會被選中。 邏輯如下所示:

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

    如果一個任務(wù)擁有一個有名字的外向轉(zhuǎn)移:
    taskService.getOutcomes() 返回包含這個轉(zhuǎn)移名稱的集合。
    taskService.completeTask(taskId)
    會使用這個單獨的外向轉(zhuǎn)移。
    taskService.completeTask(taskId, null)
    會拋出一個異常(因為這里沒有無名稱的轉(zhuǎn)移)。
    taskService.completeTask(taskId, "anyvalue")
    會拋出一個異常。
    taskService.completeTask(taskId, "myName")
    會根據(jù)給定的名稱使用轉(zhuǎn)移。

    如果一個任務(wù)擁有多個外向轉(zhuǎn)移,其中一個轉(zhuǎn)移沒有名稱,其他轉(zhuǎn)移都有名稱:
    taskService.getOutcomes() 返回包含一個 null 值和其他轉(zhuǎn)移名稱的集合。
    taskService.completeTask(taskId)
    會使用沒有名字的轉(zhuǎn)移。
    taskService.completeTask(taskId, null)
    會使用沒有名字的轉(zhuǎn)移。
    taskService.completeTask(taskId, "anyvalue")
    會拋出異常。
    taskService.completeTask(taskId, "myName")
    會使用名字為 'myName' 的轉(zhuǎn)移。

    如果一個任務(wù)擁有多個外向轉(zhuǎn)移,每個轉(zhuǎn)移都擁有唯一的名字:
    taskService.getOutcomes() 返回包含所有轉(zhuǎn)移名稱的集合。
    taskService.completeTask(taskId)
    會拋出異常,因為這里沒有無名稱的轉(zhuǎn)移。
    taskService.completeTask(taskId, null)
    會拋出異常,因為這里沒有無名稱的轉(zhuǎn)移。
    taskService.completeTask(taskId, "anyvalue")
    會拋出異常。
    taskService.completeTask(taskId, "myName")
    會使用名字為 'myName' 的轉(zhuǎn)移。

    任務(wù)可以擁有一批候選人。候選人可以是用戶也可以是用戶組。用戶可以接收自己是候選人的任務(wù)。接收任務(wù)的意思是用戶會被設(shè)置為被分配給任務(wù)的人。在那之后,其他用戶就不能接收這個任務(wù)了。

    人們不應(yīng)該在任務(wù)做工作,除非他們被分配到這個任務(wù)上。用戶界面應(yīng)該顯示表單,如果他們被分配到這個任務(wù)上,就允許用戶完成任務(wù)。對于有了候選人,但是還沒有分配的任務(wù),唯一應(yīng)該暴露的操作就是 接收任務(wù)

     

    JBPM4 – ExecutionService

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

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

    上面 service 的方法會去查找 key ICL 的最新版本的流程定義, 然后在最新的流程定義里啟動流程實例。

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

    原來已經(jīng)啟動的流程,還是按照啟動時刻的版本執(zhí)行。


    指定流程版本 -- ById
    換句話說,你如果想根據(jù)特定的版本啟動流程實例, 便可以使用流程定義的 id 啟動流程實例。如下所示:

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


    使用 key

    我們可以為新啟動的流程實例分配一個 key( 注意: 這個 key 不是 process key ,而是啟動的 instance key ) ,這個 key 是用戶執(zhí)行的時候定義的,有時它會作為 業(yè)務(wù) key” 引用。一個業(yè)務(wù) key 必須在流程定義的所有版本范圍內(nèi)是唯一的。通常很容易在業(yè)務(wù)流程領(lǐng)域找到這種 key 。比如,一個訂單 id 或者一個保險單號。
    ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL", "CL92837");

    // 2 個參數(shù):
    // 
    第一個參數(shù) processkey ,通過這個 key 啟動 process 的一個實例
    // 
    第二個參數(shù)為這里所說的實例 key(instance key)

    key 可以用來創(chuàng)建流程實例的 id ,格式為 {process-key}.{execution-id} 。所以上面的代碼會創(chuàng)建一個 id ICL.CL92837 的流向( execution )。

    如果沒有提供用戶定義的 key ,數(shù)據(jù)庫就會把主鍵作為 key 這樣可以使用如下方式獲得 id
    ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL");
    String pid = processInstance.getId();

    最好使用一個用戶定義的 key 特別在你的應(yīng)用代碼中,找到這樣的 key 并不困難。提供給一個用戶定義的 key ,你可以組合流向的 id ,而不是執(zhí)行一個基于流程變量的搜索 - 那種方式太消耗資源了。

    使用變量

    當(dāng)一個新的流程實例啟動時就會提供一組對象參數(shù)。 將這些參數(shù)放在 variables 變量里, 然后可以在流程實例創(chuàng)建和啟動時使用。
    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 的特定的版本

    其他的參數(shù),其余還可以在啟動 Instance 的時候,給流程 2 個參數(shù):
    InstanceKey
    :這個 instanceKey 必須在整個流程定義的所有范圍版本中唯一,如果用戶不給于提供,系統(tǒng)也會自己生成;
    一個 Map<String, ?> 表:啟動流程時候給予的變量信息

    執(zhí)行等待的流向

    當(dāng)使用一個 state 活動時,執(zhí)行(或流程實例)會在到達(dá) state 的時候進(jìn)行等待,直到一個 signal (也叫外部觸發(fā)器)出現(xiàn)。 signalExecution 方法可以被用作這種情況。執(zhí)行通過一個執(zhí)行 id (字符串)來引用。

    在一些情況下,到達(dá) state 的執(zhí)行會是流程實例本身。但是這不是一直會出現(xiàn)的情況。在定時器和同步的情況,流程是執(zhí)行樹形的根節(jié)點。所以我們必須確認(rèn)你的 signal 作用在正確的流程路徑上。

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

    在事件監(jiān)聽器 StartExternalWork 中,你可以執(zhí)行那些需要額外完成的部分。在這個事件監(jiān)聽器里,你也可以通過 execution.getId() 獲得確切的流程 id 。那個流程 id ,在額外的工作完成后,你會需要它來提供給 signal 操作的:

    executionService.signalExecutionById (executionId); 

    這里有一個可選的(不是太推薦的)方式,來獲得流程 id ,當(dāng)流程到達(dá) state 活動的時候。只可能通過這種方式獲得執(zhí)行 id ,如果你知道哪個 JBPM API 調(diào)用了之后,流程會進(jìn)入 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

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

    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 獲得這些方法的更多信息。

    有時,我們需要獲得指定流程實例已經(jīng)過的節(jié)點的完整列表。下面的查詢語句可以用來獲得所有已經(jīng)執(zhí)行的節(jié)點列表:

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

    上面的查詢與通過 execution id 查詢有一些不同。有時 execution id 和流程實例 id 是不同的, 當(dāng)一個節(jié)點中使用了定時器, execution id 中就會使用額外的后綴, 這就會導(dǎo)致當(dāng)我們通過 execution id 查詢時, 這個節(jié)點不會出現(xiàn)在結(jié)果列表中。

     

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

    錯誤 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 這三個包復(fù)制到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 '??'

    如果一個任務(wù)擁有一個沒用名稱的外向轉(zhuǎn)移:

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

    如果一個任務(wù)擁有一個有名字的外向轉(zhuǎn)移:

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

    如果一個任務(wù)擁有多個外向轉(zhuǎn)移,其中一個轉(zhuǎn)移沒有名稱,其他轉(zhuǎn)移都有名稱:

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

    如果一個任務(wù)擁有多個外向轉(zhuǎn)移,每個轉(zhuǎn)移都擁有唯一的名字:

    taskService.getOutcomes() 返回包含所有轉(zhuǎn)移名稱的集合。 taskService.completeTask(taskId) 會拋出異常,因為這里沒有無名稱的轉(zhuǎn)移。 taskService.completeTask(taskId, null) 會拋出異常,因為這里沒有無名稱的轉(zhuǎn)移。 taskService.completeTask(taskId, "anyvalue") 會拋出異常。 taskService.completeTask(taskId, "myName") 會使用名字為 'myName' 的轉(zhuǎn)移。

     

    解決方案:

     

    根據(jù)以上分析,可得到解決方案:

     

    1 、只擁有一個外向轉(zhuǎn)移時(對應(yīng)上文所述 1 2 情況):

     

    Map map = new HashMap();

    map.put("",…… // 各種參數(shù)

    taskService.setVariables(taskId,map);

    taskService.completeTask(taskId);

     

    3 、擁有多個外向轉(zhuǎn)移時(上文 3 4 種情況):

    Map map = new HashMap();

    map.put("",…… // 各種參數(shù)

    taskService.setVariables(taskId,map);

     

    // 如想轉(zhuǎn)移至有名稱的外向轉(zhuǎn)移:

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

     

    // 如想轉(zhuǎn)移至無名稱的外向轉(zhuǎn)移:

    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 經(jīng)理審批 " to = " 經(jīng)理審批 " />

       </ task >

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

          < transition g = "-29,-14" name = " 批準(zhǔn) " to = "exclusive1" />

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

       </ task >

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

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

          < transition g = "-31,-16" name = " 結(jié)束 " 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 = " 結(jié)束 " to = "end1" />

       </ task >

    </ process >

    步驟:

    發(fā)布流程:將畫好的流程圖,發(fā)布到j(luò)bpm 框架中(放到j(luò)bpm 數(shù)據(jù)庫中),這個流程是全局的,與用戶無關(guān)。發(fā)布流程后會返回一個流程id ,我們會用流程id 得到 ProcessDefinition 流程定義。 發(fā)布方法如下:

    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" ));

           // 發(fā)起流程,僅僅就是預(yù)定義任務(wù),即在系統(tǒng)中創(chuàng)建一個流程,這是全局的,與具體的登陸 用戶無關(guān)。然后,在啟動流程時,才與登陸用戶關(guān)聯(lián)起來

           String did = repositoryService .createDeployment()

                  .addResourcesFromZipInputStream(zis).deploy();

        }

    啟動流程:流程定義好后,并不能用,我們需要將其實例化,實例化流程將關(guān)聯(lián)用戶,同時將實例寫入數(shù)據(jù)庫中。啟動流程方法如下:

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

           executionService .startProcessInstanceById(id, map);

        }

    流程一旦啟動就通過start 節(jié)點,流到下一個任務(wù)節(jié)點。

    獲取待辦任務(wù)列表:不同的用戶登錄后通過如下方式獲得自己的待辦任務(wù)

        public List<Task> getTasks(String roleName) {

           return taskService .findPersonalTasks(roleName);

        }

    在流程中每一個任務(wù)節(jié)點都關(guān)聯(lián)了一個 action 請求,用于處理待辦任務(wù)的視圖( view

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


    另一例子

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

    下載地址 http://download.csdn.net/source/2671387

    總結(jié)及參考文章:

    參考文章:http://www.tkk7.com/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 網(wǎng), http://code.google.com/p/family168/downloads/list

     

    控制流程活動:

    原子活動:

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    posted on 2011-07-24 16:20 SIMONE 閱讀(35065) 評論(6)  編輯  收藏 所屬分類: JAVA

    FeedBack:
    # re: Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8整合例子(附完整的請假流程例子,jbpm基礎(chǔ),常見問題解決)[未登錄]
    2014-01-15 15:42 | 無名
    我想知道關(guān)鍵是里面的jpdl怎么讓他在在數(shù)據(jù)庫中生成一遍產(chǎn)生一個id  回復(fù)  更多評論
      
    # re: Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8整合例子(附完整的請假流程例子,jbpm基礎(chǔ),常見問題解決)
    2014-04-30 16:43 | anne
    寫得非常詳細(xì),能把lib包中的jar文件發(fā)給我嗎?  回復(fù)  更多評論
      
    # re: Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8整合例子(附完整的請假流程例子,jbpm基礎(chǔ),常見問題解決)
    2014-09-30 11:48 | kongsdfefef
    發(fā)生了男方是的呢fenrf芳都是  回復(fù)  更多評論
      
    # re: Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8整合例子(附完整的請假流程例子,jbpm基礎(chǔ),常見問題解決)[未登錄]
    2014-12-04 15:10 | aaa
    寫得好垃圾啊,這是在自娛自樂嗎?  回復(fù)  更多評論
      
    # re: Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8整合例子(附完整的請假流程例子,jbpm基礎(chǔ),常見問題解決)
    2015-09-15 22:36 | marc.sun
    拜讀!  回復(fù)  更多評論
      
    主站蜘蛛池模板: WWW亚洲色大成网络.COM | 成年男女免费视频网站| 婷婷久久久亚洲欧洲日产国码AV| 久久精品成人免费观看97| 91麻豆国产自产在线观看亚洲| 一区二区视频在线免费观看| 亚洲精品国产电影| h片在线观看免费| 亚洲人成色77777| 亚欧日韩毛片在线看免费网站| 亚洲国产精品久久久久网站 | 免费无码又黄又爽又刺激| 99999久久久久久亚洲| 免费看的一级毛片| 免费无毒a网站在线观看| 国产日产亚洲系列最新| 日韩视频在线观看免费| 亚洲小说图片视频| 国产成人免费网站在线观看| 一级做a免费视频观看网站| 国产成人A人亚洲精品无码| ww4545四虎永久免费地址| 亚洲丁香婷婷综合久久| 亚洲精品综合久久| 精品一区二区三区免费毛片爱 | 亚洲AV无码一区二区三区在线| 国产精品成人免费一区二区| 老司机午夜性生免费福利| 亚洲AV日韩精品久久久久久| 国产一级特黄高清免费大片| 国产成人精品免费大全| 在线观看亚洲精品国产| 亚洲午夜免费视频| 亚洲一级片在线观看| 亚洲AV无码乱码在线观看| 人人玩人人添人人澡免费| 亚洲综合精品第一页| 亚洲自偷自偷偷色无码中文| 青娱分类视频精品免费2| 72pao国产成视频永久免费| 亚洲日本视频在线观看|