image.png工作流Flowable

项目基于Flowable 6 实现了工作流的功能。本章节,我们将介绍工作流的相关功能。
以请假流程为例,讲解系统支持的两种表单方式的工作流:

  1. 流程表单:在线配置动态表单,无需建表与开发
  2. 业务表单:业务需建立独立的数据库表,并开发对应的表单、详情界面

整个过程包括:

  1. 定义流程:【管理员】新建流程、设计流程模型、并设置用户任务的审批人,最终发布流程
  2. 发起流程:【员工】选择流程,并发起流程实例
  3. 审批流程:【审批人】接收到流程任务,审批结果为通过或不通过

image.png

1. 请假流程【流程表单】

1.1 第一步:定义流程

登录账号 admin、密码 admin123 的用户,扮演【管理员】的角色,进行流程的定义。
① 访问 [工作流程 -> 流程管理 -> 流程模型] 菜单,点击 [新建流程] 按钮,填写流程标识、流程名称。如下图所示:
1652239926232-3d401476-920b-4af5-b915-283fa6b5e1db.png

  • 流程标识:对应 BPMN 流程文件 XML 的 id 属性,不能重复,新建后不可修改。
  • 流程名称:对应 BPMN 流程文件 XML 的 name 属性。

    1. <!-- 这是一个 BPMN XML 的示例,主要看 id 和 name 属性 -->
    2. <?xml version="1.0" encoding="UTF-8"?>
    3. <bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" id="diagram_Process_1647305370393" targetNamespace="http://activiti.org/bpmn">
    4. <bpmn2:process id="common-form" name="通用表单流程" isExecutable="true" />
    5. <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    6. <bpmndi:BPMNPlane id="common-form_di" bpmnElement="common-form" />
    7. </bpmndi:BPMNDiagram>
    8. </bpmn2:definitions>

    ② 访问 [工作流程 -> 流程管理 -> 流程表单] 菜单,点击 [新增] 按钮,新增一个名字为 leave-form 的表单。如下图所示:
    1652239926371-aebde31a-00aa-4663-8ab1-4c5838fd5f1e.png
    流程表单的实现?
    基于 https://github.com/JakHuang/form-generator项目实现的动态表单。
    回到 [工作流程 -> 流程管理 -> 流程模型] 菜单,点击 [修改流程] 按钮,配置表单类型为流程表单,选择名字为 leave-form 的流程表单。如下图所示:
    1652239926343-24c4775a-219b-439d-9c2f-416995b8666c.png
    ③ 点击 [设计流程] 按钮,在线设计请假流程模型,包含两个用户任务:领导审批、HR 审批。如下图所示:
    1652239926366-fa05568a-65ce-4894-b35d-805fee2aee72.png
    设计流程的实现?
    基于 https://github.com/miyuesc/bpmn-process-designer项目实现,它的底层是 bpmn-js
    ④ 点击 [分配规则] 按钮,设置用户任务的审批人。其中,规则类型用于分配用户任务的审批人,目前有 7 种规则:角色、部门成员、部门负责人、岗位、用户、用户组、自定义脚本,基本可以满足绝大多数场景,是不是非常良心。

  • 设置【领导审批】的规则类型为自定义脚本 + 流程发起人的一级领导,如下图所示: image.png

  • 设置【HR 审批】的规则类型为岗位 + 人力资源,如下图所示: 1652239928064-367c7cff-0d3f-49a8-a4f4-448c952e272f.png

规则类型的实现?
可见 module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java代码,目前暂时支持分配一个审批人。
⑤ 点击 [发布流程] 按钮,把定义的流程模型部署出去。部署成功后,就可以发起该流程了。如下图所示:
image.png
修改流程后,需要重新发布流程吗?
需要,必须重新发布才能生效。每次流程发布后,会生成一个新的流程定义,版本号从 v1 开始递增。
发布成功后,会部署新版本的流程定义,旧版本的流程定义将被挂起。当然,已经发起的流程不会受到影响,还是走老的流程定义。

1.2 第二步:发起流程

登录账号 admin、密码 admin123 的用户,扮演【员工】的角色,进行流程的发起。
① 访问 [工作流程 -> 任务管理 -> 我的流程] 菜单,点击 [发起流程] 按钮,可以看到可以选择的流程定义的列表。
1652239928283-db02e3bd-4456-44b1-b2d5-1c24bee70adb.png
② 选择名字为通用表单的流程定义,发起请假流程。填写请假表单信息如下:
image.png
③ 点击提交成功后,可在我的流程中,可看到该流程的状态、结果。
1652239928839-00fd693c-1bcc-4629-986a-7d0368506a8a.png
④ 点击 [详情] 按钮,可以查看申请的表单信息、审批记录、流程跟踪图。
1652239929204-1b246d5b-4139-42da-95f5-e5de382ce684.png

1.2 第三步:审批流程(领导审批)

