1 开始

1.1 状态机

01.状态机
    状态机解决流程问题
    工作流:就是一个可以处理复杂情况的状态机。
    例如,员工请假这个流程:首先员工提交请假申请,假设有项目经理进行审批,审批有两种结果:通过或者拒绝。
    实现上面这个需求:
    1. 创建一张请假表,表中有员工的 id,请假的天数、请假的理由、项目经理的 id、请假的状态 status。
    2. 当员工请假的时候,就自动向这张表中添加一条记录。
    3. 然后,当项目经理登录到 OA 的时候,就来这张表中查询自己需要审批的请假申请,查到之后,可以选择批准或者拒绝。
    4. 接下来,员工登录之后,就可以查询到自己的请假申请的审批结果。
    在这样的实现思路中,请假的流程我们是通过 status 这个字段来控制的。例如:
    ● status=0 表示待审批
    ● status=1 表示审批通过
    ● status=2 表示拒绝
    上面这个例子,status 就是状态码,通过这个字段的值来控制流程的状态,这种方式我们可以称之为使用状态机来解决流程问题,但是,这种思路,只能解决非常简单的流程问题。

02.一些复杂的流程
    a.报销审批流程
        在这个流程中,已经没法使用 status 去描述这个请假走到哪一步了。如果非要用 status,那么 status 可能会有很多取值:
        ● 0:表示员工提交报销申请
        ● 1: 表示部门经理审批通过
        ● 2:表示部门经理审批不通过,员工需要重新提交
        ● 3:表示大区经理审批通过
        ● 4:表示大区经理审批不通过
        ● 。。。
    b.笔记本电脑生产流程
        这个流程中, 不仅有串行任务,也有并行任务。虽然技术上来说,status 也还能做,
        但是,用 status 字段去描述这个流程,会非常非常复杂。

03.三大工作流
    三大主流工作流,只要掌握其中一个,另外两个可以非常容易的上手。
    最早的工作流是 jBPM,可以目前市面上大部分工作流的共同祖先。
    ● Activiti:当 jBPM 发展到 jBPM4 这个版本的时候,内部发生了分歧,然后一波人出来单干,基于 jBPM4 开发出来了 Activiti5;留下来的人,继续开发 jBPM5 的时候,几乎完全重写了 jBPM4 的代码。目前 Activiti 的设计侧重于云,即更靠拢 Spring Cloud、Docker、K8s 等。
    ● Flowable:Activiti5 在发展了一段时间之后,又从中分离出来一个团队,开发出来了 Flowable。Flowable 目前的核心思路还是做一个功能非常非常完善的流程引擎工具。除了常用的最最基本的工作流之外,Flowable 还提供了很多扩展点。
    ● Camunda:Activiti5 发展没多久,从 Activiti5 中分离中的团队,开发的 Camunda。在这三个主流的流程引擎中,Camunda 是最为轻量级的一个,如果我们的系统,当用户在使用的过程中,需要动态的绘制流程图,那么可以使用 Camunda,这是一个小巧的工具,可以非常的方便的嵌入到我们自己的系统中。Camunda 还提供了一个 bpmn.js 的工具,可以非常方便的实现流程图的绘制。

04.流程图
    工作流执行的基础是流程图。
    一个完整的流程,要干嘛,先得画出来一个完整的流程图。
    上面介绍了三种不同的工作流,那么三种不同的工作流的流程图绘制方式是否一样?
    其实,流程图的绘制,有一套统一的标准:BPMN(Business Process Model And Notation),中文译作业务流程模型和标记法。
    BPMN 就是一套图形化表示法,用图形来绘制、梳理业务流程模型。就是说,BPMN 其实是一套非常古老的流程图规范,Activiti、Flowable 以及 Camunda 都是支持这个规范的。所以,无论使用哪一个流程图,都可以依照 BPMN 规范去绘制流程图。
    虽然 BPMN 大家都支持,但是,在具体的使用细节上,不同的流程引擎还是有差别的。

1.2 核心组成

01.流程分类
    事件
    连线
    任务
    网关

02.事件
    开始事件/结束事件等等。
    这是我们上面用到的事件,实际上,还有很多其他类型的事件。

03.连线
    连接各个不同元素之间的线条,就是连线。
    注意,线条之上,可能会有条件。
    例如,在互斥网关上,满足一定的条件,流程图就继续往下走,不满足条件,流程图就回到之前的某一个位置上。

