jbpm_工作流框架笔记
1.?工作流基礎(chǔ)
1.1.?工作流相關(guān)概念
工作流(Workflow),就是“業(yè)務(wù)過(guò)程的部分或整體在計(jì)算機(jī)應(yīng)用環(huán)境下的自動(dòng)化”,它主要解決的是“使在多個(gè)參與者之間按照某種預(yù)定義的規(guī)則傳遞文檔、信息或任務(wù)的過(guò)程自動(dòng)進(jìn)行,從而實(shí)現(xiàn)某個(gè)預(yù)期的業(yè)務(wù)目標(biāo),或者促使此目標(biāo)的實(shí)現(xiàn)”。
通俗的說(shuō),流程就是多個(gè)人在一起合作完成某件事情的步驟,把步驟變成計(jì)算機(jī)能理解的形式就是工作流。
工作流管理系統(tǒng)(WfMS,Workflow?Management?System)的主要功能是通過(guò)計(jì)算機(jī)技術(shù)的支持去定義、執(zhí)行和管理工作流,協(xié)調(diào)工作流執(zhí)行過(guò)程中工作之間以及群體成員之間的信息交互。工作流需要依靠工作流管理系統(tǒng)來(lái)實(shí)現(xiàn)。工作流管理系統(tǒng)是定義、創(chuàng)建、執(zhí)行工作流的系統(tǒng),應(yīng)能提供以下三個(gè)方面的功能支持:
1.?定義工作流:包括具體的活動(dòng)、規(guī)則等
2.?運(yùn)行控制功能:在運(yùn)行環(huán)境中管理工作流過(guò)程,對(duì)工作流過(guò)程中的活動(dòng)進(jìn)行調(diào)度
3.?運(yùn)行交互功能:指在工作流運(yùn)行中,WfMS與用戶(活動(dòng)的參與者)及外部應(yīng)用程序工具交互的功能。
一、?定義工作流
二、?執(zhí)行工作流
采用工作流管理系統(tǒng)的優(yōu)點(diǎn)
1.?提高系統(tǒng)的柔性,適應(yīng)業(yè)務(wù)流程的變化?
2.?實(shí)現(xiàn)更好的業(yè)務(wù)過(guò)程控制,提高顧客服務(wù)質(zhì)量
3.?降低系統(tǒng)開(kāi)發(fā)和維護(hù)成本
工作流框架有:Jbpm、OSWorkflow、ActiveBPEL、YAWL等
OA(辦公自動(dòng)化)主要技術(shù)之一就是工作流。
1.2.?開(kāi)源工作流jBPM4.4介紹
jBPM?即java?Business?Process?Management,是基于java的業(yè)務(wù)流程管理系統(tǒng)。jBPM是市面上相當(dāng)流行的一款開(kāi)源工作流引擎,引擎底層基于Active?Diagram模型。jBPM4.4使用了hibernate(3.3.1版),因此可以很好的支持主流數(shù)據(jù)庫(kù)。jBPM4.4共有18張表。
jBPM官方主頁(yè):http://www.jboss.org/jbpm
2.?準(zhǔn)備jBPM4.4環(huán)境
2.1.?jBPM4.4所需環(huán)境
jBPM?requires?a?JDK?(standard?java)?version?5?or?higher.?http://java.sun.com/javase/downloads/index.jsp?
To?execute?the?ant?scripts,?you'll?need?apache?ant?version?1.7.0?or?higher:?http://ant.apache.org/bindownload.cgi
2.2.?下載相關(guān)資源
1,?jBPM下載地址:http://sourceforge.net/projects/jbpm/files/
2,?Eclipse下載地址(?Eclipse?IDE?for?Java?EE?Developers?(163?MB),Version:3.5?):http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/galileo
2.3.?安裝流程設(shè)計(jì)器(GPD,Eclipse插件)
GPD(Graphical?Process?Designer)是一個(gè)Eclipse插件。
安裝方法說(shuō)明(jBPM4.4User?Guide,?2.11.2.?Install?the?GPD?plugin?into?eclipse):
?Help?-->?Install?New?Software...?
?Click?Add...?
?In?dialog?Add?Site?dialog,?click?Archive...?
?Navigate?to?install/src/gpd/jbpm-gpd-site.zip?and?click?'Open'?
?Clicking?OK?in?the?Add?Site?dialog?will?bring?you?back?to?the?dialog?'Install'?
?Select?the?jPDL?4?GPD?Update?Site?that?has?appeared?
?Click?Next...?and?then?Finish?
?Approve?the?license?
?Restart?eclipse?when?that?is?asked
查看是否成功安裝了插件:WindowàPreference中是否有Jboss?jBPM項(xiàng)。
2.4.?在Eclipse中添加jPDL4.4?Schema校驗(yàn)
流程定義文件的xsd文件的路徑為:JBPM_HOME/src/jpdl-4.4.xsd。
添加到Eclipse中的方法為(jBPM4.4?User?Guide,?2.11.5.?Adding?jPDL?4?schema?to?the?catalog):
?Click?Window?-->?Preferences?
?Select?XML?-->?XML?Catalog?
?Click?'Add...'?
?The?'Add?XML?Catalog?Entry'?dialog?opens?
?Click?the?button?with?the?map-icon?next?to?location?and?select?'File?System...'?
?In?the?dialog?that?opens,?select?file?jpdl-4.4.xsd?in?the?src?directory?of?the?jBPM?installation?root.?
?Click?'Open'?and?close?all?the?dialogs
2.5.?準(zhǔn)備jBPM4.4的開(kāi)發(fā)環(huán)境
2.5.1.?添加jBPM4.4的jar包
1.?${JBPM_HOME}/jbpm.jar(核心包)
2.?JBPM_HOME/lib/*.jar,不添加以下jar包:servlet-api.jar,?junit.jar。其中junit.jar一定不要添加,因?yàn)槭?/span>3.8.2版本,與我們使用的junit4有沖突。
3.?所使用的數(shù)據(jù)庫(kù)對(duì)應(yīng)的驅(qū)動(dòng)的jar包(第2步所添加的jar包中已包含mysql的jdbc驅(qū)動(dòng)jar包)。
2.5.2.?添加并定制配置文件
1.?配置文件可以從JBPM_HOME/examples/src/中拷貝:
jbpm.cfg.xml、
logging.properties、
jbpm.hibernate.cfg.xml。
2.?修改logging.properties中的日志輸出級(jí)別為WARNING:?java.util.logging.ConsoleHandler.level=WARNING
3.?修改jbpm.hibernate.cfg.xml中的數(shù)據(jù)庫(kù)連接信息。如果使用MySql,使用的方言一定要是org.hibernate.dialect.MySQL5InnoDBDialect。
4.?數(shù)據(jù)庫(kù)連接編碼一定要是UTF-8。否則可能會(huì)在部署含有中文字符的流程定義時(shí)會(huì)拋異常,說(shuō)sql語(yǔ)法錯(cuò)誤。
說(shuō)明:如果要改變jbpm.hibernate.cfg.xml的文件名稱,需要做:
1、從JBPM_HOME/src/中拷貝jbpm.tx.hibernate.cfg.xml放到工程的src/下,然后進(jìn)行修改。
2、修改jbpm.tx.hibernate.cfg.xml中的hibernate主配置文件的路徑配置(指定的是相對(duì)于classpath的相對(duì)路徑)。
2.5.3.?初始化數(shù)據(jù)庫(kù)
1,?方法一:執(zhí)行sql腳本文件${JBPM4.4_HOME}/install/src/db/create/jbpm.*.create.sql
2,?方法二:使用Hibernate的自動(dòng)建表,在jbpm.hibernate.cfg.xml中配置:hibernate.hbm2ddl.auto=update。
3.?核心概念與相關(guān)API(Service?API)
3.1.?概念:Process?definition,?process?instance?,??execution
3.1.1.?Process?definition
ProcessDefinition,流程定義:
一個(gè)流程的步驟說(shuō)明。如一個(gè)請(qǐng)假流程、報(bào)銷流程、借款流程等,是一個(gè)規(guī)則。
例:
3.1.2.?Process?instance
ProcessInstance,流程實(shí)例:
代表流程定義的一次執(zhí)行。如張三昨天按請(qǐng)假流程請(qǐng)了一次假。一個(gè)流程實(shí)例包括了所有運(yùn)行階段,?其中最典型的屬性就是跟蹤當(dāng)前節(jié)點(diǎn)的指針。
3.1.3.?Execution
Execution,執(zhí)行:
一般情況下,一個(gè)流程實(shí)例是一個(gè)執(zhí)行樹(shù)的根節(jié)點(diǎn)。?
使用樹(shù)狀結(jié)構(gòu)的原因在于,?這一概念只有一條執(zhí)行路徑,?使用起來(lái)更簡(jiǎn)單。?業(yè)務(wù)API不需要了解流程實(shí)例和執(zhí)行之間功能的區(qū)別。?因此,?API里只有一個(gè)執(zhí)行類型來(lái)引用流程實(shí)例和執(zhí)行。
假設(shè)匯款和存檔可以同時(shí)執(zhí)行,那么主流程實(shí)例就包含了2個(gè)用來(lái)跟蹤狀態(tài)的子節(jié)點(diǎn):
4.1.?ProcessEngine與Service?API
4.1.1.?Configuration與ProcessEngine
Interacting?with?jBPM?occurs?through?services.?The?service?interfaces?can?be?obtained?from?the?ProcessEngine?which?is?build?from?a?Configuration.?A?ProcessEngine?is?thread?safe?and?can?be?stored?in?a?static?member?field.
使用默認(rèn)的配置文件(jbpm.cfg.xml)生成Configuration并構(gòu)建ProcessEngine:
ProcessEngine?processEngine?=?new?Configuration()
.buildProcessEngine();
或是使用如下代碼獲取使用默認(rèn)配置文件的、單例的ProcessEngine對(duì)象:
ProcessEngine?processEngine?=?Configuration.getProcessEngine();
或是使用指定的配置文件(要放到classPath下):
ProcessEngine?processEngine?=?new?Configuration()
??????.setResource("my-own-configuration-file.xml")
??????.buildProcessEngine();
4.1.2.?jBPM?Service?API
jBPM所有的操作都是通過(guò)Service完成的,以下是獲取Service的方式:
RepositoryService?repositoryService?=?processEngine
.getRepositoryService();
ExecutionService?executionService?=?processEngine
.getExecutionService();
TaskService?taskService?=?processEngine
.getTaskService();
HistoryService?historyService?=?processEngine
.getHistoryService();
ManagementService?managementService?=?processEngine
.getManagementService();
各個(gè)Service的作用:
| RepositoryService | 管理流程定義 |
| ExecutionService | 管理執(zhí)行的,包括啟動(dòng)、推進(jìn)、刪除Execution等操作 |
| TaskService | 管理任務(wù)的 |
| HistoryService | 歷史管理(執(zhí)行完的數(shù)據(jù)管理,主要是查詢) |
| IdentityService | jBPM的用戶、組管理 |
| ManagementService |
4.1.3.?API風(fēng)格
方法調(diào)用鏈
每一個(gè)方法都是流程有關(guān)的一個(gè)業(yè)務(wù)操作,默認(rèn)是一個(gè)獨(dú)立的事務(wù)。
4.1.4.?查詢的有關(guān)API(風(fēng)格)
| 功能說(shuō)明 | 相應(yīng)的查詢API |
| 查詢“流程定義” | ProcessDefinitionQuery?processDefinitionQuery?=? processEngine.getRepositoryService() .createProcessDefinitionQuery(); |
| 查詢“執(zhí)行對(duì)象” (流程實(shí)例) | ProcessInstanceQuery?processInstanceQuery?=? processEngine.getExecutionService()?// .createProcessInstanceQuery(); |
| 查詢“任務(wù)” | TaskQuery?taskQuery?=?// processEngine.getTaskService()// .createTaskQuery(); |
| 查詢“執(zhí)行歷史” (流程實(shí)例歷史) | HistoryProcessInstanceQuery?historyProcessInstanceQuery?=? processEngine.getHistoryService() .createHistoryProcessInstanceQuery(); |
| 查詢“任務(wù)歷史” | HistoryTaskQuery?historyTaskQuery?=? processEngine.getHistoryService() .createHistoryTaskQuery(); |
以上列出的Query對(duì)象有:
1.?ProcessDefinitionQuery
2.?ProcessInstanceQuery
3.?TaskQuery
4.?HistoryProcessInstanceQuery
5.?HistoryTaskQuery
這些Query對(duì)象的使用方法都是一致的,如下所示:
1,?添加過(guò)濾條件:調(diào)用其中的有關(guān)方法指定條件即可。如:
a)?processDefinitionQuery.processDefinitionKey("請(qǐng)假")是指定查詢key為”請(qǐng)假”的流程定義;
b)?taskQuery.assignee("張三")是指定辦理人為”張三”的任務(wù)。
2,?添加排序條件:
a)?調(diào)用?xxQuery.orderAsc(property),表示按某屬性升序排列
b)?調(diào)用?xxQuery.orderDesc(property),表示按某屬性降序排列
c)?可指定多個(gè)排序條件,就是代表第1順序,第2順序…等。
d)?屬性名在各自的Query對(duì)象(接口)中有常量定義,如:
i.?ProcessDefinitionQuery.PROPERTY_ID
ii.?ProcessDefinitionQuery.PROPERTY_KEY
iii.?TaskQuery.PROPERTY_NAME
iv.?TaskQuery.PROPERTY_ASSIGNEE
3,?指定分頁(yè)有關(guān)信息:
a)?調(diào)用方法xxQuery.page(firstResult,?maxResults);
b)?這是指定first與max的值(就是Hibernate中的Query.setFirstResult()與Query.setMaxResults())
c)?如果沒(méi)有調(diào)用這個(gè)方法,代表要查詢出符合條件的所有記錄。
4,?查詢得到結(jié)果:
a)?調(diào)用方法xxQuery.list();?表示查詢列表
b)?調(diào)用方法?xxQuery.uniqueResult();?表示查詢唯一的結(jié)果
c)?調(diào)用方法xxQuery.count();?表示查詢符合條件的記錄數(shù)量
5.?管理流程定義
沒(méi)有更新功能
5.1.?部署流程定義
注意區(qū)分Deployment與ProcessDefinition
5.1.1.?示例代碼1:流程定義有關(guān)文件在classpath中
String?deploymentId?=?processEngine.getRepositoryService()
.createDeployment()
.addResourceFromClasspath("process/test.jpdl.xml")
.addResourceFromClasspath("process/test.png")
.deploy();
5.1.2.?示例代碼2:一次添加多個(gè)流程定義有關(guān)文件(要先打成zip包)
String?deploymentId?=?processEngine.getRepositoryService()
.createDeployment()
.addResourcesFromZipInputStream(zipInputStream)
.deploy();
5.1.3.?說(shuō)明
1,?.addResourceFromClasspath(resource);?可以調(diào)用多次以添加多個(gè)文件。文件重復(fù)添加也不會(huì)報(bào)錯(cuò)。
2,?.addResourceFromInputStream(resourceName,?inputStream)添加一個(gè)文件(使用InputStream)
3,?.addResourcesFromZipInputStream(zipInputStream)添加多個(gè)文件,里面也可以有文件夾。
4,?以上方法可以在一起調(diào)用。
5.2.?刪除流程定義
5.2.1.?示例代碼1:刪除流程定義,如果有關(guān)聯(lián)的流程實(shí)例信息則報(bào)錯(cuò)
repositoryService.deleteDeployment(deploymentId);
5.2.2.?示例代碼2:刪除流程定義,并刪除關(guān)聯(lián)的流程實(shí)例與歷史信息
repositoryService.deleteDeploymentCascade(deploymentId);
5.3.?查詢流程定義
5.3.1.?相關(guān)查詢API說(shuō)明:ProcessDefinitionQuery
RepositoryService.createProcessDefinitionQuery()
5.3.2.?示例代碼1:查詢所有流程定義
//?1,構(gòu)建查詢
ProcessDefinitionQuery?pdQuery?=?processEngine.getRepositoryService()?
.createProcessDefinitionQuery()//?
.orderAsc(ProcessDefinitionQuery.PROPERTY_NAME)//
.orderDesc(ProcessDefinitionQuery.PROPERTY_VERSION);
//?2,查詢出總數(shù)量與數(shù)據(jù)列表
long?count?=?pdQuery.count();
List<ProcessDefinition>?list?=?pdQuery.page(0,?100).list();//?分頁(yè):取出前100條記錄
//?3,顯示結(jié)果
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());?//
}
5.3.3.?示例代碼2:查詢所有最新版本的流程定義列表
//?1,查詢,按version升序排序,則最大版本排在最后面
List<ProcessDefinition>?all?=?processEngine.getRepositoryService()//
.createProcessDefinitionQuery()//
.orderAsc(ProcessDefinitionQuery.PROPERTY_VERSION)
.list();
//?2,過(guò)濾出所有不同Key的最新版本(因?yàn)樽畲蟀姹驹谧詈竺?#xff09;
Map<String,?ProcessDefinition>?map?=?new?HashMap<String,?ProcessDefinition>();?//?map的key是流程定義的key,map的vlaue是流程定義對(duì)象
for?(ProcessDefinition?pd?:?all)?{
map.put(pd.getKey(),?pd);
}
Collection<ProcessDefinition>?result?=?map.values();
//?3,顯示結(jié)果
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());
}
5.4.?獲取部署對(duì)象中的文件資源內(nèi)容
//?資源的名稱,就是?jbpm4_lob?表中的?NAME_?列表值
String?deploymentId?=?"90001";
String?resourceName?=?"test.png";?
InputStream?in?=?processEngine.getRepositoryService()
.getResourceAsStream(deploymentId,?resourceName);
5.5.?獲取流程圖中某活動(dòng)的坐標(biāo)
String?processDefinitionId?=?"test-1";?//?流程定義的id
String?activityName?=?"start1";?//?活動(dòng)的名稱
ActivityCoordinates?c?=?processEngine.getRepositoryService()
.getActivityCoordinates(processDefinitionId,?activityName);
System.out.println("x="?+?c.getX()?
+?",y="?+?c.getY()?
+?",width="?+?c.getWidth()?
+?",height="?+?c.getHeight());
6.?執(zhí)行流程實(shí)例
6.1.?啟動(dòng)流程實(shí)例
說(shuō)明:流程實(shí)例創(chuàng)建后,直接就到開(kāi)始活動(dòng)后的第一個(gè)活動(dòng),不會(huì)在開(kāi)始活動(dòng)停留。
6.1.1.?示例代碼1:使用指定key的最新版本的流程定義啟動(dòng)流程實(shí)例
ProcessInstance?pi?=?processEngine.getExecutionService()
.startProcessInstanceByKey(processDefinitionKey);
6.1.2.?示例代碼2:使用指定key的最新版本的流程定義啟動(dòng)流程實(shí)例,并設(shè)置一些流程變量
//?準(zhǔn)備流程變量
Map<String,?Object>?variables?=?new?HashMap<String,?Object>();
variables.put("申請(qǐng)人",?"張三");
variables.put("報(bào)銷金額",?1000.00);
//?啟動(dòng)流程實(shí)例,并設(shè)置一些流程變量
ProcessInstance?pi?=?processEngine.getExecutionService()
.startProcessInstanceByKey(processDefinitionKey,?variables);
6.2.?向后執(zhí)行一步(Signal)
6.2.1.?示例代碼1:向后執(zhí)行一步,使用唯一的outcome離開(kāi)活動(dòng)
processEngine.getExecutionService().signalExecutionById(executionId);
6.2.2.?示例代碼2:向后執(zhí)行一步,使用唯一的outcome離開(kāi)活動(dòng),并設(shè)置一些流程變量
Map<String,?Object>?variables?=?new?HashMap<String,?Object>();
variables.put("審批結(jié)果",?"同意");
processEngine.getExecutionService()
.signalExecutionById(executionId,?variables);
6.2.3.?示例代碼3:向后執(zhí)行一步,使用指定的outcome離開(kāi)活動(dòng)
String?outcome=?"to?end1";
processEngine.getExecutionService()
.signalExecutionById(executionId,?outcome);
6.2.4.?示例代碼4:向后執(zhí)行一步,使用指定的outcome離開(kāi)活動(dòng),并設(shè)置一些流程變量
String?outcome=?"to?end1";
Map<String,?Object>?variables?=?new?HashMap<String,?Object>();
variables.put("審批結(jié)果",?"同意");
processEngine.getExecutionService()
.signalExecutionById(executionId,?outcome,?variables);
6.3.?查詢?nèi)蝿?wù)
6.3.1.?查詢個(gè)人任務(wù)列表
方式1:TaskService.findPersonalTasks(userId);
方式2:List<Task>?list?=?taskService.createTaskQuery()
.assignee(userId)
.list();
//?顯示任務(wù)信息
for?(Task?task?:?taskList)?{
System.out.println("id="?+?task.getId()//?任務(wù)的id
+?",name="?+?task.getName()//?任務(wù)的名稱
+?",assignee="?+?task.getAssignee()//?任務(wù)的辦理人
+?",createTime="?+?task.getCreateTime()?//?任務(wù)的創(chuàng)建(生成)的時(shí)間
+?",executionId="?+?task.getExecutionId());//?任務(wù)所屬流程實(shí)例的id
}
6.3.2.?查詢組任務(wù)列表
方式1:?taskService.findGroupTasks(userId);
方式2:?List<Task>?list?=?processEngine.getTaskService()//
.createTaskQuery()//
.candidate(userId)//
.list();
6.4.?完成任務(wù)
6.4.1.?正常完成任務(wù)(也可以同時(shí)設(shè)置一些流程變量)
String?taskId?=?"420001";
processEngine.getTaskService().completeTask(taskId);
processEngine.getTaskService().completeTask(taskId,?outcome);
processEngine.getTaskService().completeTask(taskId,?outcome,?variables);
6.4.2.?自行控制任務(wù)完成后是否可向后流轉(zhuǎn)
String?taskId?=?"420001";
//?1,設(shè)置為false代表:辦理完任務(wù)后不向后移動(dòng)(默認(rèn)為true)
TaskImpl?taskImpl?=?(TaskImpl)?processEngine
.getTaskService().getTask(taskId);
taskImpl.setSignalling(false);?
//?2,辦理完任務(wù)
processEngine.getTaskService().completeTask(taskId);
6.5.?拾取任務(wù)
1,?TaskService.takeTask(taskId,?userId),拾取組任務(wù)到個(gè)人任務(wù)列表中,如果任務(wù)有assignee,則會(huì)拋異常。
2,?processEngine.getTaskService().assignTask(taskId,?userId),轉(zhuǎn)交任務(wù)給其他人,(如果任務(wù)有assignee,則執(zhí)行這個(gè)方法代表重新分配。也可以把assignee設(shè)為null表示組任務(wù)沒(méi)有人辦理了)
6.6.?設(shè)置與獲取流程變量
6.6.1.?設(shè)置流程變量
6.6.1.1.?方式1:根據(jù)?executionId?設(shè)置或獲取流程變量
ExecutionService.setVariable(executionId,?name,?value);
Object?obj?=?executionService.getVariable(executionId,?"請(qǐng)假人");
6.6.1.2.?方式2:根據(jù)?taskId?設(shè)置或獲取流程變量
TaskService.setVariables(taskId,?variables);?//?一次設(shè)置多個(gè)變量
Object?obj?=?executionService.getVariable(executionId,?"請(qǐng)假人");
6.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.?
6.7.?直接結(jié)束流程實(shí)例(自己手工結(jié)束)
String?processInstanceId?=?"test.10001";
processEngine.getExecutionService()
.endProcessInstance(processInstanceId,?ProcessInstance.STATE_ENDED);
7.?jBPM4.4的流程定義語(yǔ)言(設(shè)計(jì)流程)
7.1.?process(流程)
是.jpdl.xml的根元素,可以指定的屬性有:
| 屬性名 | 作用說(shuō)明 |
| name | 流程定義的名稱,用于顯示。 |
| key | 流程定義的key,用于查詢。 如未指定,則默認(rèn)為name的值。 |
| version | 版本,如果指定,則不能與已有的流程定義的版本重復(fù);如未指定,則此key的流程定義的第1個(gè)為版本1,以后的是版本遞增(每次加1) |
7.2.?transition(連線、轉(zhuǎn)移)
1,?一個(gè)活動(dòng)中可以指定一個(gè)或多個(gè)Transition(Start中只能有一個(gè),End中沒(méi)有)。
a)?開(kāi)始活動(dòng)中只能有一個(gè)Transition。
b)?結(jié)束活動(dòng)中沒(méi)有Transition。
c)?其他活動(dòng)中有1條或多條Transition
2,?如果只有一個(gè),則可以不指定名稱(名稱是null);如果有多個(gè),則要分別指定唯一的名稱。
7.3.?流轉(zhuǎn)控制活動(dòng)
7.3.1.?start(開(kāi)始活動(dòng))
代表流程的開(kāi)始邊界,一個(gè)流程有且只能有一個(gè)Start活動(dòng)。開(kāi)始活動(dòng)只能指定一個(gè)Transition。在流程實(shí)例啟動(dòng)后,會(huì)自動(dòng)的使用這個(gè)唯一的Transition離開(kāi)開(kāi)始活動(dòng),到一下個(gè)活動(dòng)。
7.3.2.?end、end-error、end-cancel(結(jié)束活動(dòng))
代表流程的結(jié)束邊界,可以有多個(gè),也可以沒(méi)有。如果有多個(gè),則到達(dá)任一個(gè)結(jié)束活動(dòng),整個(gè)流程就都結(jié)束了;如果沒(méi)有,則到達(dá)最后那個(gè)沒(méi)有Transition的活動(dòng),流程就結(jié)束了。
7.3.3.?state(狀態(tài)活動(dòng))
功能:等待。
7.3.4.?task(任務(wù)活動(dòng))
分配任務(wù):
1,?actor=#{String型的變量}
2,?AssignmentHandler,需要在<task>元素中寫(xiě)<assignment-handler?class="AssignmentHandlerImpl"/>子元素。
a)?指定的類要實(shí)現(xiàn)AssignmentHandler接口
b)?在其中可以使用Assignable.setAssignee(String),分配個(gè)人任務(wù)。
7.3.5.?decision(判斷活動(dòng))
1,使用expression,如:expr="#{'to?state2'}"
2,使用Handler,要實(shí)現(xiàn)DecisionHandler接口
3,如果同時(shí)配置了expression與Handler,則expression有效,忽略Handler。
7.3.6.?fork、join(分支/聚合活動(dòng))
這是多個(gè)分支并行(同時(shí))執(zhí)行的,并且所有的分支Execution都到Join活動(dòng)后才離向后執(zhí)行。
7.4.?自定義活動(dòng)(Custom)
1,在<custom>元素中指定class屬性為指定的類。
2,這個(gè)類要實(shí)現(xiàn)ExternalActivityBehaviour接口,其中有兩個(gè)方法:
1,execute(ActivityExecution),節(jié)點(diǎn)的功能代碼
2,signal(ActivityExecution,?String,?Map),在當(dāng)前節(jié)點(diǎn)等待時(shí),外部發(fā)信號(hào)時(shí)的行為
3,在execute()方法中,可以調(diào)用以下方法對(duì)流程進(jìn)行控制
1,ActivityExecution.waitForSignal(),在當(dāng)前節(jié)點(diǎn)等待。
2,ActivityExecution.takeDefaultTransition(),使用默認(rèn)的Transition離開(kāi),當(dāng)前節(jié)點(diǎn)中定義的第一個(gè)為默認(rèn)的。
3,ActivityExecution.take(String?transitionName),使用指定的Transition離開(kāi)
4,ActivityExecution.end(),結(jié)束流程實(shí)例
4,也可以實(shí)現(xiàn)ActivityBehaviour接口,只有一個(gè)方法execute(ActivityExecution),這樣就不能等待,否則signal時(shí)會(huì)有類轉(zhuǎn)換異常。
7.5.?事件
1,?在根元素中,或在節(jié)點(diǎn)元素中,使用<on?event="">元素指定事件,其中event屬性代表事件的類型。
2,?在<on>中用子元素<event-listener?class="EventListenerImpl"?/>,指定處理的類,要求指定的類要實(shí)現(xiàn)EventListener接口
3,? 事件類型:
a)?<on>元素放在根元素(<process>)中,可以指定event為start或end,表示流程的開(kāi)始與結(jié)束。
b)?<on>元素放在節(jié)點(diǎn)元素中,可以指定event為start或end,表示節(jié)點(diǎn)的進(jìn)入與離開(kāi)
c)?在Start節(jié)點(diǎn)中只有end事件,在End節(jié)點(diǎn)中只有start事件。
d)?在<transition>元素中直接寫(xiě)<event-listener?class="">,就是配置事件。(因?yàn)樵谶@里只有一個(gè)事件,所以不用寫(xiě)on與類型)
e)?在<task>元素中還可以配置assign事件,是在分配任務(wù)時(shí)觸發(fā)的。
8.?jBPM4.4應(yīng)用
8.1.?與Spring集成(jBPM4.4?Developers?Guide,?Chapter?17.?Spring?Integration)
8.1.1.?在jbpm.cfg.xml中
1,刪除配置:<import?resource="jbpm.tx.hibernate.cfg.xml"?/>
2,增加配置:<import?resource="jbpm.tx.spring.cfg.xml"?/>
8.1.2.?在applicationContext.xml中配置
<!--?配置ProcessEngine(整合jBPM4)?-->
<!--?jbpmCfg是相對(duì)于classpath的相對(duì)路徑,默認(rèn)值為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"?/>
8.1.3.?測(cè)試
@Test?//?測(cè)試ProcessEngine
public?void?testProcessEngine()?{
ProcessEngine?processEngine?=?(ProcessEngine)ac.getBean("processEngine");
Assert.assertNotNull(processEngine);
}
8.1.4.?注意事項(xiàng)
如果做了JBPM4.4與Spring整合(使用了jbpm.tx.spring.cfg.xml),則在程序中就一定要使用Spring注入ProcessEngine,千萬(wàn)不能使用Configuration.getProcessEngine()生成ProcessEngine,因?yàn)檫@時(shí)內(nèi)部的代碼有以下邏輯:如果整合了Spring但沒(méi)有ApplicationContext,就默認(rèn)讀取applicationContext.xml創(chuàng)建ApplicationContext實(shí)例并從中獲取名為”P(pán)rocessEngine”的對(duì)象。而這時(shí)如果把pe?=?Configuration.getProcessEngine()寫(xiě)成某Spring中管理的bean的初始化代碼,就會(huì)有無(wú)限循環(huán),不停的創(chuàng)建ApplicationContext了!
8.2.?自行控制事務(wù)
1,?修改?jbpm.tx.hibernate.cfg.xml
a)?不讓jBPM自行管理事務(wù):去掉<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,?要使用同一個(gè)SessionFactory,且都要使用?SessionFactory.getCurrentSession()?獲取?Session:
a)?同一個(gè)SessionFactory:SessionFactory?sf?=?processEngine.get(SessionFactory.class)
b)?在?BaseDaoImpl?中增加:
i.?getSession()?{?return?HibernateUtils.getSessionFactory().getCurrentSession();?}
ii.?getProcessEngine(){?return?org.jbpm.api.Configuration.getProcessEngine();?}
4,?統(tǒng)一的打開(kāi)與提交或回滾事務(wù):使用?OpenSessionInViewFilter?控制事務(wù)。
8.3.?啟動(dòng)Tomcat后,訪問(wèn)JSP時(shí)(使用的是MyEclipse自帶的Tomcat,是6.0的版本),報(bào)錯(cuò):???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
說(shuō)明:原因是Jbpm的juel.jar,?juel-engine.jar,?juel-impl.jar包和Tomcat6.0中的el-api.jar包沖突了。
有三個(gè)解決辦法:
1,方法一:在MyEclipse的Preferences?->?MyEclipse?->?Application?Servers?->?Tomcat?->?..?->?Paths?中配置?Append?to?classpath,選中?juel.jar,?juel-engine.jar,?juel-impl.jar?這三個(gè)jar包就可以了。
2,方法二:將?juel.jar,?juel-engine.jar,?juel-impl.jar?這三個(gè)包復(fù)制到tomcat6下?lib/?中,并刪除原來(lái)的el-api.jar,
切記還要把工程中?WEB-INF\lib?下的?juel.jar,?juel-engine.jar,?juel-impl.jar?刪除,不然還是要沖突。
3,方法三:換成tomcat5.5,就沒(méi)有問(wèn)題了。
8.4.?完成流程實(shí)例中的最后一個(gè)任務(wù)時(shí)報(bào)錯(cuò)(任務(wù)實(shí)例結(jié)束時(shí)),或刪除流程定義級(jí)聯(lián)刪除流程實(shí)例時(shí),報(bào)錯(cuò)如下:
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_`))
解決辦法:把方言設(shè)為?MySQL5InnoDBDialect,不能是?MySQLDialect。
總結(jié)
以上是生活随笔為你收集整理的jbpm_工作流框架笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 什么中央空调的能耗比较低?
- 下一篇: 别墅二手房为什么难卖?