扩展activiti 支持任意属性扩展

        本文主要讲解如何扩展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);
}

 

 

更多源码见 https://gitee.com/wtr/workflow

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

eclipsewangwfUN

棋盘内,车无轮马无缰,叫声将军

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值