登录账号 test、密码 test123 的用户,扮演【审批人】的角色,进行请假流程的【领导审批】任务。
① 访问 [工作流程 -> 任务管理 -> 待办任务] 菜单,可以查询到需要审批的任务。
1652239929219-affeb216-d98c-4d8c-8704-20eba24d2848.png
② 点击 [审批] 按钮,填写审批建议,并点击 [通过] 按钮,这样任务的审批就完成了。
1652239929792-8af63f1b-61eb-4393-967f-45f1d52fcad8.png
③ 访问 [工作流程 -> 任务管理 -> 已办任务] 菜单,可以查询到已经审批的任务。
1652239930149-f732525b-2aa4-4855-9be9-b7f6914c61cc.png


此时,使用【员工】的角色,访问 [工作流程 -> 任务管理 -> 我的流程] 菜单,可以看到流程流转到了【HR 审批】任务。
1652239930226-b2fa1b8a-094b-4b42-a7fe-3e1dc577b15b.png

1.3 第三步:审批流程(HR 审批)

登录账号 hrmgr、密码 hr123 的用户,扮演【审批人】的角色,进行请假流程的【HR 审批】任务。
① 访问 [工作流程 -> 任务管理 -> 待办任务] 菜单,点击 [审批] 按钮,填写审批建议,并点击 [通过] 按钮。


此时,使用【员工】的角色,访问 [工作流程 -> 任务管理 -> 我的流程] 菜单,可以看到流程处理结束,最终审批通过。
1652239930358-7c573b48-ade6-4a5e-b761-f26faa230a9a.png

2. 请假流程【业务表单】

根据业务需要,业务通过建立独立的数据库表(业务表)记录申请信息,而流程引擎只负责推动流程的前进或者结束。两者需要进行双向的关联:

  • 每一条业务表记录,通过它的流程实例的编号( process_instance_id )指向对应的流程实例
  • 每一个流程实例,通过它的业务键( BUSINESSKEY ) 指向对应的业务表记录。

以项目中提供的 OALeave请假举例子,它的业务表 bpm_oa_leave 和流程引擎的流程实例的关系如下图:
image.png
也因为业务建立了独立的业务表,所以必须开发业务表对应的列表、表单、详情页面。不过,审核相关的功能是无需重新开发的,原因是业务表已经关联对应的流程实例,流程引擎审批流程实例即可。
下面,我们以项目中的 OALeave为例子,详细讲解下业务表单的开发与使用的过程。

2.0 第零步:业务开发

① 新建业务表 bpm_oa_leave,建表语句如下:

CREATE TABLE `bpm_oa_leave` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '请假表单主键',
  `user_id` bigint NOT NULL COMMENT '申请人的用户编号',
  `type` tinyint NOT NULL COMMENT '请假类型',
  `reason` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '请假原因',
  `start_time` datetime NOT NULL COMMENT '开始时间',
  `end_time` datetime NOT NULL COMMENT '结束时间',
  `day` tinyint NOT NULL COMMENT '请假天数',
  `result` tinyint NOT NULL COMMENT '请假结果',
  `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '流程实例的编号',
  `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='OA 请假申请表';
  • processinstance_id 字段,关联流程引擎的流程实例对应的 ACT_HI_PROCINST 表的 PROC_INST_ID 字段
  • result 字段,请假结果,需要通过 Listener 监听回调结果,稍后来看看

② 实现业务表的【后端】业务逻辑,具体代码可以看看如下两个类:

重点是看流程发起的逻辑,它定义了 /bpm/oa/leave/create 给业务的表单界面调用,UML 时序图如下:
image.png
具体的实现代码比较简单,如下图所示:
image.png

  • PROCESS_KEY 静态变量:是业务对应的流程模型的编号,稍后会进行创建编号为 oa_leave 的流程模型。
  • BpmProcessInstanceApi定义了 #createProcessInstance(…) 方法,用于创建流程实例,业务无需关心底层是 Activiti 还是 Flowable 引擎,甚至未来可能的 Camunda 引擎。

③ 实现业务表的【前端】业务逻辑,具体代码可以看看如下三个页面:

  • leave/create.vue
  • leave/detail.vue
  • leave/index.vue

另外,在 router/index.js中定义 create.vue 和 detail.vue 的路由,配置如下:

{
  path: '/bpm',
    component: Layout,
      hidden: true,
        redirect: 'noredirect',
          children: [{
            path: 'oa/leave/create',
            component: (resolve) => require(['@/views/bpm/oa/leave/create'], resolve),
            name: '发起 OA 请假',
            meta: {title: '发起 OA 请假', icon: 'form', activeMenu: '/bpm/oa/leave'}
          }, {
            path: 'oa/leave/detail',
            component: (resolve) => require(['@/views/bpm/oa/leave/detail'], resolve),
            name: '查看 OA 请假',
            meta: {title: '查看 OA 请假', icon: 'view', activeMenu: '/bpm/oa/leave'}
          }
                    ]
}

为什么要做独立的 create.vueindex.vue 页面?

  • 创建流程时,需要跳转到 create.vue 页面,填写业务表的信息,才能提交流程。
  • 审批流程时,需要跳转到 detail.vue 页面,查看业务表的信息。

