1. 程式人生 > >JBPM(二)---JBPM工作流基本操作

JBPM(二)---JBPM工作流基本操作

流程定義的管理:
將定義業務流程,部署到 jbpm框架中 (流程定義 jpdl.xml 描述檔案)
通過gpd 外掛 先根據業務流程,繪製流程圖 (holiday.jpdl.xml 和 holiday.png )

流程定義部署 :
先獲得 ProcessEngine 物件,再獲得對應 Service (六個Service)

ExecutionService    getExecutionService() // 流程例項管理 

 HistoryService     getHistoryService() // 歷史記錄管理

IdentityService     getIdentityService()
// 使用者認證管理 ManagementService getManagementService() // 任務排程 RepositoryService getRepositoryService() // 流程定義管理 TaskService getTaskService() // 任務關聯

操作流程定義,需要使用 RepositoryService
deployment 將需要釋出到JBPM框架中流程檔案,新增到物件中

        // 1、 先獲得流程引擎 (JBPM程式設計核心)
        Configuration configuration = new Configuration();
ProcessEngine processEngine = configuration.buildProcessEngine();//新建一個引擎 // 2、通過引擎獲得需要Service RepositoryService repositoryService = processEngine.getRepositoryService(); // 3、釋出流程定義 NewDeployment deployment = repositoryService.createDeployment(); deployment.addResourceFromClasspath
("holiday.jpdl.xml"); deployment.addResourceFromClasspath("holiday.png"); deployment.deploy();

流程定義釋出,影響的資料表分析
JBPM的資料記錄採用流水號 id ,在 jbpm4_property 表中用來儲存下次操作的開始id, Value 初始化值是1, 每進行過一輪資料庫操作,記錄+10000

jbpm4_deployment 流程定義釋出表,每釋出一個流程,在該表插入1條記錄 ,DBID 就是流水號

jbpm4_lob 存放大資料(二進位制) 存放釋出流程定義檔案

jbpm4_deployprop 流程定義屬性表 ,每釋出一個流程,將流程屬性資訊儲存到該表

langid 是jpdl語言規範版本號、pdid 流程定義唯一標識、pdkey 流程定義關鍵字、pdversion 流程定義版本號
在繪製流程定義時,name值就是預設的key值 ,version每次釋出相同key ,version自動+1

釋出流程定義,在實際開發中,都是通過 zip壓縮包釋出

        //釋出流程定義
        NewDeployment deployment = repositoryService.createDeployment();
        deployment.addResourcesFromZipInputStream(new ZipInputStream(new FileInputStream("holiday.zip")));
        deployment.deploy();

流程定義查詢 :
通過 ProcessDefinitionQuery查詢流程定義資訊

ProcessDefinitionQuery processDefinitionQuery 
= repositoryService.createProcessDefinitionQuery();

對 ProcessDefinitionQuery 新增查詢條件

processDefinitionId(processDefinitionId)
processDefinitionKey(key)
processDefinitionName(name)
processDefinitionNameLike(name)
page(firstResult, maxResults)
orderAsc(property)
orderDesc(property)

通過 指定屬性查詢,可以進行排序和分頁 查詢

List<ProcessDefinition> list = processDefinitionQuery
.orderDesc(ProcessDefinitionQuery.PROPERTY_VERSION)
.page(0, 2).list();

根據釋出編號 和 資源名稱可以獲得 該流程相關資源

        // 查詢流程圖
        // deploymentId 來自 jbpm4_deployment表 DBID
        // ResourceName 來自 jbpm4_lob 表 NAME
        InputStream in = repositoryService.getResourceAsStream("1", "holiday/holiday.png");
        OutputStream out = new FileOutputStream("c:/test.png");
        int b ;
        while((b=in.read())!=-1){
            out.write(b);
        }
        in.close();
        out.close();

流程定義的刪除 :

把流程 徹底從JBPM 框架中刪除了
RepositoryService 提供兩個方法 用來刪除 流程定義
可以通過流程定義釋出id刪除流程定義
方式一:如果有關聯流程例項資訊則報錯
repositoryService.deleteDeployment(deploymentId);
方式二:刪除流程定義,並刪除關聯流程例項
repositoryService.deleteDeploymentCascade(deploymentId);
Cascade 級聯的含義, 刪除流程定義時,管理流程例項資訊 也會被一起刪除,執行刪除後,關聯 lob表和 prop表資料也都刪除了, 關聯流程例項資訊也會被刪除
可以通過流程定義的key來刪除
如果沒有指定key屬性,那麼流程的名稱就是key