04.任务
    用户任务:需要人工参与完成的工作建模。
    服务任务:机器自动完成的事情,例如用户请假,经理审批通过,审批通过之后,想通过企业微信给用户发送一个通知,告诉他请假通过。这样的任务,可以使用服务任务,当流程走到这一步的时候,自动调用某一个 Java Bean,或者某一个远程服务去完成通知的发送,这是自动完成的,不需要人工介入。
    活动:活动可以算是一种特殊的任务。活动之中,往往可以在活动中,调用另外一个流程使之作为当前流程的子流程去执行。活动一般又可以继续细分为用户活动、脚本活动等等。。。
    接收任务:这个接收任务中,其实并不需要做什么额外的事情,流程到这一步就自动停下来,需要人工去助力一把,去推动流程继续向下走。
    发送任务:将消息发送给外部的参与者。
    脚本任务:一个自动化的活动,当流程执行到脚本任务的时候,自动执行相应的脚本。齿轮表示这是一个服务任务,也就是系统自动完成的,系统自动完成的方式有很多种,其中一种是提前将自己的业务逻辑在 Java 类中写好,然后这里配置一下类的完整路径即可
    业务规则任务:BPMN2.0 中引入的用来对接业务规则的引擎,业务规则主要用于同步执行一个或者多个规则。虽然这里分类比较多,但是实际上,任务主要就两种:用户任务:需要用户介入的任务。服务任务:机器自动完成的任务。发送任务、接收任务、脚本任务等等,这些其实都是服务任务的细分而已。

05.网关
    互斥网关:这个可以有多个入口,但是只有一个有效的出口。
    并行网关:并行网关一般是成对出现的,当有并行操作的时候,可以使用并行网关。
    相容网关:这种网关可能会存在多个有效的出口。
    事件网关:通过中间事件驱动的网关,当等待的事件触发之后,才会触发决策。

1.3 实战流程

01.绘制一个报销流程图,大致流程:
    1. 启动一个流程。
    2. 执行一个用户任务,这个用户任务交给流程的启动人去执行。这个用户任务中,填入报销材料,例如用户名、金额、用途。
    3. 系统自动判断一下/或者人工判断报销金额是否大于 1000。
    4. 如果报销金额小于等于 1000,那么这个报销任务交给 组长审批:
      a. 组长审批通过,则流程结束。
      b. 组长审批不通过,则流程回到第 2 步,用户重新去填写报销资料。
    5. 如果报销金额大于 1000,那么这个报销任务先交给经理审批:
      a. 经理审批通过,则交给 CEO 审批:
        ⅰ. CEO 审批通过,流程结束。
        ⅱ. CEO 审批不通过,流程回到步骤 2 中。
      b. 经理审批不通过,则流程回到步骤 2 中。

02.对于一个 UserTask 而言,任务处理人有四种:
    流程发起人,由流程的启动人/发起人来处理这个流程。
    单个用户,直接指定某一个具体的用户来处理这个流程,注意这里只能指定一个用户,并且这个用户将来在处理任务的时候,不需要认领,直接就可以处理。
    候选用户:可以同时指定多个用户来处理这个 UserTask,将来用户在处理的时候,需要先认领(Claim)任务,然后才能处理。
    候选组:可以同时指定多个用户组来处理这个 UserTask,这个处理的时候,也需要先认领,再处理。

03.基本概念
    流程定义(ProcessDefinition):我们绘制的流程图、流程的 XML 文件,就是我们的流程定义。
    流程(ProcessInstance):一个启动了流程实例就是一个流程,流程可以是已经执行完毕的,也可以是正在执行中的。流程的定义相当于是一个类,而流程则相当于是一个对象。
    任务(Task):一个 ProcessInstance 中,需要具体处理的节点就是一个任务。
    在 flowable-ui 中,绘制好的流程图,可以直接部署称为一个 App。

04.表单问题
    在流程中,传递流程参数有两种方式:流程变量、表单
    这两种方式都可以传递参数,区别在于,流程变量是零散的,而表单是整的。
    对于通过表单传递的参数,我们也可以按照流程变量的方式去访问单个的表单参数,
    例如在上面的流程图中,我们有 ${money <= 1000},这里的 money 实际上是表单中的参数,但是我们可以直接通过 $ 表达式去访问。
    还有如 ${managers_approve_or_reject_radio_button=="拒绝"},也是直接访问表单中的变量。

