1.引言
2.技术选型
3.Flowable引擎介绍
3.1 基础元素
3.2 API说明
3.3系统数据表介绍
4.流程图建模绘制
4.1 BPMN 2.0协议
4.2 绘制
5.快速开始
5.1 导入starter
5.2 导入建模
5.3 查询流程建模的基本信息
5.4 创建审批工单
5.5 获取待审批工单
5.6 审批工单
5.7 事件监听
6.总结
7.参考资料
当我们在日常工作和业务中需要进行各种审批流程时,可能会面临一系列技术和业务上的挑战。手动处理这些审批流程可能会导致开发成本的增加以及业务复杂度的上升。在这种情况下,引入工作流引擎能够带来很多好处,让我们一起来看看:
通过引入工作流引擎,我们可以克服手动处理审批流程所带来的开发成本高和业务复杂度的挑战。它使得开发人员能够更专注于业务逻辑的实现,快速构建符合实际需求的审批系统。同时,流程图的可视化设计和条件判断的支持,使得业务流程更加清晰、透明,降低了错误发生的概率,提高了审批过程的效率和准确性。这将为企业带来更高的效益和竞争力。
目前市面上比较主流的几个工作流引擎包括Activiti、Flowable、Camunda等,体系较为成熟,使用最为广泛的是activiti,flowable跟activiti本质上没什么区别,是由activiti改版而来,但是两者后续发展路线则不一样,Activiti后续发展重心是在商业版与云上面,并未对核心功能与性能优化上有过多的跟进优化,而flowable当下重心则是针对功能性、扩展性、性能上进行迭代优化。
当然,具体选型还是要看业务实际的需要,目前activiti迭代的方向并不是当下我们业务所需要的,我们更重视性能、扩展性这一块,而flowbale与Camunda之间为什么选择了flowable呢,则是因为flowable社区较为活跃,遇到并处理问题上更为效率,并且面对多节点审批时,异步任务是提升吞吐率的优质之选。
下面我将简单介绍下flowable的一些功能以及模块。
这些是Flowable中的一些基础元素,它们构成了流程引擎的核心。通过这些元素,我们可以灵活地设计和管理复杂的业务流程,使得流程执行更加高效、透明和可控。
在调用开始之前,我们简单说明一下各个api的作用以及应用场景:
启动后会自动生成一些内置的系统表(如果不想自动生成可以通过配置关闭),这里简单介绍一下表的含义:
ACT_HI_*: 历史数据表,例如:
表名 | 含义 |
---|---|
ACT_HI_PROCINST | 历史流程实例表,存储已完成的流程实例信息,包括流程开始时间、结束时间等。 |
ACT_HI_TASKINST | 历史任务实例表,存储已完成的任务实例信息,包括任务开始时间、结束时间、办理人等。 |
ACT_HI_VARIABLE | 历史流程变量表,用于存储在流程运行时设置的变量信息。 |
ACT_RU_*: 运行时的数据表,节点结束时清除,例如:
表名 | 含义 |
---|---|
ACT_RU_EXECUTION | 运行时流程执行实例表,存储当前正在执行的流程实例信息。 |
ACT_RU_TASK | 运行时任务表,存储当前正在执行的任务信息。 |
ACT_RU_VARIABLE | 运行时流程变量表,用于存储在流程运行时设置的变量信息。 |
另外,flowable支持定期清理历史数据,业务侧可以定义一个时间范围,超过时间范围可以认为数据可以被清理,系统内部会自行将数据物理删除,为历史表做瘦身操作。
不过我们业务侧接入的时候,往往业务需要创建几个符合我们具体业务场景的表,例如工单表、任务表虽然框架提供了,但是并没有记录详细的状态,这些状态是我们业务自己定义的,所以需要额外创建业务工单表、审批任务(节点)表、流水表等来进行数据上的冗余来满足实际的业务场景。
我们可以通过可视化后台绘制流程建模,生成BPMN格式的文件,那么BMPN又是什么呢?
BPMN(Business Process Model and Notation)是一种用于建模业务流程的标准化符号和语法,用于描述业务流程的各个环节和活动。BPMN的最新版本是BPMN 2.0,它是业务流程建模领域的国际标准,由OMG(Object Management Group)制定和发布。
BPMN 2.0的主要目标是提供一种统一的标准,使得不同人员和组织能够使用相同的符号和语法来建模和理解业务流程,从而增加流程的可视化和可读性。
它具有以下特点和优势:
我们可以从Flowable官网下载flowable-ui部署到本地来启动可视化后台,可以使用在线的Flowable Modeler来绘制,这里我们使用官网的flowable-ui来绘制。
具体下载启动过程我就不过多赘述了,flowable-ui是基于 springboot2.0开发的,可以直接以下方式来启动:
java -jar flowable-ui.war
启动成功后如图所示:
我们打开建模器应用程序并点击【创建流程】按钮,我们可以给模型进行一个简单的定义.
如图绘制了一个最简单的流程建模
我们也可以给用户任务分配一些基础属性,这里我们配置一个固定用户, 当然这里也支持占位符来动态控制
这样一个最简单的流程建模(不含复杂节点、网关等)就绘制完毕了,绘制完成后会生成一个xml文件,
接下来我会从导入到执行来执行执行一遍该流程。
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.6.0</version>
</dependency>
@Test
public void createConfig() throws Exception{
File file = new File("/Users/xxx/Documents/flowbale/model/testModel.bpmn20.xml");
final FileInputStream fileInputStream = new FileInputStream(file);
final Deployment deploy = repositoryService.createDeployment()
.addInputStream("testModel.bpmn20.xml", fileInputStream).tenantId("类似于业务线的id,可以做数据隔离用")
.name("testModel").deploy();
System.out.println("id=" + deploy.getId());
}
@Test
public void getProcessDefinition() {
final ProcessDefinition rst =
repositoryService.createProcessDefinitionQuery().processDefinitionKey("testModel").orderByProcessDefinitionVersion().desc().list().get(0);
System.out.println(rst.toString());
}
// processDefinitionKey 流程建模的key
// businessId 具有业务属性的id
// variableMap变量的map 结果会存入 ACT_RU_VARIABLE表中,如果审批人传入的是变量就需要再节点执行前将变量传入到系统中
Map<String, Object> variableMap = new HashMap();
variableMap.put("testUserList", Lists.newArrayList("nick","jack","tony"));
String processDefinitionKey = "testModel";
Long businessId = 1L;
String tenantId = "1001";
runtimeService.startProcessInstanceByKeyAndTenantId(processDefinitionKey, businessId + "", variableMap, tenantId);
final List<Task> taskList = taskService.createTaskQuery().taskAssignee("jack").list()
Map<String, Object> variableMap = new HashMap();
// 我们自己定义了一个内部标准化字段,flag代表着节点是通过还是驳回,在互斥网关判断通过驳回的时候会用到。
variableMap.put("flag", 1);
taskService.complete(taskId), variableMap);
我们通过上述用例了解了一个工单是如何操作流转的,但是一个完整的审批服务是应该有消息推送的,当审批节点到达某个人需要提醒他进行审批操作,或者审批工单结束了需要通知发起人,我们应该如何操作呢?Flowable提供了便携的事件监听器,不需要我们额外编写代码来判断是否到达相应的节点,我们这里常用的就是节点创建、节点完成、流程结束等。
Flowable支持的事件有几十种,具体大家请自行去官网参考,下面仅展示“流程结束事件”监听器的代码用例:
package com.zhuanzhuan.workflow_engine.config;
import com.zhuanzhuan.workflow_engine.listener.*;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
import org.flowable.common.engine.api.delegate.event.FlowableEventDispatcher;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
/**
* @author:Live
* @desc:
* @date: 19:55 2023/1/13
*/
@Configuration
@Slf4j
public class FlowableListenerConfiguration implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
private SpringProcessEngineConfiguration configuration;
@Autowired
private ProcessEndListener processEndListener;
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
FlowableEventDispatcher dispatcher = configuration.getEventDispatcher();
dispatcher.addEventListener(processEndListener, FlowableEngineEventType.PROCESS_COMPLETED);
}
}
package com.zhuanzhuan.workflow_engine.listener;
import com.bj58.zhuanzhuan.zzarch.common.util.JsonUtil;
import com.zhuanzhuan.workflow_engine.entity.dto.WorkflowOrderDTO;
import com.zhuanzhuan.workflow_engine.enums.CurrentFlagEnum;
import com.zhuanzhuan.workflow_engine.enums.WorkflowStateEnum;
import com.zhuanzhuan.workflow_engine.mq.MqConstant;
import com.zhuanzhuan.workflow_engine.mq.body.ProcessExchangeMsgBody;
import com.zhuanzhuan.workflow_engine.mq.producer.ProducerHandler;
import com.zhuanzhuan.workflow_engine.service.WorkflowOrderBizService;
import com.zhuanzhuan.workflow_engine.wrapper.FlowableWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
import org.flowable.engine.delegate.event.impl.FlowableEntityEventImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author:Live
* @desc:
* @date: 19:34 2023/1/13
*/
@Component
@Slf4j
public class ProcessEndListener implements FlowableEventListener {
@Override
public void onEvent(FlowableEvent flowableEvent) {
// 流程结束的监听器,发送mq、给发起人发送消息在此进行
}
@Override
public boolean isFailOnException() {
// 抛异常, 不姑息
return true;
}
@Override
public boolean isFireOnTransactionLifecycleEvent() {
// event触发时机跟着 getOnTransaction走
return true;
}
@Override
public String getOnTransaction() {
// 提交事务后触发
return TransactionState.COMMITTED.name();
}
}
以上就是Flowable工作流引擎的简介以及基本用法,我们实际生产建设过程中,还需要基于框架进行拓展开发来满足我们项目的实际需要,例如是否需要引入用户组、权限管理的模块、是否存在性能问题从而引入异步任务的模块、是否需要冗余业务表来满足定制化查询的需求,这些都属于扩展玩法,需要我们根据实际需求按需接入。毕竟没有最好的架构,只有最适合的架构,选择适合自己的才是最重要的。
1.flowable官方文档 https://www.flowable.org/documentation.html
2.技术选型参考 https://www.zhihu.com/question/59274016/answer/2398240513
关于作者
王锐刚,线上回收业务后端开发工程师
想了解更多转转公司的业务实践,欢迎点击关注下方公众号: