工做流Jpbm4.4工做流知識點總結(工做流開發寶典)

Jbpm工做流開發過程當中的一些知識點總結,方便之後開發使用!java

目錄:mysql

1、工做流框架的搭建spring

2、工做流框架的流程開發sql

  一、管理流程定義數據庫

    ①部署流程定義apache

    ②查詢流程定義api

    ③刪除流程定義tomcat

    ④獲取部署對象中的文件資源內容session

    ⑤ 獲取流程圖中某活動的座標app

  二、執行流程實例

    ①啓動流程實例

    ②向後執行一步

    ③查詢任務

    ④完成任務

    ⑤拾取任務

    ⑥獲取流程中的變量

3、Jbpm和spring整合

 

 

第一章 工做流框架的搭建

1.1. 準備jBPM4.4的開發環境

1.1.1. 添加jBPM4.4jar

  1. ${JBPM_HOME}/jbpm.jar(核心包)
  2. JBPM_HOME/lib/*.jar,不添加如下jar包:servlet-api.jar, junit.jar。其中junit.jar必定不要添加,由於是3.8.2版本,與咱們使用的junit4有衝突。
  3. 所使用的數據庫對應的驅動的jar包(第2步所添加的jar包中已包含mysqljdbc驅動jar包)。
  4. 配置文件能夠從JBPM_HOME/examples/src/中拷貝:
    jbpm.cfg.xml
    logging.properties//要注意版本的問題,接口和實現類要相同版本
    jbpm.hibernate.cfg.xml
  5. 修改logging.properties中的日誌輸出級別WARNING: java.util.logging.ConsoleHandler.level=WARNING
  6. 修改jbpm.hibernate.cfg.xml中的數據庫鏈接信息。若是使用MySQL,使用的方言必定要是org.hibernate.dialect.MySQL5InnoDBDialect。
  7. 數據庫鏈接編碼必定要是UTF-8。不然可能會在部署含有中文字符的流程定義時會拋異常,說sql語法錯誤。

第二章 工做流框架的流程開發

1.1. 部署流程定義

注意區分Deployment與ProcessDefinition

1.1.1. 示例代碼1:流程定義有關文件在classpath

String deploymentId = processEngine.getRepositoryService()

.createDeployment()

.addResourceFromClasspath("process/test.jpdl.xml")

.addResourceFromClasspath("process/test.png")

.deploy();

1.1.2. 示例代碼2:一次添加多個流程定義有關文件(要先打成zip包)

String deploymentId = processEngine.getRepositoryService()

.createDeployment()

.addResourcesFromZipInputStream(zipInputStream)

.deploy();

1.1.3. 說明

1, .addResourceFromClasspath(resource); 能夠調用屢次以添加多個文件。文件重複添加也不會報錯。

2, .addResourceFromInputStream(resourceName, inputStream)添加一個文件(使用InputStream

3, .addResourcesFromZipInputStream(zipInputStream)添加多個文件,裏面也能夠有文件夾。

4, 以上方法能夠在一塊兒調用。

 

1.2. 刪除流程定義

1.2.1. 示例代碼1:刪除流程定義,若是有關聯的流程實例信息則報錯

repositoryService.deleteDeployment(deploymentId);

1.2.2. ?示例代碼2:刪除流程定義,並刪除關聯的流程實例與歷史信息

repositoryService.deleteDeploymentCascade(deploymentId);

關聯:關聯的流程實例,就是流程定義中執行過的那些實例【已經放到了歷史表中,級聯刪除的就是同時刪除那些執行過了的實例】,

1.3. 查詢流程定義

1.3.1. 相關查詢API說明:ProcessDefinitionQuery

RepositoryService.createProcessDefinitionQuery()

 

1.3.2. 示例代碼1:查詢全部流程定義

// 1,構建查詢

ProcessDefinitionQuery pdQuery = processEngine.getRepositoryService() 

.createProcessDefinitionQuery()// 

.orderAsc(ProcessDefinitionQuery.PROPERTY_NAME)//

.orderDesc(ProcessDefinitionQuery.PROPERTY_VERSION);

 

// 2,查詢出總數量與數據列表

long count = pdQuery.count();

List<ProcessDefinition> list = pdQuery.page(0, 100).list();// 分頁:取出前100條記錄

 

// 3,顯示結果

System.out.println(count);

for (ProcessDefinition pd : list) {

System.out.println("id=" + pd.getId()//

+ ",deploymentId=" + pd.getDeploymentId()//

+ ",name=" + pd.getName()//

+ ",version=" + pd.getVersion()//

+ ",key=" + pd.getKey()); //

}

1.3.3. 示例代碼2:查詢全部最新版本的流程定義列表

// 1,查詢,按version升序排序,則最大版本排在最後

List<ProcessDefinition> all = processEngine.getRepositoryService()//

.createProcessDefinitionQuery()//

.orderAsc(ProcessDefinitionQuery.PROPERTY_VERSION)

.list();

// 2,過濾出全部不一樣Key的最新版本(由於最大版本在最後面)

Map<String, ProcessDefinition> map = new HashMap<String, ProcessDefinition>(); // mapkey是流程定義的keymapvlaue是流程定義對象

for (ProcessDefinition pd : all) {

map.put(pd.getKey(), pd);

}

Collection<ProcessDefinition> result = map.values();

// 3,顯示結果

for (ProcessDefinition pd : result) {

System.out.println("deploymentId=" + pd.getDeploymentId()// 

+ ",\t id=" + pd.getId()// 流程定義的id,格式:{key}-{version}

+ ",\t name=" + pd.getName()

+ ",\t key=" + pd.getKey()

+ ",\t version=" + pd.getVersion());

}

1.4. 獲取部署對象中的文件資源內容

// 資源的名稱,就是 jbpm4_lob 表中的 NAME_ 列表值

String deploymentId = "90001";

String resourceName = "test.png"; 

InputStream in = processEngine.getRepositoryService()

.getResourceAsStream(deploymentId, resourceName);

1.5. 獲取流程圖中某活動的座標

String processDefinitionId = "test-1"; // 流程定義的id

String activityName = "start1"; // 活動的名稱

 

ActivityCoordinates c = processEngine.getRepositoryService()

.getActivityCoordinates(processDefinitionId, activityName);

System.out.println("x=" + c.getX() 

+ ",y=" + c.getY() 

+ ",width=" + c.getWidth() 

+ ",height=" + c.getHeight());

 

2. 執行流程實例

2.1. 啓動流程實例

說明:流程實例建立後,直接就到開始活動後的第一個活動,不會在開始活動停留。

2.1.1. 示例代碼1:使用指定key的最新版本的流程定義啓動流程實例

ProcessInstance pi = processEngine.getExecutionService()

.startProcessInstanceByKey(processDefinitionKey);

2.1.2. 示例代碼2:使用指定key的最新版本的流程定義啓動流程實例,並設置一些流程變量

// 準備流程變量

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

variables.put("申請人", "張三");

variables.put("報銷金額", 1000.00);

 

// 啓動流程實例,並設置一些流程變量

ProcessInstance pi = processEngine.getExecutionService()

.startProcessInstanceByKey(processDefinitionKey, variables);

2.2. 向後執行一步(Signal

2.2.1. 示例代碼1:向後執行一步,使用惟一的outcome離開活動

processEngine.getExecutionService().signalExecutionById(executionId);

2.2.2. 示例代碼2:向後執行一步,使用惟一的outcome離開活動,並設置一些流程變量

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

variables.put("審批結果", "贊成");

 

processEngine.getExecutionService()

.signalExecutionById(executionId, variables);

 

2.2.3. 示例代碼3:向後執行一步,使用指定的outcome離開活動

String outcome= "to end1";

processEngine.getExecutionService()

.signalExecutionById(executionId, outcome);

2.2.4. 示例代碼4:向後執行一步,使用指定的outcome離開活動,並設置一些流程變量

String outcome= "to end1";

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

variables.put("審批結果", "贊成");

 

processEngine.getExecutionService()

.signalExecutionById(executionId, outcome, variables);

 

2.3. 查詢任務

2.3.1. 查詢我的任務列表

方式1TaskService.findPersonalTasks(userId);

 

方式2List<Task> list = taskService.createTaskQuery()

.assignee(userId)

.list();

 

// 顯示任務信息

for (Task task : taskList) {

System.out.println("id=" + task.getId()// 任務的id

+ ",name=" + task.getName()// 任務的名稱

+ ",assignee=" + task.getAssignee()// 任務的辦理人

+ ",createTime=" + task.getCreateTime() // 任務的建立(生成)的時間

+ ",executionId=" + task.getExecutionId());// 任務所屬流程實例的id

}

2.3.2. 查詢組任務列表

方式1 taskService.findGroupTasks(userId);

 

方式2 List<Task> list = processEngine.getTaskService()//

.createTaskQuery()//

.candidate(userId)//

.list();

2.4. 完成任務

2.4.1. 正常完成任務(也能夠同時設置一些流程變量)

String taskId = "420001";

processEngine.getTaskService().completeTask(taskId);

 

processEngine.getTaskService().completeTask(taskId, outcome);

 

processEngine.getTaskService().completeTask(taskId, outcome, variables);

 

2.4.2. 自行控制任務完成後是否可向後流轉

String taskId = "420001";

 

// 1設置爲false表明:辦理完任務後不向後移動(默認爲true

TaskImpl taskImpl = (TaskImpl) processEngine

.getTaskService().getTask(taskId);

taskImpl.setSignalling(false); 

 

// 2,辦理完任務

processEngine.getTaskService().completeTask(taskId);

2.5. 拾取任務

1, TaskService.takeTask(taskId, userId),拾取組任務到我的任務列表中,若是任務有assignee,則會拋異常。

2, processEngine.getTaskService().assignTask(taskId, userId),轉交任務給其餘人,(若是任務有assignee,則執行這個方法表明從新分配。也能夠把assignee設爲null表示組任務沒有人辦理了)

2.6. 設置與獲取流程變量

2.6.1. 設置流程變量

2.6.1.1. 方式1:根據 executionId 設置或獲取流程變量

ExecutionService.setVariable(executionId, name, value);

 

Object obj = executionService.getVariable(executionId, "請假人");

2.6.1.2. 方式2:根據 taskId 設置或獲取流程變量

TaskService.setVariables(taskId, variables); // 一次設置多個變量

 

Object obj = executionService.getVariable(executionId, "請假人");

2.6.1.3. 流程變量所支持的值的類型(jBPM User Guide,7.2. Variable types)

7.2. Variable types

jBPM supports following Java types as process variables:

 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

For persistence of these variable, the type of the variable is checked in the order of this list. The first match will determine how the variable is stored. 

2.7. 直接結束流程實例(本身手工結束)

String processInstanceId =  "test.10001";

processEngine.getExecutionService()

.endProcessInstance(processInstanceId, ProcessInstance.STATE_ENDED);

 

第三章  jbpm與spring整合

1.1. 與Spring集成(jBPM4.4 Developers Guide, Chapter 17. Spring Integration

1.1.1. 在jbpm.cfg.xml

1,刪除配置:<import resource="jbpm.tx.hibernate.cfg.xml" />

2,增長配置:<import resource="jbpm.tx.spring.cfg.xml" />

1.1.2. 在applicationContext.xml中配置

<!-- 配置ProcessEngine(整合jBPM4) -->

<!-- jbpmCfg是相對於classpath的相對路徑,默認值爲jbpm.cfg.xml -->

<bean id="springHelper" 

class="org.jbpm.pvm.internal.processengine.SpringHelper">

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

</bean>

<bean id="processEngine" factory-bean="springHelper" 

factory-method="createProcessEngine" />

1.1.3. 測試

@Test // 測試ProcessEngine

public void testProcessEngine() {

ProcessEngine processEngine = (ProcessEngine)ac.getBean("processEngine");

Assert.assertNotNull(processEngine);

}

 

1.1.4. 注意事項

若是作了JBPM4.4Spring整合(使用了jbpm.tx.spring.cfg.xml),則在程序中就必定要使用Spring注入ProcessEngine,千萬不能使用Configuration.getProcessEngine()生成ProcessEngine,由於這時內部的代碼有如下邏輯:若是整合了Spring但沒有ApplicationContext,就默認讀取applicationContext.xml建立ApplicationContext實例並從中獲取名爲」ProcessEngine」的對象。而這時若是把pe = Configuration.getProcessEngine()寫成某Spring中管理的bean的初始化代碼,就會有無限循環,不停的建立ApplicationContext了!

1.2. 自行控制事務

1, 修改 jbpm.tx.hibernate.cfg.xml

a) 不讓jBPM自行管理事務:去掉<standard-transaction-interceptor />

b) 讓Jbpm使用SessionFactory.getCurrentSession():修改成 <hibernate-session current="true" />

2, 配置可使用SessionFactory.getCurrentSession(),在jbpm.hibernate.cfg.xml 中配置:<property name="hibernate.current_session_context_class">thread</property>

3, 要使用同一個SessionFactory,且都要使用 SessionFactory.getCurrentSession() 獲取 Session

a) 同一個SessionFactorySessionFactory sf = processEngine.get(SessionFactory.class)

b) 在 BaseDaoImpl 中增長:

  1. getSession() { return HibernateUtils.getSessionFactory().getCurrentSession(); }
  2. getProcessEngine(){ return org.jbpm.api.Configuration.getProcessEngine(); }

4, 統一的打開與提交或回滾事務:使用 OpenSessionInViewFilter 控制事務。

 

1.3. 啓動Tomcat後,訪問JSP時(使用的是MyEclipse自帶的Tomcat,是6.0的版本),報錯:   Caused by: java.lang.LinkageError: loader constraints violated when linking javax/el/ExpressionFactory class

at org.apache.jsp.WEB_002dINF.jsp.UserAction.loginUI_jsp._jspInit(loginUI_jsp.java:39)

at org.apache.jasper.runtime.HttpJspBase.init(HttpJspBase.java:52)

at org.apache.jasper.servlet.JspServletWrapper.getServlet(JspServletWrapper.java:159)

at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:329)

at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)

at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)

... 40 more

 

說明:緣由是Jbpmjuel.jar, juel-engine.jar, juel-impl.jar包和Tomcat6.0中的el-api.jar包衝突了。

有三個解決辦法:

1,方法一:在MyEclipsePreferences -> MyEclipse -> Application Servers -> Tomcat -> .. -> Paths 中配置 Append to classpath,選中 juel.jar, juel-engine.jar, juel-impl.jar 這三個jar包就能夠了。

2,方法二:將 juel.jar, juel-engine.jar, juel-impl.jar 這三個包複製到tomcat6下 lib/ 中,並刪除原來的el-api.jar

切記還要把工程中 WEB-INF\lib 下的 juel.jar, juel-engine.jar, juel-impl.jar 刪除,否則仍是要衝突。

3,方法三:換成tomcat5.5,就沒有問題了。

 

1.4. 完成流程實例中的最後一個任務時報錯(任務實例結束時),或刪除流程定義級聯刪除流程實例時,報錯以下:

com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`itcastoa_20100909/jbpm4_execution`, CONSTRAINT `FK_EXEC_INSTANCE` FOREIGN KEY (`INSTANCE_`) REFERENCES `jbpm4_execution` (`DBID_`))

 

解決辦法:把方言設爲 MySQL5InnoDBDialect,不能是 MySQLDialect

相關文章
相關標籤/搜索