// 先根據key 進行查詢,在執行刪除
    ProcessDefinitionQuery processDefinitionQuery = 
                repositoryService.createProcessDefinitionQuery();
    List<ProcessDefinition> list = 
processDefinitionQuery.processDefinitionKey("holiday").list();
    for (ProcessDefinition processDefinition : list) {          
        repositoryService.deleteDeploymentCascade(processDefinition.getDeploymentId());
    }

流程定義沒有修改功能,可以釋出一個新流程,版本自動+1

程式碼示例:

package com.my.jbpm;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.ZipInputStream;

import org.jbpm.api.Configuration;
import org.jbpm.api.NewDeployment;
import org.jbpm.api.ProcessDefinition;
import org.jbpm.api.ProcessDefinitionQuery;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.RepositoryService;
import org.junit.Test;

public class JBPMTest2 {

    @Test
    //部署 流程定義檔案 
    public void deploy1(){
        // 1、 先獲得流程引擎 (JBPM程式設計核心)
        Configuration configuration = new Configuration();
        ProcessEngine processEngine = configuration.buildProcessEngine();//新建一個引擎

        // 2、通過引擎獲得需要Service 
        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 3、釋出流程定義
        NewDeployment deployment = repositoryService.createDeployment();
        deployment.addResourceFromClasspath("holiday.jpdl.xml");
        deployment.addResourceFromClasspath("holiday.png");
        deployment.deploy();
    }

    @Test
    // 部署流程定義檔案 (zip格式,內含資料夾)
    public void deploy2() throws FileNotFoundException{
        // 1、 先獲得流程引擎 (JBPM程式設計核心)
        Configuration configuration = new Configuration();
        ProcessEngine processEngine = configuration.buildProcessEngine();//新建一個引擎

        // 2、通過引擎獲得需要Service 
        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 3、釋出流程定義
        NewDeployment deployment = repositoryService.createDeployment();
        deployment.addResourcesFromZipInputStream(new ZipInputStream(new FileInputStream("holiday.zip")));
        deployment.deploy();
    }

    @Test
    // 流程定義查詢 
    public void query(){
        // 1、流程引擎
        Configuration configuration = new Configuration();
        ProcessEngine processEngine = configuration.buildProcessEngine();//新建一個引擎

        // 2、獲得對應的Service
        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 3、 查詢流程定義
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> list = processDefinitionQuery.orderDesc(ProcessDefinitionQuery.PROPERTY_VERSION).page(0, 2).list(); // 查詢所有流程定義
        for (ProcessDefinition processDefinition : list) {
            System.out.println(processDefinition.getId()); // 列印id
        }
    }

    @Test
    // 查詢流程定義圖 
    public void queryPng() throws IOException{
        // 1、流程引擎
        Configuration configuration = new Configuration();
        ProcessEngine processEngine = configuration.buildProcessEngine();//新建一個引擎

        // 2、獲得對應的Service
        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 3. 查詢流程圖
        // deploymentId 來自 jbpm4_deployment表 DBID
        // ResourceName 來自 jbpm4_lob 表 NAME
        InputStream in = repositoryService.getResourceAsStream("1", "holiday/holiday.png");
        OutputStream out = new FileOutputStream("c:/test.png");
        int b ;
        while((b=in.read())!=-1){
            out.write(b);
        }
        in.close();
        out.close();
    }

    @Test
    // 刪除流程定義
    public void delete(){
        // 1、流程引擎
        Configuration configuration = new Configuration();
        ProcessEngine processEngine = configuration.buildProcessEngine();//新建一個引擎

        // 2、獲得對應的Service
        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 3、執行刪除 
        // deploymentId 是 jbpm4_deployment 的 DBID
        repositoryService.deleteDeploymentCascade("10001");
    }

