一个系列搞懂自研工作流(一)-流程定义

3,925 阅读3分钟

为什么要做自研工作流

工作流作为企业数字化不可或缺的一部分,在企业生产中举足轻重。随着钉钉、飞书等企业app的飞速发展,线上审批也走进了大家的工作中,很多企业为了业务定制化会自己开发工作流平台。绝大多数企业会采用市场上现有的工作流方案,如activiti5/6/7、Camunda等开源框架,但是过重的框架会让整体工作流平台过于臃肿,许多功能其实在现有业务中根本用不到。所以,自研工作流就是为了更加贴合自身业务,更加轻量级的开发。

特点

  • 轻量级
  • 符合大多数简单的业务场景
  • 标准化流程,遵循BMPN规范

如何做

在网上搜索了许多文章,大多数是对于activi的解析以及如何使用,对于自研工作流的方案确是少之又少。这就是我写这个系列的文章的目的,通过自身对自研工作流的实际开发和理解,用文字的形式帮助更多的人在开发中得到更多的灵感。

概念理解

首先需要先去了解BMPN规范,知道工作流的流程图是长什么样子的,里面的关键节点有什么.具体可以看我的另一篇文章简单工作流设计

如图所示 将流程定义可以抽象成节点和连线 节点包含开始节点、任务节点、结束节点、网关节点等。连线则是表示节点关系的对象。正是这两个对象元素组成了流程定义。 本篇文章着重讲述如何定义元素来解析流程

BaseModel

定义节点和连线的基础属性如标识的id和名称

public class BaseModel implements Serializable {


    /**
     * 元素ID
     */
    private String id;

    /**
     * 元素显示名称
     */
    private String displayName;

 }

NodelModel

NodelModel是node节点的抽象对象,是对所有节点的一个对象声明。节点的子类包括:开始节点、任务节点、结束节点、网关节点等。NodelModel包含的元素主要分为两部分:基础属性(所有节点共有的属性)和节点行为(执行节点动作)。

  • 基础属性:类型、进线对象list、出线对象list、回退节点
  • 节点行为:前置拦截器、后置拦截器、方法execute()
public abstract class NodeModel extends BaseModel {
    /**
     * 输入节点连线list
     */
    private List<LineModel> inputs = new ArrayList<>();

    /**
     * 输出节点连线list
     */
    private List<LineModel> outputs = new ArrayList<>();

    /**
     * 节点类型
     */
    private String type;

    /**
     * 前置局部拦截器实例集合
     */
    private List<SmartFlowInterceptor> preInterceptorList = new ArrayList<>();

    /**
     * 后置局部拦截器实例集合
     */
    private List<SmartFlowInterceptor> postInterceptorList = new ArrayList<>();

    /**
     * rollback target 目标节点
     */
    private NodeModel rollbackTarget;
    

@Override
public void execute(Execution execution) {
    // 前置拦截器
    intercept(preInterceptorList, execution);

    // 核心执行处理
    exec(execution);

    // 后置拦截器
    intercept(postInterceptorList, execution);
    }
}

连线

将流程定义分为节点和连线,刚刚已经定义了节点,现在来定义一下连线。将这两个元素定义完之后就可以进行流程解析了。

  • 来源节点:一个连线仅有一个来源节点
  • 目标节点:一个连线仅有一个目标节点.如此就可以通过获取目标节点,执行节点动作来完成流程流转。
public class LineModel extends BaseModel {

    /**
     * source 来源节点
     */
    private NodeModel source;

    /**
     * target 目标节点
     */
    private NodeModel target;

    /**
     * 是否可执行|默认false
     */
    private boolean enabled = false;

    @Override
    public void execute(Execution execution) {
        // 不可执行,则返回
        if (!enabled || target == null) return;

        // 重要步骤,放入执行对象中,在后续动作执行中取出使用。
        execution.setCurrentExecutionNode(target);
        target.execute(execution);
    }
}

后续

下一篇文章将介绍如何解析json字符串来获取流程对象。 一个系列搞懂自研工作流(二)流程定义解析