最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java?工作流引擎設(shè)計(jì)實(shí)現(xiàn)解析流程定義文件

 更新時(shí)間:2023年05月11日 10:01:20   作者:mldong  
這篇文章主要為大家介紹了java?工作流引擎設(shè)計(jì)與實(shí)現(xiàn)及流程定義文件解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

在上一篇我們手動(dòng)構(gòu)建了一個(gè)流程對(duì)象并簡(jiǎn)單打印執(zhí)行,其構(gòu)建流程對(duì)象的方式并不是很友好。為了更方便的構(gòu)建流程對(duì)象,我們采用全新的方式,即解析基礎(chǔ)篇提到的流程定義文件,并將其轉(zhuǎn)成流程模型。 以下是要解析的樣例文件:

src/test/resources/leave.json

{
  "name": "leave",
  "displayName": "請(qǐng)假",
  "instanceUrl": "leaveForm",
  "nodes": [
    {
      "id": "start",
      "type": "snaker:start",
      "x": 340,
      "y": 160,
      "properties": {
        "width": "120",
        "height": "80"
      },
      "text": {
        "x": 340,
        "y": 200,
        "value": "開(kāi)始"
      }
    },
    {
      "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": "請(qǐng)假申請(qǐng)"
      }
    },
    {
      "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": "部門(mén)領(lǐng)導(dǎo)審批"
      }
    },
    {
      "id": "end",
      "type": "snaker:end",
      "x": 980,
      "y": 160,
      "properties": {
        "width": "120",
        "height": "80"
      },
      "text": {
        "x": 980,
        "y": 200,
        "value": "結(jié)束"
      }
    }
  ],
  "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
        }
      ]
    }
  ]
}

類圖

流程圖

代碼實(shí)現(xiàn)

model/logicflow/LfPoint.java

package com.mldong.flow.engine.model.logicflow;
import lombok.Data;
import java.io.Serializable;
/**
 *
 * logicFlow坐標(biāo)
 * @author mldong
 * @date 2023/4/26
 */
@Data
public class LfPoint implements Serializable {
    private int x; // x軸坐標(biāo)
    private int y; // y軸坐標(biāo)
}

LogicFlow模型對(duì)象

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節(jié)點(diǎn)
 * @author mldong
 * @date 2023/4/26
 */
@Data
public class LfNode implements Serializable {
    private String id; // 節(jié)點(diǎn)唯一id
    private String type; // 節(jié)點(diǎn)類型
    private int x; // 節(jié)點(diǎn)中心點(diǎn)x軸坐標(biāo)
    private int y; // 節(jié)點(diǎn)中心點(diǎn)y軸坐標(biāo)
    Dict properties; // 節(jié)點(diǎn)屬性
    Dict text; // 節(jié)點(diǎn)文本
}

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; // 源節(jié)點(diǎn)id
    private String targetNodeId; // 目標(biāo)節(jié)點(diǎn)id
    private Dict properties; // 邊屬性
    private Dict text; // 邊文本
    private LfPoint startPoint; // 邊開(kāi)始點(diǎn)坐標(biāo)
    private LfPoint endPoint; // 邊結(jié)束點(diǎn)坐標(biāo)
    private List<LfPoint> pointsList; // 邊所有點(diǎn)集合
}

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;// 過(guò)期時(shí)間(常量或變量)
    private String instanceUrl; // 啟動(dòng)實(shí)例的url,前后端分離后,定義為路由名或或路由地址
    private String instanceNoClass; // 啟動(dòng)流程時(shí),流程實(shí)例的流水號(hào)生成類
    private List<LfNode> nodes; // 節(jié)點(diǎn)集合
    private List<LfEdge> edges; // 邊集合
}

解析類

parser/NodeParser.java

package com.mldong.flow.engine.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;
/**
 *
 * 節(jié)點(diǎn)解析接口
 * @author mldong
 * @date 2023/4/26
 */
