小白学流程引擎-FLowable(二) — 从零搭建自己的FLowable服务 — 搭建流程服务-FLowable的新手指南
创始人
2024-02-25 11:12:24
0

一、介绍

纵览Gitee搜索Flowable开源项目,大多都是已开发好的项目,而笔者从零开始搭建属于自己的Flowable引擎,并且是可以拿到生产上使用的。

二、软件架构

Springboot + Flowable + modeler + idm + Mysql
SrpingBoot version:2.7.5
Flowable version:6.3.0
Mysql version:8.0.26
JDK:8

三、SpringBoot整合Flowable

3.1 使用spring initializer快速创建spring Boot项目

步骤:
1,打开idea,创建工程:file -> newproject ,选择spring initializer;
2,然后填写项目命名后,选择JDK8,Maven;
3,选择功能模块,选Web和lombok即可;
4,点Finish,就能够自动创建工程,并能导入相应依赖了;
5,Maven加载依赖后,运行主程序类看是否成功。

3.2 pom.xml文件引入依赖配置

引入Flowable依赖,这里选择Springboot-starter,毕竟是springboot项目。
添加必要的依赖。

org.springframework.bootspring-boot-starter-weborg.projectlomboklomboktrueorg.springframework.bootspring-boot-starter-testtestcom.baomidoumybatis-plus-boot-starter3.0.3com.alibabafastjson1.2.79mysqlmysql-connector-javaruntimeorg.flowableflowable-spring-boot-starter6.3.0

3.3 application.yml配置

在application.yml文件中加入以下配置。

server:port: 8080spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/spider-flowable?charset=utf8mb4&useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf-8username: rootpassword: 12345678mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: trueflowable:#关闭定时任务JOBasync-executor-activate: false#将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。database-schema-update: true

3.4 运行项目

项目启动的时候检查如果数据库对应的表结构没有创建,会帮助我们先创建对应的表结构。到此Springboot整合Flowable就搞定了,
项目启动后,刷新数据库,你会发现多了61张表,都是以ACT为前缀的表名。
知道为什么Flowable自带的数据库的表名为啥是以ACT为前缀吗?
因为Flowable是基于Activiti6衍生出来的版本。

数据库结构如图:
在这里插入图片描述

四、定义流程文件

FLowable流程的运行,其实是用一个满足BPMN格式的XML文件来执行的,至于XML内容格式是怎么样的后续在学习。

在项目中的resources下新建一个processes文件夹,processes目录下的任何BPMN 2.0流程定义都会被自动部署。

1,在processes文件夹下新建holiday-request.bpmn20.xml文件
2,文件内容复制如下:




五、运行项目并测试

咱来测试一下功能,小试牛刀,更多功能在后面文章再细谈。
在test文件夹下新建测试类SpiderFlowableTest,代码如下。

package com.example.spiderFlowable;import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @author xiong.bo* @version 1.0* @date 2022/11/27 10:41 上午*/@SpringBootTest
public class SpiderFlowableTest {@Autowiredprivate RepositoryService repositoryService;@Autowiredprivate RuntimeService runtimeService;@Autowiredprivate TaskService taskService;@Autowiredprivate HistoryService historyService;/*** 模拟-部署流程* 说明:* 流程定义有版本的概念,bpmn文件有改动,需要部署后才生效*/@Testvoid createDeployment() {Deployment deployment = repositoryService.createDeployment().addClasspathResource("processes/holiday-request.bpmn20.xml").deploy();System.out.println(deployment.getId());System.out.println(JSON.toJSONString(deployment));}/*** 获取流程定义*/@Testvoid getProcessDefinition() {ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId("17504").singleResult();System.out.println("definitionId:" + processDefinition.getId());System.out.println("definition:" + JSONUtil.toJsonStr(processDefinition));}/*** 启动流程* 模拟用户发起一个请假流程*/@Testvoid startProcessDefinition() {Map variables = new HashMap<>();variables.put("employee", "李四");variables.put("nrOfHolidays", "4");variables.put("description", "外出请假");//启动流程实例有多个方法,这里调用流程key的方法来启动ProcessInstance holidayProcessInstance = runtimeService.startProcessInstanceByKey("holidayRequest", variables);System.out.println("processInstanceId:" + holidayProcessInstance.getProcessInstanceId());}/*** 获取任务* 用户发起流程后,相关的人员能够查询该任务**/@Testvoid getTask(){List tasks = taskService.createTaskQuery().active().includeProcessVariables()//值为admin是管理员可以查看所有的,测试.taskCandidateOrAssigned("admin").list();System.out.println("You have " + tasks.size() + " tasks:");for (int i = 0; i < tasks.size(); i++) {Task task = tasks.get(i);System.out.println((i + 1) + ") " + "taskId: " + task.getId() + ", taskName: " + task.getName());}}/*** 审批任务* 说明:* 1,变量approved同流程定义文件里面顺序流定义的变量* 2,taskId是上一个获取用户任务的taskId值,也就是要指定哪一个用户任务往下执行*/@Testvoid completeTask(){Map variables = new HashMap<>();variables.put("approved", true);String taskId = "20008";taskService.complete(taskId,variables);}/*** 查看历史任务* 说明:* taskAssignee: 分配人* finished:已完成状态的**/@Testvoid historyTask(){List hisList = historyService.createHistoricActivityInstanceQuery().taskAssignee("admin").finished().list();hisList.stream().forEach(e -> System.out.println(JSONUtil.toJsonStr(e)));}
}

1,部署流程