05.注意
    在一个流程图中,开始节点必须有且只有一个,结束节点可以有多个。

1.4 附:flowable

01.安装
    a.源码地址
        https://github.com/flowable/flowable-engine
    b.编译的步骤
        1.clone 代码: git clone [email protected]:flowable/flowable-engine.gi
        2.切换分支 git checkout -b origin/6.7.2切换到 6.7.2 这个版本。
    c.先来看下源码的目录结构
        LICENSE:开源协议。
        README.md:flowable 介绍文档。
        distro:主要是保存了不同环境下的信息。
        docker:将 flowable 构建成 docker 镜像的脚本。
        docs:flowable 的文档。
        ide-settings:这是如果想在 Eclipse 或者 IDEA 中快速使用 flowable 时候的配置。
        k8s:flowable 支持 k8s 的一些脚本和配置。
        modules:flowable 中所有的核心功能代码都在这个里边。
        pom.xml:maven 的坐标文件。
        qa:提供了很多各种各样的配置模版,例如如果我们需要在传统的 SSM 中配置 flowable,配置文件可以直接参考 qa 中的,但是我们现在主要是 Spring Boot 开发,在 Spring Boot 中,基本上用不到 qa 中的配置模版。
        scripts:这个目录下放了常用的脚本文件。
        tooling:这个目录中列出来了单元测试的模版。

02.项目编译要点
    a.第1步
        用 IDEA 打开项目。在 IDEA 中,直接 open 源码即可,不需要 Import Project。
    b.第2步
        由于 IDEA 无法识别出所有的 Maven 工程,查看是否识别出来 Maven 工程的方式:
        pom.xml 文件是蓝色的,或者工程名加粗了,
        【重点!!!】如果有 IDEA 未识别出来的 Maven 工程,都需要挨个手动添加,添加方式就是打开项目的 pom.xml 文件,右键单击,选择 Add as Maven Project(添加为Maven项目)
    c.第3步
        对于 Maven 工程,IDEA 会自动去下载所需要的依赖,但是由于这里需要下载的依赖比较多,所以下载的时候比较费时间,耐心等一下。最终也有可能会下载失败:i:先去本地 Maven 仓库,搜索以 .lastupdated结尾的文件,并删除。
    d.注意
        如果前面步骤不管用,那么就去 settings.xml 文件中,修改远程仓库地址,切换为 阿里云或者华为云等提供的镜像站,然后再重新导入。
        <mirrors>
          <!-- mirror
           | Specifies a repository mirror site to use instead of a given repository. The repository that
           | this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used
           | for inheritance and direct lookup purposes, and must be unique across the set of mirrors.
           |
          <mirror>
            <id>mirrorId</id>
            <mirrorOf>repositoryId</mirrorOf>
            <name>Human Readable Name for this Mirror.</name>
            <url>http://my.repository.com/repo/path</url>
          </mirror>
           -->
            <mirror>
            <id>alimaven</id>
            <name>aliyun maven</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <mirrorOf>central</mirrorOf>
          </mirror>
        </mirrors>

03.H2数据库
    1.Java 编写的数据库。
    2.可以基于内存来使用。
    3.也可以基于文件,基于文件,类似于移动端的 Sqlite。

1.5 附:flowable-ui

00.工具
    官方:flowable-ui
    IDEA:flowable-bpmn-visualizer
    Eclipse:Flowable Eclipse Designer
    Camunda:bpmn.js

01.安装
    a.下载
        https://github.com/flowable/flowable-engine/releases/download/flowable-6.7.2/flowable-6.7.2.zip
        这个 zip 包下载之后,里边有一个 wars 文件夹,里边包含了 flowable-ui 的 war 包。
        然后,就像启动 Spring Boot 一样,直接启动这个 war 包即可:
    b.启动
        java -jar flowable-ui.war
    c.访问
        http://localhost:8080/flowable-ui/
        admin,test
        zs/ls/ww,123456

02.功能模块
    a.介绍1
        flowable-ui 是完整的 flowable 体验 DEMO,而不仅仅只是一个流程图的绘制工具。所以它里边不仅可以画流程图,还可以运行流程图,既然能够运行流程图,那么就需要身份管理。
        1.任务应用程序:我们绘制好的流程图,可以直接将之发布到一个应用中,然后在这里进行部署,这个模块其实就是这些部署的应用程序。
        2.建模器应用程序:这个专门用来画流程图的。
        3.管理员应用程序:这个主要用来管理应用,一些具有管理员权限的用户,可以通过这个功能模块去查询 BPMN、DMN、FORM 等等信息。
        4.身份管理应用程序:这个功能模块,为所有的 flowable-ui 应用程序提供一个单点登录功能,并且还可以为这些用户设置用户组、用户权限等。
    b.介绍2
        Flowable提供了几个web应用,用于演示及介绍Flowable项目提供的功能:
        1.Flowable Task: 运行时任务应用。提供了启动流程实例、编辑任务表单、完成任务,以及查询流程实例与任务的功能。
        2.Flowable Modeler: 让具有建模权限的用户可以创建流程模型、表单、选择表与应用定义。
        3.Flowable Admin: 管理应用。让具有管理员权限的用户可以查询BPMN、DMN、Form及Content引擎,并提供了许多选项用于修改流程实例、任务、作业等。管理应用通过REST API连接至引擎,并与Flowable Task应用及Flowable REST应用一同部署。
        4.Flowable IDM: 身份管理应用。为所有Flowable UI应用提供单点登录认证功能,并且为拥有IDM管理员权限的用户提供了管理用户、组与权限的功能。
    c.简单来说
        Flowable Task:测试、体验流程
        Flowable Modeler:画流程图
        Flowable Admin:后台管理
        Flowable IDM:创建用户、分配角色

03.创建流程
    a.managers_approve_or_reject
        managers_approve_or_reject
        ${form_managers_approve_or_reject_outcome=="同意"}
        ${form_managers_approve_or_reject_outcome=="拒绝"}
    b.ceo_approve_or_reject
        ${form_ceo_approve_or_reject_outcome=="同意"}
        ${form_ceo_approve_or_reject_outcome=="拒绝"}
    c.leader_approve_or_reject
        ${form_leader_approve_or_reject_outcome=="同意"}
        ${form_leader_approve_or_reject_outcome=="拒绝"}
    d.managers_approve_or_reject_radio_button
        ${managers_approve_or_reject_radio_button=="同意"}
        ${managers_approve_or_reject_radio_button=="拒绝"}

1.6 附:flowable-bpmn-visualizer

01.主要组件
    a.开始事件
        ID                                         startEvent
        Name                                       开始一个请假流程
        Documentation
        Form key
        Form field validation
        Message reference
        Escalation reference
        Error reference
        Signal reference
        Form properties                            Add property
        Execution listeners                        Add execution listeners
    b.任务
        ID                                         approveRequest
        Name                                       批准或者拒绝请假请求
        Documentation
        Is for compensation
        Asynchronous
        Assignee                                   当前的UserTask由哪个用户处理,这里如果是传递变量需要用 ${} 表达式,如果是字符串,直接写即可,例如,这个节点由一个名为 BNTang 的用户来处理
        Candidate Users                            当前的UserTask由哪些候选用户处理
        Candidate Groups                           当前的UserTask由哪个Group来处理,Group相当于我们平时说的角色
        Skip expression
        Due date
        Category
        Form key
        Form field validation
        Priority
        Form properties                            Add property
        Execution listeners                        Add execution listeners
    c.网关(Exclusive gateway,排它网关)
        ID                                         approveOrRejectGateway
        Name
        Documentation
        Default flow element                       gateway_to_approve
    d.任务
        ID                                         sendApproveEmail
        Name                                       发送请假审批通过的邮箱
        Documentation
        Is for compensation
        Asynchronous
        Exclusive
        Expression
        Delegate expression
        Class
        Skip expression
        Is activity triggerable?
        Result variable name
        Use local scope for result varaible
        Failed job retry cycle
        Fields                                     Add field
        Execution listeners                        Add execution listeners
        -----------------------------------------------------------------------------------------------------
        ID                                         sendRejectEmail
        Name                                       发送请假被拒绝的邮箱
        Documentation
        Is for compensation
        Asynchronous
        Exclusive
        Expression
        Delegate expression
        Class                                      top.it6666.flowable.Approve
        Skip expression
        Is activity triggerable?
        Result variable name
        Use local scope for result varaible
        Failed job retry cycle
        Fields                                     Add field
        Execution listeners                        Add execution listeners
    e.结束任务
        ID                                         endEvent
        Name
        Documentation
        Escalation reference
        Error reference
        Execution listeners                        Add execution listeners