    @Test
    // 刪除所有key 為 holiday 的流程
    public void deleteByKey(){
        // 1、流程引擎
        Configuration configuration = new Configuration();
        ProcessEngine processEngine = configuration.buildProcessEngine();//新建一個引擎

        // 2、獲得對應的Service
        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 3、先根據key 進行查詢,在執行刪除
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey("holiday").list();
        for (ProcessDefinition processDefinition : list) {
            repositoryService.deleteDeploymentCascade(processDefinition.getDeploymentId());
        }
    }


}

流程例項操作: 通過ExecutionService對流程例項進行操作

啟動流程例項 :
通過例項pdid啟動
executionService.startProcessInstanceById(“holiday-1”);
通過例項pdkey啟動(預設啟動相同key最新例項)
executionService.startProcessInstanceByKey(“holiday”);
如果多個流程具有相同key,會啟動版本最高的那個流程

啟動流程例項,影響的資料表:
jbpm4_execution 正在執行流程例項資訊表,ExecutionId例項ID,ID_: holiday.10001

jbpm4_hist_procinst 流程例項歷史記錄表

啟動例項,流轉到任務節點 jbpm4_task 正在執行任務資料表

jbpm4_hist_task 任務歷史記錄表

jbpm4_hist_actinst 活動的歷史記錄表

流程例項流轉操作:
通過 ExecutionService 提供 signalExecutionById (ExecutionId )
根據流程例項id 進行流轉
直接中止流程
processEngine.getExecutionService().endProcessInstance(ExecutionId, ProcessInstance.STATE_ENDED);

程式碼示例:

package com.my.jbpm;

import org.jbpm.api.Configuration;
import org.jbpm.api.ExecutionService;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.ProcessInstance;
import org.junit.Test;

public class JBPMTest3 {

    @Test
    // 啟動一個流程 例項
    public void demo1(){
        // 有一個人 要執行請假流程
        // 1、流程引擎
        ProcessEngine processEngine = new Configuration().buildProcessEngine();

        // 2、獲得對應的Service物件 
        ExecutionService executionService = processEngine.getExecutionService();

        // 3、啟動具體流程 
        // 根據 pdId 啟動
        // executionService.startProcessInstanceById("holiday-1");
        // 根據key啟動 
        executionService.startProcessInstanceByKey("holiday");
    }

    @Test
    // 流程例項 向後流轉
    public void demo2(){
        // 1、流程引擎
        ProcessEngine processEngine = new Configuration().buildProcessEngine();

        // 2、獲得對應的Service物件 
        ExecutionService executionService = processEngine.getExecutionService();

        // 3、向後流轉
        // ExecutionId 流程例項id 在 jbpm4_execution 表 ID_ 欄位
        // 在向後流轉時,"to 部門經理審批" 是 transition的 name 屬性
        executionService.signalExecutionById("holiday.10001","to 員工請假申請");
    }

    @Test
    // 流程例項 流轉 (直接中止)
    public void demo3(){
        // 1、流程引擎
        ProcessEngine processEngine = new Configuration().buildProcessEngine();

        // 2、獲得對應的Service物件 
        ExecutionService executionService = processEngine.getExecutionService();

        // 3、中止流程 
        executionService.endProcessInstance("holiday.10001", ProcessInstance.STATE_ENDED);
    }

}

任務操作 :TaskService 進行任務節點操作
在實際開發中, 任務節點,通常不使用流程例項流轉功能 signalExecutionById
任務辦理,都是通過 特定使用者,以form表單提交方式進行的,任務辦理後,流轉自動流轉
在流程圖上面,為每個任務,指定任務的負責人 ,assignee屬性用來指定 個人任務
這裡寫圖片描述

新增負責人後的holiday.jpdl.xml

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

<process name="holiday" xmlns="http://jbpm.org/4.4/jpdl">
   <start g="369,43,48,48" name="start1">
      <transition g="-93,-22" name="to 員工請假申請" to="員工請假申請"/>
   </start>
   <task g="358,168,92,52" name="員工請假申請" assignee="員工">
      <transition g="-93,-22" name="to 部門經理審批" to="部門經理審批"/>
   </task>
   <end g="378,384,48,48" name="end1"/>
   <task g="364,281,92,52" name="部門經理審批" assignee="部門經理">
      <transition g="-50,-22" name="to end1" to="end1"/>
   </task>
