我们知道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