IT俱乐部 Java java 工作流引擎设计实现解析流程定义文件

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

引言

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

src/test/resources/leave.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
{
  "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": {
        "width": "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
        }
      ]
    }
  ]
}

类图

流程图

代码实现

model/logicflow/LfPoint.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.mldong.flow.engine.model.logicflow;
import cn.hutool.core.lang.Dict;
import lombok.Data;
import java.io.Serializable;
/**
 *
 * logicFlow节点
 * @author 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 nodes; // 节点集合
    private List edges; // 边集合
}

解析类

parser/NodeParser.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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;
/**
 *
 * 节点解析接口
 * @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 edges);
    /**
     * 解析完成后,提供返回NodeModel对象
     * @return 节点模型
     */
    NodeModel getModel();
}

parser/AbstractNodeParser.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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<LfEdge> 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<LfEdge> nodeEdges = getEdgeBySourceNodeId(lfNode.getId(), edges);
        nodeEdges.forEach(edge->{
            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->{
                    return point.getX()+","+point.getY();
                }).collect(Collectors.joining(";")));
            } else {
                if(ObjectUtil.isNotNull(edge.getStartPoint()) && 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<LfEdge> getEdgeByTargetNodeId(String targetNodeId,List<LfEdge> edges) {
        return edges.stream().filter(edge->{
            return edge.getTargetNodeId().equals(targetNodeId);
        }).collect(Collectors.toList());
    }
    /**
     * 获取节点输出
     * @param sourceNodeId 源节点id
     * @param edges
     * @return
     */
    private List<LfEdge> getEdgeBySourceNodeId(String sourceNodeId,List<LfEdge> edges) {
        return edges.stream().filter(edge->{
            return edge.getSourceNodeId().equals(sourceNodeId);
        }).collect(Collectors.toList());
    }
}

parser/impl/StartParser.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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节点特有属性
     * @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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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<?> clazz);
    /**
     * 判断是否存在给定的服务名称
     * @param name 服务名称
     * @return
     */
    boolean exist(String name);
    /**
     * 根据给定的类型查找服务实例
     * @param clazz 类型
     * @return
     */
    <T> T find(Class<T> clazz);
    /**
     * 根据给定的类型查找所有此类型的服务实例
     * @param clazz 类型
     * @return
     */
    <T> List<T> findList(Class<T> clazz);
    /**
     * 根据给定的服务名称、类型查找服务实例
     * @param name 服务名称
     * @param clazz 类型
     * @return
     */
    <T> T findByName(String name, Class<T> clazz);
}

impl/SimpleContext.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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;
/**
 *
 * 简单的上下文发现实现类
 * @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<?> clazz) {
        dict.put(name, ReflectUtil.newInstance(clazz));
    }
    @Override
    public boolean exist(String name) {
        return ObjectUtil.isNotNull(dict.getObj(name));
    }
    @Override
    public <T> T find(Class<T> clazz) {
        for (Map.Entry<String, Object> entry : dict.entrySet()) {
            if (clazz.isInstance(entry.getValue())) {
                return clazz.cast(entry.getValue());
            }
        }
        return null;
    }
    @Override
    public <T> List<T> findList(Class<T> clazz) {
        List<T> res = new ArrayList<>();
        for (Map.Entry<String, Object> entry : dict.entrySet()) {
            if (clazz.isInstance(entry.getValue())) {
                res.add(clazz.cast(entry.getValue()));
            }
        }
        return res;
    }
    @Override
    public <T> T findByName(String name, Class<T> clazz) {
        for (Map.Entry<String, Object> entry : dict.entrySet()) {
            if (entry.getKey().equals(name) && clazz.isInstance(entry.getValue())) {
                return clazz.cast(entry.getValue());
            }
        }
        return null;
    }
}

core/ServiceContext.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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 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,"未注册服务上下文");
        context.put(name, object);
    }
    public static void put(String name, Class<?> 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 <T> T find(Class<T> clazz) {
        Assert.notNull(context,"未注册服务上下文");
        return context.find(clazz);
    }
    public static <T> List<T> findList(Class<T> clazz) {
        Assert.notNull(context,"未注册服务上下文");
        return context.findList(clazz);
    }
    public static <T> T findByName(String name, Class<T> clazz) {
        Assert.notNull(context,"未注册服务上下文");
        return context.findByName(name, clazz);
    }
}

解析入口类

parser/ModelParser.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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 nodes = lfModel.getNodes();
        List 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 工作流引擎的资料请关注IT俱乐部其它相关文章!

本文收集自网络,不代表IT俱乐部立场,转载请注明出处。https://www.2it.club/code/java/8044.html
上一篇
下一篇
联系我们

联系我们

在线咨询: QQ交谈

邮箱: 1120393934@qq.com

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部