02.主要组件
    a.连接1
        ID                                        startEvent_to_approveRequest
        Name
        Documentation
        Source reference                          startEvent
        Target reference                          approveRequest
        Condition expression                      条件表达式,用于判断流程的走向
        Condition expression type
        Execution listeners                       Add execution listeners
    b.连接2
        ID                                        approveRequest_to_approveOrRejectGateway
        Name
        Documentation
        Source reference                          approveRequest
        Target reference                          approveOrRejectGateway
        Condition expression
        Condition expression type
        Execution listeners                       Add execution listeners
    c.排它网关,是
        ID                                        gateway_to_approve
        Name                                      从网关到请求同意
        Documentation
        Source reference                          approveOrRejectGateway
        Target reference                          sendApproveEmail
        Condition expression                      "${approve}"
        Condition expression type                 tFormalExpression
        Default flow element
        Execution listeners                       Add execution listeners
        -----------------------------------------------------------------------------------------------------
        从排他性网关出来的线条中,有一个 Condition expression,这个表示这个线条执行的条件。
        具体来说,就是当用户在审批的时候,本质上其实就是传递一个变量,变量值为 true 或者 false。
        下图中的 ${approve} 表示这个变量的名字为 approve。
    d.排它网关,否
        ID                                        gateway_to_reject
        Name                                      从网关到请求被拒绝
        Documentation
        Source reference                          approveOrRejectGateway
        Target reference                          sendRejectEmail
        Condition expression                      "${!approve}"
        Condition expression type                 tFormalExpression
        Default flow element
        Execution listeners                       Add execution listeners
        -----------------------------------------------------------------------------------------------------
        从排他性网关出来的线条中,有一个 Condition expression,这个表示这个线条执行的条件。
        具体来说,就是当用户在审批的时候,本质上其实就是传递一个变量,变量值为 true 或者 false。
        下图中的 ${approve} 表示这个变量的名字为 approve。
    e.连接3
        ID                                        sendApproveEmail_to_endEvent
        Name
        Documentation
        Source reference                          sendApproveEmail
        Target reference                          endEvent
        Condition expression
        Condition expression type
        Execution listeners                       Add execution listeners
    f.连接4
        ID                                        sendRejectEmail_to_endEvent
        Name
        Documentation
        Source reference                          sendRejectEmail
        Target reference                          endEvent
        Condition expression
        Condition expression type
        Execution listeners                       Add execution listeners