public interface NodeParser {
    String NODE_NAME_PREFIX="snaker:"; // 節(jié)點(diǎn)名稱前輟
    String TEXT_VALUE_KEY = "value"; // 文本值
    String WIDTH_KEY = "width"; // 節(jié)點(diǎn)寬度
    String HEIGHT_KEY = "height"; // 節(jié)點(diǎn)高度
    String PRE_INTERCEPTORS_KEY = "preInterceptors"; // 前置攔截器
    String POST_INTERCEPTORS_KEY = "postInterceptors"; // 后置攔截器
    String EXPR_KEY = "expr"; // 表達(dá)式key
    String HANDLE_CLASS_KEY = "handleClass"; // 表達(dá)式處理類
    String FORM_KEY = "form"; // 表單標(biāo)識(shí)
    String ASSIGNEE_KEY = "assignee"; // 參與人
    String ASSIGNMENT_HANDLE_KEY = "assignmentHandler"; // 參與人處理類
    String TASK_TYPE_KEY = "taskType"; // 任務(wù)類型(主辦/協(xié)辦)
    String PERFORM_TYPE_KEY = "performType"; // 參與類型(普通參與/會(huì)簽參與)
    String REMINDER_TIME_KEY = "reminderTime"; // 提醒時(shí)間
    String REMINDER_REPEAT_KEY = "reminderRepeat"; // 重復(fù)提醒間隔
    String EXPIRE_TIME_KEY = "expireTime"; // 期待任務(wù)完成時(shí)間變量key
    String AUTH_EXECUTE_KEY = "autoExecute"; // 到期是否自動(dòng)執(zhí)行Y/N
    String CALLBACK_KEY = "callback"; // 自動(dòng)執(zhí)行回調(diào)類
    String EXT_FIELD_KEY = "field"; // 自定義擴(kuò)展屬性
    /**
     * 節(jié)點(diǎn)屬性解析方法,由解析類完成解析
     * @param lfNode LogicFlow節(jié)點(diǎn)對(duì)象
     * @param edges 所有邊對(duì)象
     */
    void parse(LfNode lfNode, List<LfEdge> edges);
    /**
     * 解析完成后,提供返回NodeModel對(duì)象
     * @return 節(jié)點(diǎn)模型
     */
    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 {
    // 節(jié)點(diǎn)模型對(duì)象
    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);
        });
        // 調(diào)用子類特定解析方法
        parseNode(lfNode);
    }
    /**
     * 子類實(shí)現(xiàn)此類完成特定解析
     * @param lfNode
     */
    public abstract void parseNode(LfNode lfNode);
    /**
     * 由子類各自創(chuàng)建節(jié)點(diǎn)模型對(duì)象
     * @return
     */
    public abstract NodeModel newModel();
    @Override
    public NodeModel getModel() {
        return nodeModel;
    }
    /**
     * 獲取節(jié)點(diǎn)輸入
     * @param targetNodeId 目標(biāo)節(jié)點(diǎn)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());
    }
    /**
     * 獲取節(jié)點(diǎn)輸出
     * @param sourceNodeId 源節(jié)點(diǎn)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;
/**
 *
 * 開(kāi)始節(jié)點(diǎn)解析類
 * @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;
/**
 *
 * 結(jié)束節(jié)點(diǎn)解析類
 * @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;
/**
 *
 * 任務(wù)節(jié)點(diǎn)解析類
 * @author mldong
 * @date 2023/4/26
 */