</process>

檢視流程執行到哪個任務節點

        // 查詢 當前流程例項的任務 
        TaskQuery taskQuery = taskService.createTaskQuery();// 任務查詢
        List<Task> list = taskQuery.executionId("holiday.10001").list(); // 根據流程例項id 查詢 
        for (Task task : list) {
            System.out.println(task.getName());
        }

檢視個人任務
taskService.createTaskQuery().assignee(“張三”).list(); // 用於負責查詢
taskService.findPersonalTasks(“張三”);

        // 查詢個人任務
        List<Task> list = taskService.findPersonalTasks("員工"); // userId 就是 assignee 值
        for (Task task : list) {
            System.out.println("任務編號:" + task.getId() +", 任務名稱:" + task.getName());
        }

任務編號,就是 jbpm4_task 表 DBID

個人任務辦理:TaskService提供completeTask(taskId)完成指定的任務
taskService.completeTask(“20001”);
辦理任務後,流程自動向後流轉

Task節點通常需要特定人蔘與完成,使用 completeTask
signalExecutionById 主要用於自動流轉活動節點(不需要人工干預 )

程式碼示例:

package com.my.jbpm;

import java.util.List;

import org.jbpm.api.Configuration;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.TaskQuery;
import org.jbpm.api.TaskService;
import org.jbpm.api.task.Task;
import org.junit.Test;

public class JbpmTest4 {

    @Test
    // 查詢流程例項的當前任務 
    public void demo1(){
        // 1、 流程引擎
        ProcessEngine processEngine = new Configuration().buildProcessEngine();

        // 2、 獲得對應Service
        TaskService taskService = processEngine.getTaskService();

        // 3、查詢 當前流程例項的任務 
        TaskQuery taskQuery = taskService.createTaskQuery();// 任務查詢
        List<Task> list = taskQuery.executionId("holiday.10001").list(); // 根據流程例項id 查詢 
        for (Task task : list) {
            System.out.println(task.getName());
        }
    }

    @Test
    // 查詢個人任務
    public void demo2(){
        // 1、 流程引擎
        ProcessEngine processEngine = new Configuration().buildProcessEngine();

        // 2、 獲得對應Service
        TaskService taskService = processEngine.getTaskService();

        // 3、查詢個人任務
        List<Task> list = taskService.findPersonalTasks("部門經理"); // userId 就是 assignee 值
        for (Task task : list) {
            System.out.println("任務編號:" + task.getId() +", 任務名稱:" + task.getName());
        }
    }

    @Test
    // 辦理個人任務 
    public void demo3(){
        // 1、 流程引擎
        ProcessEngine processEngine = new Configuration().buildProcessEngine();

        // 2、 獲得對應Service
        TaskService taskService = processEngine.getTaskService();

        // 3、辦理個人任務
        // taskId 是 jbpm4_task 表 DBID
        taskService.completeTask("20001");
    }

}

流程變數操作 :
JBPM支援的流程變數型別
 java.lang.String
 java.lang.Long
 java.lang.Double
 java.util.Date
 java.lang.Boolean
 java.lang.Character
 java.lang.Byte
 java.lang.Short
 java.lang.Integer
 java.lang.Float
 byte[] (byte array)
 char[] (char array)
 hibernate entity with a long id
 hibernate entity with a string id
 serializable

流程例項變數的讀寫:
變數是和流程例項相關的資料,操作流程變數,通常使用 ExecutionService 和 TaskService 兩個物件

在流程例項啟動時,通過ExecutionService 儲存流程變數

Map<String,Object> variables = new HashMap<String, Object>();
variables.put("test", "Hello JBPM");
executionService.startProcessInstanceByKey("holiday",variables);

在執行後,流程例項變數 儲存 jbpm4_variable 表中

ExecutionService 結合 ExecutionId 進行流程變數 讀寫

// 讀取
String company = 
(String) executionService.getVariable("holiday.30001", "test");
// 寫入
executionService.setVariable("holiday.30001", "weather", "陰天");

TaskService 結合 taskId 進行流程變數 讀寫

// 讀取
String weather = (String) taskService.getVariable("30003", "weather");

// 寫入
Map<String,Object> variables = new HashMap<String, Object>();
variables.put("年齡", 20);
taskService.setVariables("30003", variables);

