【warm-flow】推荐一个好用的工作流引擎+博主的二次封装,开箱即用

目录

1.什么是工作流

2.flow-work工作流引擎

2.1.为什么要选它

2.2.使用

2.3.博主的二次封装


1.什么是工作流

在很多场景中,材料需要在不同节点间流转,比如常见的OA系统、ERP系统,系统中的工单、请假条、通知、绩效考核单、合同等等。工作流引擎就是专门用来负责这种流转型业务的。博主在前一篇文章中以activiti工作引擎为例对工作流的核心概念做了分享,有兴趣的读者可以移步:

【工作流引擎】一切需要流转的业务的核心-CSDN博客

总结起来:

工作流引擎是一种软件组件,用于自动化和管理企业中的业务流程。其主要功能包括:

  • 流程定义:定义业务流程的步骤、条件和规则。
  • 任务分配:自动分配任务给相关人员或系统。
  • 状态跟踪:监控任务的状态,确保流程按计划执行。
  • 信息传递:确保信息在流程参与者之间正确传递。
  • 集成与扩展:与其他系统(如ERP、CRM)集成,实现数据共享和协调。
  • 监控与报告:提供流程执行情况的监控和报告功能。
  • 灵活性与可配置性:可根据企业需求进行配置和定制。
  • 合规与审计:提供审计跟踪功能,确保流程符合法规要求。

工作流引擎帮助企业提高效率、减少错误,并确保业务流程的标准化和一致性。

2.flow-work工作流引擎

2.1.为什么要选它

博主最近在做一个小的ERP系统,订单的流转是整个系统的核心,所以选择一个靠谱且简单易用的工作流引擎成了重中之重。工作流引擎作为一个基础软件组件,经过这么多年的市场积累,开源的其实五花八门。常见的开源工作流引擎就有:

  • Activiti:一个轻量级的工作流引擎,易于使用且具有很好的文档支持。Activiti支持BPMN 2.0标准,并且拥有活跃的社区支持。
  • JBPM (JBoss BPM Suite):JBPM是Red Hat的一部分,它不仅是一个工作流引擎,还提供了一个完整的业务流程管理(BPM)套件。JBPM同样支持BPMN 2.0。
  • Flowable:Flowable是一个专注于高性能的企业级工作流引擎,同样支持BPMN 2.0标准。它以其灵活性和可扩展性著称,适用于多种应用场景。
  • Camunda:Camunda是一个全面的BPM平台,提供了一个强大的工作流引擎,支持BPMN 2.0,并且拥有丰富的工具集,包括模型器、任务列表等。
  • OSWorkFlow:这是一个较早的工作流引擎项目,虽然不如上述几个流行,但它仍然被一些组织使用,尤其是在那些需要高度定制化的工作流场景中。

这些开源这些大的工作流引擎经过多年迭代后能力很强,支持很多扩展,但中小型项目的开发根本就用不到其中的大部分能力。而且因为能力太强了,使用起来会很重,诸多配置、依赖,徒增了开发成本。所以博主在开发这个小型erp的时候决定去git上找一个轻量化的、开发成本不高、能开箱即食不做过多配置的工作流引擎。经过挑选、使用、比对后推荐warm-flow这一款工作流引擎,git地址:

warm-flow: Warm-Flow国产工作流引擎🎉,其特点简洁轻量但又不简单,五脏俱全,组件独立,可扩展,可满足中小项目的组件。解决flowable和activities复杂、学习成本高和集成难等痛点。

2.2.使用

项目的尾巴上有演示地址和文档:

在演示地址中可以很方便的画流程图,然后导出流程文件。文档中直接用代码示例,拷贝出来直接就能用。

2.3.博主的二次封装

博主这里直接把自己简单做的二次封装分享出来,大家可以直接基于warm-flow+博主的封装形成一个拿来就能用的工作类,这个类可以方便的开始任务、推进流程、启用/禁用流程等工作流的核心操作,用来对付简单的流程类业务应该是够了。

依赖:

<!--工作流 start-->
        <dependency>
            <groupId>io.github.minliuhua</groupId>
            <artifactId>warm-flow-core</artifactId>
            <version>1.2.4</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>io.github.minliuhua</groupId>
            <artifactId>warm-flow-plugin-spel</artifactId>
            <version>1.2.4</version>
        </dependency>

        <dependency>
            <groupId>io.github.minliuhua</groupId>
            <artifactId>warm-flow-mybatis-sb-starter</artifactId>
            <version>1.2.4</version>
        </dependency>
        <!--工作流 end-->

代码:

package com.ruoyi.web.core.workflow;

import com.warm.flow.core.FlowFactory;
import com.warm.flow.core.dto.FlowCombine;
import com.warm.flow.core.dto.FlowParams;
import com.warm.flow.core.entity.Definition;
import com.warm.flow.core.entity.Instance;
import com.warm.flow.core.entity.Task;
import com.warm.flow.core.enums.SkipType;
import com.warm.flow.core.service.DefService;
import com.warm.flow.core.service.InsService;
import com.warm.flow.core.service.TaskService;
import com.warm.flow.core.utils.FlowConfigUtil;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

@Component
public class WorkFlowEngine {
    @Resource
    private DefService defService;

    @Resource
    private InsService insService;

    @Resource
    private TaskService taskService;

    private String flowCode;

    private Long workFlowId;

    private String path;


