工作流 订阅
工作流(Workflow),指“业务过程的部分或整体在计算机应用环境下的自动化”。是对工作流程及其各操作步骤之间业务规则的抽象、概括描述。在计算机中,工作流属于计算机支持的协同工作(CSCW)的一部分。后者是普遍地研究一个群体如何在计算机的帮助下实现协同工作的。工作流主要解决的主要问题是:为了实现某个业务目标,利用计算机在多个参与者之间按某种预定规则自动传递文档、信息或者任务。工作流概念起源于生产组织和办公自动化领域,是针对日常工作中具有固定程序活动而提出的一个概念,目的是通过将工作分解成定义良好的任务或角色,按照一定的规则和过程来执行这些任务并对其进行监控,达到提高工作效率、更好的控制过程、增强对客户的服务、有效管理业务流程等目的。尽管工作流已经取得了相当的成就,但对工作流的定义还没有能够统一和明确。Georgakopoulos给出的工作流定义是:工作流是将一组任务组织起来以完成某个经营过程:定义了任务的触发顺序和触发条件,每个任务可以由一个或多个软件系统完成,也可以由一个或一组人完成,还可以由一个或多个人与软件系统协作完成。1993年工作流管理联盟(Workflow Management Coalition,WfMC)作为工作流管理的标准化组织而成立,标志着工作流技术逐步走向成熟。WfMC对工作流给出定义为:工作流是指一类能够完全自动执行的经营过程,根据一系列过程规则,将文档、信息或任务在不同的执行者之间进行传递与执行。 展开全文
工作流(Workflow),指“业务过程的部分或整体在计算机应用环境下的自动化”。是对工作流程及其各操作步骤之间业务规则的抽象、概括描述。在计算机中,工作流属于计算机支持的协同工作(CSCW)的一部分。后者是普遍地研究一个群体如何在计算机的帮助下实现协同工作的。工作流主要解决的主要问题是:为了实现某个业务目标,利用计算机在多个参与者之间按某种预定规则自动传递文档、信息或者任务。工作流概念起源于生产组织和办公自动化领域,是针对日常工作中具有固定程序活动而提出的一个概念,目的是通过将工作分解成定义良好的任务或角色,按照一定的规则和过程来执行这些任务并对其进行监控,达到提高工作效率、更好的控制过程、增强对客户的服务、有效管理业务流程等目的。尽管工作流已经取得了相当的成就,但对工作流的定义还没有能够统一和明确。Georgakopoulos给出的工作流定义是:工作流是将一组任务组织起来以完成某个经营过程:定义了任务的触发顺序和触发条件,每个任务可以由一个或多个软件系统完成,也可以由一个或一组人完成,还可以由一个或多个人与软件系统协作完成。1993年工作流管理联盟(Workflow Management Coalition,WfMC)作为工作流管理的标准化组织而成立,标志着工作流技术逐步走向成熟。WfMC对工作流给出定义为:工作流是指一类能够完全自动执行的经营过程,根据一系列过程规则,将文档、信息或任务在不同的执行者之间进行传递与执行。
信息
应用学科
计算机科学、管理学
适用领域
云计算
中文名
工作流
外文名
Workflow
工作流工作流类型
工作流(WorkFlow)就是工作流程的计算模型,即将工作流程中的工作如何前后组织在一起的逻辑和规则在计算机中以恰当的模型进行表示并对其实施计算。工作流要解决的主要问题是:为实现某个业务目标,在多个参与者之间,利用计算机,按某种预定规则自动传递工作流属于计算机支持的协同工作(Computer Supported Cooperative Work,CSCW)的一部分。后者是普遍地研究一个群体如何在计算机的帮助下实现协同工作的。许多公司采用纸张表单,手工传递的方式,一级一级审批签字,工作效率非常低下,对于统计报表功能则不能实现。而采用工作流软件,使用者只需在电脑上填写有关表单,会按照定义好的流程自动往下跑,下一级审批者将会收到相关资料,并可以根据需要修改、跟踪、管理、查询、统计、打印等,大大提高了效率,实现了知识管理,提升了公司的核心竞争力。 工作流2.0的定义是:实现工作过程管理的自动化、智能化和整合化。工作流2.0最主要的特征就是可以灵便的实现数据整合和数据统计,消除信息孤岛,既能实现OA办公系统内部工作流之间的数据整合,如借款与报销、预算与决算等,又能实现OA办公系统工作流与其他业务系统之间的数据整合,如HR、ERP、CRM等。工作流2.0能彻底的弥补工作流1.0的不足,它不但实现OA办公系统内部的数据整合,也实现OA办公系统和第三方应用系统之间的数据整合。如果给工作流1.0打上标签的话,那就是“无纸化、重复工作、流程孤岛、系统孤岛、数据孤岛”;工作流2.0对应的便是“智能化、效率质量提升、外部数据整合、消除信息孤岛、内部数据整合”。毫无疑问,工作流2.0更加智能,更加整合,能够实现数据的同步交换和共享的特征更受用户欢迎,能有效帮助企业简化多余流程,是未来工作流技术发展的方向。
收起全文
精华内容
下载资源
问答
  • 工作流
    千次阅读
    2021-08-26 13:48:41

    最近一个项目中需要独自设计一个表单式工作流功能模块,在此将整个功能模块的设计思路分享出来。



    1. 需求及分析

    此处所有的需求是建立在医院临床信息管理系统之上的。这里只分析关于表单式工作流功能模块的需求。

    关于表单式工作流功能模块的需求全部整理如下:

    • 1.一个患者在不同时期要填写的表单不同。
    • 2.每个患者的手术类型不同,也就意味着,每个患者的各个时期可能都不相同。
    • 3.每个时期需要单独填写多张表单,相同时期要填写表单的相同。
    • 4.在每个时期要填写的其中一张表单中,可能一条患者信息对应一条记录,也可能一条患者信息对应多条记录。比如在手术期的一张检查表单中,一条患者信息只对应一条记录,但是术后期的一张检查表单中,可能会有手术后30天的情况,也会有手术后60天的情况,也就是一条患者信息对应多条记录。
    • 5.对于某一个患者,要能单独的处理它的工作流(也就是不同时期的表单)。
    • 6.对于某一个时期,要能单独处理在这个时期的所有患者信息。
    • 7.对每张表单要有增删改查操作,在每个时期,都要能通过各种方式查询患者的信息。

    针对这些需求,对整个工作流功能模块初步的想法大概是这个样子:

    在这里插入图片描述

    • 1.每位患者可以绑定一个工作流程,称为表单式的工作流。
    • 2.每个流程由若干个节点组成。
    • 3.医生在一个时期处理完所有的表单后,点击完成该流程节点即可进入下一流程节点。
    • 4.医生还可以修改一个患者已经完成的流程节点的数据,但是无法查看还未达到的流程节点的数据。

    2. 功能实现分析

    上述要实现的表单式的工作流跟oa系统中的工作流不大一样,oa系统中的工作流一般是这样几个步骤:

    • 1.设计流程。上级设计一种办事的流程,其中包含若干个节点,一个节点代表着一个审批人,所有节点审批都通过后才算完成,一个节点不通过,就会被打回。
    • 2.发起流程。由普通员工发起一个流程申请,发起后,员工无法修改这张表单,随后这张表单会跟随流程一级一级审批。
    • 3.流程审批。有若干上级审批流程,点击审批通过,该表单就会进入下以流程节点,点审批失败,流程会终止或者打回。
    • 4.流程通过。所有流程通过之后,会得到流程通过的凭证,就可以拿着这个凭证去处理相关的事情。

    整个oa系统的工作流功能的核心就是多级审批机制,但我们需求中的表单式的工作流,并不设计审批机制,整个工作流的功能可以简单理解为:一条患者信息选择流程后会在各个时期不停流动,在一个时期需要填写非常多的表单,这些表单填写完成后,医生点击进入下一流程,患者信息即可进入下一流程,但是这条患者信息已经留在了每个时期的表单中,医生仍然可以查看和修改这条信息。

    oa式的工作流的实现非常复杂,市面上也有商业化和开源的工作流框架和引擎,但是针对我们这个需求来看,如果硬加使用,只会使整个业务更加复杂,因此,最好的办法就是自己设计一种简单工作流机制,实现上述全部的需求。

    3. 工作流结构设计

    根据上面的需求分析和功能实现的分析,设计的整个工作流结构如下:

    在这里插入图片描述

    • 每个工作流包含若干个节点。
    • 每个节点包含基本信息和若干个表单。
    • 每个患者绑定一个工作流,患者在每个工作流节点需要处理多张表单。

    4. 数据库设计

    4.1 总设计思路

    根据上面的分析,总的设计思路如下:

    • 每个不同的时期有一张主表,主要记载患者的id,每当有患者信息到达该节点时,记录患者的id,一共有两种方式记载。两种方式各有好处。综合考虑还是第1种方式最好。
      • 1.只记载患者信息的id。
      • 2.记载同步记载所有患者信息。
      • 不管使用哪种方法,都需要将患者的id作为主表的主键,这样方便查询子表中的信息。
      • 如果使用第1种方法,那么每张主表中其实主要就是吧包含主键。但在每个时期,都需要联合患者表一起查询数据。
      • 如果使用第2种方法,那么每张主表需要同步患者的所有信息,且不管在哪修改了患者信息,都需要在所有主表同步患者的消息。
    • 每个时期的若干小表都是主表的子表,包含该小表需要填写的所有数据字段,外键是主表的id。
    • 流程节点表中绑定一张主表。
      • 这样设计的好处就是,在每一个流程节点处,还能看到许多该流程节点的其它信息。
    • 工作流表绑定若干个流程节点。
    • 个患者绑定一个工作流,并且存储当前节点,下一节点。

    4.1 各时期主表设计

    各时期的主表主要干的事情就是存储患者信息的id,代表着患者正处于当前流程节点或者已经完成该流程节点。

    患者id模式

    • 这种模式很简单,基本上不需要什么字段。
    字段说明
    id患者id
    权限管理需要的其它字段

    同步所有患者信息模式

    • 这种方式需要同步主表的所有字段。
    字段说明
    id患者id
    患者表所有字段

    4.2 每个时期的若干小表

    存储基本信息,关键是外键是主表的id。

    字段说明
    id唯一id
    所有数据字段

    4.3 流程节点表

    主要是绑定主表,还可以添加一个时期的额外数据,比如一个时期的表单填写提示。

    字段说明
    id唯一id
    master_table主表名称
    权限控制相关字段
    该时期的其它数据字段

    4.4 工作流表

    在工作流表中绑定多个工作节点有两种方式:

    • 1.根据最多节点数目设置若干个节点字段,存储流程节点的id。
    • 2.设置一个字段,字符串拼接的形式,存储所有流程节点id。

    同样,两种方式各有好处:

    • 使用第1种方式,需要需求中最多节点个数完全确定,才方便设计合适的字段。
    • 使用第2种方式,可以存储任意个节点,但在拿出处理的时候有些麻烦。

    一个字段模式

    字段说明
    id唯一id
    process_name工作流名称
    process_des工作流描述
    process_ndoes所有节点id
    权限控制相关的其它字段

    多个字段模式

    • 其中哈希值主要用来工作流判重。
    字段说明
    id唯一id
    process_name工作流名称
    process_des工作流描述
    node_num节点数目
    process_hash工作流哈希值
    node1节点1
    node2节点2
    node3节点3
    若干节点
    权限控制相关的其它字段

    4.5 患者表

    患者表中和流程相关的一共三个字段:工作流id,当前节点id,下一节点id。其中存储下一节点id的做法类似单链表。

    字段说明
    id唯一id
    process_id工作流id
    current_node_id当前节点id
    next_node_id下一节点id
    所有数据字段

    5.接口设计

    5.1 针对工作流节点的接口

    • 1.新增工作流节点。

      • 需要保证工作流节点所绑定的主表id和名称是唯一的。
    • 2.修改工作流节点。

      • 如果修改了工作流绑定的主表,先要判断这个节点所在工作流是否被患者绑定,如果绑定了,那么将无法修改主表。
    • 3.删除工作流节点。

      • 需要保证该节点未绑定任何工作流。
    • 4.查询工作流节点。

      • 查询该节点的所有数据。

    5.2 针对工作流的接口

    • 1.新增工作流。

      • 需要保证工作流节点不重复,重复就会出错。
      • 需要保证节点数大于0.
      • 需要保证整条节点链表不重复。
      • 如果是多字段模式的,还需要检验是否依次填写节点。
    • 2.修改工作流。

      • 如果已经有患者绑定了工作流,那么将不能修改工作流的节点。
    • 3.删除工作流。

      • 如果已经有患者绑定了工作流,那么将不能删除工作流的节点。
    • 4.查询工作流。

      • 查询工作流的所有字段。

    5.3 针对患者的接口

    • CRUD操作略。

    • 查询患者流程信息。

      • 需要获取患者所处流程的所有节点信息。
      • 需要判断哪些节点已经完成,正处于哪个节点,哪些节点还未到达。
    • 患者流程通过。

      • 患者的信息将会插入下一节点对应的主表。
      • 修改患者当前节点,下一节点。

    6. 前端页面设计

    6.1 针对化患者信息处

    • 在操作一栏中能够处理患者的流程。
      在这里插入图片描述

    6.2 患者流程处理处

    在这里插入图片描述

    6.3 具体时期处

    在这里插入图片描述

    7.其它

    这种表单式工作流的设计,理论上是可以抽取出来成为一个独立的框架,待日后有时间精力再去尝试。


    ATFWUS 2021-08-26

    更多相关内容
  • activiti工作流文档,超详细,从0基础开始入门,包括数据库介绍、核心api等介绍,满足日常开发所需
  • Activiti工作流示例ActivitiDemo 本示例带有全部源码,详细使用Canvas动画演示了Activiti工作流引擎的使用。非常实用,非常先进和完整。希望您会喜欢。
  • 不使用工作流存在以下问题工作流优缺点什么是工作流引擎尝试自己构建工作流引擎有哪些选型方案呢基于bpmn标准进行流程定义国产自定义如何使用SnakerFlow工作流以请假流程来看下数据库中数据流转情况初始状态员工发起...

    为什么使用工作流引擎?

    反证法,如果不使用工作流引擎,请假流程举例,从头开始开发流程的业务逻辑:(来看看会出现哪些问题?使用工作流能解决哪些问题?又会带来什么问题?

    • 一、业务流程梳理

      • 员工发起请假单
      • 组长审批
      • 请假天数小于等于2天
        • 结束
      • 请假天数大于2天
        • 总经理审批
        • 结束

      流程定义可能是hardcoding或者存储在某张表

    • 二、每个节点都要记录当前操作人和判断下个节点

      • 员工发起请假单 (记录谁发起的以及判断下个节点)

        • 员工填写请假单并提交
          • 存入leave表,创建人,创建时间
          • 存入transfer状态流转表, userId nextUserId等 驱动到下一个节点
            • nextUserId根据上面的流程定义获取
      • 组长审批 (记录谁发起的以及判断下个节点)

        • 同意或者拒绝
          • 存入transfer状态流转表, userId nextUserId等 驱动到下一个节点
            • nextUserId根据上面的流程定义获取
      • 请假天数小于等于2天 (记录谁发起的以及判断下个节点)

        • if(day<=2)
          • 结束
      • 请假天数大于2天 (记录谁发起的以及判断下个节点)

        • if(day>2)
          • 总经理审批 (记录谁发起的以及判断下个节点)
          • 结束

    如果再来个用车流程报销流程等,那么你的项目将无法维护

    不使用工作流存在以下问题

    • 流程设计没有可视化

    • 流程没有版本管理,热部署等

    • 每个活动的流转都需要硬性判断下一步活动节点及其操作人

    • 每次操作都需要维护业务数据和流程的相关数据

    • 缺乏数据管理、流程监控等功能

    工作流优缺点

    对上面共性问题进行抽象,抽象,抽象,可以得出下面的视图。

    业务流程进行了抽象分离降低耦合

    优点

    • 具有可视化的流程设计工具
    • 业务数据和流程数据的分离,可以进行更专注的性能优化,业务划分
    • 内置API能很好的完成常见的功能场景
    • 具有完善的流程监控体系
    • 具备大量的自定义扩展接口

    缺点

    • 需要额外的学习成本

    什么是工作流引擎

    所谓工作流引擎是指workflow作为应用系统的一部分,并为之提供对各应用系统有决定作用的根据角色、分工和条件的不同决定信息传递路由、内容等级等核心解决方案。工作流引擎包括流程的节点管理、流向管理、流程样例管理等重要功能。(来自百科)

    尝试自己构建工作流引擎

    以下内容取自:https://www.cnblogs.com/duck-and-duck/p/14436373.html

    并进行了部分修改。

    第1天

    我查了一天啥是工作流,然后做出了如下版本:

    img

    • 按顺序添加任意个审批人组成一个链表,最后加一个结束节点
    • 记录当前审批人,当审批完后,审批人向后移动一位
    • 当审批人对应结束节点时,流程结束

    每个节点执行人是hardcoding的

    第二天

    发现部分业务需要支持会签节点

    我又查了一天啥是会签节点,发现会签节点就是一个大节点,里面有很多审批人,当这个大节点里的所有人都审批通过后,才能进入下一个节点。

    翻了原来的链表式设计:

    img

    第三天

    发现部分业务需要支持条件节点

    要根据表单的内容确定下一步进入哪个分支。

    第四天

    审批人多加两种类型,比如可以从表单中选择下一个审批人,还有根据发起人不同选择不同的审批人。

    第五天

    需要满足xxx需求,卒。。。

    看来实现一个工作流引擎还是蛮难的,那有什么可选的轮子吗

    有哪些选型方案呢

    工作流整体流程如下:

    建模(事前)运行 (事中)管理 (事后)监控(全生命周期)
    流程设计engine驱动数据管理流程监控

    基于bpmn标准进行流程定义

    什么是BPMN

    BPMN 是 Business Process Modeling Notation 的简称,即业务流程建模与标注。BPMN 定义了一个业务流程图,这个流程图被设计用于创建业务流程操作的图形化模型 。 而一个业务流程模型( Business Process Model ),指一个由图形对象( graphical objects )组成的网状图,图形对象包括活动(activities) 和用于定义这些活动执行顺序的流程控制器( flow controls )。

    代表实现产品如下:

    • JBPM

    • Activiti

    • Flowable

    国产自定义

    • snaker
    • jflow

    如何使用SnakerFlow工作流

    仅列出常见功能场景实现,具体介绍和详情文档参见:Spring Boot 集成SnakerFlow流程引擎,简介、功能列表、详细解读、扩展点分析

    ☎️ ☎️ ☎️ 已开源基于SnakerFlow轻量级工作流引擎的脚手架项目 easy-admin

    详情参见:终于写了个开源项目,easy-admin 为打造一款简单、轻量级的后台管理系统脚手架

    以请假流程来看下数据库中数据流转情况

    相关源码已开源

    ☎️ ☎️ ☎️ 已开源基于SnakerFlow轻量级工作流引擎的脚手架项目 easy-admin

    详情参见:终于写了个开源项目,easy-admin 为打造一款简单、轻量级的后台管理系统脚手架

    初始状态

    wf_process

    员工发起请假申请

    args.put("user1", StpUtil.getLoginIdAsString());
    args.put("user2", "yang");
    args.put("user3", "zhang");
    Object day = args.get("day");
    if (day != null) {
        args.put("day", Integer.valueOf((String) day));
    }b
    snakerEngineFacets.startAndExecute(name, version, StpUtil.getLoginIdAsString(), args);
    

    员工laker发起一个请假单,请假3

    laker的待办列表为空,已办列表如下:

    yang的待办列表如下:

    当前监控流程图

    wf_order

    wf_task

    wf_task_actor

    wf_hist_order

    wf_hist_task

    wf_hist_task_actor

    常见功能

    流程标题

    我们经常希望待办任务列表有一列是流程实例的名称,即标题,例如,我们希望流程的标题是:张三 - 2019-12-04 16:40:20的请假申请 ,通常会采用一个命名规则:发起人+发起时间+流程模型名称把它作为流程的标题。这时候就希望启动流程实例时可以设置流程实例的名称。

    args.put(SnakerEngine.ID, "张三 - 2019-12-04 16:40:20的请假申请");
    snakerEngineFacets.startAndExecute(name, version, StpUtil.getLoginIdAsString(), args);
    

    发起申请

    args.put(SnakerEngine.ID, "张三 - 2019-12-04 16:40:20的请假申请");
    snakerEngineFacets.startAndExecute(name, version, StpUtil.getLoginIdAsString(), args);
    

    我的发起

    QueryFilter filter = new QueryFilter();
    filter.setOperator(operator);
    filter.orderBy("create_Time").order(DESC);
    snakerEngineFacets.getEngine().query().getHistoryOrders(page, filter);
    

    我的待办

    Page<WorkItem> page = new Page<>(30);
    snakerEngineFacets.getEngine().query().getWorkItems(page,
            new QueryFilter().setOperator(operator));
    

    我的已办

    Page<WorkItem> page = new Page<>(30);
    snakerEngineFacets.getEngine().query().getHistoryWorkItems(page,
            new QueryFilter().setOperator(operator));
    

    催办

    List<Task> tasks = snakerEngineFacets.getEngine().query().getActiveTasks(new QueryFilter().setOrderId(orderId));
    根据这个task跟指定人发消息
    

    转办

    转办任务(换当前办理人,或者叫变更当前办理人)

    snakerEngineFacets.transferMajor(taskId, operator, nextOperators);
    

    驳回

    驳回/退回上一步/退回至(即退回到历史某一个节点)

    snakerEngineFacets.executeAndJump(taskId, operator, args, nodeName);
    

    撤回

    根据历史任务id,撤回由该历史任务派发的所有活动任务,如果无活动任务,则不允许撤回

    snakerEngineFacets.getEngine().task().withdrawTask(taskId, operator);
    

    抄送

    实例的抄送类似于邮箱里面的抄送功能,一般用于将该流程实例抄送给领导查阅。

    新增表wf_cc_order根据实例id、创建人、抄送人创建抄送记录engine.order().createCCOrder(String orderId, String creator, String... actorIds)更新状态用于更新抄送记录为已经阅读engine.order().updateCCStatus(String orderId, String... actorIds)    
    

    加签

    加签(增加另一人或多人的审批)

    engine.task().addTaskActor(String taskId, 1, String... actorIds)
    

    会签

    会签(通常用于审批后给相关的人签字确认,以获得工作上的协调。)

    snaker的会签目前相对比较简单,仅仅是根据任务节点的performType属性值确定是否产生多个相同任务。

    performType的值有两种,分别是ANYALL

    ANY多个参与者时,任何一个完成任务即继续流转 (或签

    ALL多个参与者时,所有都需要完成任务才能继续流转

    会签只需要在流程定义时,将任务节点的属性performType值设置为ALL即可,当调用api时传递多个参与者时,则自动派发与参与者数量相同的任务。会签任务必须等待所有参与者完成后,才继续流转

    或签

    同上

    ☎️ ☎️ ☎️ 已开源基于SnakerFlow轻量级工作流引擎的脚手架项目 easy-admin

    详情参见:终于写了个开源项目,easy-admin 为打造一款简单、轻量级的后台管理系统脚手架

    展开全文
  • 工作流引擎Activiti详解

    千次阅读 2021-11-15 15:28:15
    什么是工作流1.1 工作流介绍1.2 工作流系统1.3 工作流实现方式1.4 工作流实现原理2. Activiti7概述2.1 Activiti介绍2.2 Activiti使用3. Activiti环境配置3.1 创建数据库3.2 初始化数据库表:3.3 创建数据库表3.4 ...

    1. 什么是工作流

    1.1 工作流介绍

    工作流(Workflow),就是通过计算机对业务流程自动化执行管理。它主要解决的是“使在多个参与者之间按照某种预定义的规则自动进行传递文档、信息或任务的过程,从而实现某个预期的业务目标,或者促使此目标的实现”。

    1.2 工作流系统

    什么是工作流系统
    具有工作流程功能的软件系统。用于更好的管理业务流程。

    适用行业,各行各业
    比如,消费品行业,制造业,电信服务业,银证险等金融服务业,物流服务业,物业服务业,物业管理,大中型进出口贸易公司,政府事业机构,研究院所及教育服务业等,特别是大的跨国企业和集团公司。

    具体场景,凡是涉及到业务流程的所有场景
    (1) 关键业务流程:订单、报价处理、合同审核、客户电话处理、供应链管理等
    (2) 行政管理类:出差申请、加班申请、请假申请、用车申请、各种办公用品申请、购买申请、日报周报等凡是原来手工流转处理的行政表单。
    (3) 人事管理类:员工培训安排、绩效考评、职位变动处理、员工档案信息管理等。
    (4) 财务相关类:付款请求、应收款处理、日常报销处理、出差报销、预算和计划申请等。
    (5) 客户服务类:客户信息管理、客户投诉、请求处理、售后服务管理等。

    1.3 工作流实现方式

    目前常见的工作流程有两种方式:
    (1)通过状态字段实现流程控制。原始,适合简单流程控制。
    (2)工作流引擎实现流程控制。适用场景更广泛,扩展性更好。

    1.4 工作流实现原理

    Activiti牛批之处在于,它在不改变代码的前提下实现各种业务流程的管理,适用性,扩展性很优秀。

    activiti通过创建流程实例引擎,可以实现不同流程的流转,通过不断读取创建的流程节点实现流程流转。

    2. Activiti7概述

    2.1 Activiti介绍

    Activiti 是一个工作流引擎, activiti 可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言(BPMN2.0)进行定义,业务系统按照预先定义的流程进行执行,实现了业务系统的业务流程由 activiti 进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的健壮性,同时也减少了系统开发维护成本。

    当然这里还有一些小故事,Alfresco 软件在 2010 年 5 月 17 日宣布 Activiti 业务流程管理(BPM)开源项目的正式启动, 其首席架构师由业务流程管理 BPM 的专家 Tom Baeyens 担任, Tom Baeyens 就是原来 jbpm 的架构师,而 jbpm 是一个非常有名的工作流引擎,当然 activiti 也是一个工作流引擎。
    官方网站: https://www.activiti.org/

    下边介绍三个名词概念,就不长篇大论了,简单总结下。
    1.1 BPM:BPM(Business Process Management),即业务流程管理。
    1.1 BPM系统:那就是业务流程管理的系统。
    1.1 BPMN,这个比较噢重要,多说两句,具体往下看。
    BPMN(Business Process Model And Notation) - 业务流程模型和符号 是由 BPMI(BusinessProcess Management Initiative)开发的一套标准的业务流程建模符号,使用 BPMN 提供的符号可以创建业务流程。

    总结来说就是用来建模业务流程的标准规则,一个个符号!
    在这里插入图片描述

    2.2 Activiti使用

    一般情况下都是通过创建BPMN进行业务流程建模,两种方式,idea插件或者eclipse插件,通过符号创建流程。
    idea安装bpmn插件
    在 IDEA 的 File 菜单中找到子菜单”Settings”,后面我们再选择左侧的“plugins”菜单,如下图所示
    在这里插入图片描述在这里插入图片描述

    3. Activiti环境配置

    3.1 创建数据库

    CREATE DATABASE activiti DEFAULT CHARACTER SET utf8;
    

    3.2 初始化数据库表:

    1. 创建Maven工程
      在这里插入图片描述
    2. 加入依赖
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.activiti.demo</groupId>
        <artifactId>activiti_demo</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <!-- 定义统一版本 -->
        <properties>
            <slf4j.version>1.6.6</slf4j.version>
            <log4j.version>1.2.12</log4j.version>
        </properties>
    
        <dependencies>
            <!-- 引入依赖activiti -->
            <dependency>
                <groupId>org.activiti</groupId>
                <artifactId>activiti-engine</artifactId>
                <version>7.0.0.Beta1</version>
            </dependency>
    
            <dependency>
                <groupId>org.activiti</groupId>
                <artifactId>activiti-spring</artifactId>
                <version>7.0.0.Beta1</version>
            </dependency>
    
            <dependency>
                <groupId>org.activiti</groupId>
                <artifactId>activiti-bpmn-model</artifactId>
                <version>7.0.0.Beta1</version>
            </dependency>
    
            <dependency>
                <groupId>org.activiti</groupId>
                <artifactId>activiti-bpmn-converter</artifactId>
                <version>7.0.0.Beta1</version>
            </dependency>
    
            <dependency>
                <groupId>org.activiti</groupId>
                <artifactId>activiti-json-converter</artifactId>
                <version>7.0.0.Beta1</version>
            </dependency>
    
            <dependency>
                <groupId>org.activiti</groupId>
                <artifactId>activiti-bpmn-layout</artifactId>
                <version>7.0.0.Beta1</version>
            </dependency>
    
            <dependency>
                <groupId>org.activiti.cloud</groupId>
                <artifactId>activiti-cloud-services-api</artifactId>
                <version>7.0.0.Beta1</version>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.40</version>
            </dependency>
    
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
    
            <!-- log start -->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
            <!-- log end -->
    
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.4.5</version>
            </dependency>
    
            <dependency>
                <groupId>commons-dbcp</groupId>
                <artifactId>commons-dbcp</artifactId>
                <version>1.4</version>
            </dependency>
    
        </dependencies>
    
        <repositories>
            <repository>
                <id>alfresco</id>
                <name>Activiti Releases</name>
                <url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases/</url>
                <releases>
                    <enabled>true</enabled>
                </releases>
            </repository>
        </repositories>
    
    </project>
    
    1. 配置日志
    # Set root category priority to INFO and its only appender to CONSOLE.
    #log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
    log4j.rootCategory=debug, CONSOLE, LOGFILE
    
    # Set the enterprise logger category to FATAL and its only appender to CONSOLE.
    log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
    
    # CONSOLE is set to be a ConsoleAppender using a PatternLayout.
    log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
    log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
    log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
    
    # LOGFILE is set to be a File appender using a PatternLayout.
    log4j.appender.LOGFILE=org.apache.log4j.FileAppender
    log4j.appender.LOGFILE.File=d:/axis.log
    log4j.appender.LOGFILE.Append=true
    log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
    log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
    
    
    
    1. 配置activity.cfg.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    						http://www.springframework.org/schema/contex http://www.springframework.org/schema/context/spring-context.xsd
    						http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    
        <!--数据源配置dbcp-->
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/activiti"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
        </bean>
        <!--activiti单独运行的ProcessEngine配置对象(processEngineConfiguration),使用单独启动方式
            默认情况下:bean的id=processEngineConfiguration
        -->
    
        <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
            <!--代表数据源-->
            <property name="dataSource" ref="dataSource"></property>
    
            <!--
             关于 processEngineConfiguration 中的 databaseSchemaUpdate 参数, 通过此参数设计 activiti
                数据表的处理策略,参数如下:
                false(默认):检查数据库表的版本和依赖库的版本, 如果版本不匹配就抛出异常。
                true: 构建流程引擎时,执行检查,如果需要就执行更新。 如果表不存在,就创建。
                create-drop: 构建流程引擎时创建数据库表, 关闭流程引擎时删除这些表。
                drop-create:先删除表再创建表。
                create: 构建流程引擎时创建数据库表, 关闭流程引擎时不删除这些表。
             -->
    
            <!--代表是否生成表结构-->
            <property name="databaseSchemaUpdate" value="true"/>
    
        </bean>
    </beans>
    
    1. 编写代码
    
    /**
     * Activiti初始化25张表
     * 执行的是activiti-engine-7.0.0.Beta1.jar包下对应不同内置好的sql语句
     * org\activiti\db\drop\activiti.db2.drop.engine.sql
     *
     * @author zrj
     * @date 2020/12/29
     * @since V1.0
     **/
    public class ActivitiInit {
    
        /**
         * 方式一
         */
        @Test
        public void GenActivitiTables() {
    
            // 1.创建ProcessEngineConfiguration对象。第一个参数:配置文件名称;第二个参数:processEngineConfiguration的bean的id
            ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource( "activiti.cfg.xml", "processEngineConfiguration" );
            // 2.创建ProcessEngine对象
            ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
            // 3.输出processEngine对象
            System.out.println( processEngine );
    
        }
    
        /**
         * 方式二
         */
        @Test
        public void GenActivitiTables2() {
            //条件:1.activiti配置文件名称:activiti.cfg.xml   2.bean的id="processEngineConfiguration"
            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
            System.out.println( processEngine );
        }
    }
    

    3.3 创建数据库表

    执行上边的代码。

    3.4 数据库表命名规则

    在这里插入图片描述

    Activiti 的表都以 ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的 API 对应。
    
    ACT_RE_*: 'RE'表示 repository。这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
    ACT_RU_*: 'RU'表示 runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti 只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
    ACT_HI_*: 'HI'表示 history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
    ACT_GE_*: 'GE'表示 general。 通用数据, 用于不同场景下
    

    4. Activiti架构简介

    activiti.cfg.xml
    activiti 的引擎配置文件,包括: ProcessEngineConfiguration 的定义、数据源定义、事务管理器等,此文件其实就是一个 spring 配置文件,下面是一个基本的配置只配置了 ProcessEngineConfiguration和数据源。

    ProcessEngineConfiguration
    流程引擎的配置类,通过 ProcessEngineConfiguration 可以创建工作流引擎 ProceccEngine,常用的两种方法。

    ProcessEngine
    工作流引擎,相当于一个门面接口,通过 ProcessEngineConfiguration 创建 processEngine,通过ProcessEngine 创建各个 service 接口。

    Service
    通过 ProcessEngine 创建 Service, Service 是工作流引擎提供用于进行工作流部署、执行、管理的服务接口。

    在这里插入图片描述

    5. Activiti入门案例

    5.1 流程定义

    什么是流程定义
    流程定义是线下按照 bpmn2.0 标准去描述 业务流程,通常使用 activiti-explorer(web 控制台)或 activiti-eclipse-designer 插件对业务流程进行建模,这两种方式都遵循 bpmn2.0 标准。本教程使用activiti-eclipse-designer 插件完成流程建模。使用 designer 设计器绘制流程,会生成两个文件: .bpmn和.png

    创建bpmn文件
    Palette(画板)

    在 eclipse 或 idea 中安装 activiti-designer 插件即可使用,画板中包括以下结点:
    Connection—连接
    Event---事件
    Task---任务
    Gateway---网关
    Container—容器
    Boundary event—边界事件
    Intermediate event- -中间事件
    流程图设计完毕保存生成.bpmn 文件
    

    idea创建bpmn
    在这里插入图片描述在这里插入图片描述
    生成png图片
    第一步:将 holiday.bpmn 文件改为扩展名 xml 的文件名称: holiday.xml
    第二步: 在 holiday.xml 文件上面,点右键并选择 Diagrams 菜单,再选择 Show BPMN2.0 Designe
    在这里插入图片描述
    第三步: 打开后的效果图如下:
    在这里插入图片描述
    打开如下窗口,注意填写文件名及扩展名,选择好保存图片的位置:
    在这里插入图片描述第五步:中文乱码的解决
    1.打开 IDEA 安装路径,找到如下的安装目录
    在这里插入图片描述
    根据自己所安装的版本来决定,我使用的是 64 位的 idea,所以在 idea64.exe.vmoptions 文件的最后
    一行追加一条命令: -Dfile.encoding=UTF-8
    如下所示
    在这里插入图片描述一定注意,不要有空格,否则重启 IDEA 时会打不开,然后 重启 IDEA,把原来的 png 图片删掉,再重新生成,即可解决乱码问题

    5.2 部署流程

    什么是流程部署
    将线下定义的流程部署到 activiti 数据库中,这就是流程定义部署,通过调用 activiti 的 api 将流程定义的 bpmn 和 png 两个文件一个一个添加部署到 activiti 中,也可以将两个文件打成 zip 包进行部署。

    单个文件部署方式
    分别将 bpmn 文件和 png 图片文件部署
    压缩包部署方式

    /**
     * 流程定义的部署
     * activiti表有哪些?
     * act_re_deployment  部署信息
     * act_re_procdef     流程定义的一些信息
     * act_ge_bytearray   流程定义的bpmn文件及png文件
     *
     * @author zrj
     * @date 2020/12/29
     * @since V1.0
     **/
    public class ActivitiDeployment {
    
        /**
         * 方式一
         * 分别将 bpmn 文件和 png 图片文件部署
         */
        @Test
        public void activitiDeploymentTest() {
            //1.创建ProcessEngine对象
            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    
            //2.得到RepositoryService实例
            RepositoryService repositoryService = processEngine.getRepositoryService();
    
            //3.进行部署
            Deployment deployment = repositoryService.createDeployment()
                    .addClasspathResource( "diagram/holiday.bpmn" )
                    .addClasspathResource( "diagram/holiday.png" )
                    .name( "请假申请单流程" )
                    .deploy();
    
            //4.输出部署的一些信息
            System.out.println( deployment.getName() );
            System.out.println( deployment.getId() );
        }
    
        /**
         * 方式二
         * 将 holiday.bpmn 和 holiday.png 压缩成 zip 包
         */
        @Test
        public void activitiDeploymentTest2() {
            //1.创建ProcessEngine对象
            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    
            //2.得到RepositoryService实例
            RepositoryService repositoryService = processEngine.getRepositoryService();
    
            //3.转化出ZipInputStream流对象
            InputStream is = ActivitiDeployment.class.getClassLoader().getResourceAsStream( "diagram/holidayBPMN.zip" );
    
            //将 inputstream流转化为ZipInputStream流
            ZipInputStream zipInputStream = new ZipInputStream( is );
    
            //3.进行部署
            Deployment deployment = repositoryService.createDeployment()
                    .addZipInputStream( zipInputStream )
                    .name( "请假申请单流程" )
                    .deploy();
    
            //4.输出部署的一些信息
            System.out.println( deployment.getName() );
            System.out.println( deployment.getId() );
        }
    
    }
    

    操作数据表

     -- activiti表有哪些?
     -- 部署信息
    select * from act_re_deployment ;
     
    -- 流程定义的一些信息
    select * from act_re_procdef;
     
     -- 流程定义的bpmn文件及png文件
    select * from act_ge_bytearray;
    

    5.3 启动流程

    
    /**
     * 启动流程实例:
     * 前提是先已经完成流程定义的部署工作
     * 背后影响的表:
     * act_hi_actinst     已完成的活动信息
     * act_hi_identitylink   参与者信息
     * act_hi_procinst   流程实例
     * act_hi_taskinst   任务实例
     * act_ru_execution   执行表
     * act_ru_identitylink   参与者信息
     * act_ru_task  任务
     *
     * @author zrj
     * @date 2020/12/29
     * @since V1.0
     **/
    public class ActivitiStartInstance {
        public static void main(String[] args) {
            //1.得到ProcessEngine对象
            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    
            //2.得到RunService对象
            RuntimeService runtimeService = processEngine.getRuntimeService();
    
            //3.创建流程实例  流程定义的key需要知道 holiday
            ProcessInstance processInstance = runtimeService.startProcessInstanceByKey( "holiday" );
    
            //4.输出实例的相关信息
            System.out.println( "流程部署ID" + processInstance.getDeploymentId() );
            System.out.println( "流程定义ID" + processInstance.getProcessDefinitionId() );
            System.out.println( "流程实例ID" + processInstance.getId() );
            System.out.println( "活动ID" + processInstance.getActivityId() );
    
        }
    }
    

    5.4 流程定义查询

    
    /**
     * 流程定义查询
     *
     * @author zrj
     * @date 2020/12/29
     * @since V1.0
     **/
    public class QueryProceccDefinition {
    
        @Test
        public void queryProceccDefinition() {
            // 流程定义key
            String processDefinitionKey = "holiday";
            //1.得到ProcessEngine对象
            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    
            // 获取repositoryService
            RepositoryService repositoryService = processEngine.getRepositoryService();
            // 查询流程定义
            ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
            //遍历查询结果
            List<ProcessDefinition> list = processDefinitionQuery
                    .processDefinitionKey( processDefinitionKey )
                    .orderByProcessDefinitionVersion().desc().list();
    
            for (ProcessDefinition processDefinition : list) {
                System.out.println( "------------------------" );
                System.out.println( " 流 程 部 署 id : " + processDefinition.getDeploymentId() );
                System.out.println( "流程定义id: " + processDefinition.getId() );
                System.out.println( "流程定义名称: " + processDefinition.getName() );
                System.out.println( "流程定义key: " + processDefinition.getKey() );
                System.out.println( "流程定义版本: " + processDefinition.getVersion() );
            }
        }
    }
    

    5.5 流程定义删除

       /**
         * 删除指定流程id的流程
         */
        public void deleteDeployment() {
            // 流程部署id
            String deploymentId = "8801";
            //1.得到ProcessEngine对象
            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    
            // 通过流程引擎获取repositoryService
            RepositoryService repositoryService = processEngine.getRepositoryService();
            //删除流程定义, 如果该流程定义已有流程实例启动则删除时出错
            repositoryService.deleteDeployment( deploymentId );
            //设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设
            //置为false非级别删除方式,如果流程
            repositoryService.deleteDeployment( deploymentId, true );
        }
    

    5.6 流程定义资源查询

       /**
         * 获取资源
         */
        @Test
        public void getProcessResources() throws IOException {
            // 流程定义id
            String processDefinitionId = "";
            //1.得到ProcessEngine对象
            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
            // 获取repositoryService
            RepositoryService repositoryService = processEngine.getRepositoryService();
            // 流程定义对象
            ProcessDefinition processDefinition = repositoryService
                    .createProcessDefinitionQuery()
                    .processDefinitionId( processDefinitionId ).singleResult();
            //获取bpmn
            String resource_bpmn = processDefinition.getResourceName();
            //获取png
            String resource_png = processDefinition.getDiagramResourceName();
            // 资源信息
            System.out.println( "bpmn: " + resource_bpmn );
            System.out.println( "png: " + resource_png );
            File file_png = new File( "d:/purchasingflow01.png" );
            File file_bpmn = new File( "d:/purchasingflow01.bpmn" );
            // 输出bpmn
            InputStream resourceAsStream = null;
            resourceAsStream = repositoryService.getResourceAsStream( processDefinition.getDeploymentId(), resource_bpmn );
            FileOutputStream fileOutputStream = new FileOutputStream( file_bpmn );
            byte[] b = new byte[1024];
            int len = -1;
            while ((len = resourceAsStream.read( b, 0, 1024 )) != -1) {
                fileOutputStream.write( b, 0, len );
            }
            // 输出图片
            resourceAsStream = repositoryService.getResourceAsStream( processDefinition.getDeploymentId(), resource_png );
            fileOutputStream = new FileOutputStream( file_png );
            // byte[] b = new byte[1024];
            // int len = -1;
            while ((len = resourceAsStream.read( b, 0, 1024 )) != -1) {
                fileOutputStream.write( b, 0, len );
            }
        }
    
    展开全文
  • 工作流是什么

    千次阅读 2021-01-26 10:51:43
    刚入职一家公司不久,昨天去和经理与客户对接需求的之前,经理问我接触过工作流没有之前。作为一个20年毕业的老人了,只能尴尬的说一句没有我下去会去了解下。这里我就暂且找一下别人总结的文章和大家一起学习下。 ...

    刚入职一家公司不久,昨天去和经理与客户对接需求的之前,经理问我接触过工作流没有之前。作为一个20年毕业的老人了,只能尴尬的说一句没有我下去会去了解下。这里我就暂且找一下别人总结的文章和大家一起学习下。

    一、什么是工作流

    工作流(Workflow),是对工作流程及其各操作步骤之间业务规则的抽象、概括描述。 工作流建模,即将工作流程中的工作如何前后组织在一起的逻辑和规则,在计算机中以恰当的模型表達并对其实施计算。 工作流要解决的主要问题是:为实现某个业务目标,利用计算机在多个参与者之间按某种预定规则自动传递文档、信息或者任务。

    那么再简单点说,我认为工作流就是对业务的流程化抽象。WFMC给出了工作流参考模型如下:
    在这里插入图片描述
    为什么称之为“流”,则是各个节点通过内外部驱动触发引起节点的推进,形成一个流式的状态达到业务终点。比如一次用户查看淘宝商品的费用、一次支付成功后的权益开通、一次用户注册、一次调度任务的运行等,都是可以是一个工作流。

    从代码层面上来说,工作流是对业务逻辑代码的按照指定的流程格式化。即原来可以用代码直接完成的任务流程,借助工作流工具来进行标准格式化、视图化。

    另外要提一点,工作流本身是一种工程化的设计思想,在特定场景下,也是一种业务的实现方式。对于狭义的通用工程来说,工作流只是一种设计模式,或者说思维方式,不涉及任何的具体编码,即所有业务代码还是需要人工完成,只是用工作流的方式来规划和编排代码运行方式。而对于某些垂直的业务,工作流本身就是业务实现的具体方式,比如审批流的配置,可以直接通过工作流引擎的方式,直接实现配置化编排业务。
    在这里插入图片描述

    二、什么是工作流引擎

    1、工作流引擎

    我们明白为什么需要工作流以及什么是工作流的定义。那么工作流引擎则是实现驱动工作流的一套实现工具。工作流本质上是业务流的抽象,因此不同分类的业务流则形成了不同的工作流,进而有不同的工作流引擎来负责对不同类别的工作流进行具体的定义和实现。

    工作流设计器,我们常说的工作流引擎,一般都包括设计器的能力,即负责对业务流程的拖拽式工具, 有插件式也有WEB云端式的。
    比如我们上述的审批流,则是一种特殊的工作流,该业务流程的特点,就是需要较多的人工介入参与同意/拒绝的操作。

    因此实现审批流的引擎提供的图形化配置能力,并且具备和组织用户直接关联的功能及调用外部服务的能力。
    在这里插入图片描述
    工作流引擎拥有插件视图、XML源码和编译生成的运行代码,可以通过引擎,可以把视图解析成一套简单的可执行代码框架,帮助编排我们自己实现所需要的业务BEAN。

    通用型的工作流引擎,比较知名的有jBPM5与Activiti,阿里巴巴集团则使用tbbpm多一些。下面是国外对于常用的开源的工作流引擎的一个对比。
    在这里插入图片描述
    在这里插入图片描述
    市面上比较知名的开源工作流引擎有jbpm和acitivi。

    三、为什么需要工作流

    相信大家都了解流水线的好处,蒸汽时代就是将手工化转变成了流水线化,手工有明显的一个缺点,就是生产效率极低,而流水线则可以提高生成效率。

    那么工作流则是将业务流水线化,从原来的一团处理逻辑清晰的划分成为若干个步骤,每个步骤流转清晰明显。每个模块有非常高的内聚,模块之前有非常清晰的依赖。

    外网最高的工作流的优点回答如下:

    Workflows can help streamline and automate repeatable business tasks, minimizing room for errors and increasing overall efficiency. This, in turn, dramatically improves your business. Managers can make quicker, smarter decisions and employees are empowered to collaborate in a more productive and agile way.
    举个例子,退款本身非常复杂,运营、产品、技术、财务可能都无法从单一的角色来解释清楚到底退款的整个链路和关键环节,但是通过工作流的方式来呈现,则所有人能快速看到退款到底是个什么样的业务。

    根据实际业务中对工作流的大量使用,我们总结出工作流有以下的优点:

    1、业务可视化

    首先,最大的优点,就是可以借助工作流引擎,让业务可视化,可以通过视图看到整个业务流程,每个节点执行什么业务逻辑一目了然,分支处理、异常处理也非常清晰。

    在这里插入图片描述
    如上述工作流,你一眼就看到,退款成功后该处理哪些事情。业务懂了,自然写代码也就更快了。

    2、业务可编排

    如果业务永远不变化,那么我们硬编码在一个方法里也无所谓。但是我们知道业务千变万化的,软件设计很重要的一个指标就是灵活可扩展。工作流流程的重编排,则可以使得业务进一步在代码层面增加灵活性。可以通过节点的调整来快速调整业务流程,可以灵活增删节点,而不至于对整个流程有影响。

    还是以上面的为例,如果要增加一个【关闭用户权益】的节点,或者删除【用户消息】,那么我们很容易利用工作流增删原有流程。这里实现了代码可维护里最核心的两点:

    改动代码最简单和改动代码最快。

    3、自动重试

    对于某些工作流来说,工作流引擎提供了框架层面持久化和自动重试的能力。
    在这里插入图片描述
    上述是实际交易生产系统接收支付宝支付成功后回调后要处理的异步流程。而且在业务变化时,还需要对流程里动态增删业务功能。由于像【优惠券处理】或者【活动处理】节点依赖条件较多,很可能会处理失败需要重试,但是又不想把所有节点重试一遍,此时工作流引擎的持久化和节点重试能力,则是非常完美的方案。

    四、工作流使用场景

    那么适合用工作流的业务有什么特点?

    1、领域业务高复杂度

    对于偏向业务系统的逻辑,并且具备一定的领域专业性,比如进销存、CRM、订单管理等具备一定的领域复杂度的业务,可以用工作流模式,来实现业务的可视化。从全局的业务视角来观察整体系统架构,而不至于在代码大山面前无从下手。

    2、多节点、长链路

    比如询价需要经过加载用户信息、加载商品、加载优惠、计费等多个节点,每个节点都相对独立。此类业务就比较适合用无状态的内存工作流。

    3、状态持久化和自动重试

    对于异步的调度流程,例如订单支付成功后,驱动下游业务系统开通、发送用户提醒消息、扣减库存等异步流程节点,需要持久化每个节点的执行状态,同时在流程失败的情况下系统框架能进行重试恢复。

    五、工作流分类

    那么工作流该如何分类,如何抽象和归类自身的业务?这是一个首要问题,从经验上来看,我们把工作流按照业务特性分成了以下几类:

    1、内存工作流

    在这里插入图片描述
    内存工作流是最近简单的一类工作流,该类工作流无需持久化,无需状态,在内存调用完成即可。这种工作流也表示业务本身无状态、无需持久化的。比如用户的一次询价行为,用户到详情页查看价格和库存,对于后端来说是一个非常复杂的调用流程,因此会把这一次调用抽象成工作流。
    在这里插入图片描述
    此类流程用硬编码的方式也能很好的实现,但是用工作流的方式,则会使得业务可视化,从视图上就能快速的看出业务是如何运转的,有哪些分支等。同时也使的每个节点能够最大程度的复用。

    2、状态机工作流

    在这里插入图片描述
    当我们需要记录每个节点是否执行成功,并且具备系统自动重试的时候,我们就需要状态机工作流。状态机是在内存工作流的基础上,增加每个节点状态持久化,并增加重试机制。

    我们以一个工作流为例,状态机工作流的一个实例,即对应一个业务上产的流程实例,对应在market_bpm_statemachine_instance的一条记录。
    在这里插入图片描述
    在一条实例里,记录当前处理节点[current_node]、当前处理状态[status]、当前节点重试次数[retry_times]、当前节点处理异常信息[error_message]以及业务主键ID[biz_id]。

    当某个节点处理失败后,节点置为异常状态,工作流调度模块会捞取失败的节点继续按照工作流预定义的流程重试, 直到重试到指定的配置次数后,将整个流程置为执行失败,此时需要人工介入。

    另外,一般的工作流引擎提供了默认集成的调度框架,我们也可以自己采用第三方的调度工具,只要使用IStateMachineQueryService框架内置的接口查询出待执行的数据即可。

    3、人工工作流

    在这里插入图片描述
    人工工作流,又可以认为是外部触发驱动工作流,至少是存在一个或者多个节点是待外部确认才能推进整体业务流程。

    和状态机相比,人工工作流多了外部触发的功能。为某一些需要外部触发的业务提供了很好的支持,比如业务流程依赖审批的,比如退款流程,需要负责人审批通过后才能进行打款;比如报销打款,需要财务审批成功后,才能对报销单进行打款核销;还有一些物流流程,用户确认到货后,驱动流程继续往下走,比如提供售后服务、关闭物流单等。

    以工作流为例,人工工作流的设计会稍微复杂一些,分了多个表,每个表我简介一下其意义

    bpm_workflow_instance : 工作流实例表,表示一个具体执行的业务流 bpm_task_instance : 任务实例,将工作流的每个节点当做一个任务实例存储下来,描述一个工作流实例里 每个节点的具体状态 bpm_param_instance : 参数实例,工作流或者任务实例的上下文入参快照 bpm_timer_task:处理定时任务表,比如人工节点未审批自动超期等 bpm_sequence :生成上述四个表的主键ID表
    可以看到和状态机相比,人工工作流多了对每个任务的流式快照以及定时功能,主要是解决人工等外部触发的自动、超期等问题。

    六、工作流设计准则

    我们可以认为,对于复杂流式业务,面向工作流编程是一个思路,也是一个基本设计理念和方向。如何面向工作流设计?如何让工作流更好的辅助业务编排和业务推进,则是一个需要认真思考的话题。

    1、流程抽象

    首要的工作,就是要把业务抽象流程化。即将业务用精简的流程图的方式展现出来。对业务的深刻理解,才能抽象出业务流程,包括业务链路、关键节点和分支、异常和重试逻辑、是否需要持久化、是否需要外部输入信息。

    这个环节实际上就是领域驱动设计里的,成为领域专家或者和领域业务专家对焦业务的重要部分,即深入业务,读出业务真正的核心流程、异常流程、分支流程以及容错流程。
    在这里插入图片描述
    在这里插入图片描述
    这里需要对业务流程多问几个问题,比如询价流程里,商品加载不到怎么处理?退款流程里等待ISV确认同意退款,如果ISV一直没有同意怎么办?报销流程里,审批单提交了财务人员离职了怎么办?这些问题都思考清楚了,对整体业务流程也就有了一个全面的认识,才能清楚的定义真正的业务流程和业务流程闭环。

    另外,根据业务类型,选择是否需要持久化节点,比如用户询价、查看商品详情等只读业务,则直接采用内存式工作流;如果有持久化重试需求,比如处理支付回调消息,驱动开通用户权益,当流程处理失败,必须保存当前的流程快照并且需要进行重试补偿,则可以选用状态机工作流。当需要有外部用户触发,例如用户审批等人工节点参与,则可以使用人工工作流。

    画出最优的业务流程图,是工作流设计中的首要,也是最重要的一个步骤。

    2、流程编排

    完成业务流程产出后,就要利用工作流引擎工具提供的功能,对业务流进行具体的实现,即“流程编排”。流程编排包括几部分:画出工作流图、工作流配置等。

    如上述的退款业务,首先需要将业务流程化编排,抽象出核心的关键节点,比如【退订判断】,判断是否符合退款条件,其次【更新订单】将订单更新为退款申请中,给用户一个良好的体验,然后将【订购置为退款中】,防止退款期间系统产生新的订单,然后【汇金申请退订】向底层交易发起退款申请,根据底层返回成功和失败分别做【订单订购恢复】的回滚操作以及【保存退款申请】的结束动作。

    编排需要判断哪些是自动节点,哪些需要用判断节点,调用失败如何处理等。就理论上而言,每个节点都可能执行失败,即每个节点都可以做成判断节点,但是这样的缺点很明显,主要链路不清晰,分支非常多,即大家会额外的去关注节点失败的分支,尽管实际上可能无需单独关注异常分支。

    在这里插入图片描述
    如上图所示,同样的一个流程,可以有两种编排的方法,进而也导致了接口有着不同的设计。那么到底如何编排节点是最优的?有个约定的标准:

    以业务流程判断为分支节点,屏蔽系统或非预期的业务异常分支,系统或非预期的业务异常在工作流框架外统一处理

    即以上述退款为例,调用订单更新在正常情况下理论上应该一定是成功的,因此无需设计成判断节点,可以直接设置成自动节点,当该接口发生不在预期的异常时,可以直接throw系统异常,直接在节点外进行捕获处理。具体参考“异常处理”步骤的推荐做法。

    3、接口设计

    面向工作流的接口设计原则,首先满足接口本身的设计原则“高内聚低耦合”。为了满足节点工作流的复用性,接口尽量要保持基本入参,而不要使用复杂对象或者弱类型的MAP入参。

       /**      
         * 订单置为退款中(一个不好的设计,中间的一个节点,入参采用了复杂上下文请求ProdRefundApplyRequest,其他业务无法复用)      * @return     
     */     
    ServiceResult<Boolean> updateOrderRefunding(ProdRefundApplyRequest     prodRefundApplyRe
    

    上述接口则抽象度不够,导致调用困难(组装ProdRefundApplyRequest上下文复杂),复用困难(其他业务可能不包含ProdRefundApplyRequest内的字段或者属性)。

    /**      * isv 确认(一个好的设计,中间的一个节点,入参采用了基本的入参,其他节点和业务可以快速复用)      *      
    * @param mainOrderId 退款主订单      
    * @param opUid       
    操作人uid       
    * @param orgId       操作人的组织id      
    * @return      * @throws ServiceException      
    */     
    Boolean confirmByProvider(Long mainOrderId, Long orgId,      Long opUid) throws ServiceException;
    

    4、异常处理

    如何统一处理工作流中的异常?一般的工作流引擎工具中就设计了对异常的统一处理方式。但是还是需要接口设计本身对异常加以处理,避免对于异常的处理不合理,导致流程难以理解和捕捉。

    在这里插入图片描述
    上图就是一个较为通用的处理办法,工作流本身不处理业务异常,业务异常统一上抛至应用层处理。另外捕获Exception,防止工作流本身产生的任何异常(如果工作流已经处理,则可以忽略)。

    统一处理异常的优点是可以统一工作流节点错误实现方式,还可以打印错误提醒日志,方便快速定位工作流运行期间产生的异常问题。

    七、总结与思考

    工作流提供了一种很好的工程化的方式来解决业务问题,使得业务抽象、流程格式化、易维护和易拓展,一定程度的业务可视化。

    从工程上来说,通用工作流即是一块可同步执行或异步执行的代码块上,增加了格式化和视图化。

    当然,工作流设计模式也不是放之四海皆准。引入工作流本身会增加工程难度,特别是目前没有一个非常极致体验的工作流引擎的情况下。就笔者来说,常用的tbbpm就存在较多的问题,比如图形拖拽不美观、上下文变量设置麻烦、容易出异常未知问题。另外对于一些简单的业务逻辑,几段代码搞定的,也无需考虑使用工作流。

    工作流用的好的话,也是对整体业务思维逻辑的体现。工作流能划清楚,至少业务已经懂了,剩下的只是撸码问题,而撸码是最简单的。就好比一个算法题,设计算法是最难的,具体代码实现则降低了一个数量级,当然,编程功底不过关的另说。

    工作流用得好,从另外一个角度来说,业务可维护、业务可视化,对后来者学习和维护的成本都很低。基本上来说,用工作流设计的逻辑,很少出现翔一样的不可维护,想打人的代码。

    工作流用的好,整个流程具备闭环,具有很强的容错性。异常分支的考虑、错误节点的重试、异常节点告警、节点持久化、超时节点配置,系统就具备很强的鲁棒性了。

    工作流用的好,当然,下班就会更早。

    总而言之,只要符合复杂领域多节点长链路的业务,都可以采用工作流的方式,至少,可以使用工作流的思考方式。

    展开全文
  • java工作流详解

    千次阅读 2020-08-04 18:21:41
    什么是工作流工作流:两个或两个以上的人,为了共同的目标,连续的以串行或并行的方式去完成某一业务。 业务:工作流所指业务涵盖了与经营相关的活动。 串行或并行:业务中的步骤也许以一步接着一步的方式进行...
  • Activiti工作流

    千次阅读 2021-01-29 09:29:44
    目录Activiti工作流概念Activiti7介绍 Activiti工作流 概念 工作流。通过计算机对业务流程自动化执行管理,主要解决的是“使在多个参与者之间按照某种预定义的规则自动进行传递文档、信息或任务的过程,从而实现某个...
  • Java 实现简单工作流

    千次阅读 2021-02-12 08:51:51
    工作流主要运用到反射机制创建一张工作流表如:主键 | 工作流Code | 工作流内容其中工作流,内容为Json格式工作流内容如下{"procCode": "OPS","procName": "c端补齐(乘客信息补全)","taskControlVoList": [{"sortNo...
  • jBPM4工作流应用开发指南.pdf

    千次下载 热门讨论 2012-05-14 11:46:00
    jBPM4工作流应用开发指南 胡奇写的,十分赞!!
  • Camunda工作流引擎入门

    千次阅读 2021-05-22 22:40:05
    Camunda还包括决策模型和表示法(DMN)决策引擎,以便业务用户可以定义和维护直接与工作流引擎集成的可执行业务规则。 Camunda BPM是Apache 2.0许可下的开源软件,这意味着您可以直接访问源代码和最小的供应商锁定...
  • 今天就带大家了解一下什么是java的工作流,以及为大家介绍一下哪些工作流框架比较好。简单来说,java工作流就是一个基于java开发的流程框架,一般情况下,好的工作流在开发时是不需要写代码的,直接配置就可以了。它...
  • ASP.NET RoadFlow工作流引擎源码

    热门讨论 2015-01-16 21:45:01
    基于角色的权限管理等先进设计理念 是您开发OA CRM HR 等企事业各种应用管理系统的最佳基础平台 路德软件兼承 “开放 分享 进步” 的原则 对RoadFlow 工作流引擎开源 希望与广大工作流开发者共同进步 二 功能介绍 1 ...
  • Java实现自定义工作流

    千次阅读 2020-09-07 14:46:01
    工作流不太熟悉的可以先看下工作流相关内容: 链接: https://blog.csdn.net/zhengxiuchen86/article/details/81304676. 相关表结构、实体创建 流程主表:tbl_workflow_requestbase(这里以项目工地工作流为例) @...
  • Camunda工作流引擎一

    千次阅读 多人点赞 2020-07-07 22:38:03
    基于SpringBoot 应用 的 Camunda 工作流引擎 教程
  • 工作流

    千次阅读 2018-01-02 17:59:17
    共有90款 工作流引擎开源软件驰骋工作流引擎 ccflow 开源的驰骋工作流引擎简介 驰骋工作流引擎研发与2003年,具有.net与java两个版本,它们代码结构、数据库结构、设计思想、功能组成、操作手册完全相同。流程表单...
  • Activiti工作流与业务整合实战

    千次阅读 2020-12-07 14:33:34
    Activiti工作流与业务整合进行实践,技术调研对比JBPM与Activiti工作流的特性,结合实际业务和技术背景对Activiti进行改造和融合,通过Aop切面抽离工作流业务,通过Spel进行形参实参绑定及复杂数据结构传参,通过...
  • .Net 工作流 XBPM V3

    2013-04-22 12:57:49
    简单易用、与业务应用耦合度及低的.NET平台工作流 - XBPM v3 [开源部分] 标准WEB服务接口 XBPM工作流的Web Serivce接口是XBPM工作流API基础上的一个扩展(开源),通过提供标准的接口服务于开发其它非.Net平台的...
  • RoadFlow2.7.5 MVC开源工作流快速开发框架源码 工作流引擎快速开发框架源码 需要源码用来学习的小伙伴,可以私信我获取开源地址。 开发环境:VS2013+SQLserver/mysql/oracle+.NET4.0 部署环境:IIS7或以上;SQL...
  • 工作流流程实例迁移

    千次阅读 2020-02-02 20:09:35
    本文重点讲解Flowable的这些APi使用,以及对比Camunda工作流引擎流程实例迁移功能。 流程迁移API说明 流程迁移API服务类可以通过流程引擎类进行获取,如下所示: processMigrationService = processEngine....
  • Activiti7工作流引擎介绍

    万次阅读 2019-02-19 19:27:31
    第1章 什么是工作流 1.1 工作流介绍 工作流(Workflow),就是通过计算机对业务流程自动化执行管理。它主要解决的是“使在多个参与者 之间按照某种预定义的规则自动进行传递文档、信息或任务的过程,从而实现某个预期...
  • KNIME工作流的建立实验

    千次阅读 多人点赞 2021-03-10 07:48:53
    1. 实验相关知识 ...由菜单栏、快捷工具栏、KNIME Explorer(项目资源管理器)、Workflow Coach(社区推荐的工作流节点)、Node Repository(节点存储仓库)、Workflow Editor(工作流编辑区)、Node Descri
  • activiti工作流简介

    万次阅读 2019-02-01 12:45:50
    工作流简介 工作流定义 工作流:  就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行,从而实现某个预期的...
  • 若依框架使用、activiti工作流
  • flowable工作流所有业务概念

    万次阅读 多人点赞 2021-09-27 09:58:47
    1.什么是工作流审批 根据本人的理解,就是审批流程管理。 2.什么是flowable 1.官方解释 官方解释如下: Flowable 项目提供了一套核心的开源业务流程引擎,这些引擎紧凑且高效。它们为开发人员、系统管理员和业务...
  • 力软敏捷开发框架工作流实现技术

    千次阅读 2019-05-28 10:16:49
    工作流管理联盟(WFMC)提出了一个工作流参考模型,约定了工作流系统的体系结构、应用接口及特性,主要目的是为了实现工作流技术的标准化和开放性。下面简要介绍系统中的各个部分,并对参考模型中的五类接口进行描述...
  • 一文带你了解如何编辑工作流流程图

    万次阅读 多人点赞 2021-10-24 09:06:40
    1.通用审批流程组件 1.编辑表单 申请人和审批人都会有各自表单(在需要的情况下)。在编辑流程时,第一步就是编辑表单。 1.编辑申请人表单 这里需要要记住表单key,在与流程图挂接时需要。...如果需要在后续审批中...
  • 工作流(Workflow) -- 工作流简介

    万次阅读 多人点赞 2018-09-08 21:05:00
    ## 工作流引擎 ProcessEngine对象 这是Activiti工作的核心。负责生成流程运行时的各种实例及数据、监控和管理流程的运行。 工作流的API所有的调用都要用到工作流引擎。 数据库 Activiti的后台是有数据库的支持,...
  • Html5+jquery实现的工作流设计器。剥离了原来的各种内部设置,做成了纯粹的设计器,通用性更广。 提供了常用的调用函数,以便大家可以在外部进行设置扩展。需要的朋友赶快下了。都是开源的js文件。 使用和说明,...
  • Java 流行的工作流引擎

    千次阅读 2021-02-21 19:18:22
    Java 流行的工作流引擎 JBPM 工作流 JBPM 是一个Java业务流程管理系统,是JBoss中一款开源的工作流引擎,是一个轻量级的,使用BPMN 2规范可扩展的 工作流引擎,也是一个工作流管理系统,它可以运行在任何java环境...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,515,488
精华内容 606,195
关键字:

工作流