本文主要讲解如何扩展activiti,使其支持任意属性配置。
先来看下效果
这个流程的分支二这个人员设置,实际存放xml格式如下:
<userTask id="Activity_03o1wx2" name="分支二" workflow:assignee="">
<extensionElements>
<workflow:rules>
<workflow:field name="assignmentrule">
<workflow:string>{"combo":{"type":"sdar"},"advanced":{"dataType":"user"},"handleType":"candidate","handler":"02020072317480678600000101001100","handlerName":"流程发起人","candidate":{"users":[{"value":"25711a8bbcc542f985877c2d09a5d744","name":"王五","lname":"wangwu"}]}}</workflow:string>
</workflow:field>
<workflow:field name="transferrule">
<workflow:string>{"type":"manual","nodeSelectType":"system","autoCondition":[]}</workflow:string>
</workflow:field>
<workflow:field name="handlerule">
<workflow:string>{"handleType":"grab","counterSign":{"handleScope":"user"}}</workflow:string>
</workflow:field>
<workflow:field name="formrule">
<workflow:string>{}</workflow:string>
</workflow:field>
</workflow:rules>
</extensionElements>
<incoming>Flow_1wjzuu6</incoming>
<outgoing>Flow_1dv7b8l</outgoing>
</userTask>
assignmentrule就是我自己定义的办理人员规则,实际使用中我们可以根据我们的需求任务扩展属性,只要设计好我们属性对象的json格式就行,大概看一下我们定义的一些属性规则
"stencil": {
"id": "UserTask"
},
"properties": {
"overrideid": "applyStep", //自定义ID
"name": "申请登记",//节点名称
"documentation": "这是申请登记",//节点描述
"formrule" :{//表单设置
"formType":"dynamic",//表单类型 dynamic:动态 url:在线
"urlForm":"/apply/form",//formType为url 时有值
"dynamicForm":{//formType为dynamic 时有值
"formId":"applyForm",//表单ID
"formName":"申请登记单",//表单名称
"fields":[{//表单字段设置
"fieldId":"applyId",//字段 ID
"fieldName":"申请人",//字段 名称
"readOnly":true,//是否只读
"hidden":false//是否显示
}]
},
"mobileForm":""//手机表单
},
"assignmentrule": { //分配设置
"handler":"zsld", //选择常用处理人是有值
"candidate": {//人员选择
"users": [{ //候选人
"value": "11", //用户ID
"name":"张三"//用户名称
}, {
"value": "22",
"name":"李四"
}],
"depts": [{//候选组
"value": "33",//机构ID
"name":"武汉研发中心"//机构名称
}],
"roles": [{//修行角色
"value": "44",//角色ID
"name":"项目经理"//角色名称
}]
},
"advanced":{//高级设置
"type":"class", //class:条件类 sql:sql查询 var:变量 rest:restfull接口
"classSetting":{//条件类设置
"className":"com.cestc.test.Handler",//类
"expression": "",//监听表达式
"delegateExpression": "",//监听代理表达式
"inputParams":[{//输入参数
"paramName":"age", //参数名称
"paramType":"int", //参数类型
"paramValue":"18" //参数值
}],
"outputResult":{//输出结果变量
"value":"conditionResult", //变量值
"name":"条件结果" //变量显示
}
},
"restSetting":{
"url":"http://test/getValue"
},
"sqlSetting":{//sql设置
"dataSource":"",//数据源
"sql":"select count(1) from user" //具体SQL
},
"varSetting":{//变量条件
"varId":"11",//比较变量ID
"varName":"年龄",//比较变量名称
}
}
},
"handlerule":{//办理设置
"handleType":"grab", //grab:抢占 counterSign:会签
"counterSign":{//会签设置
"type": "Parallel", //Parallel:并行 Sequence:串行
"checkAll":true, //是否参与人都要会签完成
"passRate": 0.5, //同意比例
"rejectBack":true, //结论不同意是否退回
"backNode":{//结论不同意退回节点
"nodeId":"applyId",//退回节点ID
"nodeName":"申请节点"//退回节点名称
},
"resultVar":{//会签结论变量绑定
"varId":"applyId",//绑定变量ID
"varName":"申请人"//绑定变量名
},
"decisionMaker":{//决策人
"passDM":[{//同意决策人
"value":"11",//决策人ID
"name":"张三"
}],
"rejectDM":[{//拒绝决策人
"value":"2",
"name":"李四"
}]
}
}
},
"transferrule":{//流转设置
"type":"manual",//manual:手动 auto:自动批转 conditionAuto:条件自动批转
"autoCondition":"HANDLER_EQ_STARTER,HANDLER_APPEARED"//选择自动审批条件 HANDLER_EQ_STARTER:处理人是发起人 HANDLER_APPEARED:处理人已经出现过 HANDLER_EQ_PRE:处理人与上一步相同HANDLER_NONE:当前节点找不到处理人
},
"backrule":{ //驳回设置
"nodes":[{ //可驳回节点
"nodeId":"apply", //节点ID
"nodeName":"申请登记"//节点名称
}],
"backWay":"order"//驳回返回方式 order :按流程图运行 direct:直流回该节点
},
"recallrule":{//撤回设置
"recallType":"none", //none:不能撤回 all://所有节点可撤回 pre_node://前一节点可以撤回
"backWay":"order"//撤回返回方式 order :按流程图运行 direct:直流回该节点
},
"timelimitrule":{//时效规则
"timeType":"workday",//workday:工作日 calday:自然日
"timeLimit":{ //审批时间限制
"day":0, //天
"hour":1,//小时
"minute":0//分
},
"timeoutNotify":"imsg,wmsg",//imsg:内部消息 emsg:邮件消息 smsg:短信 wmsg:微信消息
"urgeTime":{//催办提前时间
"day":0, //天
"hour":1,//小时
"minute":0//分
},
"circularUrge":false,
"circularUrgeTime":{
"day":0, //天
"hour":1,//小时
"minute":0//分
},
"urgeNotify":"imsg"//imsg:内部消息 emsg:邮件消息 smsg:短信 wmsg:微信消息
},
"executionlisteners": {//执行监听
"executionListeners": [{
"event": "start",//监控事件
"implementation": "com.test.userListener",//监听实现
"api":"//data/api/getUsers",//网关API
"className": "com.test.userListener",//监听实现类
"expression": "",//监听表达式
"delegateExpression": "",//监听代理表达式
"fields": [{//输入参数
"name": "fieldName2",
"implementation": "21233",
"stringValue": "21233",
"expression": "",
"string": ""
}, {
"name": "fieldName111",
"implementation": "${dfsd}",
"stringValue": "",
"expression": "${dfsd}",
"string": ""
}]
}, {
"event": "end",
"implementation": "${testMethod}",
"className": "",
"expression": "${testMethod}",
"delegateExpression": ""
}]
},
"tasklisteners": {//任务监听
"taskListeners": [
{
"event": "create",
"implementation": "${test}",
"className": "",
"expression": "${test}",
"delegateExpression": "",
"fields": [
{
"name": "age",
"implementation": "18",
"stringValue": "18",
"expression": "",
"string": ""
}
]
}
]
},
"operaterule": {//按钮设置
"opbtns": [{//按钮集合
"value": "02020061213421486600000101001101", //按钮ID
"btnName": "同意"//按钮名称
}, {
"value": "02020061213421486600000101001102",
"btnName": "拒绝"
}]
}
}
那是如何实现的呢,主要的原理就是扩展 extensionElements 元素,让各个属性规则以json的格式存放到下面。
参考以前的
writeListeners处理新增
writeRules
package com.cestc.workflow.core.definition.xmlmodelconverter.converter.export;
import com.cestc.workflow.utils.SpringUtil;
import com.cestc.workflow.core.definition.xmlmodelconverter.constants.BpmnXMLConstants;
import com.cestc.workflow.core.engine.util.BpmnXMLUtil;
import com.cestc.workflow.core.model.*;
import com.cestc.workflow.core.engine.rulemanager.converter.RuleConverter;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.xml.stream.XMLStreamWriter;
import java.util.Map;
/**
* 规则解析,对应extensionElements下的workflow:rules标签
*/
public class WorkflowRuleExport implements BpmnXMLConstants {
public static boolean writeRules(BaseElement element, boolean didWriteExtensionStartElement, XMLStreamWriter xtw) throws Exception {
didWriteExtensionStartElement = writeRules(ELEMENT_RULES, element, didWriteExtensionStartElement, xtw);
return didWriteExtensionStartElement;
}
private static boolean writeRules(String xmlElementName, BaseElement element, boolean didWriteExtensionStartElement, XMLStreamWriter xtw) throws Exception {
if (!didWriteExtensionStartElement) {
xtw.writeStartElement(ELEMENT_EXTENSIONS);
didWriteExtensionStartElement = true;
}
xtw.writeStartElement(WF_EXTENSIONS_PREFIX, xmlElementName, WF_EXTENSIONS_NAMESPACE);
for (Map.Entry<String, RuleConverter> entry : RuleConverter.ruleConverterMap.entrySet()) {
if (entry.getValue().getRule(element) != null) {
xtw.writeStartElement(WF_EXTENSIONS_PREFIX, ELEMENT_FIELD, WF_EXTENSIONS_NAMESPACE);
BpmnXMLUtil.writeDefaultAttribute(ATTRIBUTE_FIELD_NAME, entry.getKey(), xtw);
xtw.writeStartElement(WF_EXTENSIONS_PREFIX, ELEMENT_FIELD_STRING, WF_EXTENSIONS_NAMESPACE);
xtw.writeCData(SpringUtil.getBean(ObjectMapper.class).writeValueAsString(entry.getValue().getRule(element)));
xtw.writeEndElement();
xtw.writeEndElement();
}
}
xtw.writeEndElement();
return didWriteExtensionStartElement;
}
}
参考listenerParse 新增worflowRuleParase
package com.cestc.workflow.core.definition.xmlmodelconverter.converter.parser.child;
import com.cestc.workflow.core.model.*;
import com.cestc.workflow.core.model.Process;
import com.cestc.workflow.core.engine.rulemanager.converter.RuleConverter;
import org.springframework.util.CollectionUtils;
import javax.xml.stream.XMLStreamReader;
/**
* 元素规则解析
*
* @author liubo
*/
public class WorkflowRuleParser extends BaseChildElementParser {
@Override
public String getElementName() {
return ELEMENT_RULES;
}
@Override
public void parseChildElement(XMLStreamReader xtr, BaseElement parentElement, BpmnModel model) throws Exception {
boolean readyWithChildElements = false;
BaseChildElementParser parser = new FieldExtensionParser();
WorkflowRule workflowRule = new WorkflowRule();
while (readyWithChildElements == false && xtr.hasNext()) {
xtr.next();
if (xtr.isStartElement()) {
if (parser.getElementName().equals(xtr.getLocalName())) {
parser.parseChildElement(xtr, workflowRule, model);
}
} else if (xtr.isEndElement() && getElementName().equalsIgnoreCase(xtr.getLocalName())) {
readyWithChildElements = true;
}
}
if (parentElement instanceof UserTask || parentElement instanceof SequenceFlow || parentElement instanceof Process || parentElement instanceof TimerEventDefinition || parentElement instanceof ServiceTask) {
if (!CollectionUtils.isEmpty(workflowRule.getFieldExtensions())) {
workflowRule.getFieldExtensions().stream().forEach(fieldExtension -> {
RuleConverter converter = RuleConverter.ruleConverterMap.get(fieldExtension.getFieldName());
if (converter != null) {
converter.convertJsonToRule(parentElement, fieldExtension.getStringValue());
}
});
}
}
}
}
定义规则转换处理类负责各个属性规则的处理就行了
package com.cestc.workflow.core.engine.rulemanager.converter;
import com.cestc.workflow.core.model.BaseElement;
import com.cestc.workflow.core.model.UserTask;
import com.cestc.workflow.core.definition.TaskDefinition;
import com.fasterxml.jackson.databind.JsonNode;
import java.util.HashMap;
import java.util.Map;
/**
* 规则转换
* @author breeze
* @since 2020/7/16 19:33
*/
public abstract class RuleConverter {
public static Map<String, RuleConverter> ruleConverterMap = new HashMap<String, RuleConverter>();
public static final String NODE_FORM_RULE = "formrule";
public static final String NODE_ASSIGNMENT_RULE = "assignmentrule";
public static final String NODE_HANDLE_RULE = "handlerule";
public static final String NODE_BACK_RULE = "backrule";
public static final String NODE_RECALL_RULE = "recallrule";
public static final String NODE_TRANSFER_RULE = "transferrule";
public static final String NODE_OPERATE_RULE = "operaterule";
public static final String NODE_TIMELIMIT_RULE = "timelimitrule";
public static final String NODE_VAR_RULE = "varrule";
public static final String NODE_CONDITION_RULE = "conditionrule";
public static final String NODE_APP_RULE="apprule";
public static final String NODE_TIMER_RULE="timerrule";
public static final String NODE_SAVE_RULE="saverule";
public static final String NODE_APIPARAM_RULE="apiparamrule";
public static final String NODE_CUSTOMBTN_RULE="custombtnrule";
public static final String NODE_FLOWDURATION_RULE="flowdurationrule";
public static final String NODE_APPROVE_RULE="approverule";
public static final String NODE_SELECT_RULE="nodeselectrule";
static{
ruleConverterMap.put(NODE_FORM_RULE,new FormRuleConverter());//表单规则
ruleConverterMap.put(NODE_ASSIGNMENT_RULE,new AssignmentRuleConverter());//分配规则
ruleConverterMap.put(NODE_HANDLE_RULE,new HandleRuleConverter());//办理规则
ruleConverterMap.put(NODE_BACK_RULE,new BackRuleConverter());//回退规则
ruleConverterMap.put(NODE_RECALL_RULE,new RecallRuleConverter());//撤回规则
ruleConverterMap.put(NODE_TRANSFER_RULE,new TransferRuleConverter());//流转规则
ruleConverterMap.put(NODE_OPERATE_RULE,new OperateRuleConverter());//操作规则
ruleConverterMap.put(NODE_TIMELIMIT_RULE,new TimeLimitRuleConverter());//时效规则
ruleConverterMap.put(NODE_VAR_RULE,new VarRuleConverter());//流程变量规则
ruleConverterMap.put(NODE_CONDITION_RULE,new ConditionRuleConverter());//连线条件规则
ruleConverterMap.put(NODE_SAVE_RULE,new SaveRuleConverter());//保存分类
ruleConverterMap.put(NODE_TIMER_RULE,new TimerRuleConverter());//定时设置分类
ruleConverterMap.put(NODE_APP_RULE,new AppRuleConverter());//保存分类
ruleConverterMap.put(NODE_APIPARAM_RULE,new ApiParamRuleConverter());//api参数规则
ruleConverterMap.put(NODE_CUSTOMBTN_RULE,new CustomBtnRuleConverter());//自定义按钮参数规则
ruleConverterMap.put(NODE_FLOWDURATION_RULE,new FlowDurationRuleConverter());//流程期限参数规则
ruleConverterMap.put(NODE_APPROVE_RULE,new ApproveRuleConverter());//审批规则
// 节点选择模式
ruleConverterMap.put(NODE_SELECT_RULE, new NodeSelectRuleConverter());
}
public abstract void convertJsonToElement(JsonNode objectNode, BaseElement element);
public abstract String getNodeFlag();
public abstract Object getRule(BaseElement element);
public abstract void convertJsonToRule(BaseElement element, String ruleJsonStr);
public abstract void copyTaskToDefinition(TaskDefinition taskDefinition, UserTask userTask);
}