    /**
     * 初始化工作流
     * @param path 流程文件路径
     */
    public void initPath(String path) {
        this.path = path;
    }


    /**
     * 启用流程
     */
    public void enable() {
        deploy();
        publish();
    }


    /**
     * 禁用流程
     */
    public void disable() {
        unActive();
        unPublish();
        removeDef(workFlowId);
    }

    private void deploy() {
        try {
            //解析出flowCode
            FileInputStream fileInputStream = new FileInputStream(this.path);
            FlowCombine flowCombine = FlowConfigUtil.readConfig(fileInputStream);
            flowCode = flowCombine.getDefinition().getFlowCode();
            //流程文件入库
            workFlowId = defService.importXml(new FileInputStream(this.path)).getId();
            System.out.println("流程发布成功,流程ID:" + workFlowId);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void publish() {
        ArrayList<String> flowCodeList = new ArrayList<>();
        flowCodeList.add(flowCode);
        defService.publish(defService.queryByCodeList(flowCodeList).stream().findFirst().map(Definition::getId).orElse(0L));
    }

    private void active() {
        ArrayList<String> flowCodeList = new ArrayList<>();
        flowCodeList.add(flowCode);
        defService.active(defService.queryByCodeList(flowCodeList).stream().findFirst().map(Definition::getId).orElse(0L));
    }

    private void unActive() {
        ArrayList<String> flowCodeList = new ArrayList<>();
        flowCodeList.add(flowCode);
        defService.unActive(defService.queryByCodeList(flowCodeList).stream().findFirst().map(Definition::getId).orElse(0L));
    }

    private void unPublish() {
        ArrayList<String> flowCodeList = new ArrayList<>();
        flowCodeList.add(flowCode);
        defService.unPublish(defService.queryByCodeList(flowCodeList).stream().findFirst().map(Definition::getId).orElse(0L));
    }

    private void removeDef(Long workFlowId) {
        defService.removeDef(Collections.singletonList(workFlowId));
    }


    /**
     * 开始一个新的流程
     * @return
     */
    public Long start() {
        FlowParams flowParams = FlowParams.build().flowCode(flowCode)
                .handler("1")
                .skipType(SkipType.PASS.getKey())
                .permissionFlag(Arrays.asList("role:1", "role:2"));

        Instance instance = insService.start("1", flowParams);
        System.out.println("流程启动成功,实例ID" + instance.getId());
        List<Task> list = taskService.list(FlowFactory.newTask().setInstanceId(instance.getId()));
        list.forEach(
                task -> {
                    System.out.println("taskID:" + task.getId());
                }
        );
        return instance.getId();
    }


    /**
     * 推动流程
     * @param instanceId 流程示例id
     * @param isPass 通过还是拒绝
     */
    public void push(Long instanceId, boolean isPass) {
        String condition = isPass ? SkipType.PASS.getKey() : SkipType.REJECT.getKey();
        FlowParams flowParams = FlowParams.build().flowCode(flowCode)
                .handler("1")
                .skipType(SkipType.PASS.getKey())
                .permissionFlag(Arrays.asList("1", "2"));
        Instance instance = insService.skipByInsId(instanceId, flowParams.skipType(condition)
                .permissionFlag(Arrays.asList("1", "1")));
        System.out.println("流程推动成功,实例ID:" + instance.toString());
    }
}

### Warm-Flow 数据库表结构查询与操作 Warm-Flow一个用于管理业务流程的工作流引擎,在其数据库设计中,主要涉及多个核心表来存储不同类型的元数据和运行时数据。对于 warm-flow 的表结构查询与操作,可以基于官方提供的文档以及 SQL 脚本来了解具体的细节。 #### 表结构概述 根据 warm-flow 维基页面中的描述,warm-flow 使用了一套标准化的表结构来支持工作流定义、实例化及其执行过程[^1]。这些表格通常包括但不限于: - **WF_FLOW_DEFINITION**: 存储工作流模板信息。 - **WF_PROCESS_INSTANCE**: 记录每一个正在运行或已完成的工作流实例详情。 - **WF_TASK**: 描述任务节点属性及状态变更情况。 - **WF_HISTORIC_TASK**: 历史任务记录表,保存已经结束的任务的相关信息。 以上提到的一些基础表名可能因版本差异而有所不同;具体名称应当参照实际部署环境下的配置文件或者通过查看建表语句确认。 #### 升级注意要点 随着 warm-flow 版本迭代更新,某些字段的数据类型可能会发生变化。例如,在一次特定升级过程中(如 v1.2.6),`flow_status` 字段由原来的数值型更改为字符串类型,这意味着任何依赖此字段的应用程序都需要相应调整以适应新的数据格式[^2]。 #### 监听器机制增强 自 v1.1.4 开始引入了监听器生命周期的概念,并增加了对创建任务监听的支持,同时还优化了一些功能特性,比如允许起始节点也能够被纳入历史任务记录之中[^3]。这表明 warm-flow 不仅关注于基本的功能实现,同时也注重提升系统的灵活性和可扩展性。 为了更好地理解和操作 warm-flow 中涉及到的各种表结构,建议开发者们定期查阅最新发布的官方指南和技术博客文章获取最准确的信息源码示例。 ```sql -- 示例SQL:查询所有未完成的任务列表 SELECT * FROM WF_TASK WHERE STATUS != 'COMPLETED'; ```
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_BugMan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值