向流程例項中,儲存複雜物件
做法一 : 將物件實現Serializable 介面
變數資訊 jbpm4_variable 表中,Class:blob, converter:ser-bytes 說明物件 是 序列化儲存
資料儲存 jbpm4_lob 表中

做法二 : 將物件配置成Hibernate PO物件
long型別或者String 型別主鍵
Class: hld-long 是hibernate的long型別主鍵實體物件
ClassName: com.my.jbpm.Product 完整類名
Long-value : 1 是PO物件id

程式碼示例:
User.java

package com.my.jbpm;

import java.io.Serializable;

//將User物件 儲存流程例項中(序列化)
public class User implements Serializable{
    private Integer id ;
    private String name;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }



}

Product.java

package com.my.jbpm;

//儲存流程變數 (配置 PO物件)
public class Product {

    private Long id ;
    private String name;
    private Double price ;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Double getPrice() {
        return price;
    }
    public void setPrice(Double price) {
        this.price = price;
    }




}

Product.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.my.jbpm.Product" table="product">
        <id name="id">
            <generator class="identity"></generator>
        </id>
        <property name="name"></property>
        <property name="price"></property>
    </class>
</hibernate-mapping>

JBPMTest5.java

package com.my.jbpm;

import java.util.HashMap;
import java.util.Map;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.jbpm.api.Configuration;
import org.jbpm.api.ExecutionService;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.TaskService;
import org.junit.Test;

public class JBPMTest5 {

        @Test
        public void demo1(){
            // 1、 流程引擎
            ProcessEngine processEngine = new Configuration().buildProcessEngine();
            // 2、獲得Service
            ExecutionService executionService = processEngine.getExecutionService();
            // 3、啟動流程例項
            Map<String,Object> variables = new HashMap<String, Object>();
            variables.put("company", "傳智播客");
            executionService.startProcessInstanceByKey("holiday",variables);
        }

        @Test
        public void demo2(){
            // 1、 流程引擎
            ProcessEngine processEngine = new Configuration().buildProcessEngine();
            // 2、獲得Service
            ExecutionService executionService = processEngine.getExecutionService();
            // 3、讀寫流程變數 
            // 讀取
            String company = (String) executionService.getVariable("holiday.30001", "company");
            System.out.println(company);
            // 寫入
            executionService.setVariable("holiday.30001", "weather", "陰天");
        }

        // 案例三 : 使用TaskService 結合 taskId 讀寫流程變數 
        @Test
        public void demo3(){
            // 1、 流程引擎
            ProcessEngine processEngine = new Configuration().buildProcessEngine();
            // 2、獲得Service
            TaskService taskService = processEngine.getTaskService();
            // 3、讀寫流程變數 
            // 讀取
            String weather = (String) taskService.getVariable("30003", "weather");
            System.out.println(weather);
            // 寫入
            Map<String,Object> variables = new HashMap<String, Object>();
            variables.put("年齡", 20);
            taskService.setVariables("30003", variables);
        }   

        @Test
        // 流程例項,儲存序列化物件 
        public void demo4(){
            // 1、 流程引擎
            ProcessEngine processEngine = new Configuration().buildProcessEngine();
            // 2、獲得Service
            ExecutionService executionService = processEngine.getExecutionService();
            // 3、 儲存User物件
            User user = new User();
            user.setId(1);
            user.setName("Rose");

            executionService.setVariable("holiday.30001", "user", user);
        }

        @Test
        // 流程例項,儲存PO物件
        public void demo5(){
            // 1、 流程引擎
            ProcessEngine processEngine = new Configuration().buildProcessEngine();
            // 2、獲得Service
            ExecutionService executionService = processEngine.getExecutionService();
            // 3、 儲存Product物件
            Product product = new Product();
            product.setName("冰箱");
            product.setPrice(3000d);

            Session session = new org.hibernate.cfg.Configuration().configure("jbpm.hibernate.cfg.xml").buildSessionFactory().openSession();
            Transaction transaction = session.beginTransaction();
            session.save(product);
            transaction.commit();
            session.close();

            // 關聯到流程變數
            executionService.setVariable("holiday.30001", "product", product);
        }

}