背景:参与的项目使用到了流程引擎SmartEngine,文档连接,因为流程引擎,规则引擎,权限等是业务系统非常常见的基础服务平台,总结一下还是很有必要的。
基础概念:
- 流程定义:就是一套bpmn文件,定义了流程的基本信息。有多少节点,每个节点一票还是全票等信息。
- 流程实例:一个运行时的流程。
- 人物:可以理解为一个审批节点,可以指派给多人,一个流程中,包含多个任务
- 加签:在一个流程实例中,审批节点动态加一个人。
- 会签:一个节点多个审批人,而多个人同时处理一个任务,这种任务我们称之为会签任务。
从流程引擎的核心领域来讲,大概就这几块:
- 流程配置域,对应流程定义的操作:创建,修改,删除流程定义。
- 流程启动域,对应实例的操作:启动,终止操作。
- 审批域,对应每个热任务的操作:同意,拒绝。
流程域
- 流程定义表
| name | status | bizId | bizType | processDefId | bpmnId | version |
|---|---|---|---|---|---|---|
| 流程名称 | 启动禁用 | 业务系统ID | 业务系统类型 | 流程定义Id | bpmn的Id | 流程定义版本 |
- 流程节点定义表
| processDefId | version | nodeOrder | name | type | roleType | empIds | rule |
|---|---|---|---|---|---|---|---|
| 流程定义Id | 版本 | 顺序 | 节点名称 | 需要/无需审批 | 节点角色类型 | 节点角色类型是指定人此字段为工号 |
一票/全票 |
- 节点审批人快照表
| processDefId | version | processInstanceId | taskNmae | empId | empName |
|---|---|---|---|---|---|
| 流程定义Id | 版本 | 实例id | 节点名称 | 工号 | 姓名 |
其中流程定义ID是我们自己生成的,作为流程定义的唯一标识,bpmnId是由smartEngine生成的,依赖smartEngine的DeploymentCommandService,这服务是smartEngine提供的,其实就相当于,smartEngine已经做了一套流程定义的全部接口,我们只是在外面套了一层业务表,用来使用。还有就是smartEngine自带的几张引擎内使用的表,这个我们不能进行操作。
版本号的作用:当流程已经有实例并且运行中了,这个时候,流程定义有更新,如果没有版本号是区分不开,新版本和老版本的。如果有了版本号:那流程定义有更新,则影响不到老版本的运行,老版本的去查询节点配置等信息,根据版本号就很容易区分开。不会出现:流程跑着跑着,节点审批人变了的情况。
时序图:
@startuml
'https://plantuml.com/sequence-diagram
autonumber
collections 业务系统
collections 流程引擎服务
collections bpmn解析
control SmartEngine服务
database 流程引擎数据库
业务系统 -> 流程引擎服务: 新增操作,携带流程节点等信息
流程引擎服务 --> 流程引擎数据库: 存储流程定义表
流程引擎服务 --> 流程引擎数据库: 存储流程节点表
流程引擎服务 --> bpmn解析: 调用解析器生成下bpmn文件
bpmn解析 --> SmartEngine服务: bpmn自带接口调用
SmartEngine服务 --> 流程引擎数据库: 存储bpmn信息
流程引擎服务 <-- 流程引擎数据库: 返回结果
业务系统 <-- 流程引擎服务: 返回结果
hide footbox
@enduml
实例域
这里依赖,smartEngine的几个服务:
- processCommandService:用于流程启动
- repositoryCommandService:用于部署操作
- repositoryQueryService:用于查询流程配置
首先,查询流程定义表, 拿到最新版本配置信息,这时候我们就能拿到版本号,流程定义Id信息了,我们需要依赖repositoryQueryService的cachedProcessDefinition接口,了解到当前版本有没有部署过,没有部署过,则调用部署接口部署,部署完成后启动,
部署究竟是个什么概念?
我其实没太理解,为啥吧加载bpmn文件到内存和启动流程步骤拆开,我感觉smartEngine完全可以对使用系统屏蔽这个细节。在启动接口内部做好这个就好了。。
同步操作时序图:
@startuml
'https://plantuml.com/sequence-diagram
autonumber
collections 业务系统
collections 流程引擎服务
control SmartEngine服务
database 流程引擎数据库
业务系统 -> 流程引擎服务: 流程启动操作,携带业务系统id等参数
流程引擎服务 --> 流程引擎数据库: 查询流程定义表最新的版本信息
流程引擎服务 --> SmartEngine服务: 如果没有部署则先部署bpmn文件
流程引擎服务 --> SmartEngine服务: 启动流程
流程引擎服务 <-- SmartEngine服务: 返回结果
业务系统 <-- 流程引擎服务: 返回结果
hide footbox
@enduml
启动流程后,异步的去初始化,审批人快照表,用于展示每个节点的审批人信息,这里也有个简单的策略,根据节点的roleType来决定人是如何查询的,业务系统配置的接口 or 调用自己默认的几个角色,比如主管之类的。
异步操作时序图:
@startuml
'https://plantuml.com/sequence-diagram
autonumber
queue 消息队列
collections 流程引擎服务
collections 业务系统
database 流程引擎数据库
消息队列 -> 流程引擎服务: 异步动作启动
流程引擎服务 --> 流程引擎数据库: 查询流程节点定义信息
流程引擎服务 --> 业务系统: 查询业务系统获取每个节点的审批人信息
流程引擎服务 --> 流程引擎数据库: 存储快照表,每个节点的审批人
消息队列 <-- 流程引擎服务: 返回结果
hide footbox
@enduml
审批域
通过/拒绝
这里涉及到如下的表:
- 审批结果记录表
| name | status | bizId | bizType | processDefId | bpmnId | version | taskStatus |
|---|---|---|---|---|---|---|---|
| 流程名称 | 启动禁用 | 业务系统ID | 业务系统类型 | 流程定义Id | bpmn的Id | 流程定义版本 | 任务状态 |
-
点审批后,以审批通过为例,需要先拿到当前审批人在此实例下task对象,然后提交task驱动当前节点前进
这里依赖,smartEngine的几个服务:
- variableQueryService: 根据实例Id查询实例的一些变量信息
- taskQueryService:对实例中的task做查询操作
- taskCommandService:对实例中的task做驱动操作
时序图:
@startuml
'https://plantuml.com/sequence-diagram
autonumber
collections 业务系统
collections 流程引擎服务
control SmartEngine服务
业务系统 --> 流程引擎服务: 审批通过
流程引擎服务 --> SmartEngine服务: 根据实例id查询流程定义信息variableQueryService
流程引擎服务 --> SmartEngine服务: 查询操作人的任务信息taskQueryService,幂等操作
流程引擎服务 --> SmartEngine服务: 驱动task走流程taskCommandService
流程引擎服务 --> 流程引擎服务: 审批结果记录表记录节点状态
业务系统 <-- 流程引擎服务: 返回
hide footbox
@enduml
流程中加签
加签的业务语义就是,当前节点到一个人了,这个人想让另一个人先看看,看对方的想法是同意还是拒绝
@startuml
'https://plantuml.com/sequence-diagram
autonumber
collections 业务系统
collections 流程引擎服务
collections 权限服务
control SmartEngine服务
database 流程引擎数据库
业务系统 -> 流程引擎服务: 当前节点加签
流程引擎服务 --> SmartEngine服务: 更新当前流程变量,打个标记有加签节点
流程引擎服务 --> SmartEngine服务: 新增一个加签节点task,使用taskInstanceStorage存储
流程引擎服务 --> SmartEngine服务: taskCommandService的addTaskAssigneeCandidate关联审批人
流程引擎服务 --> 流程引擎数据库: 存储审批记录表,新增加签节点
业务系统 <-- 流程引擎服务: 返回
hide footbox
@enduml
一键审批
当一个审批节点很长的时候,或者特殊情况,特别着急,想快速走完审批流程,等等这些都是使用中常见的场景,因此从业务中抽象出来了一键审批的这样的功能,而往往一键审批功能仅仅对部分人开放,比如大领导,系统管理员等角色。
这里依赖,smartEngine的几个服务:
- ProcessEngineConfiguration:引擎初始化的配置类
- RelationShipDatabaseInstanceStorage:使用update操作,用于直接更新流程状态
- ProcessQueryService:查询流程实例对象
@startuml
'https://plantuml.com/sequence-diagram
autonumber
collections 业务系统
collections 流程引擎服务
collections 权限服务
control SmartEngine服务
database 流程引擎数据库
业务系统 -> 流程引擎服务: 一键审批调用
流程引擎服务 --> 权限服务: 权限校验,是否能一键审批
流程引擎服务 --> 流程引擎数据库: 更新审批记录表,审批结束,类型为一键审批
流程引擎服务 --> SmartEngine服务: 直接更新当前流程实例状态为结束
业务系统 <-- 流程引擎服务: 返回
hide footbox
@enduml
展示域
任务展示
依赖SmartEngine的TaskAssigneeDispatcher接口,实现其必要的方法可以做到,可参考文档,
依赖下面的一张表
- 审批结果记录表
| name | status | bizId | bizType | processDefId | bpmnId | version | taskStatus |
|---|---|---|---|---|---|---|---|
| 流程名称 | 启动禁用 | 业务系统ID | 业务系统类型 | 流程定义Id | bpmn的Id | 流程定义版本 | 任务状态 |
当smartEngine每次实例任务节点开启的时候,会回调当前实现类其时序图,如下所示:
@startuml
'https://plantuml.com/sequence-diagram
autonumber
control SmartEngine服务
collections 流程引擎服务
collections 业务系统
database 流程引擎数据库
SmartEngine服务 --> 流程引擎服务: 节点启动回调TaskAssigneeDispatcher实现类
流程引擎服务 --> 业务系统: 查询当前节点审批人信息
流程引擎服务 --> 流程引擎数据库: 初始化节点审批信息到:审批结果记录表
流程引擎数据库 --> SmartEngine服务: 返回
hide footbox
@enduml
当查询待审批,已完成,拒绝等任务的作展示的时候,可以用此业务表即可实现。
审批详情展示
通过两张业务表实现
- 审批结果记录表
| name | status | bizId | bizType | processDefId | bpmnId | version | taskStatus |
|---|---|---|---|---|---|---|---|
| 流程名称 | 启动禁用 | 业务系统ID | 业务系统类型 | 流程定义Id | bpmn的Id | 流程定义版本 | 任务状态 |
- 节点审批人快照表
| processDefId | version | processInstanceId | taskNmae | empId | empName |
|---|---|---|---|---|---|
| 流程定义Id | 版本 | 实例id | 节点名称 | 工号 | 姓名 |
依赖两张业务表来展示,审批节点详情信息
@startuml
'https://plantuml.com/sequence-diagram
autonumber
collections 业务系统
collections 流程引擎服务
业务系统 --> 流程引擎服务: 查询审批详情
流程引擎服务 --> 流程引擎服务: 查询审批记录表
流程引擎服务 --> 流程引擎服务: 查询快照表
流程引擎服务 --> 流程引擎服务: 组装审批节点展示信息
业务系统 <-- 流程引擎服务: 返回
hide footbox
@enduml