一、BPM
Business Process Modeling ,即业务流程建模 , 是业务流程管理的核心方法和工具。 对业务流程进行表述的方式,它是过程分析与重组的重要基础,这种表述方式大大优化了软件开发和运行效率。
业务流程建模包括了流程节点建模、流程内容建模、流程权限建模等三个方面的内容。
Q:为什么要使用BPM?
A:业务流程模型是从业务需求出发的,采用的是图形化的方法描述软件系统的业务流程,它与活动图相比:bpm注重业务流程,让业务用户更容易理解,适合于业务用户使用,而活动图主要描述的是应用程序,适合于软件开发人员使用。
Q:业务流程建模在项目开发中处于哪一个阶段?
A: 如下图:
二、BPMN业务流程建模与标记
BPMN,即业务流程建模与标记(手法),是用于构建BPM业务流程图的一种建模语言标准。它为用户提供一套容易理解的标准符号,用户根据一定标准,运用这些符号形象化描述指定工作流的业务流程。这个业务流程模型示意图即为BPMN图。
BPMN有以下4个基本元素:
流对象(Flow Objects):包括事件、活动、网关,是BPMN中的核心元素;
事件: 一个事件用圆圈来描述,表示一个业务流程期间发生的东西。
活动: 一个活动用圆角矩形表示,是要处理工作的一般术语。
网关: 条件用熟悉的菱形表示,用于控制序列流的分支与合并。
连接对象(Connecting Objects):包括顺序流、消息流、关联;
顺序流: 用一个带实心箭头的实心线表示,用于指定活动执行的顺序。
消息流: 消息流用一条带有开箭头的虚线表示,用于描述两个独立的业务参与者之间发送和接受的消息流动。
关联: 用一根带有线箭头的点线表示关联, 关联用于展示活动的输入和输出。
泳道(Swimlanes):包括池和道两种类型;
池:表示流程中的主要参与者,用来分开不同的组织
道:用于活动按职能或者角色分类
人工信息(Artifacts):包括数据对象、组、注释。
数据对象: 数据对象是一个显示活动是如何需要或产生数据的。它们通过关联与活动连接起来。
组: 组用一个虚线的圆角矩形表示,用于记录或分析的目的,但不影响顺序流。
注释: 注释是建模者为BPMN图的读者提供附加文本信息的一个机制。
BPMN符号一览表:https://www.edrawsoft.cn/bpmn-symbols/
Q:为什么要利用BPMN建模?
A:1. BPMN为业务相关者提供易于理解的标准标记法(符号),其中业务相关者包括创造与梳理流程的业务分析师、负责实施流程的技术开发者、以及业务管理者和监督人。用标准符号对业务流程进行建模描述的BPMN,扮演着促进这些人员在业务流程设计和实施之间沟通交流的角色;2. BPMN是从许多已经存在的建模标记中吸收再生的,形成的一套标准的标记语言。它的出现,规范了建模标记的标准,改善了因为存在不同的业务建模工具和标记而导致的交流理解的混乱情况;3. BPMN通过解决在业务流程管理上存在的问题,提高业务实施与管理的效率,最终达到促进企业的管理发展的目的。
Q:可以用什么工具进行BPMN建模?
A: Visio、亿图图示BPMN图软件、Process On流程图设计器
以点外卖为例
对外卖进行业务流程建模与标记:
- 顾客在外面系统选择一份Pizza,然后下单,经过事件网关接下来可以执行两种操作,一是经过了一定时间之后可以催促店家,二是当外卖抵达时支付;
- 店员接到订单之后通过并行网关,让厨师去做Pizza,当面对顾客催单的情况,跟顾客解释,让顾客冷静下来;
- 厨师制做Pizza;
- 外卖小哥送外卖,发送消息外卖已经在路上了,当外卖送到时收钱,最后结束。
三、认识Flowable
Flowable的定义
Flowable是一个使用Java编写的轻量级业务流程引擎。Flowable流程引擎可用于部署BPMN 2.0流程定义(用于定义流程的行业XML标准),创建这些流程定义的流程实例,进行查询,访问运行中或历史的流程实例与相关数据,等等 。
所有使用Flowable方法的共同点是核心引擎。
核心引擎是一组服务的集合,并提供管理与执行业务流程的API。
初步了解Flowable的API
使用ProcessEngine,可以获得各种提供工作流/BPM方法的服务。
RepositoryService 服务提供了管理与控制部署(deployments)
与流程定义(process definitions)
的操作。
RuntimeService 用于启动流程定义的新流程实例,用于查询流程实例与执行(Execution)。
TaskService 是需要人类用户操作的任务的核心。
IdentityService 用于管理(创建,更新,删除,查询……)组与用户。
如何部署流程定义
Flowable引擎需要流程定义为BPMN 2.0格式,这是一个业界广泛接受的XML标准。 BPMN是一个广泛接受与支持的,展现流程的注记方法 。示例一个xml流程定义文件:
有了流程定义文件之后,流程引擎会将XML文件存储在数据库中,这样可以在需要的时候获取它。流程定义转换为内部的、可执行的对象模型,这样使用它就可以启动流程实例。
为了比较好地理解xml流程定义文件,可以将它转化为流程定义图:
流程
定义流程文件:建立文件名以.bpmn.xml或者.bpmn结尾的流程文件,里边应用BPMN的标签即可。
接下来先认识一下BPMN的元素
definitions,是根节点
process节点:
id属性,将映射为Flowable
ProcessDefinition
对象的key参数。 可以使用RuntimeService
中的startProcessInstanceByKey
方法,使用id
来启动这个流程定义的新流程实例。name属性(可选)将映射为
ProcessDefinition
的name参数 。
process节点下有:
<documentation> 流程名字
<startEvent> 开始事件,属性有id,name。
<endEvent> 结束事件,属性有id,name。
<userTask> 用户任务,属性有id,name。
<exclusiveGateway> 排他网关,属性有id。
<sequenceFlow> 用于定义用户顺序流,属性有id,name,sourceRef,TargetRef。
<bpmndi:BPMNDiagram> 用于绘制流程图。可以看到有定义流程图的属性。
事件
定义:流程生命周期中发生的事情 ,在流程定义图中用圆圈表示。
分类:1. 捕获: 当流程执行到达这个事件时,会等待直到触发器动作。
2. 抛出: 当流程执行到达这个事件时,会触发一个触发器。
定义事件-->定时器事件、错误事件、信号事件、消息事件
启动事件-->空启动、定时器启动、消息启动、错误启动
结束事件-->空结束、错误结束、终止结束、取消结束
边界事件-->定时器边界、错误边界、信号边界、补偿边界
捕获中间事件-->定时器捕获、信号捕获、消息捕获
抛出中间事件-->空抛出、信号抛出、补偿抛出
事件的种类繁多,此处就不一一介绍了,详细请参考Flowable BPMN用户手册:
https://tkjohn.github.io/flowable-userguide/#bpmnTask
顺序流
顺序流是流程中两个元素间的连接器。在流程执行过程中,一个元素被访问后,会沿着其所有出口顺序流继续执行。 顺序流在流程定义文件中对应的是<sequenceFlow>节点, 需要有流程唯一的id,并引用存在的源与目标元素。
顺序流分为条件顺序流和默认顺序流。
条件顺序流:用<conditionExpression>时标注。当离开BPMN 2.0活动时,默认行为是计算其每个出口顺序流上的条件。当条件计算为true时,选择该出口顺序流。如果该方法选择了多条顺序流,则会生成多个执行,流程会以并行方式继续。
默认顺序流:有活动的default属性定义。当天件顺序流都不满足时才会选择默认顺序流。
网关
用于控制执行的流向(排他、并行、包容),网关用其中带有图标的菱形表示。
排他网关
当执行到达这个网关时,会按照所有出口顺序流定义的顺序对它们进行计算。选择第一个条件计算为true的顺序流(当没有设置条件时,认为顺序流为true)继续流程。 (上面那张图就是排他网关的运用)
并行网关
网关也可以建模流程中的并行执行。在流程模型中引入并行的最简单的网关,就是并行网关。它可以将执行分支(fork)为多条路径,也可以合并多条入口路径的执行。
包容网关
排他网关与并行网关的组合。 与排他网关一样,可以在包容网关的出口顺序流上定义条件,包容网关会计算条件。然而主要的区别是,包容网关与并行网关一样,可以同时选择多于一条出口顺序流。
任务
用户任务用于对需要人工执行的任务进行建模。当流程执行到达用户任务时,会为指派至该任务的用户或组的任务列表创建一个新任务。
用户任务在XML中如下定义:
通过TaskService获取特定用户办理的任务:
更多操作(例如:用户指派)需查看Flowable BPMN用户手册:
https://tkjohn.github.io/flowable-userguide/#bpmnTask
附录
下面通过一个demo,可以更好地理解流程定义文件。
<process id="Expense" name="ExpenseProcess" isExecutable="true">
<documentation>报销流程</documentation>
<startEvent id="start" name="开始"></startEvent>
<userTask id="fillTask" name="出差报销" flowable:assignee="${taskUser}">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler">
<![CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
</userTask>
<exclusiveGateway id="judgeTask"></exclusiveGateway>
<userTask id="directorTak" name="经理审批">
<extensionElements>
<flowable:taskListener event="create" class="com.haiyang.flowablespringboot.handler.ManagerTaskHandler"></flowable:taskListener>
</extensionElements>
</userTask>
<userTask id="bossTask" name="老板审批">
<extensionElements>
<flowable:taskListener event="create" class="com.haiyang.flowablespringboot.handler.BossTaskHandler"></flowable:taskListener>
</extensionElements>
</userTask>
<sequenceFlow id="directorNotPassFlow" name="驳回" sourceRef="directorTak" targetRef="fillTask">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="bossNotPassFlow" name="驳回" sourceRef="bossTask" targetRef="fillTask">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow1" sourceRef="start" targetRef="fillTask"></sequenceFlow>
<sequenceFlow id="flow2" sourceRef="fillTask" targetRef="judgeTask"></sequenceFlow>
<sequenceFlow id="judgeMore" name="大于500元" sourceRef="judgeTask" targetRef="bossTask">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${money > 500}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="judgeLess" name="小于500元" sourceRef="judgeTask" targetRef="directorTak">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${money <= 500}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="bossPassFlow" name="通过" sourceRef="bossTask" targetRef="end">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="directorPassFlow" name="通过" sourceRef="directorTak" targetRef="end">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
</sequenceFlow>
<endEvent id="end" name="结束"></endEvent>
</process>
对应的流程解读: