惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

腾讯CDC
Schneier on Security
Schneier on Security
B
Blog RSS Feed
aimingoo的专栏
aimingoo的专栏
P
Proofpoint News Feed
A
About on SuperTechFans
Recorded Future
Recorded Future
Recent Announcements
Recent Announcements
Microsoft Security Blog
Microsoft Security Blog
L
LangChain Blog
Hugging Face - Blog
Hugging Face - Blog
The GitHub Blog
The GitHub Blog
Google DeepMind News
Google DeepMind News
T
Tailwind CSS Blog
Vercel News
Vercel News
H
Hackread – Cybersecurity News, Data Breaches, AI and More
MyScale Blog
MyScale Blog
V2EX - 技术
V2EX - 技术
N
Netflix TechBlog - Medium
F
Fortinet All Blogs
V
Visual Studio Blog
Martin Fowler
Martin Fowler
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
博客园 - Franky
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
The Exploit Database - CXSecurity.com
F
Full Disclosure
Scott Helme
Scott Helme
H
Heimdal Security Blog
博客园 - 叶小钗
Google DeepMind News
Google DeepMind News
Cyberwarzone
Cyberwarzone
Application and Cybersecurity Blog
Application and Cybersecurity Blog
V
Vulnerabilities – Threatpost
Blog — PlanetScale
Blog — PlanetScale
Security Latest
Security Latest
WordPress大学
WordPress大学
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
Troy Hunt's Blog
S
SegmentFault 最新的问题
Forbes - Security
Forbes - Security
Jina AI
Jina AI
S
Securelist
小众软件
小众软件
Simon Willison's Weblog
Simon Willison's Weblog
J
Java Code Geeks
AWS News Blog
AWS News Blog
N
News and Events Feed by Topic
博客园 - 三生石上(FineUI控件)
量子位

博客园 - 航宇

关于table中使用了colspan后导致列宽度失效问题 Tomcat9 easyui-datagrid中文分页乱码,提示按钮中文乱码解决方法 修复tomcat9.0中文乱码 maven项目中更新了核心库后导致一些包提示未定义,如:The import org.json cannot be resolved js代码突然在花括号回车自动多加了一个大括号 SQL0419N 十进制除法运算无效,因为结果将有一个负小数位。 SQLSTATE=42911 android listview里包含组件(checkbox)点击事件和Item的点击事件冲突 jsp页面的html代码显示不出来,提示Uncaught SyntaxError: Unexpected token < hibernate中怎样配置两个联合属性为唯一约束(非联合主键) maven 在clean package时,出现:找不到符号 [ERROR] 符号: 方法 sqlDdlFilter(java.lang.String) 解决办法 生成验证码 给area标签添加红色边框 android shape 怎么在底部画横线 ListView点击事件失效(item里面有button按钮控件)解决方法 [IBM][CLI Driver] SQL0270N 函数不受支持(原因码:"75")。 SQLSTATE=42997 ScrollView嵌套Linearlayout显示不全的解决办法 android 可以在程序代码中设置样式:style 基于Zxing的二维码的二维码扫描之横屏扫描 Tomcat Connector的三种运行模式
如何实现Activiti的分支条件的自定义配置(转)
航宇 · 2018-08-08 · via 博客园 - 航宇

一、Activiti的流程分支条件的局限

Activiti的流程分支条件目前是采用脚本判断方式,并且需要在流程定义中进行分支条件的设定,如下图所示:



 

Xml代码  收藏代码

  1. <sequenceFlow id="flow2" sourceRef="exclusiveGw" targetRef="theTask1">  
  2.   <conditionExpression xsi:type="tFormalExpression">${input == 1}</conditionExpression>  
  3. </sequenceFlow>  
  4. <sequenceFlow id="flow3" sourceRef="exclusiveGw" targetRef="theTask2">  
  5.   <conditionExpression xsi:type="tFormalExpression">${input == 2}</conditionExpression>  
  6. </sequenceFlow>  
  7. <sequenceFlow id="flow4" sourceRef="exclusiveGw" targetRef="theTask3">  
  8.   <conditionExpression xsi:type="tFormalExpression">${input == 3}</conditionExpression>  
  9. </sequenceFlow>  

从上面的定义可以看到,流程的分支条件存在以下两个致命的局限性:

1.分支条件需要在流程定义(XML)中设定,这要求流程定义必须由开发人员来设计及编写

2.分支条件比较简单,一般为boolean表达式,表达式里的为单变量的判断处理。

以上两个局限性限制了流程的分支判断处理必须由开发人员来设定,而国内的大部分的流程应用都要求是普通的业务人员即可处理,或者是由有一定计算机基础的人员来设置处理。这要求我们对流程的条件设置提出了更高的要求,上一节我们通过修改Activiti的流程定义的XML中的分支条件表达式,同时刷新流程定义的引擎缓存,如下的代码就是基于这种方式:

Java代码  收藏代码

  1. JsonNode jsonObject=objectMapper.readTree(configJson);  
  2.   JsonNode configsNode=jsonObject.get("configs");  
  3.               
  4.   BpmSolution bpmSolution=bpmSolutionManager.get(solId);  
  5.   BpmDef bpmDef=bpmDefManager.getLatestBpmByKey(bpmSolution.getDefKey(), ContextUtil.getCurrentTenantId());  
  6.             ActProcessDef processDef=actRepService.getProcessDef(bpmDef.getActDefId());  
  7.             String processDefXml=actRepService.getBpmnXmlByDeployId(bpmDef.getActDepId());  
  8.               
  9.             System.out.println("xml:"+processDefXml);  
  10.               
  11.             ActNodeDef sourceNode=processDef.getNodesMap().get(nodeId);  
  12.             ByteArrayInputStream is=new ByteArrayInputStream(processDefXml.getBytes());  
  13.               
  14.             Map<String,String> map = new HashMap<String,String>();    
  15.             map.put("bpm","http://www.omg.org/spec/BPMN/20100524/MODEL");    
  16.             map.put("xsi","http://www.omg.org/spec/BPMN/20100524/MODEL");    
  17.             SAXReader saxReader = new SAXReader();    
  18.             saxReader.getDocumentFactory().setXPathNamespaceURIs(map);    
  19.             Document doc = saxReader.read(is);    
  20.                   
  21.             
  22.             Element rootEl=doc.getRootElement();  
  23.               
  24.             if(configsNode!=){  
  25.                 
  26.                 JsonNode configs=configsNode.get("conditions");  
  27.                 if(configs!=){  
  28.                     Iterator<JsonNode> it=configs.elements();  
  29.                     while(it.hasNext()){  
  30.                         ObjectNode config=(ObjectNode)it.next();  
  31.                         String tmpNodeId=config.get("nodeId").textValue();  
  32.                         String tmpCondition=config.get("condition").textValue();  
  33.                           
  34.                         Element seqFlow=(Element)rootEl.selectSingleNode("/bpm:definitions/bpm:process/bpm:sequenceFlow[@sourceRef='"  
  35.                         +sourceNode.getNodeId()+"' and @targetRef='"+tmpNodeId+"']");  
  36.                         if(seqFlow==continue;  
  37.                           
  38.                         Element conditionExpress=(Element)seqFlow.selectSingleNode("bpm:conditionExpression");  
  39.                         if(conditionExpress==){  
  40.                             conditionExpress=seqFlow.addElement("conditionExpression");  
  41.                             conditionExpress.addAttribute("xsi:type", "tFormalExpression");  
  42.                         }else{  
  43.                             conditionExpress.clearContent();  
  44.                         }  
  45.                         conditionExpress.addCDATA(tmpCondition);  
  46.                           
  47.                     }  
  48.                 }  
  49.             }  
  50.             
  51.             actRepService.doModifyXmlAndClearCache(bpmDef.getActDefId(),bpmDef.getActDepId(), doc.asXML());  

【说明】

1.基于这种方式容易出错,因为流程的分支条件写回流程定义的XML是比较容易出问题的,同时不清楚人员填写什么条件回XML文件中。

2.对于Jsaas中的一个流程定义可用于多个流程解决方案中使用配置不同的条件不太适合,因为一个流程定义是一样,但可能会分支的条件设置不一样。

基于以上的要求,为此我们对Activiti进行扩展,以使得我们可以允许流程引擎在分支判断处理中,执行我们的条件设置,其原理如下:



 

当流程引擎跳至分支条件判断处理时,可以让它执行我们的脚本设置条件,条件满足时,则跳至我们的设置的目标节点,从而实现干预流程引擎本身的执行方式,为了不影响Activiti的原的运行机制,我们还是保留其旧的执行判断方式。

二、Activiti的扩展点

Activiti的流程扩展是比较灵活的,我们通过改写这个ExclusiveGateway的节点的行为方法即可,其实现方法如下:

Java代码  收藏代码

  1. package com.redxun.bpm.activiti.ext;  
  2. import java.util.Iterator;  
  3. import javax.annotation.Resource;  
  4. import org.activiti.engine.impl.bpmn.behavior.ExclusiveGatewayActivityBehavior;  
  5. import org.activiti.engine.impl.pvm.PvmTransition;  
  6. import org.activiti.engine.impl.pvm.delegate.ActivityExecution;  
  7. import org.apache.commons.lang.StringUtils;  
  8. import org.slf4j.Logger;  
  9. import org.slf4j.LoggerFactory;  
  10.   
  11. import com.redxun.bpm.core.entity.config.ExclusiveGatewayConfig;  
  12. import com.redxun.bpm.core.entity.config.NodeExecuteScript;  
  13. import com.redxun.bpm.core.manager.BpmNodeSetManager;  
  14. import com.redxun.core.script.GroovyEngine;  
  15. import com.sun.star.uno.RuntimeException;  
  16. @SuppressWarnings("serial")  
  17. public class ExclusiveGatewayActivityBehaviorExt extends ExclusiveGatewayActivityBehavior{  
  18.       
  19.     protected static Logger log = LoggerFactory.getLogger(ExclusiveGatewayActivityBehaviorExt.class);  
  20.       
  21.     
  22.     @Resource  
  23.     BpmNodeSetManager bpmNodeSetManager;  
  24.     
  25.     @Resource GroovyEngine groovyEngine;  
  26.       
  27.     @Override  
  28.     protected void leave(ActivityExecution execution) {  
  29.         log.debug("enter ExclusiveGatewayActivityBehaviorExt=======================");  
  30.         if (log.isDebugEnabled()) {  
  31.             log.debug("Leaving activity '{}'", execution.getActivity().getId());  
  32.          }  
  33.         String solId=(String)execution.getVariable("solId");  
  34.         String nodeId=execution.getActivity().getId();  
  35.         log.debug("solid is {} and nodeId is {}",solId,nodeId);  
  36.           
  37.         if(StringUtils.isNotEmpty(solId)&& StringUtils.isNotBlank(nodeId)){  
  38.             ExclusiveGatewayConfig configs=bpmNodeSetManager.getExclusiveGatewayConfig(solId, nodeId);  
  39.             for(NodeExecuteScript script:configs.getConditions()){  
  40.                 String destNodeId=script.getNodeId();  
  41.                 String condition=script.getCondition();  
  42.                 log.debug("dest node:{}, condition is {}",destNodeId,condition);  
  43.                 
  44.                 Object boolVal=groovyEngine.executeScripts(condition, execution.getVariables());  
  45.                 if(boolVal instanceof Boolean){  
  46.                     Boolean returnVal=(Boolean)boolVal;
  47.                     if(returnVal==true){  
  48.                         
  49.                         Iterator<PvmTransition> transitionIterator = execution.getActivity().getOutgoingTransitions().iterator();  
  50.                         while (transitionIterator.hasNext()) {  
  51.                               PvmTransition seqFlow = transitionIterator.next();  
  52.                               if(destNodeId.equals(seqFlow.getDestination().getId())){  
  53.                                   execution.take(seqFlow);  
  54.                                   return;  
  55.                               }  
  56.                         }  
  57.                     }  
  58.                 }else{  
  59.                     throw new RuntimeException("表达式:\n "+condition+"\n返回值不为布尔值(true or false)");  
  60.                 }  
  61.             }  
  62.         }  
  63.         
  64.         super.leave(execution);  
  65.           
  66.     }  
  67. }  

我们通过继续改写了这个分支节点的跳出机制,并且通过脚本引擎来执行其条件分支的判断处理,但流程引擎并不了解我们扩展的类,这时我们需要配置Activiti流程引擎的行为动作工厂类,如下所示:

Java代码  收藏代码

  1. package com.redxun.bpm.activiti.ext;  
  2.   
  3. import org.activiti.bpmn.model.ExclusiveGateway;  
  4. import org.activiti.engine.impl.bpmn.behavior.ExclusiveGatewayActivityBehavior;  
  5. import org.activiti.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory;  
  6.   
  7. public class ActivityBehaviorFactoryExt extends DefaultActivityBehaviorFactory {  
  8.       
  9.     private ExclusiveGatewayActivityBehaviorExt exclusiveGatewayActivityBehaviorExt;  
  10.       
  11.     
  12.     public void setExclusiveGatewayActivityBehaviorExt(ExclusiveGatewayActivityBehaviorExt exclusiveGatewayActivityBehaviorExt) {  
  13.         this.exclusiveGatewayActivityBehaviorExt = exclusiveGatewayActivityBehaviorExt;  
  14.     }  
  15.       
  16.     
  17.     @Override  
  18.     public ExclusiveGatewayActivityBehavior createExclusiveGatewayActivityBehavior(ExclusiveGateway exclusiveGateway) {  
  19.         return exclusiveGatewayActivityBehaviorExt;  
  20.     }  
  21. }  

三、Activiti的Spring配置的更改

在Activiti的流程引擎配置中加入新的流程行为动作执行工厂类。配置如下所示,注意activityBehaviorFactory的属性配置:

Xml代码  收藏代码

  1. <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">  
  2.     <property name="dataSource" ref="dataSource" />  
  3.     <property name="transactionManager" ref="transactionManager" />  
  4.     <property name="databaseSchemaUpdate" value="true" />  
  5.     <property name="jobExecutorActivate" value="false" />  
  6.     <property name="enableDatabaseEventLogging" value="false" />  
  7.     <property name="databaseType" value="${db.type}" />  
  8.     <property name="idGenerator" ref="actIdGenerator"/>  
  9.     <property name="eventListeners">  
  10.       <list>  
  11.         <ref bean="globalEventListener"/>  
  12.       </list>  
  13.     </property>  
  14.     <property name="activityFontName" value="宋体"/>  
  15.     <property name="labelFontName" value="宋体"/>  
  16.     
  17.     <property name="activityBehaviorFactory" ref="activityBehaviorFactoryExt"/>  
  18.   </bean>  
  19.     
  20.     
  21.   <bean id="activityBehaviorFactoryExt" class="com.redxun.bpm.activiti.ext.ActivityBehaviorFactoryExt">  
  22.     <property name="exclusiveGatewayActivityBehaviorExt" ref="exclusiveGatewayActivityBehaviorExt"/>  
  23.   </bean>  
  24.     
  25.   <bean id="exclusiveGatewayActivityBehaviorExt" class="com.redxun.bpm.activiti.ext.ExclusiveGatewayActivityBehaviorExt"/>  

通过以上方式扩展后,节点的分支设置可以把条件表达式写成以下方式,同时条件存于流程定义的外部表中:


 

posted on 2018-08-08 21:19  航宇  阅读(12244)  评论()    收藏  举报