我們知道jbpm4.4提供了三種比較方便的分支跳轉方式,如下所示:
1.通過expression
<?xml version="1.0" encoding="UTF-8"?>
<process name="DecisionExpression" xmlns="http://jbpm.org/4.4/jpdl">
<start g="16,102,48,48">
<transition to="evaluate document"/>
</start>
<decision name="evaluate document" expr="#{content}" g="96,102,48,48">
<transition name="good" to="submit document" g="120,60:-36,23" />
<transition name="bad" to="try again" g=":-15,-21" />
<transition name="ugly" to="give up" g="120,189:-35,-41" />
</decision>
<state name="submit document" g="175,35,122,52" />
<state name="try again" g="176,100,122,52" />
<state name="give up" g="177,164,122,52" />
</process>
2.通過handler
<?xml version="1.0" encoding="UTF-8"?>
<process name="DecisionHandler" xmlns="http://jbpm.org/4.4/jpdl">
<start g="16,102,48,48">
<transition to="evaluate document" name=""/>
</start>
<decision name="evaluate document" g="96,102,48,48">
<handler class="org.jbpm.examples.decision.handler.ContentEvaluation"/>
<transition name="good" to="submit document" g="120,60:-37,22" />
<transition name="bad" to="try again" g=":-19,-22" />
<transition name="ugly" to="give up" g="120,189:-33,-39" />
</decision>
<state name="submit document" g="175,35,122,52" />
<state name="try again" g="176,100,122,52" />
<state name="give up" g="177,164,122,52" />
</process>
3.通過condition
<?xml version="1.0" encoding="UTF-8"?>
<process name="DecisionConditions" xmlns="http://jbpm.org/4.4/jpdl">
<start g="16,102,48,48">
<transition to="evaluate document" />
</start>
<decision name="evaluate document" g="96,102,48,48">
<transition to="submit document" g="120,60:">
<condition expr="#{content=="good"}" />
</transition>
<transition to="try again">
<condition expr="#{content=="bad"}" />
</transition>
<transition to="give up" g="120,189:" />
</decision>
<state name="submit document" g="175,35,122,52"/>
<state name="try again" g="176,100,122,52"/>
<state name="give up" g="177,164,122,52"/>
</process>
我們發現這種方式,若一旦我們的流程定義完成後,再想在運行中動態改變這種分支條件的設計就很難了,但是我們知道可以在流程定義發佈到後臺後,我們可以提供動態修改xml的方式,用handler的方式加上我們的分支決定的decision(需要實現jpbm的decision接口即可),通過handler來實現分支有一個比較大的優點就是我們可以在handler動態去執行我們需要工作流額外執行的代碼,並且可以通過這個判斷來決定其跳轉的路徑。
但我們不可能爲所有的有分支決定的流程都加一個decision handler,並且在裏面進行動態的分支判斷。那樣的工作很大,並且不靈活。
我們看一下第二種handler的接口:
package org.jbpm.examples.decision.handler;
import org.jbpm.api.jpdl.DecisionHandler;
import org.jbpm.api.model.OpenExecution;
public class ContentEvaluation implements DecisionHandler {
private static final long serialVersionUID = 1L;
public String decide(OpenExecution execution) {
String content = (String) execution.getVariable("content");
if (content.equals("you're great")) {
return "good";
}
if (content.equals("you gotta improve")) {
return "bad";
}
return "ugly";
}
}
在這裏我們可以看到,可以通過動態返回跳轉路徑則可。在上面我說過了,不能把這個返回值交給具體的decisionHandler來決定,這個決定應該由流程運行來動態決定,我們需要告訴這個handler,你需要按我的規則來運行計算,得到一個運行跳轉的路徑。於是我想到能不能用bsh有腳本來動態返回告訴這個handler如何執行。
以下我們以一個簡單的訂單流程來說明如何實現這個動態設計分支跳轉。
首先我在線設計了一個流程,如下所示:
發佈後,設計其分支條件,如下所示:
我們在條件那裏加入流程干預:
String tranTo="金額小於2000元";
if(price*quantity>=2000){
tranTo="金額大於等於2000";
}
這個tranTo則是由我們系統的管理員來控制,大家發現其本身就是java代碼來的,熟悉一些簡單的java語法均可以。當然若我們在這裏還可以做一些更復雜的操作,如執行調用第三方系統的接口等。
那麼以上的price與quantity變量來自哪裏呢?它們是流程表單裏的字段,於是我們爲這個流程動態綁定一個流程表單。
首先我們設計一個流程表單:
其對應的字段映射爲:
在後臺綁定該表單:
啓動流程:
執行後,可以看到流程自動判斷跳轉:
我們看一下本身我們的handler如何寫:
package com.htsoft.oa.workflow.handler;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.api.ProcessDefinition;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.jpdl.DecisionHandler;
import org.jbpm.api.model.Activity;
import org.jbpm.api.model.OpenExecution;
import bsh.EvalError;
import bsh.Interpreter;
import com.htsoft.core.util.AppUtil;
import com.htsoft.oa.model.flow.ProHandleComp;
import com.htsoft.oa.service.flow.ProHandleCompService;
/**
* 實現分支決定,可以在這裏根據業務邏輯計算,決定分支的跳轉
* @author
*
*/
public class DecisionHandlerImpl implements DecisionHandler{
private static final Log logger=LogFactory.getLog(DecisionHandlerImpl.class);
@Override
public String decide(OpenExecution execution) {
logger.debug("enter decision handler....");
ProcessEngine processEngine=(ProcessEngine)AppUtil.getBean("processEngine");
ProHandleCompService proHandleCompService=(ProHandleCompService)AppUtil.getBean("proHandleCompService");
String pdId=execution.getProcessDefinitionId();
ProcessDefinition processDefinition= processEngine.getRepositoryService().createProcessDefinitionQuery().processDefinitionId(pdId).uniqueResult();
String deployId=processDefinition.getDeploymentId();
Activity curActivity=execution.getActivity();
List<ProHandleComp> list=proHandleCompService.getByDeployIdActivityNameHandleType(deployId, curActivity.getName(), ProHandleComp.HANDLE_TYPE_HANDLER);
if(list.size()>0){
ProHandleComp proHandleComp=list.get(0);
logger.info("exeCode:" + proHandleComp.getExeCode());
//執行動態
Interpreter it=new Interpreter();
try {
//取得所有流程變量,放於bsh環境,方便在bsh腳本環境中運行以方便決定流程跳轉
Map<String,Object> vars=(Map<String,Object>)execution.getVariables();
Iterator<Entry<String, Object>> iterator= vars.entrySet().iterator();
while(iterator.hasNext()){
Entry<String, Object> entry=iterator.next();
String key=entry.getKey();
Object val=entry.getValue();
it.set(key.replace(".", "_"), val);
}
logger.info("dynamic execution code tranTo:"+proHandleComp.getExeCode());
it.eval(proHandleComp.getExeCode());
String tran=(String)it.get("tranTo");
logger.info("return tranTo:"+tran);
return tran;
} catch (EvalError e) {
e.printStackTrace();
}
}
return null;
}
}
裏面其實比較簡單,就是通過動態執行那個給用戶開放的代碼片段,並且根據其tranTo變量的值來決定其如何跳轉,在上面的例子就是流程表單中的金額是否大於2000元來跳轉。
同樣,我們知道jbpm4_lob中存着jbpm4的流程定義的xml文件,只要把動態修改jbpm4的流程定義,可以爲我們的作何節點加上我們需要流程動態執行的事件及代碼。請關注後續的文章,有介紹如何擴展jbpm4的流程事件。
在線看預覽情況:
http://bbs.jee-soft.cn/swf/design_decision.html
http://bbs.jee-soft.cn/posts/list/285.page#384
在線測試地址:
網通:
http://oa.jee-soft.cn:8080/index.jsp
電信:
http://office.jee-soft.cn:8080/index.jsp
用戶:admin,密碼:1