03.示例XML
    <?xml version="1.0" encoding="UTF-8"?>
    <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef">
      <!--
      process:流程定义的根元素,一个BPMN 2.0文档中可以包含多个process元素,每个process元素都是一个独立的流程定义。
      -->
      <process id="Demo00" name="Demo00" isExecutable="true">
        <!--
        startEvent:开始事件,流程定义中必须包含一个开始事件,用于标识流程定义的启动点。
        -->
        <startEvent id="startEvent" name="开始一个请假流程"/>
        <!--
        userTask:用户任务,流程定义中可以包含多个用户任务,用于标识流程中的一个任务。
        -->
        <userTask id="approveRequest" name="批准或者拒绝请假请求"/>
        <!--
        sequenceFlow:顺序流,用于标识流程中的执行顺序。
        -->
        <sequenceFlow id="startEvent_to_approveRequest" sourceRef="startEvent" targetRef="approveRequest"/>
        <!--
        exclusiveGateway:排他网关,用于标识流程中的分支和合并。
        -->
        <exclusiveGateway id="approveOrRejectGateway" default="gateway_to_approve"/>
        <!--
        sequenceFlow:顺序流,用于标识流程中的执行顺序。
        -->
        <sequenceFlow id="approveRequest_to_approveOrRejectGateway" sourceRef="approveRequest" targetRef="approveOrRejectGateway"/>
        <!--
        serviceTask:服务任务,用于标识流程中的一个服务任务。
        -->
        <serviceTask id="sendApproveEmail" flowable:exclusive="true" name="发送请假审批通过的邮箱"/>
        <!--
        sequenceFlow:顺序流,用于标识流程中的执行顺序。
        -->
        <sequenceFlow id="gateway_to_approve" sourceRef="approveOrRejectGateway" targetRef="sendApproveEmail">
          <!--
          conditionExpression:条件表达式,用于标识顺序流的条件。
          -->
          <conditionExpression xsi:type="tFormalExpression">${approve}</conditionExpression>
        </sequenceFlow>
        <!--
        serviceTask:服务任务,用于标识流程中的一个服务任务。
        -->
        <serviceTask id="sendRejectEmail" flowable:exclusive="true" name="发送请假被拒绝的邮箱" flowable:class="top.it6666.flowable.Approve"/>
        <!--
        sequenceFlow:顺序流,用于标识流程中的执行顺序。
        -->
        <sequenceFlow id="gateway_to_reject" sourceRef="approveOrRejectGateway" targetRef="sendRejectEmail" name="从网关到请求被拒绝">
          <conditionExpression xsi:type="tFormalExpression">${!approve}</conditionExpression>
        </sequenceFlow>
        <!--
        sequenceFlow:顺序流,用于标识流程中的执行顺序。
        -->
        <sequenceFlow id="sendApproveEmail_to_endEvent" sourceRef="sendApproveEmail" targetRef="endEvent"/>
        <sequenceFlow id="sendRejectEmail_to_endEvent" sourceRef="sendRejectEmail" targetRef="endEvent"/>
        <endEvent id="endEvent"/>
      </process>
      <bpmndi:BPMNDiagram id="BPMNDiagram_Demo00">
        <bpmndi:BPMNPlane bpmnElement="Demo00" id="BPMNPlane_Demo00">
          <!--
          开始节点
          -->
          <bpmndi:BPMNShape id="shape-720716bb-7992-4c79-9289-7697c965a250" bpmnElement="startEvent">
            <omgdc:Bounds x="-550.0" y="65.0" width="30.0" height="30.0"/>
          </bpmndi:BPMNShape>
          <!--
          用户任务
          -->
          <bpmndi:BPMNShape id="shape-4bbbd282-b4b4-4ebc-a979-f148f400e7d2" bpmnElement="approveRequest">
            <omgdc:Bounds x="-425.0" y="40.0" width="100.0" height="80.0"/>
          </bpmndi:BPMNShape>
          <!--
          sequenceFlow:顺序流,用于标识流程中的执行顺序。
          -->
          <bpmndi:BPMNEdge id="edge-c9de96ec-da86-43c6-b84f-c185782ac4ff" bpmnElement="startEvent_to_approveRequest">
            <omgdi:waypoint x="-520.0" y="80.0"/>
            <omgdi:waypoint x="-425.0" y="80.0"/>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNShape id="shape-7d5f411f-f2e2-4c4a-ac43-368ef7489c11" bpmnElement="approveOrRejectGateway">
            <omgdc:Bounds x="-230.0" y="60.0" width="40.0" height="40.0"/>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNEdge id="edge-20bcfcad-f8b8-4a3c-8f2b-1540b0903b10" bpmnElement="approveRequest_to_approveOrRejectGateway">
            <omgdi:waypoint x="-325.0" y="80.0"/>
            <omgdi:waypoint x="-275.79172" y="80.0"/>
            <omgdi:waypoint x="-230.0" y="80.0"/>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNShape id="shape-c1f0d7a5-355f-4cc7-857e-ec50ad44e5f9" bpmnElement="sendApproveEmail">
            <omgdc:Bounds x="-104.49818" y="40.0" width="100.0" height="80.0"/>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNEdge id="edge-7388f00b-1867-4b52-87e2-1c8dbcac5588" bpmnElement="gateway_to_approve">
            <omgdi:waypoint x="-190.0" y="80.0"/>
            <omgdi:waypoint x="-147.24908" y="80.00001"/>
            <omgdi:waypoint x="-104.49818" y="80.0"/>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNShape id="shape-28a27ae4-28cf-4257-8858-7fd1222f9b58" bpmnElement="sendRejectEmail">
            <omgdc:Bounds x="-104.49817" y="165.00002" width="100.0" height="80.0"/>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNEdge id="edge-c687124b-5335-44b3-9e84-4c08c759e566" bpmnElement="gateway_to_reject">
            <omgdi:waypoint x="-210.0" y="100.0"/>
            <omgdi:waypoint x="-210.0" y="185.0"/>
            <omgdi:waypoint x="-104.49817" y="185.00002"/>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge id="edge-cbdabd5a-0320-4beb-8746-8a0b2c3d982b" bpmnElement="sendApproveEmail_to_endEvent">
            <omgdi:waypoint x="-4.4981766" y="80.0"/>
            <omgdi:waypoint x="125.0" y="80.0"/>
            <omgdi:waypoint x="125.0" y="169.99998"/>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge id="edge-7ac3bda4-a111-4f1b-a1cd-0e673c8d3ed9" bpmnElement="sendRejectEmail_to_endEvent">
            <omgdi:waypoint x="-4.498169" y="185.00002"/>
            <omgdi:waypoint x="110.0" y="185.0"/>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNShape id="shape-b5991b38-6b94-478d-968a-d137717678f6" bpmnElement="endEvent">
            <omgdc:Bounds x="110.0" y="170.0" width="30.0" height="30.0"/>
          </bpmndi:BPMNShape>
        </bpmndi:BPMNPlane>
      </bpmndi:BPMNDiagram>
    </definitions>

