开发者

java 工作流引擎设计实现解析流程定义文件

开发者 https://www.devze.com 2023-05-11 11:08 出处:网络 作者: mldong
目录引言类图流程图代码实现LogicFlow模型对象解析类服务上下文相关类解析入口类配置类单元测试类运行结果引言
目录
  • 引言
  • 类图
  • 流程图
  • 代码实现
    • LogicFlow模型对象
    • 解析类
    • 服务上下文相关类
    • 解析入口类
    • 配置类
    • 单元测试类
  • 运行结果

    引言

    在上一篇我们手动构建了一个流程对象并简单打印执行,其构建流程对象的方式并不是很友好。为了更方便的构建流程对象,我们采用全新的方式,即解析基础篇提到的流程定义文件,并将其转成流程模型。 以下是要解析的样例文件:

    java 工作流引擎设计实现解析流程定义文件

    src/test/resources/leave.json

    {
      "name": "leave",
      "displayName": "请假",
      "instanceUrl": "leaveForm",
      "nodes": [
        {
          "id": "start",
          "type": "snaker:start",
          "x": 340,
          "y": 160,
          "properties": {
            "width": "120",
            "height": "80"
          },
          "text": {
            "x": 340,
            "y": 200,
            "value": "开始"
          }
        },
        {
          "id": "apply",
          "type": "snaker:task",
          "x": 520,
          "y": 160,
          "properties": {
            "assignee": "approve.operator",
            "taskType": "Major",
            "performType": "ANY",
            "autoExecute": "N",
            "width": "120",
            "height": "80",
            "field": {
              "userKey": "1"
            }
          },
          "text": {
            "x": 520,
            "y": 160,
            "value": "请假申请"
          }
        },
        {
          "id": "approveDept",
          "type": "snaker:task",
          "x": 740,
          "y": 160,
          "properties": {
            "assignmentHandler": "com.mldong.config.FlowAssignmentHandler",
            "taskType": "Major",
            "performType": "ANY",
            "autoExecute": "N",
            "width": "120",
            "height": "80"
          },
          "text": {
            "x": 740,
            "y": 160,
            "value": "部门领导审批"
          }
        },
        {
          "id": "end",
          "type": "snaker:end",
          "x": 980,
          "y": 160,
          "properties": {
            "wpythonidth": "120",
            "height": "80"
          },
          "text": {
            "x": 980,
            "y": 200,
            "value": "结束"
          }
        }
      ],
      "edges": [
        {
          "id": "t1",
          "type": "snaker:transition",
          "sourceNodeId": "start",
          "targetNodeId": "apply",
          "startPoint": {
            "x": 358,
            "y": 160
          },
          "endPoint": {
            "x": 460,
            "y": 160
          },
          "properties": {
            "height": 80,
            "width": 120
          },
          "pointsList": [
            {
              "x": 358,
              "y": 160
            },
            {
              "x": 460,
              "y": 160
            }
          ]
        },
        {
          "id": "t2",
          "type": "snaker:transition",
          "sourceNodeId": "apply",
          "targetNodeId": "approveDept",
          "startPoint": {
            "x": 580,
            "y": 160
          },
          "endPoint": {
            "x": 680,
            "y": 160
          },
          "properties": {
            "height": 80,
            "width": 120
          },
          "pointsList": [
            {
              "x": 580,
              "y": 160
            },
            {
              "x": 680,
              "y": 160
            }
          ]
        },
        {
          "id": "t3",
          "type": "snaker:transition",
          "sourceNodeId": "approveDept",
          "targetNodeId": "end",
          "startPoint": {
            "x": 800,
            "y": 160
          },
          "endPoint": {
            "x": 962,
            "y": 160
          },
          "properties": {
            "height": 80,
            "width": 120
          },
          "pointsList": [
            {
              "x": 800,
              "y": 160
            },
            {
              "x": 830,
              "y": 160
            },
            {
              "x": 830,
              "y": 160
            },
            {
              "x": 932,
              "y": 160
            },
            {
              "x": 932,
              "y": 160
            },
            {
              "x": 962,
              "y": 160
            }
          ]
        }
      ]
    }
    

    类图

    java 工作流引擎设计实现解析流程定义文件

    流程图

    java 工作流引擎设计实现解析流程定义文件

    代码实现

    model/logicflow/LfPoint.Java

    package com.mldong.flow.engine.model.logicflow;
    import lombok.Data;
    import java.io.Serializable;
    /**
     *
     * logicFlow坐标
     * @author mldong
     * @date 2023/4/26
     */
    @Data
    public class LfPoint implements Serializable {
        private int x; // x轴坐标
        private int y; // y轴坐标
    }
    

    LogicFlow模型对象

    model/logicflow/LfNode.java

    package com.mldong.flow.engine.model.logicflow;
    import cn.hutool.core.lang.Dict;
    import lombok.Data;
    import java.io.Serializable;
    /**
     *
     * logicFlow节点
     * @www.devze.comauthor mldong
     * @date 2023/4/26
     */
    @Data
    public class LfNode implements Serializable {
        private String id; // 节点唯一id
        private String type; // 节点类型
        private int x; // 节点中心点x轴坐标
        private int y; // 节点中心点y轴坐标
        Dict properties; // 节点属性
        Dict text; // 节点文本
    }
    

    model/logicflow/LfEdge.java

    package com.mldong.flow.engine.model.logicflow;
    import cn.hutool.core.lang.Dict;
    import lombok.Data;
    import java.io.Serializable;
    import java.util.List;
    /**
     *
     * LogicFlow边
     * @author mldong
     * @date 2022/6/12
     */
    @Data
    public class LfEdge implements Serializable {
        private String id; // 边唯一id
        private String type; // 边类型
        private String sourceNodeId; // 源节点id
        private String targetNodeId; // 目标节点id
        private Dict properties; // 边属性
        private Dict text; // 边文本
        private LfPoint startPoint; // 边开始点坐标
        private LfPoint endPoint; // 边结束点坐标
        private List<LfPoint> pointsList; // 边所有点集合
    }
    

    model/logicflow/LfModel.java

    package com.mldong.flow.engine.model.logicflow;
    import com.mldong.flow.engine.model.BaseModel;
    import lombok.Data;
    import java.util.List;
    /**
     *
     * logicFlow模型
     * @author mldong
     * @date 2023/4/26
     */
    @Data
    public class LfModel extends BaseModel {
        private String type; // 流程定义分类
        private String expireTime;// 过期时间(常量或变量)
        private String instanceUrl; // 启动实例的url,前后端分离后,定义为路由名或或路由地址
        private String instanceNoClass; // 启动流程时,流程实例的流水号生成类
        private List<LfNode> nodes; // 节点集合
        private List<LfEdge> edges; // 边集合
    }

    解析类

    parser/NodeParser.java

    package com.mldong.flow.eng开发者_C教程ine.parser;
    import com.mldong.flow.engine.model.NodeModel;
    import com.mldong.flow.engine.model.logicflow.LfEdge;
    import com.mldong.flow.engine.model.logicflow.LfNode;
    import java.util.List;
    /**
     *
     * 节点解析接口
     * @author mldong
     * @date 2023/4/26
     */
    public interface NodeParser {
        String NODE_NAME_PREFIX="snaker:"; // 节点名称前辍
        String TEXT_VALUE_KEY = "value"; // 文本值
        String WIDTH_KEY = "width"; // 节点宽度
        String HEIGHT_KEY = "height"; // 节点高度
        String PRE_INTERCEPTORS_KEY = "preInterceptors"; // 前置拦截器
        String POST_INTERCEPTORS_KEY = "postInterceptors"; // 后置拦截器
        String EXPR_KEY = "expr"; // 表达式key
        String HANDLE_CLASS_KEY = "handleClass"; // 表达式处理类
        String FORM_KEY = "form"; // 表单标识
        String ASSIGNEE_KEY = "assignee"; // 参与人
        String ASSIGNMENT_HANDLE_KEY = "assignmentHandler"; // 参与人处理类
        String TASK_TYPE_KEY = "taskType"; // 任务类型(主办/协办)
        String PERFORM_TYPE_KEY = "performType"; // 参与类型(普通参与/会签参与)
        String REMINDER_TIME_KEY = "reminderTime"; // 提醒时间
        String REMINDER_REPEAT_KEY = "reminderRepeat"; // 重复提醒间隔
        String EXPIRE_TIME_KEY = "expireTime"; // 期待任务完成时间变量key
        String AUTH_EXECUTE_KEY = "autoExecute"; // 到期是否自动执行Y/N
        String CALLBACK_KEY = "callback"; // 自动执行回调类
        String EXT_FIELD_KEY = "field"; // 自定义扩展属性
        /**
         * 节点属性解析方法,由解析类完成解析
         * @param lfNode LogicFlow节点对象
         * @param edges 所有边对象
         */
        void parse(LfNode lfNode, List<LfEdge> edges);
        /**
         * 解析完成后,提供返回NodeModel对象
         * @return 节点模型
         */
        NodeModel getModel();
    }

    parser/AbstractNodeParser.java

    package com.mldong.flow.engine.parser;
    import cn.hutool.core.collection.CollectionUtil;
    import cn.hutool.core.convert.Convert;
    import cn.hutool.core.lang.Dict;
    import cn.hutool.core.util.ObjectUtil;
    import cn.hutool.core.util.StrUtil;
    import com.mldong.flow.engine.model.NodeModel;
    import com.mldong.flow.engine.model.TransitionModel;
    import com.mldong.flow.engine.model.logicflow.LfEdge;
    import com.mldong.flow.engine.model.logicflow.LfNode;
    import java.util.List;
    import java.util.stream.Collectors;
    /**
     *
     * 通用属性解析(基本属性和边)
     * @author mldong
     * @date 2023/4/26
     */
    public abstract class AbstractNodeParser implements NodeParser {
        // 节点模型对象
        protected NodeModel nodeModel;
        @Override
        public void parse(LfNode lfNode, List&lt;LfEdge&gt; edges) {
            nodeModel = newModel();
            // 解析基本信息
            nodeModel.setName(lfNode.getId());
            if(ObjectUtil.isNotNull(lfNode.getText())) {
                nodeModel.setDisplayName(lfNode.getText().getStr(TEXT_VALUE_KEY));
            }
            Dict properties = lfNode.getProperties();
            // 解析布局属性
            int x = lfNode.getX();
            int y = lfNode.getY();
            int w = Convert.toInt(properties.get(WIDTH_KEY),0);
            int h = Convert.toInt(properties.get(HEIGHT_KEY),0);
            nodeModel.setLayout(StrUtil.format("{},{},{},{}",x,y,w,h));
            // 解析拦截器
            nodeModel.setPreInterceptors(properties.getStr(PRE_INTERCEPTORS_KEY));
            nodeModel.setPostInterceptors(properties.getStr(POST_INTERCEPTORS_KEY));
            // 解析输出边
            List&lt;LfEdge&gt; nodeEdges = getEdgeBySourceNodeId(lfNode.getId(), edges);
            nodeEdges.forEach(edge-&gt;{
                TransitionModel transitionModel = new TransitionModel();
                transitionModel.setName(edge.getId());
                transitionModel.setTo(edge.getTargetNodeId());
                transitionModel.setSource(nodeModel);
                transitionModel.setExpr(edge.getProperties().getStr(EXPR_KEY));
                if(CollectionUtil.isNotEmpty(edge.getPointsList())) {
                    // x1,y1;x2,y2;x3,y3……
                    transitionModel.setG(edge.getPointsList().stream().map(point-&gt;{
                        return point.getX()+","+point.getY();
                    }).collect(Collectors.joining(";")));
                } else {
                    if(ObjectUtil.isNotNull(edge.getStartPoint()) &amp;&amp; ObjectUtil.isNotNull(edge.getEndPoint())) {
                        int startPointX = edge.getStartPoint().getX();
                        int startPointY = edge.getStartPoint().getY();
                        int endPointX = edge.getEndPoint().getX();
                        int endPointY = edge.getEndPoint().getY();
                        transitionModel.setG(StrUtil.format("{},{};{},{}", startPointX, startPointY, endPointX, endPointY));
                    }
                }
                nodeModel.getOutputs().add(transitionModel);
            });
            // 调用子类特定解析方法
            parseNode(lfNode);
        }
        /**
         * 子类实现此类完成特定解析
         * @param lfNode
         */
        public abstract void parseNode(LfNode lfNode);
        /**
         * 由子类各自创建节点模型对象
         * @return
         */
        public abstract NodeModel newModel();
        @Override
        public NodeModel getModel() {
            return nodeModel;
        }
        /**
         * 获取节点输入
         * @param targetNodeId 目标节点id
         * @param edges
         * @return
         */
        private List&lt;LfEdge&gt; getEdgeByTargetNodeId(String targetNodeId,List&lt;LfEdge&gt; edges) {
            return edges.stream().filter(edge-&gt;{
                return edge.getTargetNodeId().equals(targetNodeId);
            }).collect(Collectors.toList());
        }
        /**
         * 获取节点输出
         * @param sourceNodeId 源节点id
         * @param edges
         * @return
         */
        private List&lt;LfEdge&gt; getEdgeBySourceNodeId(String sourceNodeId,List&lt;LfEdge&gt; edges) {
            return edges.stream().filter(edge-&gt;{
                return edge.getSourceNodeId().equals(sourceNodeId);
            }).collect(Collectors.toList());
        }
    }
    

    parser/impl/StartParser.java

    package com.mldong.flow.engine.parser.impl;
    import com.mldong.flow.engine.model.NodeModel;
    import com.mldong.flow.engine.model.StartModel;
    import com.mldong.flow.engine.model.logicflow.LfNode;
    import com.mldong.flow.engine.parser.AbstractNodeParser;
    /**
     *
     * 开始节点解析类
     * @author mldong
     * @date 2023/4/26
     */
    public class StartParser extends AbstractNodeParser {
        @Override
        public void parseNode(LfNode lfNode) {
        }
        @Override
        public NodeModel newModel() {
            return new StartModel();
        }
    }
    

    parser/impl/EndParser.java

    package com.mldong.flow.engine.parser.impl;
    import com.mldong.flow.engine.model.EndModel;
    import com.mldong.flow.engine.model.NodeModel;
    import com.mldong.flow.engine.model.logicflow.LfNode;
    import com.mldong.flow.engine.parser.AbstractNodeParser;
    /**
     *
     * 结束节点解析类
     * @author mldong
     * @date 2023/4/26
     */
    public class EndParser extends AbstractNodeParser {
        @Override
        public void parseNode(LfNode lfNode) {
        }
        @Override
        public NodeModel newModel() {
            return new EndModel();
        }
    }
    

    parser/impl/TaskParser.java

    package com.mldong.flow.engine.parser.impl;
    import cn.hutool.core.convert.Convert;
    import cn.hutool.core.lang.Dict;
    import com.mldong.flow.engine.enums.TaskPerformTypeEnum;
    import com.mldong.flow.engine.enums.TaskTypeEnum;
    import com.mldong.flow.engine.model.NodeModel;
    import com.mldong.flow.engine.model.TaskModel;
    import com.mldong.flow.engine.model.logicflow.LfNode;
    import com.mldong.flow.engine.parser.AbstractNodeParser;
    /**
     *
     * 任务节点解析类
     * @author mldong
     * @date 2023/4/26
     */
    public class TaskParser extends AbstractNodeParser {
        /**
         * 解析task节点特有属性
         * @param lfNode
         */
        @Override
        public void parseNode(LfNode lfNode) {
            TaskModel taskModel = (TaskModel)nodeModel;
            Dict properties = lfNode.getProperties();
            taskModel.setForm(properties.getStr(FORM_KEY));
            taskModel.setAssignee(properties.getStr(ASSIGNEE_KEY));
            taskModel.setAssignmentHandler(properties.getStr(ASSIGNMENT_HANDLE_KEY));
            taskModel.setTaskType(TaskTypeEnum.codeOf(properties.getInt(TASK_TYPE_KEY)));
            taskModel.setPerformType(TaskPerformTypeEnum.codeOf(properties.getInt(PERFORM_TYPE_KEY)));
            taskModel.setReminderTime(properties.getStr(REMINDER_TIME_KEY));
            taskModel.setReminderRepeat(properties.getStr(REMINDER_REPEAT_KEY));
            taskModel.setExpireTime(properties.getStr(EXPIRE_TIME_KEY));
            taskModel.setAutoExecute(properties.getStr(AUTH_EXECUTE_KEY));
            taskModel.setCallback(properties.getStr(CALLBACK_KEY));
            // 自定义扩展属性
            Object field = properties.get(EXT_FIELD_KEY);
            if(field!=null) {
                taskModel.setExt(Convert.convert(Dict.class, field));
            }
        }
        @Override
        public NodeModel newModel() {
            return new TaskModel();
        }
    }
    

    parser/impl/ForkParser.java

    package com.mldong.flow.engine.parser.impl;
    import com.mldong.flow.engine.model.ForkModel;
    import com.mldong.flow.engine.model.NodeModel;
    import com.mldong.flow.engine.model.logicflow.LfNode;
    import com.mldong.flow.engine.parser.AbstractNodeParser;
    /**
     *
     * 分支节点解析类
     * @author mldong
     * @date 2023/4/26
     */
    public class ForkParser extends AbstractNodeParser {
        @Override
        public void parseNode(LfNode lfNode) {
        }
        @Override
        public NodeModel newModel() {
            return new ForkModel();
        }
    }
    

    parser/impl/JoinParser.java

    package com.mldong.flow.engine.parser.impl;
    import com.mldong.flow.engine.model.JoinModel;
    import com.mldong.flow.engine.model.NodeModel;
    import com.mldong.flow.engine.model.logicflow.LfNode;
    import com.mldong.flow.engine.parser.AbstractNodeParser;
    /**
     *
     * 合并节点解析器
     * @author mldong
     * @date 2023/4/26
     */
    public class JoinParser extends AbstractNodeParser {
        @Override
        public void parseNode(LfNode lfNode) {
        }
        @Override
        public NodeModel newModel() {
            return new JoinModel();
        }
    }
    

    parser/impl/DecisionParser.java

    package com.mldong.flow.engine.parser.impl;
    import cn.hutool.core.lang.Dict;
    import com.mldong.flow.engine.model.DecisionModel;
    import com.mldong.flow.engine.model.NodeModel;
    import com.mldong.flow.engine.model.logicflow.LfNode;
    import com.mldong.flow.engine.parser.AbstractNodeParser;
    /**
     *
     * 决策节点解析类
     * @author mldong
     * @date 2023/4/26
     */
    public class DecisionParser extends AbstractNodeParser {
        /**
         * 解析decision节点特有属性python
         * @param lfNode
         */
        @Override
        public void parseNode(LfNode lfNode) {
            DecisionModel decisionModel = (DecisionModel) nodeModel;
            Dict properties = lfNode.getProperties();
            decisionModel.setExpr(properties.getStr(EXPR_KEY));
            decisionModel.setHandleClass(properties.getStr(HANDLE_CLASS_KEY));
        }
        @Override
        public NodeModel newModel() {
            return new DecisionModel();
        }
    }
    

    服务上下文相关类

    Context.java

    package com.mldong.flow.engine;
    import java.util.List;
    /**
     *
     * 服务上下文接口,类似spring的ioc
     * @author mldong
     * @date 2023/4/26
     */
    public interface Context {
        /**
         * 根据服务名称、实例向服务工厂注册
         * @param name 服务名称
         * @param object 服务实例
         */
        void put(String name, Object object);
        /**
         * 根据服务名称、类型向服务工厂注册
         * @param name 服务名称
         * @param clazz 类型
         */
        void put(String name, Class&lt;?&gt; clazz);
        /**
         * 判断是否存在给定的服务名称
         * @param name 服务名称
         * @return
         */
        boolean exist(String name);
        /**
         * 根据给定的类型查找服务实例
         * @param clazz 类型
         * @return
         */
        &lt;T&gt; T find(Class&lt;T&gt; clazz);
        /**
         * 根据给定的类型查找所有此类型的服务实例
         * @param clazz 类型
         * @return
         */
        &lt;T&gt; List&lt;T&gt; findList(Class&lt;T&gt; clazz);
        /**
         * 根据给定的服务名称、类型查找服务实例
         * @param name 服务名称
         * @param clazz 类型
         * @return
         */
        &lt;T&gt; T findByName(String name, Class&lt;T&gt; clazz);
    }
    

    impl/SimpleContext.java

    package com.mldong.flow.engine.impl;
    import cn.hutool.core.lang.Dict;
    import cn.hutool.core.util.ObjectUtil;
    import cn.hutool.core.util.ReflectUtil;
    import com.mldong.flow.enginejs.Context;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    /**
     *
     * 简单的上下文发现实现类
     * @author mldong
     * @date 2023/4/26
     */
    public class SimpleContext implements Context {
        private Dict dict = Dict.create();
        @Override
        public void put(String name, Object object) {
            dict.put(name, object);
        }
        @Override
        public void put(String name, Class&lt;?&gt; clazz) {
            dict.put(name, ReflectUtil.newInstance(clazz));
        }
        @Override
        public boolean exist(String name) {
            return ObjectUtil.isNotNull(dict.getObj(name));
        }
        @Override
        public &lt;T&gt; T find(Class&lt;T&gt; clazz) {
            for (Map.Entry&lt;String, Object&gt; entry : dict.entrySet()) {
                if (clazz.isInstance(entry.getValue())) {
                    return clazz.cast(entry.getValue());
                }
            }
            return null;
        }
        @Override
        public &lt;T&gt; List&lt;T&gt; findList(Class&lt;T&gt; clazz) {
            List&lt;T&gt; res = new ArrayList&lt;&gt;();
            for (Map.Entry&lt;String, Object&gt; entry : dict.entrySet()) {
                if (clazz.isInstance(entry.getValue())) {
                    res.add(clazz.cast(entry.getValue()));
                }
            }
            return res;
        }
        @Override
        public &lt;T&gt; T findByName(String name, Class&lt;T&gt; clazz) {
            for (Map.Entry&lt;String, Object&gt; entry : dict.entrySet()) {
                if (entry.getKey().equals(name) &amp;&amp; clazz.isInstance(entry.getValue())) {
                    return clazz.cast(entry.getValue());
                }
            }
            return null;
        }
    }
    

    core/ServiceContext.java

    package com.mldong.flow.engine.core;
    import cn.hutool.core.lang.Assert;
    import cn.hutool.core.util.ReflectUtil;
    import com.mldong.flow.engine.Context;
    import java.util.List;
    /**
     *
     * 单例服务上下文
     * @author mldong
     * @date 2022/6/12
     */
    public class SeandroidrviceContext {
        private static Context context;
        public static void setContext(Context context) {
            ServiceContext.context = context;
        }
        public static void put(String name, Object object) {
            Assert.notNull(context,"未注册服务上下文");
            context.put(name, object);
        }
        public static void put(String name, Class&lt;?&gt; clazz) {
            Assert.notNull(context,"未注册服务上下文");
            context.put(name, ReflectUtil.newInstance(clazz));
        }
        public static boolean exist(String name) {
            Assert.notNull(context,"未注册服务上下文");
            return context.exist(name);
        }
        public static &lt;T&gt; T find(Class&lt;T&gt; clazz) {
            Assert.notNull(context,"未注册服务上下文");
            return context.find(clazz);
        }
        public static &lt;T&gt; List&lt;T&gt; findList(Class&lt;T&gt; clazz) {
            Assert.notNull(context,"未注册服务上下文");
            return context.findList(clazz);
        }
        public static &lt;T&gt; T findByName(String name, Class&lt;T&gt; clazz) {
            Assert.notNull(context,"未注册服务上下文");
            return context.findByName(name, clazz);
        }
    }
    

    解析入口类

    parser/ModelParser.java

    package com.mldong.flow.engine.parser;
    import cn.hutool.core.collection.CollectionUtil;
    import cn.hutool.core.io.IoUtil;
    import cn.hutool.json.JSONUtil;
    import com.mldong.flow.engine.core.ServiceContext;
    import com.mldong.flow.engine.model.NodeModel;
    import com.mldong.flow.engine.model.ProcessModel;
    import com.mldong.flow.engine.model.TaskModel;
    import com.mldong.flow.engine.model.TransitionModel;
    import com.mldong.flow.engine.model.logicflow.LfEdge;
    import com.mldong.flow.engine.model.logicflow.LfModel;
    import com.mldong.flow.engine.model.logicflow.LfNode;
    import java.io.ByteArrayInputStream;
    import java.util.List;
    public class ModelParser {
        private ModelParser(){}
        /**
         * 将json定义文件解析成流程模型对象
         * @param bytes
         * @return
         */
        public static ProcessModel parse(byte [] bytes) {
            String json = IoUtil.readUtf8(new ByteArrayInputStream(bytes));
            LfModel lfModel = JSONUtil.parse(json).toBean(LfModel.class);
            ProcessModel processModel = new ProcessModel();
            List<LfNode> nodes = lfModel.getNodes();
            List<LfEdge> edges = lfModel.getEdges();
            if(CollectionUtil.isEmpty(nodes) || CollectionUtil.isEmpty(edges) )  {
                return processModel;
            }
            // 流程定义基本信息
            processModel.setName(lfModel.getName());
            processModel.setDisplayName(lfModel.getDisplayName());
            processModel.setType(lfModel.getType());
            processModel.setInstanceUrl(lfModel.getInstanceUrl());
            processModel.setInstanceNoClass(lfModel.getInstanceNoClass());
            // 流程节点信息
            nodes.forEach(node->{
                String type = node.getType().replace(NodeParser.NODE_NAME_PREFIX,"");
                NodeParser nodeParser = ServiceContext.findByName(type,NodeParser.class);
                if(nodeParser!=null) {
                    nodeParser.parse(node, edges);
                    NodeModel nodeModel = nodeParser.getModel();
                    processModel.getNodes().add(nodeParser.getModel());
                    if (nodeModel instanceof TaskModel) {
                        processModel.getTasks().add((TaskModel) nodeModel);
                    }
                }
            });
            // 循环节点模型,构造输入边、输出边的source、target
            for(NodeModel node : processModel.getNodes()) {
                for(TransitionModel transition : node.getOutputs()) {
                    String to = transition.getTo();
                    for(NodeModel node2 : processModel.getNodes()) {
                        if(to.equalsIgnoreCase(node2.getName())) {
                            node2.getInputs().add(transition);
                            transition.setTarget(node2);
                        }
                    }
                }
            }
            return processModel;
        }
    }

    配置类

    cfg/Configuration.java

    package com.mldong.flow.engine.cfg;
    import com.mldong.flow.engine.Context;
    import com.mldong.flow.engine.core.ServiceContext;
    import com.mldong.flow.engine.impl.SimpleContext;
    import com.mldong.flow.engine.parser.impl.*;
    public class Configuration {
        public Configuration() {
            this(new SimpleContext());
        }
        public Configuration(Context context) {
            ServiceContext.setContext(context);
            ServiceContext.put("decision", DecisionParser.class);
            ServiceContext.put("end", EndParser.class);
            ServiceContext.put("fork", ForkParser.class);
            ServiceContext.put("join", JoinParser.class);
            ServiceContext.put("start", StartParser.class);
            ServiceContext.put("task", TaskParser.class);
        }
    }
    

    单元测试类

    ModelParserTest.java

    package com.mldong.flow;
    import cn.hutool.core.io.IoUtil;
    import cn.hutool.core.lang.Dict;
    import com.mldong.flow.engine.cfg.Configuration;
    import com.mldong.flow.engine.core.Execution;
    import com.mldong.flow.engine.model.ProcessModel;
    import com.mldong.flow.engine.parser.ModelParser;
    import org.junit.Test;
    /**
     *
     * 模型解析单元测试
     * @author mldong
     * @date 2023/4/26
     */
    public class ModelParserTest {
        @Test
        public void parseTest() {
            new Configuration();
            ProcessModel processModel = ModelParser.parse(IoUtil.readBytes(this.getClass().getResourceAsStream("/leave.json")));
            Execution execution = new Execution();
            execution.setArgs(Dict.create());
            processModel.getStart().execute(execution);
        }
    }
    

    运行结果

    model:StartModel,name:start,displayName:开始,time:2023-04-26 21:32:40

    model:TaskModel,name:apply,displayName:请假申请,time:2023-04-26 21:32:41

    model:TaskModel,name:approveDept,displayName:部门领导审批,time:2023-04-26 21:32:42

    model:EndModel,name:end,displayName:结束,time:2023-04-26 21:32:42

    相关源码 mldong-flow-demo-03

    流程设计器 在线体验

    以上就是java 工作流引擎设计实现解析流程定义文件的详细内容,更多关于java 工作流引擎的资料请关注我们其它相关文章!

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号