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

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": "部門領(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
}
]
}
]
}
類圖

流程圖

代碼實現(xiàn)
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節(jié)點
* @author mldong
* @date 2023/4/26
*/
@Data
public class LfNode implements Serializable {
private String id; // 節(jié)點唯一id
private String type; // 節(jié)點類型
private int x; // 節(jié)點中心點x軸坐標
private int y; // 節(jié)點中心點y軸坐標
Dict properties; // 節(jié)點屬性
Dict text; // 節(jié)點文本
}
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é)點id
private String targetNodeId; // 目標節(jié)點id
private Dict properties; // 邊屬性
private Dict text; // 邊文本
private LfPoint startPoint; // 邊開始點坐標
private LfPoint endPoint; // 邊結(jié)束點坐標
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; // 節(jié)點集合
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é)點解析接口
* @author mldong
* @date 2023/4/26
*/
public interface NodeParser {
String NODE_NAME_PREFIX="snaker:"; // 節(jié)點名稱前輟
String TEXT_VALUE_KEY = "value"; // 文本值
String WIDTH_KEY = "width"; // 節(jié)點寬度
String HEIGHT_KEY = "height"; // 節(jié)點高度
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"; // 任務(wù)類型(主辦/協(xié)辦)
String PERFORM_TYPE_KEY = "performType"; // 參與類型(普通參與/會簽參與)
String REMINDER_TIME_KEY = "reminderTime"; // 提醒時間
String REMINDER_REPEAT_KEY = "reminderRepeat"; // 重復(fù)提醒間隔
String EXPIRE_TIME_KEY = "expireTime"; // 期待任務(wù)完成時間變量key
String AUTH_EXECUTE_KEY = "autoExecute"; // 到期是否自動執(zhí)行Y/N
String CALLBACK_KEY = "callback"; // 自動執(zhí)行回調(diào)類
String EXT_FIELD_KEY = "field"; // 自定義擴展屬性
/**
* 節(jié)點屬性解析方法,由解析類完成解析
* @param lfNode LogicFlow節(jié)點對象
* @param edges 所有邊對象
*/
void parse(LfNode lfNode, List<LfEdge> edges);
/**
* 解析完成后,提供返回NodeModel對象
* @return 節(jié)點模型
*/
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é)點模型對象
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);
});
// 調(diào)用子類特定解析方法
parseNode(lfNode);
}
/**
* 子類實現(xiàn)此類完成特定解析
* @param lfNode
*/
public abstract void parseNode(LfNode lfNode);
/**
* 由子類各自創(chuàng)建節(jié)點模型對象
* @return
*/
public abstract NodeModel newModel();
@Override
public NodeModel getModel() {
return nodeModel;
}
/**
* 獲取節(jié)點輸入
* @param targetNodeId 目標節(jié)點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());
}
/**
* 獲取節(jié)點輸出
* @param sourceNodeId 源節(jié)點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
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;
/**
*
* 開始節(jié)點解析類
* @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é)點解析類
* @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é)點解析類
* @author mldong
* @date 2023/4/26
*/
public class TaskParser extends AbstractNodeParser {
/**
* 解析task節(jié)點特有屬性
* @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;
/**
*
* 分支節(jié)點解析類
* @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é)點解析器
* @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é)點解析類
* @author mldong
* @date 2023/4/26
*/
public class DecisionParser extends AbstractNodeParser {
/**
* 解析decision節(jié)點特有屬性
* @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ù)名稱、實例向服務(wù)工廠注冊
* @param name 服務(wù)名稱
* @param object 服務(wù)實例
*/
void put(String name, Object object);
/**
* 根據(jù)服務(wù)名稱、類型向服務(wù)工廠注冊
* @param name 服務(wù)名稱
* @param clazz 類型
*/
void put(String name, Class<?> clazz);
/**
* 判斷是否存在給定的服務(wù)名稱
* @param name 服務(wù)名稱
* @return
*/
boolean exist(String name);
/**
* 根據(jù)給定的類型查找服務(wù)實例
* @param clazz 類型
* @return
*/
<T> T find(Class<T> clazz);
/**
* 根據(jù)給定的類型查找所有此類型的服務(wù)實例
* @param clazz 類型
* @return
*/
<T> List<T> findList(Class<T> clazz);
/**
* 根據(jù)給定的服務(wù)名稱、類型查找服務(wù)實例
* @param name 服務(wù)名稱
* @param clazz 類型
* @return
*/
<T> T findByName(String name, Class<T> 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;
/**
*
* 簡單的上下文發(fā)現(xiàn)實現(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<?> 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
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,"未注冊服務(wù)上下文");
context.put(name, object);
}
public static void put(String name, Class<?> clazz) {
Assert.notNull(context,"未注冊服務(wù)上下文");
context.put(name, ReflectUtil.newInstance(clazz));
}
public static boolean exist(String name) {
Assert.notNull(context,"未注冊服務(wù)上下文");
return context.exist(name);
}
public static <T> T find(Class<T> clazz) {
Assert.notNull(context,"未注冊服務(wù)上下文");
return context.find(clazz);
}
public static <T> List<T> findList(Class<T> clazz) {
Assert.notNull(context,"未注冊服務(wù)上下文");
return context.findList(clazz);
}
public static <T> T findByName(String name, Class<T> clazz) {
Assert.notNull(context,"未注冊服務(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定義文件解析成流程模型對象
* @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é)點信息
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é)點模型,構(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);
}
}
單元測試類
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);
}
}
運行結(jié)果
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:部門領(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è)計器 在線體驗
以上就是java 工作流引擎設(shè)計實現(xiàn)解析流程定義文件的詳細內(nèi)容,更多關(guān)于java 工作流引擎的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java實現(xiàn)用戶簽到BitMap功能實現(xiàn)demo
這篇文章主要為大家介紹了java實現(xiàn)用戶簽到BitMap功能實現(xiàn)demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-11-11
理解 MyBatis 是如何在 Spring 容器中初始化的
這篇文章主要介紹了理解 MyBatis 是如何在 Spring 容器中初始化的,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
java集合之CopyOnWriteArrayList源碼解析
這篇文章主要介紹了java集合之CopyOnWriteArrayList源碼解析,容器array是volatile修飾的,即set和get方法都是線程安全的,整個添加過程上了鎖,所以整體是通過volatile和lock來保證的線程安全,需要的朋友可以參考下2023-12-12
SSM+微信小程序?qū)崿F(xiàn)物業(yè)管理系統(tǒng)及實例代碼
這篇文章主要介紹了SSM+微信小程序?qū)崿F(xiàn)物業(yè)管理系統(tǒng),ssm微信小程序物業(yè)管理系統(tǒng),有網(wǎng)站后臺管理系統(tǒng),本文通過實例代碼給大家展示系統(tǒng)的功能,需要的朋友可以參考下2022-02-02
使用feign傳遞參數(shù)類型為MultipartFile的問題
這篇文章主要介紹了使用feign傳遞參數(shù)類型為MultipartFile的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03

