天天看點

工作流Jpbm4.4工作流知識點總結(工作流開發寶典) 第一章 工作流架構的搭建第二章 工作流架構的流程開發2. 執行流程執行個體第三章  jbpm與spring整合

Jbpm工作流開發過程中的一些知識點總結,友善以後開發使用!

目錄:

二、工作流架構的流程開發

  1、管理流程定義

    ①部署流程定義

    ②查詢流程定義

    ③删除流程定義

    ④擷取部署對象中的檔案資源内容

    ⑤ 擷取流程圖中某活動的坐标

  2、執行流程執行個體

    ①啟動流程執行個體

    ②向後執行一步

    ③查詢任務

    ④完成任務

    ⑤拾取任務

    ⑥擷取流程中的變量

三、Jbpm和spring整合

${JBPM_HOME}/jbpm.jar(核心包)

JBPM_HOME/lib/*.jar,不添加以下jar包:servlet-api.jar, junit.jar。其中junit.jar一定不要添加,因為是3.8.2版本,與我們使用的junit4有沖突。

所使用的資料庫對應的驅動的jar包(第2步所添加的jar包中已包含mysql的jdbc驅動jar包)。

配置檔案可以從JBPM_HOME/examples/src/中拷貝:

jbpm.cfg.xml、

logging.properties、//要注意版本的問題,接口和實作類要相同版本

jbpm.hibernate.cfg.xml。

修改logging.properties中的日志輸出級别為WARNING: java.util.logging.ConsoleHandler.level=WARNING

修改jbpm.hibernate.cfg.xml中的資料庫連接配接資訊。如果使用MySQL,使用的方言一定要是org.hibernate.dialect.MySQL5InnoDBDialect。

資料庫連接配接編碼一定要是UTF-8。否則可能會在部署含有中文字元的流程定義時會抛異常,說sql文法錯誤。

注意區分Deployment與ProcessDefinition

String deploymentId = processEngine.getRepositoryService()

.createDeployment()

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

.addResourceFromClasspath("process/test.png")

.deploy();

.addResourcesFromZipInputStream(zipInputStream)

1, .addResourceFromClasspath(resource); 可以調用多次以添加多個檔案。檔案重複添加也不會報錯。

2, .addResourceFromInputStream(resourceName, inputStream)添加一個檔案(使用InputStream)

3, .addResourcesFromZipInputStream(zipInputStream)添加多個檔案,裡面也可以有檔案夾。

4, 以上方法可以在一起調用。

repositoryService.deleteDeployment(deploymentId);

repositoryService.deleteDeploymentCascade(deploymentId);

關聯:關聯的流程執行個體,就是流程定義中執行過的那些執行個體【已經放到了曆史表中,級聯删除的就是同時删除那些執行過了的執行個體】,

RepositoryService.createProcessDefinitionQuery()

// 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,查詢,按version升序排序,則最大版本排在最後面

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

.createProcessDefinitionQuery()//

.orderAsc(ProcessDefinitionQuery.PROPERTY_VERSION)

.list();

// 2,過濾出所有不同Key的最新版本(因為最大版本在最後面)

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

for (ProcessDefinition pd : all) {

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

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

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

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

String deploymentId = "90001";

String resourceName = "test.png"; 

InputStream in = processEngine.getRepositoryService()

.getResourceAsStream(deploymentId, resourceName);

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

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

ProcessInstance pi = processEngine.getExecutionService()

.startProcessInstanceByKey(processDefinitionKey);

// 準備流程變量

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

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

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

// 啟動流程執行個體,并設定一些流程變量

.startProcessInstanceByKey(processDefinitionKey, variables);

processEngine.getExecutionService().signalExecutionById(executionId);

variables.put("審批結果", "同意");

processEngine.getExecutionService()

.signalExecutionById(executionId, variables);

String outcome= "to end1";

.signalExecutionById(executionId, outcome);

.signalExecutionById(executionId, outcome, variables);

方式1:TaskService.findPersonalTasks(userId);

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

.assignee(userId)

// 顯示任務資訊

for (Task task : taskList) {

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

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

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

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

+ ",executionId=" + task.getExecutionId());// 任務所屬流程執行個體的id

方式1: taskService.findGroupTasks(userId);

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

.createTaskQuery()//

.candidate(userId)//

String taskId = "420001";

processEngine.getTaskService().completeTask(taskId);

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

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

// 1,設定為false代表:辦理完任務後不向後移動(預設為true)

TaskImpl taskImpl = (TaskImpl) processEngine

.getTaskService().getTask(taskId);

taskImpl.setSignalling(false); 

// 2,辦理完任務

1, TaskService.takeTask(taskId, userId),拾取組任務到個人任務清單中,如果任務有assignee,則會抛異常。

2, processEngine.getTaskService().assignTask(taskId, userId),轉交任務給其他人,(如果任務有assignee,則執行這個方法代表重新配置設定。也可以把assignee設為null表示組任務沒有人辦理了)

ExecutionService.setVariable(executionId, name, value);

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

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

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. 

String processInstanceId =  "test.10001";

.endProcessInstance(processInstanceId, ProcessInstance.STATE_ENDED);

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

2,增加配置:<import resource="jbpm.tx.spring.cfg.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" />

@Test // 測試ProcessEngine

public void testProcessEngine() {

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

Assert.assertNotNull(processEngine);

如果做了JBPM4.4與Spring整合(使用了jbpm.tx.spring.cfg.xml),則在程式中就一定要使用Spring注入ProcessEngine,千萬不能使用Configuration.getProcessEngine()生成ProcessEngine,因為這時内部的代碼有以下邏輯:如果整合了Spring但沒有ApplicationContext,就預設讀取applicationContext.xml建立ApplicationContext執行個體并從中擷取名為”ProcessEngine”的對象。而這時如果把pe = Configuration.getProcessEngine()寫成某Spring中管理的bean的初始化代碼,就會有無限循環,不停的建立ApplicationContext了!

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) 同一個SessionFactory:SessionFactory sf = processEngine.get(SessionFactory.class)

b) 在 BaseDaoImpl 中增加:

getSession() { return HibernateUtils.getSessionFactory().getCurrentSession(); }

getProcessEngine(){ return org.jbpm.api.Configuration.getProcessEngine(); }

4, 統一的打開與送出或復原事務:使用 OpenSessionInViewFilter 控制事務。

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

說明:原因是Jbpm的juel.jar, juel-engine.jar, juel-impl.jar包和Tomcat6.0中的el-api.jar包沖突了。

有三個解決辦法:

1,方法一:在MyEclipse的Preferences -> 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,就沒有問題了。

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。