public class TaskParser extends AbstractNodeParser {
    /**
     * 解析task節(jié)點(diǎn)特有屬性
     * @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));
        // 自定義擴(kuò)展屬性
        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;
/**
 *
 * 分支節(jié)點(diǎn)解析類
 * @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;
/**
 *
 * 合并節(jié)點(diǎn)解析器
 * @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;
/**
 *
 * 決策節(jié)點(diǎn)解析類
 * @author mldong
 * @date 2023/4/26
 */
public class DecisionParser extends AbstractNodeParser {
    /**
     * 解析decision節(jié)點(diǎn)特有屬性
     * @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();
    }
}

服務(wù)上下文相關(guān)類

Context.java

package com.mldong.flow.engine;
import java.util.List;
/**
 *
 * 服務(wù)上下文接口,類似spring的ioc
 * @author mldong
 * @date 2023/4/26
 */
public interface Context {
    /**
     * 根據(jù)服務(wù)名稱、實(shí)例向服務(wù)工廠注冊(cè)
     * @param name 服務(wù)名稱
     * @param object 服務(wù)實(shí)例
     */
    void put(String name, Object object);
    /**
     * 根據(jù)服務(wù)名稱、類型向服務(wù)工廠注冊(cè)
     * @param name 服務(wù)名稱
     * @param clazz 類型
     */
    void put(String name, Class&lt;?&gt; clazz);
    /**
     * 判斷是否存在給定的服務(wù)名稱
     * @param name 服務(wù)名稱
     * @return
     */
    boolean exist(String name);
    /**
     * 根據(jù)給定的類型查找服務(wù)實(shí)例
     * @param clazz 類型
     * @return
     */
    &lt;T&gt; T find(Class&lt;T&gt; clazz);
    /**
     * 根據(jù)給定的類型查找所有此類型的服務(wù)實(shí)例
     * @param clazz 類型
     * @return
     */
    &lt;T&gt; List&lt;T&gt; findList(Class&lt;T&gt; clazz);
    /**
     * 根據(jù)給定的服務(wù)名稱、類型查找服務(wù)實(shí)例
     * @param name 服務(wù)名稱
     * @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.engine.Context;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
 *
 * 簡(jiǎn)單的上下文發(fā)現(xiàn)實(shí)現(xiàn)類
 * @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;
/**
 *
 * 單例服務(wù)上下文
 * @author mldong
 * @date 2022/6/12
 */
public class ServiceContext {
    private static Context context;
    public static void setContext(Context context) {
        ServiceContext.context = context;
    }
    public static void put(String name, Object object) {
        Assert.notNull(context,"未注冊(cè)服務(wù)上下文");
        context.put(name, object);
    }
    public static void put(String name, Class&lt;?&gt; clazz) {
        Assert.notNull(context,"未注冊(cè)服務(wù)上下文");
        context.put(name, ReflectUtil.newInstance(clazz));
    }
    public static boolean exist(String name) {
        Assert.notNull(context,"未注冊(cè)服務(wù)上下文");
        return context.exist(name);
    }
    public static &lt;T&gt; T find(Class&lt;T&gt; clazz) {
        Assert.notNull(context,"未注冊(cè)服務(wù)上下文");
        return context.find(clazz);
    }
    public static &lt;T&gt; List&lt;T&gt; findList(Class&lt;T&gt; clazz) {
        Assert.notNull(context,"未注冊(cè)服務(wù)上下文");
        return context.findList(clazz);
    }
    public static &lt;T&gt; T findByName(String name, Class&lt;T&gt; clazz) {
        Assert.notNull(context,"未注冊(cè)服務(wù)上下文");
        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定義文件解析成流程模型對(duì)象
     * @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());
        // 流程節(jié)點(diǎn)信息
        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);
                }
            }
        });
        // 循環(huán)節(jié)點(diǎn)模型,構(gòu)造輸入邊、輸出邊的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);
    }
}