	 /*** 模拟-部署流程* 说明:* 流程定义有版本的概念,bpmn文件有改动,需要部署后才生效*/@Testvoid createDeployment() {Deployment deployment = repositoryService.createDeployment().addClasspathResource("processes/holiday-request.bpmn20.xml").deploy();System.out.println(deployment.getId());System.out.println(JSON.toJSONString(deployment));}

运行结果:

27501
ps: System.out.println(JSON.toJSONString(deployment));输出内容太多这里不贴上了

2,获取流程定义

	/*** 获取流程定义*/@Testvoid getProcessDefinition() {ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId("17504").singleResult();System.out.println("definitionId:" + processDefinition.getId());System.out.println("definition:" + JSONUtil.toJsonStr(processDefinition));}

运行结果:

definitionId:holidayRequest:5:17506
definition:{"name":"请假流程","key":"holidayRequest","version":5,"category":"http://www.flowable.org/processdef","deploymentId":"17504","resourceName":"processes/holiday-request.bpmn20.xml","tenantId":"","isGraphicalNotationDefined":false,"hasStartFormKey":false,"suspensionState":1,"derivedVersion":0,"id":"holidayRequest:5:17506","revision":1,"isInserted":false,"isUpdated":false,"isDeleted":false,"originalPersistentState":{"suspensionState":1,"category":"http://www.flowable.org/processdef"}}

3,启动流程

	/*** 启动流程* 模拟用户发起一个请假流程*/@Testvoid startProcessDefinition() {Map variables = new HashMap<>();variables.put("employee", "李四");variables.put("nrOfHolidays", "4");variables.put("description", "外出请假");//启动流程实例有多个方法,这里调用流程key的方法来启动ProcessInstance holidayProcessInstance = runtimeService.startProcessInstanceByKey("holidayRequest", variables);System.out.println("processInstanceId:" + holidayProcessInstance.getProcessInstanceId());}

运行结果:

processInstanceId:30001

4,获取用户任务

	/*** 获取任务* 用户发起流程后,相关的人员能够查询该任务**/@Testvoid getTask(){List tasks = taskService.createTaskQuery().active().includeProcessVariables()//值为admin是管理员可以查看所有的,测试.taskCandidateOrAssigned("admin").list();System.out.println("You have " + tasks.size() + " tasks:");for (int i = 0; i < tasks.size(); i++) {Task task = tasks.get(i);System.out.println((i + 1) + ") " + "taskId: " + task.getId() + ", taskName: " + task.getName());}}

运行结果:

You have 4 tasks:
1) taskId: 10008, taskName: 同意或驳回请求
2) taskId: 12508, taskName: 同意或驳回请求
3) taskId: 20008, taskName: 同意或驳回请求
4) taskId: 7508, taskName: 同意或驳回请求

5,审批任务

	/*** 审批任务* 说明:* 1,变量approved同流程定义文件里面顺序流定义的变量* 2,taskId是上一个获取用户任务的taskId值,也就是要指定哪一个用户任务往下执行*/@Testvoid completeTask(){Map variables = new HashMap<>();variables.put("approved", true);String taskId = "20008";taskService.complete(taskId,variables);}

运行结果:
结果回调了 ApprovalSuccessDelegate ,打印出"审批通过了"

6,查看历史任务

	/*** 查看历史任务* 说明:* taskAssignee: 分配人* finished:已完成状态的**/@Testvoid historyTask(){List hisList = historyService.createHistoricActivityInstanceQuery().taskAssignee("admin").finished().list();hisList.stream().forEach(e -> System.out.println(JSONUtil.toJsonStr(e)));}

运行结果:

{"activityId":"approveTask","activityName":"同意或驳回请求","activityType":"userTask","executionId":"20005","assignee":"admin","taskId":"20008","tenantId":"","processInstanceId":"20001","processDefinitionId":"holidayRequest:5:17506","startTime":1669521326282,"endTime":1669521596820,"durationInMillis":270538,"id":"20007","revision":2,"isInserted":false,"isUpdated":false,"isDeleted":false,"originalPersistentState":{"executionId":"20005","durationInMillis":270538,"endTime":1669521596820,"assignee":"admin","taskId":"20008"}}
{"activityId":"approveTask","activityName":"同意或驳回请求","activityType":"userTask","executionId":"30005","assignee":"admin","taskId":"30008","tenantId":"","processInstanceId":"30001","processDefinitionId":"holidayRequest:6:27503","startTime":1669643905412,"endTime":1669644033366,"durationInMillis":127954,"id":"30007","revision":2,"isInserted":false,"isUpdated":false,"isDeleted":false,"originalPersistentState":{"executionId":"30005","durationInMillis":127954,"endTime":1669644033366,"assignee":"admin","taskId":"30008"}}

最基本的完成一个流程的核心功能在上面列举了,先部署流程,再启动流程,再获取任务,再完成某一个任务。

六、总结

其实你会发现,流程引擎并没有那么神秘,它强大的功能,就是通过满足BPM2.0规范的xml文件和数据库进行流转的,后面文章在学习BPM2.0规范和Flowable数据库各个表的大致作用等。

以上代码已放到笔者的Gitee仓库地址:https://gitee.com/xiongbomy/spider-flowable.git
欢迎大家star和fork。
建议大家fork此项目到你个人仓库,方便你测试或者基于此开发属于你的流程引擎,当然,基于此进行二次扩展,再拿到公司当内部系统也是可以的,只要不商用拿去卖钱~

题外话,笔者在公司主要负责公司内部的流程引擎系统的开发,使用的是Flowable,后续会记录学习Flowable的笔记,一是让自己的知识形成体系化,二是让更多想要学习Flowable的同学们得到一点点帮助也好。

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...