2 主要功能

2.1 涉及表

01.流程定义相关表
    ACT_RE_DEPLOYMENT:部署信息表,存储每次流程定义部署的元数据。
    ACT_RE_PROCDEF:流程定义表,存储流程定义的详细信息(如定义 ID、版本号、部署 ID 等)。
    ACT_RE_MODEL:模型表,用于存储通过 Flowable Modeler 创建的流程模型。
    ---------------------------------------------------------------------------------------------------------
    ACT_RE_DEPLOYMENT 和 ACT_RE_PROCDEF 是一对一的关系。
    ACT_RE_DEPLOYMENT 和 ACT_GE_BYTEARRAY 是一对多的关系,一个流程部署 ID 对应两条 ACT_GE_BYTEARRAY 表中的记录(默认)。

02.流程实例相关表
    ACT_RU_EXECUTION:流程执行实例表,存储正在运行的流程实例和执行信息。
    ACT_RU_EVENT_SUBSCR:事件订阅表,用于存储事件订阅数据(如消息事件和信号事件)。
    ACT_RU_VARIABLE运行时变量表,存储流程运行中的变量。

03.任务相关表
    ACT_RU_TASK:运行时任务表,存储正在运行的任务实例。
    ACT_RU_IDENTITYLINK:任务与用户、组之间的关系表,用于分配用户或角色到特定任务。
    ACT_RU_DEADLETTER_JOB:死信任务表,存储无法执行的任务(如失败的定时任务)。

04.历史数据相关表
    ACT_HI_PROCINST:历史流程实例表,存储已完成的流程实例记录。
    ACT_HI_ACTINST:历史活动实例表,存储每个流程节点的执行历史。
    ACT_HI_TASKINST:历史任务实例表,存储已完成的任务记录。
    ACT_HI_VARINST:历史变量表,存储流程结束后的变量信息。
    ACT_HI_DETAIL:历史详情表,记录流程实例运行期间的详细信息(如变量修改记录)。

05.作业调度相关表
    ACT_RU_JOB:定时任务表,用于存储需要执行的作业(如定时器事件)。
    ACT_RU_TIMER_JOB:定时器任务表,存储尚未触发的定时任务。
    ACT_RU_SUSPENDED_JOB:暂停任务表,存储暂停的定时任务信息。

06.其他辅助表
    ACT_ID_USER:用户信息表,存储系统用户数据。
    ACT_ID_GROUP:用户组表,存储用户组信息。
    ACT_ID_MEMBERSHIP:用户与用户组关系表。
    ACT_GE_BYTEARRAY:二进制数据表,存储流程定义的 XML 文件和模型的 JSON 数据。
    ACT_GE_PROPERTY:属性表,存储全局配置信息(如数据库 schema 版本等)。

2.2 流程定义、实例