單元測(cè)試類

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;
/**
 *
 * 模型解析單元測(cè)試
 * @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);
    }
}

運(yùn)行結(jié)果

model:StartModel,name:start,displayName:開(kāi)始,time:2023-04-26 21:32:40
model:TaskModel,name:apply,displayName:請(qǐng)假申請(qǐng),time:2023-04-26 21:32:41
model:TaskModel,name:approveDept,displayName:部門(mén)領(lǐng)導(dǎo)審批,time:2023-04-26 21:32:42
model:EndModel,name:end,displayName:結(jié)束,time:2023-04-26 21:32:42

相關(guān)源碼 mldong-flow-demo-03

流程設(shè)計(jì)器 在線體驗(yàn)

以上就是java 工作流引擎設(shè)計(jì)實(shí)現(xiàn)解析流程定義文件的詳細(xì)內(nèi)容,更多關(guān)于java 工作流引擎的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java ArrayBlockingQueue阻塞隊(duì)列的實(shí)現(xiàn)示例

    java ArrayBlockingQueue阻塞隊(duì)列的實(shí)現(xiàn)示例

    ArrayBlockingQueue是一個(gè)基于數(shù)組實(shí)現(xiàn)的阻塞隊(duì)列,本文就來(lái)介紹一下java ArrayBlockingQueue阻塞隊(duì)列的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • 使用MongoClient連接Mongodb問(wèn)題

    使用MongoClient連接Mongodb問(wèn)題

    這篇文章主要介紹了使用MongoClient連接Mongodb問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 如何利用MyBatisX插件自動(dòng)生成代碼

    如何利用MyBatisX插件自動(dòng)生成代碼

    這篇文章主要介紹了如何利用MyBatisX插件自動(dòng)生成代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • SpringBoot整合ES高級(jí)查詢方式

    SpringBoot整合ES高級(jí)查詢方式

    這篇文章主要介紹了SpringBoot整合ES高級(jí)查詢方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • springBoot service層事務(wù)控制的操作

    springBoot service層事務(wù)控制的操作

    這篇文章主要介紹了springBoot service層事務(wù)控制的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-02-02
  • Gson如何序列化內(nèi)部類

    Gson如何序列化內(nèi)部類

    本文介紹如何使用Gson對(duì)成員內(nèi)部類及靜態(tài)內(nèi)部類進(jìn)行序列化/反序列化,幫助大家更好的理解和使用gson庫(kù),感興趣的朋友可以了解下
    2020-11-11
  • Java使用EasyExcel進(jìn)行單元格合并的問(wèn)題詳解

    Java使用EasyExcel進(jìn)行單元格合并的問(wèn)題詳解

    項(xiàng)目中需要導(dǎo)出并合并指定的單元格,下面這篇文章主要給大家介紹了關(guān)于java評(píng)論、回復(fù)功能設(shè)計(jì)與實(shí)現(xiàn)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • 詳解Spring中的JavaConfig注解

    詳解Spring中的JavaConfig注解

    在開(kāi)發(fā)Java程序,尤其是Java EE應(yīng)用的時(shí)候,總是免不了與各種配置文件打交道。java注解則幫我們使之更整潔,不會(huì)配置文件滿天飛了。 下面這篇文章主要介紹了Spring中的JavaConfig注解,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-02-02
  • 如何在攔截器中獲取url路徑里面@PathVariable的參數(shù)值

    如何在攔截器中獲取url路徑里面@PathVariable的參數(shù)值

    這篇文章主要介紹了如何在攔截器中獲取url路徑里面@PathVariable的參數(shù)值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 關(guān)于springboot中對(duì)sqlSessionFactoryBean的自定義

    關(guān)于springboot中對(duì)sqlSessionFactoryBean的自定義

    這篇文章主要介紹了springboot中對(duì)sqlSessionFactoryBean的自定義方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12

最新評(píng)論

惠水县| 淳安县| 斗六市| 洱源县| 芮城县| 奉新县| 乡城县| 蒙阴县| 抚州市| 梁河县| 博野县| 南城县| 黄石市| 揭阳市| 金坛市| 广宁县| 蓝田县| 共和县| 远安县| 循化| 阿拉善右旗| 西乌珠穆沁旗| 天镇县| 闽侯县| 东方市| 大名县| 临洮县| 桐城市| 商丘市| 大埔县| 杭锦后旗| 枞阳县| 罗城| 江北区| 房产| 平舆县| 宜兰县| 弋阳县| 昔阳县| 静宁县| 美姑县|