一、Activiti的流程分支条件的局限
Activiti的流程分支条件目前是采用脚本判断方式,并且需要在流程定义中进行分支条件的设定,如下图所示:
<sequenceFlow id="flow2" sourceRef="exclusiveGw" targetRef="theTask1"> <conditionExpression xsi:type="tFormalExpression">${input == 1}</conditionExpression> </sequenceFlow> <sequenceFlow id="flow3" sourceRef="exclusiveGw" targetRef="theTask2"> <conditionExpression xsi:type="tFormalExpression">${input == 2}</conditionExpression> </sequenceFlow> <sequenceFlow id="flow4" sourceRef="exclusiveGw" targetRef="theTask3"> <conditionExpression xsi:type="tFormalExpression">${input == 3}</conditionExpression> </sequenceFlow>
从上面的定义可以看到,流程的分支条件存在以下两个致命的局限性:
1.分支条件需要在流程定义(XML)中设定,这要求流程定义必须由开发人员来设计及编写
2.分支条件比较简单,一般为boolean表达式,表达式里的为单变量的判断处理。
以上两个局限性限制了流程的分支判断处理必须由开发人员来设定,而国内的大部分的流程应用都要求是普通的业务人员即可处理,或者是由有一定计算机基础的人员来设置处理。这要求我们对流程的条件设置提出了更高的要求,上一节我们通过修改Activiti的流程定义的XML中的分支条件表达式,同时刷新流程定义的引擎缓存,如下的代码就是基于这种方式:
JsonNode jsonObject=objectMapper.readTree(configJson); JsonNode configsNode=jsonObject.get("configs"); BpmSolution bpmSolution=bpmSolutionManager.get(solId); BpmDef bpmDef=bpmDefManager.getLatestBpmByKey(bpmSolution.getDefKey(), ContextUtil.getCurrentTenantId()); ActProcessDef processDef=actRepService.getProcessDef(bpmDef.getActDefId()); String processDefXml=actRepService.getBpmnXmlByDeployId(bpmDef.getActDepId()); System.out.println("xml:"+processDefXml); ActNodeDef sourceNode=processDef.getNodesMap().get(nodeId); ByteArrayInputStream is=new ByteArrayInputStream(processDefXml.getBytes()); Map<String,String> map = new HashMap<String,String>(); map.put("bpm","http://www.omg.org/spec/BPMN/20100524/MODEL"); map.put("xsi","http://www.omg.org/spec/BPMN/20100524/MODEL"); SAXReader saxReader = new SAXReader(); saxReader.getDocumentFactory().setXPathNamespaceURIs(map); Document doc = saxReader.read(is); //Document doc=Dom4jUtil.load(is, "UTF-8"); Element rootEl=doc.getRootElement(); if(configsNode!=null){ //取得分支条件列表 JsonNode configs=configsNode.get("conditions"); if(configs!=null){ Iterator<JsonNode> it=configs.elements(); while(it.hasNext()){ ObjectNode config=(ObjectNode)it.next(); String tmpNodeId=config.get("nodeId").textValue(); String tmpCondition=config.get("condition").textValue(); Element seqFlow=(Element)rootEl.selectSingleNode("/bpm:definitions/bpm:process/bpm:sequenceFlow[@sourceRef='" +sourceNode.getNodeId()+"' and @targetRef='"+tmpNodeId+"']"); if(seqFlow==null) continue; Element conditionExpress=(Element)seqFlow.selectSingleNode("bpm:conditionExpression"); if(conditionExpress==null){ conditionExpress=seqFlow.addElement("conditionExpression"); conditionExpress.addAttribute("xsi:type", "tFormalExpression"); }else{ conditionExpress.clearContent(); } conditionExpress.addCDATA(tmpCondition); } } } //修改流程定义的XML,并且清空该流程定义的缓存 actRepService.doModifyXmlAndClearCache(bpmDef.getActDefId(),bpmDef.getActDepId(), doc.asXML());
【说明】
1.基于这种方式容易出错,因为流程的分支条件写回流程定义的XML是比较容易出问题的,同时不清楚人员填写什么条件回XML文件中。
2.对于Jsaas中的一个流程定义可用于多个流程解决方案中使用配置不同的条件不太适合,因为一个流程定义是一样,但可能会分支的条件设置不一样。
基于以上的要求,为此我们对Activiti进行扩展,以使得我们可以允许流程引擎在分支判断处理中,执行我们的条件设置,其原理如下:
当流程引擎跳至分支条件判断处理时,可以让它执行我们的脚本设置条件,条件满足时,则跳至我们的设置的目标节点,从而实现干预流程引擎本身的执行方式,为了不影响Activiti的原的运行机制,我们还是保留其旧的执行判断方式。
二、Activiti的扩展点
Activiti的流程扩展是比较灵活的,我们通过改写这个ExclusiveGateway的节点的行为方法即可,其实现方法如下:
package com.redxun.bpm.activiti.ext; import java.util.Iterator; import javax.annotation.Resource; import org.activiti.engine.impl.bpmn.behavior.ExclusiveGatewayActivityBehavior; import org.activiti.engine.impl.pvm.PvmTransition; import org.activiti.engine.impl.pvm.delegate.ActivityExecution; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.redxun.bpm.core.entity.config.ExclusiveGatewayConfig; import com.redxun.bpm.core.entity.config.NodeExecuteScript; import com.redxun.bpm.core.manager.BpmNodeSetManager; import com.redxun.core.script.GroovyEngine; import com.sun.star.uno.RuntimeException; /** * 对网关的条件判断,优先使用扩展的配置 * @author keitch * */ @SuppressWarnings("serial") public class ExclusiveGatewayActivityBehaviorExt extends ExclusiveGatewayActivityBehavior{ protected static Logger log = LoggerFactory.getLogger(ExclusiveGatewayActivityBehaviorExt.class); //节点的设置管理器 @Resource BpmNodeSetManager bpmNodeSetManager; //脚本引擎 @Resource GroovyEngine groovyEngine; @Override protected void leave(ActivityExecution execution) { log.debug("enter ExclusiveGatewayActivityBehaviorExt======================="); if (log.isDebugEnabled()) { log.debug("Leaving activity '{}'", execution.getActivity().getId()); } String solId=(String)execution.getVariable("solId"); String nodeId=execution.getActivity().getId(); log.debug("solid is {} and nodeId is {}",solId,nodeId); if(StringUtils.isNotEmpty(solId)&& StringUtils.isNotBlank(nodeId)){ ExclusiveGatewayConfig configs=bpmNodeSetManager.getExclusiveGatewayConfig(solId, nodeId); for(NodeExecuteScript script:configs.getConditions()){ String destNodeId=script.getNodeId(); String condition=script.getCondition(); log.debug("dest node:{}, condition is {}",destNodeId,condition); //执行脚本引擎 Object boolVal=groovyEngine.executeScripts(condition, execution.getVariables()); if(boolVal instanceof Boolean){ Boolean returnVal=(Boolean)boolVal;//符合条件 if(returnVal==true){ //找到符合条件的目标节点并且进行跳转 Iterator<PvmTransition> transitionIterator = execution.getActivity().getOutgoingTransitions().iterator(); while (transitionIterator.hasNext()) { PvmTransition seqFlow = transitionIterator.next(); if(destNodeId.equals(seqFlow.getDestination().getId())){ execution.take(seqFlow); return; } } } }else{ throw new RuntimeException("表达式:\n "+condition+"\n返回值不为布尔值(true or false)"); } } } //执行父类的写法,以使其还是可以支持旧式的在跳出线上写条件的做法 super.leave(execution); } }
我们通过继续改写了这个分支节点的跳出机制,并且通过脚本引擎来执行其条件分支的判断处理,但流程引擎并不了解我们扩展的类,这时我们需要配置Activiti流程引擎的行为动作工厂类,如下所示:
package com.redxun.bpm.activiti.ext; import org.activiti.bpmn.model.ExclusiveGateway; import org.activiti.engine.impl.bpmn.behavior.ExclusiveGatewayActivityBehavior; import org.activiti.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory; /** * 扩展缺省的流程节点默认工厂类,实现对Activiti节点的执行的默认行为的更改 * @author keitch * */ public class ActivityBehaviorFactoryExt extends DefaultActivityBehaviorFactory { private ExclusiveGatewayActivityBehaviorExt exclusiveGatewayActivityBehaviorExt; /** * 通过Spring容器注入新的分支条件行为执行类 * @param exclusiveGatewayActivityBehaviorExt */ public void setExclusiveGatewayActivityBehaviorExt(ExclusiveGatewayActivityBehaviorExt exclusiveGatewayActivityBehaviorExt) { this.exclusiveGatewayActivityBehaviorExt = exclusiveGatewayActivityBehaviorExt; } //重写父类中的分支条件行为执行类 @Override public ExclusiveGatewayActivityBehavior createExclusiveGatewayActivityBehavior(ExclusiveGateway exclusiveGateway) { return exclusiveGatewayActivityBehaviorExt; } }
三、Activiti的Spring配置的更改
在Activiti的流程引擎配置中加入新的流程行为动作执行工厂类。配置如下所示,注意activityBehaviorFactory的属性配置:
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> <property name="dataSource" ref="dataSource" /> <property name="transactionManager" ref="transactionManager" /> <property name="databaseSchemaUpdate" value="true" /> <property name="jobExecutorActivate" value="false" /> <property name="enableDatabaseEventLogging" value="false" /> <property name="databaseType" value="${db.type}" /> <property name="idGenerator" ref="actIdGenerator"/> <property name="eventListeners"> <list> <ref bean="globalEventListener"/> </list> </property> <property name="activityFontName" value="宋体"/> <property name="labelFontName" value="宋体"/> <!-- 用于更改流程节点的执行行为 --> <property name="activityBehaviorFactory" ref="activityBehaviorFactoryExt"/> </bean> <bean id="activityBehaviorFactoryExt" class="com.redxun.bpm.activiti.ext.ActivityBehaviorFactoryExt"> <property name="exclusiveGatewayActivityBehaviorExt" ref="exclusiveGatewayActivityBehaviorExt"/> </bean> <bean id="exclusiveGatewayActivityBehaviorExt" class="com.redxun.bpm.activiti.ext.ExclusiveGatewayActivityBehaviorExt"/>
通过以上方式扩展后,节点的分支设置可以把条件表达式写成以下方式,同时条件存于流程定义的外部表中:
相关推荐
本代码,技术为springboot activiti 工作流引擎技术,人员可以动态设置自定义流程,后台生成流程图并且部署流程,
springboot+activiti+bootstrap+angular 整合自定义流程设计,带数据库文件,适合初学者,以及需要深入研究的码农
activiti6.0实现流程图片自定义颜色 当前任务为红色,走过的任务为绿色,自定义文字颜色连线文字显示
重写流程图生产代码,需要枪原来的图片生产代码复写,原版的颜色生产不支付传入颜色参数,重写之后支持自定义颜色参数!用于区分流程状态
activiti和springboot整合只使用application.properties配置文件,解决了jdbc长时间待机连接被收回报错。使用springProcessEngineConfiguration对activiti管理
mybatis+activiti连接金仓数据库驱动和spring配置,数据库方言服务类。 项目是ssm原数据库sqlserver转金仓数据库。
整个过程不影响activiti的设计,使用的是ExecutionEntity实现任务的销毁及重新指定任务节点的方式实现最终的撤回操作
簡單activiti demo 整全SPRING
Activiti5 下 Activiti Modeler 汉化配置文件 stencilset.json 建议先备份原文件,之后替换即可
集成activiti的springboot程序,带有自定义表单设计,低代码开发平台。
Activiti可以通过自定义实现SessionFactory,实现customUserManager和customRoleManager的方式集成第三方的用户关系。 这里我介绍一个方法,可以借助Liferay的实体监听器来做用户、组、用户-组成员关系的三种同步。...
Activiti多实例任务实现会签.
开发可视化工作流配置,可以参考这个demo,可以跟自己的项目进行集成,已经与mysql8.0进行集成
结合例子简单介绍了Activiti的内置表单和外置表单
基于若依的工作流开发文档,此文档可以进行二次开发并自由创建
数据库配置文件是:workflow-designer\src\META-INF\activiti-app\activiti-app.properties 默认登录的用户名、密码:admin\test 另外,改造后只有admin可以看到所有功能,其他自建用户部分功能是不可见的,如果要...
activiti流程图高亮显示配置,为了方便别人快速配置,特此编辑此贴,盼同行们多多支持小编,原创不容易!
文档详细介绍了MyEclipse的安装以及Activiti插件的配置,并以数字城市的简单流程为例,介绍了工作流的基本建立方式
springboot2+activiti 7 整合-- 创建activiti数据库 (一)创建工程,贴出maven配置 (二)创建 activiti.cfg.xml文件 (三)建表程序
博客中activiti自定义流程demo