④ 实现业务表的【后端】监听逻辑,具体可见 BpmOALeaveResultListener监听器。它实现流程引擎定义的 BpmProcessInstanceResultEventListener抽象类,在流程实例结束时,回调通知它最终的结果是通过还是不通过。代码如下图:
image.png


至此,我们了解了 OALeave 使用业务表单所涉及到的开发,下面我们来定义对应的流程、发起该流程、并审批该流程。

2.1 第一步:定义流程

登录账号 admin、密码 admin123 的用户,扮演【管理员】的角色,进行流程的定义。
① 访问 [工作流程 -> 流程管理 -> 流程模型] 菜单,点击 [新建流程] 按钮,填写流程标识、流程名称。如下图所示:
1652239932254-978ca654-eef9-4683-9f70-5d9c2c29b824.png
注意,流程标识需要填 oa_leave。因为在 BpmOALeaveServiceImpl 类中,规定了对应的流程标识为 oa_leave。
② 点击 [修改流程] 按钮,配置表单类型为业务表单,填写表单提交路由为 /bpm/oa/leave/create(用于发起流程时,跳转的业务表单的路由)、表单查看路由为 /bpm/oa/leave/detail(用于在流程详情中,点击查看表单的路由)。如下图所示:
image.png
③ 点击 [设计流程] 按钮,在线设计请假流程模型,包含两个用户任务:领导审批、HR 审批。如下图所示:
1652239932686-d8b97daf-7658-4f8a-9cab-37ff3b0f6644.png
可以点击 oa_leave_bpmn.XML 进行下载,然后点击 [打开文件] 按钮,进行导入。
④ 点击 [分配规则] 按钮,设置用户任务的审批人。

  • 设置【领导审批】的规则类型为自定义脚本 + 流程发起人的一级领导,如下图所示: image.png
  • 设置【HR 审批】的规则类型为岗位 + 人力资源,如下图所示: 1652239933957-77291037-e3f4-4761-941a-6629d0e13ff2.png

⑤ 点击 [发布流程] 按钮,把定义的流程模型部署出去。部署成功后,就可以发起该流程了。

2.1 第二步:发起流程

登录账号 admin、密码 admin123 的用户,扮演【员工】的角色,进行流程的发起。
① 发起业务表单请假流程,两种路径:

  1. 访问 [工作流程 -> 任务管理 -> 我的流程] 菜单,点击 [发起流程] 按钮,会跳转到流程模型 oa_leave 配置的表单提交路由。 1652239933949-f39f9c74-7971-4ce5-b700-4a437ef43d95.png
  2. 访问 [工作流程 -> 请假查询] 菜单,点击 [发起请假] 按钮。 1652239933984-40cbec81-d342-48fd-9ac3-fce3fa8a0ae6.png

② 填写一个小于等于 3 天的请假,只会走【领导审批】任务;填写一个大于 3 天的请假,在走完【领导审批】任务后,会额外走【HR 审批】任务。
后续的流程,和「1. 请假流程【流程表单】」是基本一致的,这里就不重复赘述,当然你还是要试着跑一跑,了解整个的过程。

2. 项目结构

工作流的功能,由多个 Maven Module 组成,它们的关系如下图:
image.png
ykkj-module-bpm-biz-activiti 和 ykkj-module-bpm-biz-flowable 的实现代码基本是一致的,因为 Activiti 7 和 Flowable 6 的内核本质上都是 Activiti 6,两者提供的 API 也是基本一致的,差别主要在包名上,以及 Flowable 多了加签、动态增加实例中的节点等功能。
考虑到 Activiti 和 Flowable 在国内都有很大的用户群,且基本还处于一个相对均势的状态,所以项目就提供了两套实现,按照你的喜好进行跳转。 个人的话,相对比较看好 Flowable 一点,因为 Flowable 是 Tijs Rademakers 团队开发的,他们负责过 Activiti 5、Activiti 6,而 Activiti 7 现在由 Salaboy 团队负责,并没有注入太多的新特性。
当然有一点比较尴尬的是,Flowable 自从 6.4.1 版本开始,重点发力在其商业版,部分功能已经不再开源,比如说表单生成器(表单引擎)、历史数据同步至 ES、MongoDB 等其他数据源等等。
疑问:为什么不做一层中间抽象层,实现对应的 Flowable、Activiti 适配呢?
image.png
对于绝大多数团队,只会选择 Activiti 和 Flowable 其中的一个,增加抽象层后,会增加团队的学习与维护成本,不利于后续的二次开发。

3. 流程通知

流程在发生变化时,会发送通知给相关的人。目前有三个场景会有通知,通过短信的方式。
1652239935822-d926ff8e-35b2-46d9-9f33-c4ec37036021.png

遗留问题

1、不支持退回功能,退回时画上条件线,退回时根据变量判断,目前无法调回到开始节点。(需要跳过开始节点或者专门加一可用于驳回的可修改的节点。)
2、目前暂时支持分配一个审批人。
3、流程表单不支持审批节点的表单元素的权限控制。
4、业务表单不支持审批节点的表单修改功能。
5、会签功能。
6、全部流程实例管理,可对所有流程进行终止、变更节点等操作。