引言
在上一篇我们手动构建了一个流程对象并简单打印执行,其构建流程对象的方式并不是很友好。为了更方便的构建流程对象,我们采用全新的方式,即解析基础篇提到的流程定义文件,并将其转成流程模型。 以下是要解析的样例文件:
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俱乐部其它相关文章!