00.概念
    a.流程定义
        在使用 flowable 的时候,我们首先需要画一个流程图,要在我们的代码中使用流程图,就必须先把流程图部署到项目中。
        加载到系统中的流程图,就是流程定义:ProcessDefinition。
    b.流程实例
        我们启动的每一个具体的流程,就是一个流程实例 ProcessInstance。
        ProcessDefinition 相当于 Java 中的类,ProcessInstance 则相当于根据这个类创建出来的对象。

01.流程定义ProcessDefinition
    a.自动部署
        a.部署位置
            在 Spring Boot 中,凡是放在 resources/processes 目录下的流程文件,默认情况下,都会被自动部署。
            如:任意绘制一个流程图,放到 resources/processes 目录下:JsonFormatForm.bpmn20.xml
        b.自动部署
            启动 Spring Boot 项目,启动之后,这个流程就被自动部署了。
            ACT_RE_DEPLOYMENT 和 ACT_RE_PROCDEF 分别保存了流程定义相关的信息。
            ACT_GE_BYTEARRAY表则保存了刚刚定义的流程的 XML 文件以及根据这个 XML 文件所自动生成的流程图。
        c.三张表的关系
            ● ACT_RE_DEPLOYMENT 和 ACT_RE_PROCDEF 是一对一的关系。
            ● ACT_RE_DEPLOYMENT 和 ACT_GE_BYTEARRAY 是一对多的关系,一个流程部署 ID 对应两条 ACT_GE_BYTEARRAY 表中的记录(默认)。
        d.修改流程
            流程部署好之后,如果想要修改,可以直接修改,修改之后,流程会自动升级(数据库中的记录会自动更新)。
            举个例子:
            假设我们现在修改了流程定义的名字,然后重新启动 SpringBoot 项目,
            那么 ACT_RE_DEPLOYMENT 表中会增加一条部署记录,同时 ACT_RE_PROCDEF 表也会增加一条新的流程定义信息,
            新的流程信息中,该变的字段会自动变,同时版本号 VERSION_会自增 1。
            ACT_GE_BYTEARRAY 表中也会新增两条记录,和最新的版本号的定义相对应。
        e.注意
            流程图的更新,主要是以流程定义的 id 为依据,
            如果流程定义的内容发生变化,但是流程 id 没有变,则流程定义升级;
            如果流程图定义的 id 发生变化,则直接重新部署新的流程。
        f.在流程的定义中,XML 文件中的 targetNamespace 属性,其实就是流程的分类定义:
            <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef" exporter="Flowable Open Source Modeler" exporterVersion="6.7.2">
              <process id="javaboy_submit_an_expense_account2" name="javaboy的报销流程2" isExecutable="true">
                <documentation>javaboy的报销流程</documentation>
                <startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
                <userTask id="sid-71C33AD7-E892-4037-AFBB-464957E41378" name="填写报销材料" flowable:assignee="$INITIATOR" flowable:formKey="submit_an_expense_account" flowable:formFieldValidation="true">
                  <extensionElements>
                    <modeler:activiti-idm-initiator xmlns:modeler="http://flowable.org/modeler"><![CDATA[true]]></modeler:activiti-idm-initiator>
                  </extensionElements>
                </userTask>
            如果想要修改流程定义的分类,直接修改该属性即可。
        g.Spring Boot 中,关于流程定义的几个重要属性:
            spring.datasource.username=root
            spring.datasource.password=123456
            spring.datasource.url=jdbc:mysql:///flowable_process?serverTimezone=Asia/Shanghai&useSSL=false&nullCatalogMeansCurrent=true
            logging.level.org.flowable=debug
            -------------------------------------------------------------------------------------------------
            # 是否在项目启动的时候,自动去检查流程定义目录下是否有对应的流程定义文件,如果这个属性为 true(默认即次),就表示去检查,否则不检查(意味着不会自动部署流程)
            flowable.check-process-definitions=true
            # 设置流程定义文件的位置,默认位置就是 classpath*:/processes/
            flowable.process-definition-location-prefix=classpath*:/javaboy/
            # 这个是指定流程定义 XML 文件的后缀,默认后缀有两个:**.bpmn20.xml,**.bpmn
            flowable.process-definition-location-suffixes=**.bpmn20.xml,**.bpmn
    b.手动部署
        a.


        b.


        c.


        d.

3 集成框架

3.1 jflow

3.2 airflow

3.3 liteflow

3.4 flowlong

3.5 logicflow

3.6 warm-flow